diff options
Diffstat (limited to 'cli/js')
130 files changed, 0 insertions, 23439 deletions
diff --git a/cli/js/buffer.ts b/cli/js/buffer.ts deleted file mode 100644 index 4f88ff625..000000000 --- a/cli/js/buffer.ts +++ /dev/null @@ -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)); - } -} diff --git a/cli/js/build.ts b/cli/js/build.ts deleted file mode 100644 index 676e056eb..000000000 --- a/cli/js/build.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/colors.ts b/cli/js/colors.ts deleted file mode 100644 index b98611bfa..000000000 --- a/cli/js/colors.ts +++ /dev/null @@ -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, ""); -} diff --git a/cli/js/compiler.ts b/cli/js/compiler.ts deleted file mode 100644 index 7a56fe209..000000000 --- a/cli/js/compiler.ts +++ /dev/null @@ -1,1838 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// TODO(ry) Combine this implementation with //deno_typescript/compiler_main.js - -// This module is the entry point for "compiler" isolate, ie. the one -// that is created when Deno needs to compile TS/WASM to JS. -// -// It provides a single functions that should be called by Rust: -// - `bootstrapTsCompilerRuntime` -// This functions must be called when creating isolate -// to properly setup runtime. - -// NOTE: this import has side effects! -import "./ts_global.d.ts"; - -import { bold, cyan, yellow } from "./colors.ts"; -import type { CompilerOptions } from "./compiler_options.ts"; -import type { Diagnostic, DiagnosticItem } from "./diagnostics.ts"; -import { fromTypeScriptDiagnostic } from "./diagnostics_util.ts"; -import type { TranspileOnlyResult } from "./ops/runtime_compiler.ts"; -import { bootstrapWorkerRuntime } from "./runtime_worker.ts"; -import { assert, log, notImplemented } from "./util.ts"; -import { core } from "./core.ts"; - -// We really don't want to depend on JSON dispatch during snapshotting, so -// this op exchanges strings with Rust as raw byte arrays. -function getAsset(name: string): string { - const opId = core.ops()["op_fetch_asset"]; - const sourceCodeBytes = core.dispatch(opId, core.encode(name)); - return core.decode(sourceCodeBytes!); -} - -// Constants used by `normalizeString` and `resolvePath` -const CHAR_DOT = 46; /* . */ -const CHAR_FORWARD_SLASH = 47; /* / */ -// Using incremental compile APIs requires that all -// paths must be either relative or absolute. Since -// analysis in Rust operates on fully resolved URLs, -// it makes sense to use the same scheme here. -const ASSETS = "asset://"; -const OUT_DIR = "deno://"; -// This constant is passed to compiler settings when -// doing incremental compiles. Contents of this -// file are passed back to Rust and saved to $DENO_DIR. -const TS_BUILD_INFO = "cache:///tsbuildinfo.json"; - -// TODO(Bartlomieju): this check should be done in Rust -const IGNORED_COMPILER_OPTIONS: readonly string[] = [ - "allowSyntheticDefaultImports", - "allowUmdGlobalAccess", - "assumeChangesOnlyAffectDirectDependencies", - "baseUrl", - "build", - "composite", - "declaration", - "declarationDir", - "declarationMap", - "diagnostics", - "downlevelIteration", - "emitBOM", - "emitDeclarationOnly", - "esModuleInterop", - "extendedDiagnostics", - "forceConsistentCasingInFileNames", - "generateCpuProfile", - "help", - "importHelpers", - "incremental", - "inlineSourceMap", - "inlineSources", - "init", - "listEmittedFiles", - "listFiles", - "mapRoot", - "maxNodeModuleJsDepth", - "module", - "moduleResolution", - "newLine", - "noEmit", - "noEmitHelpers", - "noEmitOnError", - "noLib", - "noResolve", - "out", - "outDir", - "outFile", - "paths", - "preserveSymlinks", - "preserveWatchOutput", - "pretty", - "rootDir", - "rootDirs", - "showConfig", - "skipDefaultLibCheck", - "skipLibCheck", - "sourceMap", - "sourceRoot", - "stripInternal", - "target", - "traceResolution", - "tsBuildInfoFile", - "types", - "typeRoots", - "version", - "watch", -]; - -const DEFAULT_BUNDLER_OPTIONS: ts.CompilerOptions = { - allowJs: true, - inlineSourceMap: false, - module: ts.ModuleKind.System, - outDir: undefined, - outFile: `${OUT_DIR}/bundle.js`, - // disabled until we have effective way to modify source maps - sourceMap: false, -}; - -const DEFAULT_INCREMENTAL_COMPILE_OPTIONS: ts.CompilerOptions = { - allowJs: false, - allowNonTsExtensions: true, - checkJs: false, - esModuleInterop: true, - incremental: true, - inlineSourceMap: true, - jsx: ts.JsxEmit.React, - module: ts.ModuleKind.ESNext, - outDir: OUT_DIR, - resolveJsonModule: true, - sourceMap: false, - strict: true, - stripComments: true, - target: ts.ScriptTarget.ESNext, - tsBuildInfoFile: TS_BUILD_INFO, -}; - -const DEFAULT_COMPILE_OPTIONS: ts.CompilerOptions = { - allowJs: false, - allowNonTsExtensions: true, - checkJs: false, - esModuleInterop: true, - jsx: ts.JsxEmit.React, - module: ts.ModuleKind.ESNext, - outDir: OUT_DIR, - sourceMap: true, - strict: true, - removeComments: true, - target: ts.ScriptTarget.ESNext, -}; - -const DEFAULT_TRANSPILE_OPTIONS: ts.CompilerOptions = { - esModuleInterop: true, - inlineSourceMap: true, - jsx: ts.JsxEmit.React, - module: ts.ModuleKind.ESNext, - removeComments: true, - target: ts.ScriptTarget.ESNext, -}; - -const DEFAULT_RUNTIME_COMPILE_OPTIONS: ts.CompilerOptions = { - outDir: undefined, -}; - -const DEFAULT_RUNTIME_TRANSPILE_OPTIONS: ts.CompilerOptions = { - esModuleInterop: true, - module: ts.ModuleKind.ESNext, - sourceMap: true, - scriptComments: true, - target: ts.ScriptTarget.ESNext, -}; - -enum CompilerHostTarget { - Main = "main", - Runtime = "runtime", - Worker = "worker", -} - -interface CompilerHostOptions { - bundle?: boolean; - target: CompilerHostTarget; - unstable?: boolean; - writeFile: WriteFileCallback; - incremental?: boolean; -} - -type IncrementalCompilerHostOptions = - & Omit< - CompilerHostOptions, - "incremental" - > - & { - rootNames?: string[]; - buildInfo?: string; - }; - -interface HostConfigureResponse { - ignoredOptions?: string[]; - diagnostics?: ts.Diagnostic[]; -} - -interface ConfigureResponse extends HostConfigureResponse { - options: ts.CompilerOptions; -} - -// Warning! The values in this enum are duplicated in `cli/msg.rs` -// Update carefully! -enum MediaType { - JavaScript = 0, - JSX = 1, - TypeScript = 2, - TSX = 3, - Json = 4, - Wasm = 5, - Unknown = 6, -} - -interface SourceFileJson { - url: string; - filename: string; - mediaType: MediaType; - sourceCode: string; - versionHash: string; -} - -function getExtension(fileName: string, mediaType: MediaType): ts.Extension { - switch (mediaType) { - case MediaType.JavaScript: - return ts.Extension.Js; - case MediaType.JSX: - return ts.Extension.Jsx; - case MediaType.TypeScript: - return fileName.endsWith(".d.ts") ? ts.Extension.Dts : ts.Extension.Ts; - case MediaType.TSX: - return ts.Extension.Tsx; - case MediaType.Wasm: - // Custom marker for Wasm type. - return ts.Extension.Js; - case MediaType.Unknown: - default: - throw TypeError( - `Cannot resolve extension for "${fileName}" with mediaType "${ - MediaType[mediaType] - }".`, - ); - } -} - -/** A global cache of module source files that have been loaded. - * This cache will be rewritten to be populated on compiler startup - * with files provided from Rust in request message. - */ -const SOURCE_FILE_CACHE: Map<string, SourceFile> = new Map(); -/** A map of maps which cache resolved specifier for each import in a file. - * This cache is used so `resolveModuleNames` ops is called as few times - * as possible. - * - * First map's key is "referrer" URL ("file://a/b/c/mod.ts") - * Second map's key is "raw" import specifier ("./foo.ts") - * Second map's value is resolved import URL ("file:///a/b/c/foo.ts") - */ -const RESOLVED_SPECIFIER_CACHE: Map<string, Map<string, string>> = new Map(); - -function configure( - defaultOptions: ts.CompilerOptions, - source: string, - path: string, - cwd: string, -): ConfigureResponse { - const { config, error } = ts.parseConfigFileTextToJson(path, source); - if (error) { - return { diagnostics: [error], options: defaultOptions }; - } - const { options, errors } = ts.convertCompilerOptionsFromJson( - config.compilerOptions, - cwd, - ); - const ignoredOptions: string[] = []; - for (const key of Object.keys(options)) { - if ( - IGNORED_COMPILER_OPTIONS.includes(key) && - (!(key in defaultOptions) || options[key] !== defaultOptions[key]) - ) { - ignoredOptions.push(key); - delete options[key]; - } - } - return { - options: Object.assign({}, defaultOptions, options), - ignoredOptions: ignoredOptions.length ? ignoredOptions : undefined, - diagnostics: errors.length ? errors : undefined, - }; -} - -class SourceFile { - extension!: ts.Extension; - filename!: string; - - mediaType!: MediaType; - processed = false; - sourceCode?: string; - tsSourceFile?: ts.SourceFile; - versionHash!: string; - url!: string; - - constructor(json: SourceFileJson) { - Object.assign(this, json); - this.extension = getExtension(this.url, this.mediaType); - } - - static addToCache(json: SourceFileJson): SourceFile { - if (SOURCE_FILE_CACHE.has(json.url)) { - throw new TypeError("SourceFile already exists"); - } - const sf = new SourceFile(json); - SOURCE_FILE_CACHE.set(sf.url, sf); - return sf; - } - - static getCached(url: string): SourceFile | undefined { - return SOURCE_FILE_CACHE.get(url); - } - - static cacheResolvedUrl( - resolvedUrl: string, - rawModuleSpecifier: string, - containingFile?: string, - ): void { - containingFile = containingFile || ""; - let innerCache = RESOLVED_SPECIFIER_CACHE.get(containingFile); - if (!innerCache) { - innerCache = new Map(); - RESOLVED_SPECIFIER_CACHE.set(containingFile, innerCache); - } - innerCache.set(rawModuleSpecifier, resolvedUrl); - } - - static getResolvedUrl( - moduleSpecifier: string, - containingFile: string, - ): string | undefined { - const containingCache = RESOLVED_SPECIFIER_CACHE.get(containingFile); - if (containingCache) { - return containingCache.get(moduleSpecifier); - } - return undefined; - } -} - -function getAssetInternal(filename: string): SourceFile { - const lastSegment = filename.split("/").pop()!; - const url = ts.libMap.has(lastSegment) - ? ts.libMap.get(lastSegment)! - : lastSegment; - const sourceFile = SourceFile.getCached(url); - if (sourceFile) { - return sourceFile; - } - const name = url.includes(".") ? url : `${url}.d.ts`; - const sourceCode = getAsset(name); - return SourceFile.addToCache({ - url, - filename: `${ASSETS}/${name}`, - mediaType: MediaType.TypeScript, - versionHash: "1", - sourceCode, - }); -} - -class Host implements ts.CompilerHost { - #options = DEFAULT_COMPILE_OPTIONS; - readonly #target: CompilerHostTarget; - readonly #writeFile: WriteFileCallback; - /* Deno specific APIs */ - - constructor({ - bundle = false, - incremental = false, - target, - unstable, - writeFile, - }: CompilerHostOptions) { - this.#target = target; - this.#writeFile = writeFile; - if (bundle) { - // options we need to change when we are generating a bundle - Object.assign(this.#options, DEFAULT_BUNDLER_OPTIONS); - } else if (incremental) { - Object.assign(this.#options, DEFAULT_INCREMENTAL_COMPILE_OPTIONS); - } - if (unstable) { - this.#options.lib = [ - target === CompilerHostTarget.Worker - ? "lib.deno.worker.d.ts" - : "lib.deno.window.d.ts", - "lib.deno.unstable.d.ts", - ]; - } - } - - get options(): ts.CompilerOptions { - return this.#options; - } - - configure( - cwd: string, - path: string, - configurationText: string, - ): HostConfigureResponse { - log("compiler::host.configure", path); - const { options, ...result } = configure( - this.#options, - configurationText, - path, - cwd, - ); - this.#options = options; - return result; - } - - mergeOptions(...options: ts.CompilerOptions[]): ts.CompilerOptions { - Object.assign(this.#options, ...options); - return Object.assign({}, this.#options); - } - - /* TypeScript CompilerHost APIs */ - - fileExists(_fileName: string): boolean { - return notImplemented(); - } - - getCanonicalFileName(fileName: string): string { - return fileName; - } - - getCompilationSettings(): ts.CompilerOptions { - log("compiler::host.getCompilationSettings()"); - return this.#options; - } - - getCurrentDirectory(): string { - return ""; - } - - getDefaultLibFileName(_options: ts.CompilerOptions): string { - log("compiler::host.getDefaultLibFileName()"); - switch (this.#target) { - case CompilerHostTarget.Main: - case CompilerHostTarget.Runtime: - return `${ASSETS}/lib.deno.window.d.ts`; - case CompilerHostTarget.Worker: - return `${ASSETS}/lib.deno.worker.d.ts`; - } - } - - getNewLine(): string { - return "\n"; - } - - getSourceFile( - fileName: string, - languageVersion: ts.ScriptTarget, - onError?: (message: string) => void, - shouldCreateNewSourceFile?: boolean, - ): ts.SourceFile | undefined { - log("compiler::host.getSourceFile", fileName); - try { - assert(!shouldCreateNewSourceFile); - const sourceFile = fileName.startsWith(ASSETS) - ? getAssetInternal(fileName) - : SourceFile.getCached(fileName); - assert(sourceFile != null); - if (!sourceFile.tsSourceFile) { - assert(sourceFile.sourceCode != null); - const tsSourceFileName = fileName.startsWith(ASSETS) - ? sourceFile.filename - : fileName; - - sourceFile.tsSourceFile = ts.createSourceFile( - tsSourceFileName, - sourceFile.sourceCode, - languageVersion, - ); - sourceFile.tsSourceFile.version = sourceFile.versionHash; - delete sourceFile.sourceCode; - } - return sourceFile.tsSourceFile; - } catch (e) { - if (onError) { - onError(String(e)); - } else { - throw e; - } - return undefined; - } - } - - readFile(_fileName: string): string | undefined { - return notImplemented(); - } - - resolveModuleNames( - moduleNames: string[], - containingFile: string, - ): Array<ts.ResolvedModuleFull | undefined> { - log("compiler::host.resolveModuleNames", { - moduleNames, - containingFile, - }); - const resolved = moduleNames.map((specifier) => { - const maybeUrl = SourceFile.getResolvedUrl(specifier, containingFile); - - log("compiler::host.resolveModuleNames maybeUrl", { - specifier, - maybeUrl, - }); - - let sourceFile: SourceFile | undefined = undefined; - - if (specifier.startsWith(ASSETS)) { - sourceFile = getAssetInternal(specifier); - } else if (typeof maybeUrl !== "undefined") { - sourceFile = SourceFile.getCached(maybeUrl); - } - - if (!sourceFile) { - return undefined; - } - - return { - resolvedFileName: sourceFile.url, - isExternalLibraryImport: specifier.startsWith(ASSETS), - extension: sourceFile.extension, - }; - }); - log(resolved); - return resolved; - } - - useCaseSensitiveFileNames(): boolean { - return true; - } - - writeFile( - fileName: string, - data: string, - _writeByteOrderMark: boolean, - _onError?: (message: string) => void, - sourceFiles?: readonly ts.SourceFile[], - ): void { - log("compiler::host.writeFile", fileName); - this.#writeFile(fileName, data, sourceFiles); - } -} - -class IncrementalCompileHost extends Host { - readonly #buildInfo?: string; - - constructor(options: IncrementalCompilerHostOptions) { - super({ ...options, incremental: true }); - const { buildInfo } = options; - if (buildInfo) { - this.#buildInfo = buildInfo; - } - } - - readFile(fileName: string): string | undefined { - if (fileName == TS_BUILD_INFO) { - return this.#buildInfo; - } - throw new Error("unreachable"); - } -} - -// NOTE: target doesn't really matter here, -// this is in fact a mock host created just to -// load all type definitions and snapshot them. -let SNAPSHOT_HOST: Host | undefined = new Host({ - target: CompilerHostTarget.Main, - writeFile(): void {}, -}); -const SNAPSHOT_COMPILER_OPTIONS = SNAPSHOT_HOST.getCompilationSettings(); - -// This is a hacky way of adding our libs to the libs available in TypeScript() -// as these are internal APIs of TypeScript which maintain valid libs -ts.libs.push("deno.ns", "deno.window", "deno.worker", "deno.shared_globals"); -ts.libMap.set("deno.ns", "lib.deno.ns.d.ts"); -ts.libMap.set("deno.window", "lib.deno.window.d.ts"); -ts.libMap.set("deno.worker", "lib.deno.worker.d.ts"); -ts.libMap.set("deno.shared_globals", "lib.deno.shared_globals.d.ts"); -ts.libMap.set("deno.unstable", "lib.deno.unstable.d.ts"); - -// this pre-populates the cache at snapshot time of our library files, so they -// are available in the future when needed. -SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.ns.d.ts`, - ts.ScriptTarget.ESNext, -); -SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.window.d.ts`, - ts.ScriptTarget.ESNext, -); -SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.worker.d.ts`, - ts.ScriptTarget.ESNext, -); -SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.shared_globals.d.ts`, - ts.ScriptTarget.ESNext, -); -SNAPSHOT_HOST.getSourceFile( - `${ASSETS}/lib.deno.unstable.d.ts`, - ts.ScriptTarget.ESNext, -); - -// We never use this program; it's only created -// during snapshotting to hydrate and populate -// source file cache with lib declaration files. -const _TS_SNAPSHOT_PROGRAM = ts.createProgram({ - rootNames: [`${ASSETS}/bootstrap.ts`], - options: SNAPSHOT_COMPILER_OPTIONS, - host: SNAPSHOT_HOST, -}); - -// Derference the snapshot host so it can be GCed -SNAPSHOT_HOST = undefined; - -// This function is called only during snapshotting process -const SYSTEM_LOADER = getAsset("system_loader.js"); -const SYSTEM_LOADER_ES5 = getAsset("system_loader_es5.js"); - -function buildLocalSourceFileCache( - sourceFileMap: Record<string, SourceFileMapEntry>, -): void { - for (const entry of Object.values(sourceFileMap)) { - assert(entry.sourceCode.length > 0); - SourceFile.addToCache({ - url: entry.url, - filename: entry.url, - mediaType: entry.mediaType, - sourceCode: entry.sourceCode, - versionHash: entry.versionHash, - }); - - for (const importDesc of entry.imports) { - let mappedUrl = importDesc.resolvedSpecifier; - const importedFile = sourceFileMap[importDesc.resolvedSpecifier]; - assert(importedFile); - const isJsOrJsx = importedFile.mediaType === MediaType.JavaScript || - importedFile.mediaType === MediaType.JSX; - // If JS or JSX perform substitution for types if available - if (isJsOrJsx) { - if (importedFile.typeHeaders.length > 0) { - const typeHeaders = importedFile.typeHeaders[0]; - mappedUrl = typeHeaders.resolvedSpecifier; - } else if (importDesc.resolvedTypeDirective) { - mappedUrl = importDesc.resolvedTypeDirective; - } else if (importedFile.typesDirectives.length > 0) { - const typeDirective = importedFile.typesDirectives[0]; - mappedUrl = typeDirective.resolvedSpecifier; - } - } - - mappedUrl = mappedUrl.replace("memory://", ""); - SourceFile.cacheResolvedUrl(mappedUrl, importDesc.specifier, entry.url); - } - for (const fileRef of entry.referencedFiles) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier.replace("memory://", ""), - fileRef.specifier, - entry.url, - ); - } - for (const fileRef of entry.libDirectives) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier.replace("memory://", ""), - fileRef.specifier, - entry.url, - ); - } - } -} - -function buildSourceFileCache( - sourceFileMap: Record<string, SourceFileMapEntry>, -): void { - for (const entry of Object.values(sourceFileMap)) { - SourceFile.addToCache({ - url: entry.url, - filename: entry.url, - mediaType: entry.mediaType, - sourceCode: entry.sourceCode, - versionHash: entry.versionHash, - }); - - for (const importDesc of entry.imports) { - let mappedUrl = importDesc.resolvedSpecifier; - const importedFile = sourceFileMap[importDesc.resolvedSpecifier]; - // IMPORTANT: due to HTTP redirects we might end up in situation - // where URL points to a file with completely different URL. - // In that case we take value of `redirect` field and cache - // resolved specifier pointing to the value of the redirect. - // It's not very elegant solution and should be rethinked. - assert(importedFile); - if (importedFile.redirect) { - mappedUrl = importedFile.redirect; - } - const isJsOrJsx = importedFile.mediaType === MediaType.JavaScript || - importedFile.mediaType === MediaType.JSX; - // If JS or JSX perform substitution for types if available - if (isJsOrJsx) { - if (importedFile.typeHeaders.length > 0) { - const typeHeaders = importedFile.typeHeaders[0]; - mappedUrl = typeHeaders.resolvedSpecifier; - } else if (importDesc.resolvedTypeDirective) { - mappedUrl = importDesc.resolvedTypeDirective; - } else if (importedFile.typesDirectives.length > 0) { - const typeDirective = importedFile.typesDirectives[0]; - mappedUrl = typeDirective.resolvedSpecifier; - } - } - - SourceFile.cacheResolvedUrl(mappedUrl, importDesc.specifier, entry.url); - } - for (const fileRef of entry.referencedFiles) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier, - fileRef.specifier, - entry.url, - ); - } - for (const fileRef of entry.libDirectives) { - SourceFile.cacheResolvedUrl( - fileRef.resolvedSpecifier, - fileRef.specifier, - entry.url, - ); - } - } -} - -interface EmittedSource { - // original filename - filename: string; - // compiled contents - contents: string; -} - -type WriteFileCallback = ( - fileName: string, - data: string, - sourceFiles?: readonly ts.SourceFile[], -) => void; - -interface CompileWriteFileState { - rootNames: string[]; - emitMap: Record<string, EmittedSource>; - buildInfo?: string; -} - -interface BundleWriteFileState { - host?: Host; - bundleOutput: undefined | string; - rootNames: string[]; -} - -// Warning! The values in this enum are duplicated in `cli/msg.rs` -// Update carefully! -enum CompilerRequestType { - Compile = 0, - Transpile = 1, - Bundle = 2, - RuntimeCompile = 3, - RuntimeBundle = 4, - RuntimeTranspile = 5, -} - -function createBundleWriteFile(state: BundleWriteFileState): WriteFileCallback { - return function writeFile( - _fileName: string, - data: string, - sourceFiles?: readonly ts.SourceFile[], - ): void { - assert(sourceFiles != null); - assert(state.host); - // we only support single root names for bundles - assert(state.rootNames.length === 1); - state.bundleOutput = buildBundle( - state.rootNames[0], - data, - sourceFiles, - state.host.options.target ?? ts.ScriptTarget.ESNext, - ); - }; -} - -function createCompileWriteFile( - state: CompileWriteFileState, -): WriteFileCallback { - return function writeFile( - fileName: string, - data: string, - sourceFiles?: readonly ts.SourceFile[], - ): void { - const isBuildInfo = fileName === TS_BUILD_INFO; - - if (isBuildInfo) { - assert(isBuildInfo); - state.buildInfo = data; - return; - } - - assert(sourceFiles); - assert(sourceFiles.length === 1); - state.emitMap[fileName] = { - filename: sourceFiles[0].fileName, - contents: data, - }; - }; -} - -function createRuntimeCompileWriteFile( - state: CompileWriteFileState, -): WriteFileCallback { - return function writeFile( - fileName: string, - data: string, - sourceFiles?: readonly ts.SourceFile[], - ): void { - assert(sourceFiles); - assert(sourceFiles.length === 1); - state.emitMap[fileName] = { - filename: sourceFiles[0].fileName, - contents: data, - }; - }; -} -interface ConvertCompilerOptionsResult { - files?: string[]; - options: ts.CompilerOptions; -} - -function convertCompilerOptions(str: string): ConvertCompilerOptionsResult { - const options: CompilerOptions = JSON.parse(str); - const out: Record<string, unknown> = {}; - const keys = Object.keys(options) as Array<keyof CompilerOptions>; - const files: string[] = []; - for (const key of keys) { - switch (key) { - case "jsx": - const value = options[key]; - if (value === "preserve") { - out[key] = ts.JsxEmit.Preserve; - } else if (value === "react") { - out[key] = ts.JsxEmit.React; - } else { - out[key] = ts.JsxEmit.ReactNative; - } - break; - case "module": - switch (options[key]) { - case "amd": - out[key] = ts.ModuleKind.AMD; - break; - case "commonjs": - out[key] = ts.ModuleKind.CommonJS; - break; - case "es2015": - case "es6": - out[key] = ts.ModuleKind.ES2015; - break; - case "esnext": - out[key] = ts.ModuleKind.ESNext; - break; - case "none": - out[key] = ts.ModuleKind.None; - break; - case "system": - out[key] = ts.ModuleKind.System; - break; - case "umd": - out[key] = ts.ModuleKind.UMD; - break; - default: - throw new TypeError("Unexpected module type"); - } - break; - case "target": - switch (options[key]) { - case "es3": - out[key] = ts.ScriptTarget.ES3; - break; - case "es5": - out[key] = ts.ScriptTarget.ES5; - break; - case "es6": - case "es2015": - out[key] = ts.ScriptTarget.ES2015; - break; - case "es2016": - out[key] = ts.ScriptTarget.ES2016; - break; - case "es2017": - out[key] = ts.ScriptTarget.ES2017; - break; - case "es2018": - out[key] = ts.ScriptTarget.ES2018; - break; - case "es2019": - out[key] = ts.ScriptTarget.ES2019; - break; - case "es2020": - out[key] = ts.ScriptTarget.ES2020; - break; - case "esnext": - out[key] = ts.ScriptTarget.ESNext; - break; - default: - throw new TypeError("Unexpected emit target."); - } - break; - case "types": - const types = options[key]; - assert(types); - files.push(...types); - break; - default: - out[key] = options[key]; - } - } - return { - options: out as ts.CompilerOptions, - files: files.length ? files : undefined, - }; -} - -const ignoredDiagnostics = [ - // TS2306: File 'file:///Users/rld/src/deno/cli/tests/subdir/amd_like.js' is - // not a module. - 2306, - // TS1375: 'await' expressions are only allowed at the top level of a file - // when that file is a module, but this file has no imports or exports. - // Consider adding an empty 'export {}' to make this file a module. - 1375, - // TS1103: 'for-await-of' statement is only allowed within an async function - // or async generator. - 1103, - // TS2691: An import path cannot end with a '.ts' extension. Consider - // importing 'bad-module' instead. - 2691, - // TS5009: Cannot find the common subdirectory path for the input files. - 5009, - // TS5055: Cannot write file - // 'http://localhost:4545/cli/tests/subdir/mt_application_x_javascript.j4.js' - // because it would overwrite input file. - 5055, - // TypeScript is overly opinionated that only CommonJS modules kinds can - // support JSON imports. Allegedly this was fixed in - // Microsoft/TypeScript#26825 but that doesn't seem to be working here, - // so we will ignore complaints about this compiler setting. - 5070, - // TS7016: Could not find a declaration file for module '...'. '...' - // implicitly has an 'any' type. This is due to `allowJs` being off by - // default but importing of a JavaScript module. - 7016, -]; - -type Stats = Array<{ key: string; value: number }>; - -const stats: Stats = []; -let statsStart = 0; - -function performanceStart(): void { - stats.length = 0; - // TODO(kitsonk) replace with performance.mark() when landed - statsStart = performance.now(); - ts.performance.enable(); -} - -function performanceProgram({ - program, - fileCount, -}: { - program?: ts.Program | ts.BuilderProgram; - fileCount?: number; -}): void { - if (program) { - if ("getProgram" in program) { - program = program.getProgram(); - } - stats.push({ key: "Files", value: program.getSourceFiles().length }); - stats.push({ key: "Nodes", value: program.getNodeCount() }); - stats.push({ key: "Identifiers", value: program.getIdentifierCount() }); - stats.push({ key: "Symbols", value: program.getSymbolCount() }); - stats.push({ key: "Types", value: program.getTypeCount() }); - stats.push({ - key: "Instantiations", - value: program.getInstantiationCount(), - }); - } else if (fileCount != null) { - stats.push({ key: "Files", value: fileCount }); - } - const programTime = ts.performance.getDuration("Program"); - const bindTime = ts.performance.getDuration("Bind"); - const checkTime = ts.performance.getDuration("Check"); - const emitTime = ts.performance.getDuration("Emit"); - stats.push({ key: "Parse time", value: programTime }); - stats.push({ key: "Bind time", value: bindTime }); - stats.push({ key: "Check time", value: checkTime }); - stats.push({ key: "Emit time", value: emitTime }); - stats.push({ - key: "Total TS time", - value: programTime + bindTime + checkTime + emitTime, - }); -} - -function performanceEnd(): Stats { - // TODO(kitsonk) replace with performance.measure() when landed - const duration = performance.now() - statsStart; - stats.push({ key: "Compile time", value: duration }); - return stats; -} - -// TODO(Bartlomieju): this check should be done in Rust; there should be no -function processConfigureResponse( - configResult: HostConfigureResponse, - configPath: string, -): ts.Diagnostic[] | undefined { - const { ignoredOptions, diagnostics } = configResult; - if (ignoredOptions) { - console.warn( - yellow(`Unsupported compiler options in "${configPath}"\n`) + - cyan(` The following options were ignored:\n`) + - ` ${ignoredOptions.map((value): string => bold(value)).join(", ")}`, - ); - } - return diagnostics; -} - -function normalizeString(path: string): string { - let res = ""; - let lastSegmentLength = 0; - let lastSlash = -1; - let dots = 0; - let code: number; - for (let i = 0, len = path.length; i <= len; ++i) { - if (i < len) code = path.charCodeAt(i); - else if (code! === CHAR_FORWARD_SLASH) break; - else code = CHAR_FORWARD_SLASH; - - if (code === CHAR_FORWARD_SLASH) { - if (lastSlash === i - 1 || dots === 1) { - // NOOP - } else if (lastSlash !== i - 1 && dots === 2) { - if ( - res.length < 2 || - lastSegmentLength !== 2 || - res.charCodeAt(res.length - 1) !== CHAR_DOT || - res.charCodeAt(res.length - 2) !== CHAR_DOT - ) { - if (res.length > 2) { - const lastSlashIndex = res.lastIndexOf("/"); - if (lastSlashIndex === -1) { - res = ""; - lastSegmentLength = 0; - } else { - res = res.slice(0, lastSlashIndex); - lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); - } - lastSlash = i; - dots = 0; - continue; - } else if (res.length === 2 || res.length === 1) { - res = ""; - lastSegmentLength = 0; - lastSlash = i; - dots = 0; - continue; - } - } - } else { - if (res.length > 0) res += "/" + path.slice(lastSlash + 1, i); - else res = path.slice(lastSlash + 1, i); - lastSegmentLength = i - lastSlash - 1; - } - lastSlash = i; - dots = 0; - } else if (code === CHAR_DOT && dots !== -1) { - ++dots; - } else { - dots = -1; - } - } - return res; -} - -function commonPath(paths: string[], sep = "/"): string { - const [first = "", ...remaining] = paths; - if (first === "" || remaining.length === 0) { - return first.substring(0, first.lastIndexOf(sep) + 1); - } - const parts = first.split(sep); - - let endOfPrefix = parts.length; - for (const path of remaining) { - const compare = path.split(sep); - for (let i = 0; i < endOfPrefix; i++) { - if (compare[i] !== parts[i]) { - endOfPrefix = i; - } - } - - if (endOfPrefix === 0) { - return ""; - } - } - const prefix = parts.slice(0, endOfPrefix).join(sep); - return prefix.endsWith(sep) ? prefix : `${prefix}${sep}`; -} - -let rootExports: string[] | undefined; - -function normalizeUrl(rootName: string): string { - const match = /^(\S+:\/{2,3})(.+)$/.exec(rootName); - if (match) { - const [, protocol, path] = match; - return `${protocol}${normalizeString(path)}`; - } else { - return rootName; - } -} - -function buildBundle( - rootName: string, - data: string, - sourceFiles: readonly ts.SourceFile[], - target: ts.ScriptTarget, -): string { - // when outputting to AMD and a single outfile, TypeScript makes up the module - // specifiers which are used to define the modules, and doesn't expose them - // publicly, so we have to try to replicate - const sources = sourceFiles.map((sf) => sf.fileName); - const sharedPath = commonPath(sources); - rootName = normalizeUrl(rootName) - .replace(sharedPath, "") - .replace(/\.\w+$/i, ""); - // If one of the modules requires support for top-level-await, TypeScript will - // emit the execute function as an async function. When this is the case we - // need to bubble up the TLA to the instantiation, otherwise we instantiate - // synchronously. - const hasTla = data.match(/execute:\sasync\sfunction\s/); - let instantiate: string; - if (rootExports && rootExports.length) { - instantiate = hasTla - ? `const __exp = await __instantiate("${rootName}", true);\n` - : `const __exp = __instantiate("${rootName}", false);\n`; - for (const rootExport of rootExports) { - if (rootExport === "default") { - instantiate += `export default __exp["${rootExport}"];\n`; - } else { - instantiate += `export const ${rootExport} = __exp["${rootExport}"];\n`; - } - } - } else { - instantiate = hasTla - ? `await __instantiate("${rootName}", true);\n` - : `__instantiate("${rootName}", false);\n`; - } - const es5Bundle = target === ts.ScriptTarget.ES3 || - target === ts.ScriptTarget.ES5 || - target === ts.ScriptTarget.ES2015 || - target === ts.ScriptTarget.ES2016; - return `${ - es5Bundle ? SYSTEM_LOADER_ES5 : SYSTEM_LOADER - }\n${data}\n${instantiate}`; -} - -function setRootExports(program: ts.Program, rootModule: string): void { - // get a reference to the type checker, this will let us find symbols from - // the AST. - const checker = program.getTypeChecker(); - // get a reference to the main source file for the bundle - const mainSourceFile = program.getSourceFile(rootModule); - assert(mainSourceFile); - // retrieve the internal TypeScript symbol for this AST node - const mainSymbol = checker.getSymbolAtLocation(mainSourceFile); - if (!mainSymbol) { - return; - } - rootExports = checker - .getExportsOfModule(mainSymbol) - // .getExportsOfModule includes type only symbols which are exported from - // the module, so we need to try to filter those out. While not critical - // someone looking at the bundle would think there is runtime code behind - // that when there isn't. There appears to be no clean way of figuring that - // out, so inspecting SymbolFlags that might be present that are type only - .filter( - (sym) => - sym.flags & ts.SymbolFlags.Class || - !( - sym.flags & ts.SymbolFlags.Interface || - sym.flags & ts.SymbolFlags.TypeLiteral || - sym.flags & ts.SymbolFlags.Signature || - sym.flags & ts.SymbolFlags.TypeParameter || - sym.flags & ts.SymbolFlags.TypeAlias || - sym.flags & ts.SymbolFlags.Type || - sym.flags & ts.SymbolFlags.Namespace || - sym.flags & ts.SymbolFlags.InterfaceExcludes || - sym.flags & ts.SymbolFlags.TypeParameterExcludes || - sym.flags & ts.SymbolFlags.TypeAliasExcludes - ), - ) - .map((sym) => sym.getName()); -} - -interface ImportDescriptor { - specifier: string; - resolvedSpecifier: string; - typeDirective?: string; - resolvedTypeDirective?: string; -} - -interface ReferenceDescriptor { - specifier: string; - resolvedSpecifier: string; -} - -interface SourceFileMapEntry { - // fully resolved URL - url: string; - sourceCode: string; - mediaType: MediaType; - redirect?: string; - imports: ImportDescriptor[]; - referencedFiles: ReferenceDescriptor[]; - libDirectives: ReferenceDescriptor[]; - typesDirectives: ReferenceDescriptor[]; - typeHeaders: ReferenceDescriptor[]; - versionHash: string; -} - -/** Used when "deno run" is invoked */ -interface CompileRequest { - type: CompilerRequestType.Compile; - allowJs: boolean; - target: CompilerHostTarget; - rootNames: string[]; - configPath?: string; - config?: string; - unstable: boolean; - performance: boolean; - cwd: string; - // key value is fully resolved URL - sourceFileMap: Record<string, SourceFileMapEntry>; - buildInfo?: string; -} - -interface TranspileRequest { - type: CompilerRequestType.Transpile; - config?: string; - configPath?: string; - cwd?: string; - performance: boolean; - sourceFiles: TranspileSourceFile[]; -} - -interface TranspileSourceFile { - sourceCode: string; - fileName: string; -} - -/** Used when "deno bundle" is invoked */ -interface BundleRequest { - type: CompilerRequestType.Bundle; - target: CompilerHostTarget; - rootNames: string[]; - configPath?: string; - config?: string; - unstable: boolean; - performance: boolean; - cwd: string; - // key value is fully resolved URL - sourceFileMap: Record<string, SourceFileMapEntry>; -} - -/** Used when "Deno.compile()" API is called */ -interface RuntimeCompileRequest { - type: CompilerRequestType.RuntimeCompile; - target: CompilerHostTarget; - rootNames: string[]; - sourceFileMap: Record<string, SourceFileMapEntry>; - unstable?: boolean; - options?: string; -} - -/** Used when "Deno.bundle()" API is called */ -interface RuntimeBundleRequest { - type: CompilerRequestType.RuntimeBundle; - target: CompilerHostTarget; - rootNames: string[]; - sourceFileMap: Record<string, SourceFileMapEntry>; - unstable?: boolean; - options?: string; -} - -/** Used when "Deno.transpileOnly()" API is called */ -interface RuntimeTranspileRequest { - type: CompilerRequestType.RuntimeTranspile; - sources: Record<string, string>; - options?: string; -} - -type CompilerRequest = - | CompileRequest - | TranspileRequest - | BundleRequest - | RuntimeCompileRequest - | RuntimeBundleRequest - | RuntimeTranspileRequest; - -interface CompileResponse { - emitMap: Record<string, EmittedSource>; - diagnostics: Diagnostic; - buildInfo?: string; - stats?: Stats; -} - -interface TranspileResponse { - emitMap: Record<string, EmittedSource>; - diagnostics: Diagnostic; - stats?: Stats; -} - -interface BundleResponse { - bundleOutput?: string; - diagnostics: Diagnostic; - stats?: Stats; -} - -interface RuntimeCompileResponse { - emitMap: Record<string, EmittedSource>; - diagnostics: DiagnosticItem[]; -} - -interface RuntimeBundleResponse { - output?: string; - diagnostics: DiagnosticItem[]; -} - -function compile({ - allowJs, - buildInfo, - config, - configPath, - rootNames, - target, - unstable, - cwd, - sourceFileMap, - type, - performance, -}: CompileRequest): CompileResponse { - if (performance) { - performanceStart(); - } - log(">>> compile start", { rootNames, type: CompilerRequestType[type] }); - - // When a programme is emitted, TypeScript will call `writeFile` with - // each file that needs to be emitted. The Deno compiler host delegates - // this, to make it easier to perform the right actions, which vary - // based a lot on the request. - const state: CompileWriteFileState = { - rootNames, - emitMap: {}, - }; - const host = new IncrementalCompileHost({ - bundle: false, - target, - unstable, - writeFile: createCompileWriteFile(state), - rootNames, - buildInfo, - }); - let diagnostics: readonly ts.Diagnostic[] = []; - - host.mergeOptions({ allowJs }); - - // if there is a configuration supplied, we need to parse that - if (config && config.length && configPath) { - const configResult = host.configure(cwd, configPath, config); - diagnostics = processConfigureResponse(configResult, configPath) || []; - } - - buildSourceFileCache(sourceFileMap); - // if there was a configuration and no diagnostics with it, we will continue - // to generate the program and possibly emit it. - if (diagnostics.length === 0) { - const options = host.getCompilationSettings(); - const program = ts.createIncrementalProgram({ - rootNames, - options, - host, - }); - - // TODO(bartlomieju): check if this is ok - diagnostics = [ - ...program.getConfigFileParsingDiagnostics(), - ...program.getSyntacticDiagnostics(), - ...program.getOptionsDiagnostics(), - ...program.getGlobalDiagnostics(), - ...program.getSemanticDiagnostics(), - ]; - diagnostics = diagnostics.filter( - ({ code }) => !ignoredDiagnostics.includes(code), - ); - - // We will only proceed with the emit if there are no diagnostics. - if (diagnostics.length === 0) { - const emitResult = program.emit(); - // If `checkJs` is off we still might be compiling entry point JavaScript file - // (if it has `.ts` imports), but it won't be emitted. In that case we skip - // assertion. - if (options.checkJs) { - assert( - emitResult.emitSkipped === false, - "Unexpected skip of the emit.", - ); - } - // emitResult.diagnostics is `readonly` in TS3.5+ and can't be assigned - // without casting. - diagnostics = emitResult.diagnostics; - } - performanceProgram({ program }); - } - - log("<<< compile end", { rootNames, type: CompilerRequestType[type] }); - const stats = performance ? performanceEnd() : undefined; - - return { - emitMap: state.emitMap, - buildInfo: state.buildInfo, - diagnostics: fromTypeScriptDiagnostic(diagnostics), - stats, - }; -} - -function transpile({ - config: configText, - configPath, - cwd, - performance, - sourceFiles, -}: TranspileRequest): TranspileResponse { - if (performance) { - performanceStart(); - } - log(">>> transpile start"); - let compilerOptions: ts.CompilerOptions; - if (configText && configPath && cwd) { - const { options, ...response } = configure( - DEFAULT_TRANSPILE_OPTIONS, - configText, - configPath, - cwd, - ); - const diagnostics = processConfigureResponse(response, configPath); - if (diagnostics && diagnostics.length) { - return { - diagnostics: fromTypeScriptDiagnostic(diagnostics), - emitMap: {}, - }; - } - compilerOptions = options; - } else { - compilerOptions = Object.assign({}, DEFAULT_TRANSPILE_OPTIONS); - } - const emitMap: Record<string, EmittedSource> = {}; - let diagnostics: ts.Diagnostic[] = []; - for (const { sourceCode, fileName } of sourceFiles) { - const { - outputText, - sourceMapText, - diagnostics: diags, - } = ts.transpileModule(sourceCode, { - fileName, - compilerOptions, - reportDiagnostics: true, - }); - if (diags) { - diagnostics = diagnostics.concat(...diags); - } - emitMap[`${fileName}.js`] = { filename: fileName, contents: outputText }; - // currently we inline source maps, but this is good logic to have if this - // ever changes - if (sourceMapText) { - emitMap[`${fileName}.map`] = { - filename: fileName, - contents: sourceMapText, - }; - } - } - performanceProgram({ fileCount: sourceFiles.length }); - const stats = performance ? performanceEnd() : undefined; - log("<<< transpile end"); - return { diagnostics: fromTypeScriptDiagnostic(diagnostics), emitMap, stats }; -} - -function bundle({ - config, - configPath, - rootNames, - target, - unstable, - cwd, - sourceFileMap, - type, -}: BundleRequest): BundleResponse { - if (performance) { - performanceStart(); - } - log(">>> bundle start", { - rootNames, - type: CompilerRequestType[type], - }); - - // When a programme is emitted, TypeScript will call `writeFile` with - // each file that needs to be emitted. The Deno compiler host delegates - // this, to make it easier to perform the right actions, which vary - // based a lot on the request. - const state: BundleWriteFileState = { - rootNames, - bundleOutput: undefined, - }; - const host = new Host({ - bundle: true, - target, - unstable, - writeFile: createBundleWriteFile(state), - }); - state.host = host; - let diagnostics: readonly ts.Diagnostic[] = []; - - // if there is a configuration supplied, we need to parse that - if (config && config.length && configPath) { - const configResult = host.configure(cwd, configPath, config); - diagnostics = processConfigureResponse(configResult, configPath) || []; - } - - buildSourceFileCache(sourceFileMap); - // if there was a configuration and no diagnostics with it, we will continue - // to generate the program and possibly emit it. - if (diagnostics.length === 0) { - const options = host.getCompilationSettings(); - const program = ts.createProgram({ - rootNames, - options, - host, - }); - - diagnostics = ts - .getPreEmitDiagnostics(program) - .filter(({ code }) => !ignoredDiagnostics.includes(code)); - - // We will only proceed with the emit if there are no diagnostics. - if (diagnostics.length === 0) { - // we only support a single root module when bundling - assert(rootNames.length === 1); - setRootExports(program, rootNames[0]); - const emitResult = program.emit(); - assert(emitResult.emitSkipped === false, "Unexpected skip of the emit."); - // emitResult.diagnostics is `readonly` in TS3.5+ and can't be assigned - // without casting. - diagnostics = emitResult.diagnostics; - } - if (performance) { - performanceProgram({ program }); - } - } - - let bundleOutput; - - if (diagnostics.length === 0) { - assert(state.bundleOutput); - bundleOutput = state.bundleOutput; - } - - const stats = performance ? performanceEnd() : undefined; - - const result: BundleResponse = { - bundleOutput, - diagnostics: fromTypeScriptDiagnostic(diagnostics), - stats, - }; - - log("<<< bundle end", { - rootNames, - type: CompilerRequestType[type], - }); - - return result; -} - -function runtimeCompile( - request: RuntimeCompileRequest, -): RuntimeCompileResponse { - const { options, rootNames, target, unstable, sourceFileMap } = request; - - log(">>> runtime compile start", { - rootNames, - }); - - // if there are options, convert them into TypeScript compiler options, - // and resolve any external file references - let convertedOptions: ts.CompilerOptions | undefined; - if (options) { - const result = convertCompilerOptions(options); - convertedOptions = result.options; - } - - buildLocalSourceFileCache(sourceFileMap); - - const state: CompileWriteFileState = { - rootNames, - emitMap: {}, - }; - const host = new Host({ - bundle: false, - target, - writeFile: createRuntimeCompileWriteFile(state), - }); - const compilerOptions = [DEFAULT_RUNTIME_COMPILE_OPTIONS]; - if (convertedOptions) { - compilerOptions.push(convertedOptions); - } - if (unstable) { - compilerOptions.push({ - lib: [ - "deno.unstable", - ...((convertedOptions && convertedOptions.lib) || ["deno.window"]), - ], - }); - } - - host.mergeOptions(...compilerOptions); - - const program = ts.createProgram({ - rootNames, - options: host.getCompilationSettings(), - host, - }); - - const diagnostics = ts - .getPreEmitDiagnostics(program) - .filter(({ code }) => !ignoredDiagnostics.includes(code)); - - const emitResult = program.emit(); - - assert(emitResult.emitSkipped === false, "Unexpected skip of the emit."); - - log("<<< runtime compile finish", { - rootNames, - emitMap: Object.keys(state.emitMap), - }); - - const maybeDiagnostics = diagnostics.length - ? fromTypeScriptDiagnostic(diagnostics).items - : []; - - return { - diagnostics: maybeDiagnostics, - emitMap: state.emitMap, - }; -} - -function runtimeBundle(request: RuntimeBundleRequest): RuntimeBundleResponse { - const { options, rootNames, target, unstable, sourceFileMap } = request; - - log(">>> runtime bundle start", { - rootNames, - }); - - // if there are options, convert them into TypeScript compiler options, - // and resolve any external file references - let convertedOptions: ts.CompilerOptions | undefined; - if (options) { - const result = convertCompilerOptions(options); - convertedOptions = result.options; - } - - buildLocalSourceFileCache(sourceFileMap); - - const state: BundleWriteFileState = { - rootNames, - bundleOutput: undefined, - }; - const host = new Host({ - bundle: true, - target, - writeFile: createBundleWriteFile(state), - }); - state.host = host; - - const compilerOptions = [DEFAULT_RUNTIME_COMPILE_OPTIONS]; - if (convertedOptions) { - compilerOptions.push(convertedOptions); - } - if (unstable) { - compilerOptions.push({ - lib: [ - "deno.unstable", - ...((convertedOptions && convertedOptions.lib) || ["deno.window"]), - ], - }); - } - compilerOptions.push(DEFAULT_BUNDLER_OPTIONS); - host.mergeOptions(...compilerOptions); - - const program = ts.createProgram({ - rootNames, - options: host.getCompilationSettings(), - host, - }); - - setRootExports(program, rootNames[0]); - const diagnostics = ts - .getPreEmitDiagnostics(program) - .filter(({ code }) => !ignoredDiagnostics.includes(code)); - - const emitResult = program.emit(); - - assert(emitResult.emitSkipped === false, "Unexpected skip of the emit."); - - log("<<< runtime bundle finish", { - rootNames, - }); - - const maybeDiagnostics = diagnostics.length - ? fromTypeScriptDiagnostic(diagnostics).items - : []; - - return { - diagnostics: maybeDiagnostics, - output: state.bundleOutput, - }; -} - -function runtimeTranspile( - request: RuntimeTranspileRequest, -): Promise<Record<string, TranspileOnlyResult>> { - const result: Record<string, TranspileOnlyResult> = {}; - const { sources, options } = request; - const compilerOptions = options - ? Object.assign( - {}, - DEFAULT_RUNTIME_TRANSPILE_OPTIONS, - convertCompilerOptions(options).options, - ) - : DEFAULT_RUNTIME_TRANSPILE_OPTIONS; - - for (const [fileName, inputText] of Object.entries(sources)) { - const { outputText: source, sourceMapText: map } = ts.transpileModule( - inputText, - { - fileName, - compilerOptions, - }, - ); - result[fileName] = { source, map }; - } - return Promise.resolve(result); -} - -async function tsCompilerOnMessage({ - data: request, -}: { - data: CompilerRequest; -}): Promise<void> { - switch (request.type) { - case CompilerRequestType.Compile: { - const result = compile(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.Transpile: { - const result = transpile(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.Bundle: { - const result = bundle(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.RuntimeCompile: { - const result = runtimeCompile(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.RuntimeBundle: { - const result = runtimeBundle(request); - globalThis.postMessage(result); - break; - } - case CompilerRequestType.RuntimeTranspile: { - const result = await runtimeTranspile(request); - globalThis.postMessage(result); - break; - } - default: - log( - `!!! unhandled CompilerRequestType: ${ - (request as CompilerRequest).type - } (${CompilerRequestType[(request as CompilerRequest).type]})`, - ); - } - // Shutdown after single request - globalThis.close(); -} - -function bootstrapTsCompilerRuntime(): void { - bootstrapWorkerRuntime("TS", false); - globalThis.onmessage = tsCompilerOnMessage; -} - -// 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: { - ...globalThis.bootstrap, - tsCompilerRuntime: bootstrapTsCompilerRuntime, - }, - configurable: true, - writable: true, - }, -}); diff --git a/cli/js/compiler_api.ts b/cli/js/compiler_api.ts deleted file mode 100644 index e0488b7f6..000000000 --- a/cli/js/compiler_api.ts +++ /dev/null @@ -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]; -} diff --git a/cli/js/compiler_options.ts b/cli/js/compiler_options.ts deleted file mode 100644 index dd1a0a9f2..000000000 --- a/cli/js/compiler_options.ts +++ /dev/null @@ -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[]; -} diff --git a/cli/js/core.ts b/cli/js/core.ts deleted file mode 100644 index 5a0d95225..000000000 --- a/cli/js/core.ts +++ /dev/null @@ -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; diff --git a/cli/js/deno.ts b/cli/js/deno.ts deleted file mode 100644 index 878df8fb4..000000000 --- a/cli/js/deno.ts +++ /dev/null @@ -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; diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts deleted file mode 100644 index 6e334e223..000000000 --- a/cli/js/deno_unstable.ts +++ /dev/null @@ -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"; diff --git a/cli/js/diagnostics.ts b/cli/js/diagnostics.ts deleted file mode 100644 index d8a3f2a3c..000000000 --- a/cli/js/diagnostics.ts +++ /dev/null @@ -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[]; -} diff --git a/cli/js/diagnostics_util.ts b/cli/js/diagnostics_util.ts deleted file mode 100644 index fc2684baf..000000000 --- a/cli/js/diagnostics_util.ts +++ /dev/null @@ -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 }; -} diff --git a/cli/js/error_stack.ts b/cli/js/error_stack.ts deleted file mode 100644 index 97ce00f3a..000000000 --- a/cli/js/error_stack.ts +++ /dev/null @@ -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); diff --git a/cli/js/errors.ts b/cli/js/errors.ts deleted file mode 100644 index 52c5e50ad..000000000 --- a/cli/js/errors.ts +++ /dev/null @@ -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, -}; diff --git a/cli/js/files.ts b/cli/js/files.ts deleted file mode 100644 index e9f12a489..000000000 --- a/cli/js/files.ts +++ /dev/null @@ -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", - ); - } -} diff --git a/cli/js/globals.ts b/cli/js/globals.ts deleted file mode 100644 index aa826f63a..000000000 --- a/cli/js/globals.ts +++ /dev/null @@ -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, - ), -}; diff --git a/cli/js/globals_unstable.ts b/cli/js/globals_unstable.ts deleted file mode 100644 index 872f135a3..000000000 --- a/cli/js/globals_unstable.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -export const unstableMethods = {}; - -export const unstableProperties = {}; diff --git a/cli/js/internals.ts b/cli/js/internals.ts deleted file mode 100644 index b3fec8f4d..000000000 --- a/cli/js/internals.ts +++ /dev/null @@ -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, - }); -} diff --git a/cli/js/io.ts b/cli/js/io.ts deleted file mode 100644 index b2e6499b8..000000000 --- a/cli/js/io.ts +++ /dev/null @@ -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); - } -} diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts deleted file mode 100644 index 962179381..000000000 --- a/cli/js/lib.deno.ns.d.ts +++ /dev/null @@ -1,2028 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -/// <reference no-default-lib="true" /> -/// <reference lib="esnext" /> - -/** Deno provides extra properties on `import.meta`. These are included here - * to ensure that these are still available when using the Deno namepsace in - * conjunction with other type libs, like `dom`. */ -declare interface ImportMeta { - /** A string representation of the fully qualified module URL. */ - url: string; - - /** A flag that indicates if the current module is the main module that was - * called when starting the program under Deno. - * - * ```ts - * if (import.meta.main) { - * // this was loaded as the main module, maybe do some bootstrapping - * } - * ``` - */ - main: boolean; -} - -/** Deno supports user timing Level 3 (see: https://w3c.github.io/user-timing) - * which is not widely supported yet in other runtimes. These types are here - * so that these features are still available when using the Deno namespace - * in conjunction with other type libs, like `dom`. */ -declare interface Performance { - /** Stores a timestamp with the associated name (a "mark"). */ - mark(markName: string, options?: PerformanceMarkOptions): PerformanceMark; - - /** Stores the `DOMHighResTimeStamp` duration between two marks along with the - * associated name (a "measure"). */ - measure( - measureName: string, - options?: PerformanceMeasureOptions, - ): PerformanceMeasure; -} - -declare interface PerformanceMarkOptions { - /** Metadata to be included in the mark. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - detail?: any; - - /** Timestamp to be used as the mark time. */ - startTime?: number; -} - -declare interface PerformanceMeasureOptions { - /** Metadata to be included in the measure. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - detail?: any; - - /** Timestamp to be used as the start time or string to be used as start - * mark.*/ - start?: string | number; - - /** Duration between the start and end times. */ - duration?: number; - - /** Timestamp to be used as the end time or string to be used as end mark. */ - end?: string | number; -} - -declare namespace Deno { - /** A set of error constructors that are raised by Deno APIs. */ - export const errors: { - NotFound: ErrorConstructor; - PermissionDenied: ErrorConstructor; - ConnectionRefused: ErrorConstructor; - ConnectionReset: ErrorConstructor; - ConnectionAborted: ErrorConstructor; - NotConnected: ErrorConstructor; - AddrInUse: ErrorConstructor; - AddrNotAvailable: ErrorConstructor; - BrokenPipe: ErrorConstructor; - AlreadyExists: ErrorConstructor; - InvalidData: ErrorConstructor; - TimedOut: ErrorConstructor; - Interrupted: ErrorConstructor; - WriteZero: ErrorConstructor; - UnexpectedEof: ErrorConstructor; - BadResource: ErrorConstructor; - Http: ErrorConstructor; - Busy: ErrorConstructor; - }; - - /** The current process id of the runtime. */ - export const pid: number; - - /** Reflects the `NO_COLOR` environment variable. - * - * See: https://no-color.org/ */ - export const noColor: boolean; - - export interface TestDefinition { - fn: () => void | Promise<void>; - name: string; - ignore?: boolean; - /** If at lease one test has `only` set to true, only run tests that have - * `only` set to true and fail the test suite. */ - only?: boolean; - /** Check that the number of async completed ops after the test is the same - * as number of dispatched ops. Defaults to true.*/ - sanitizeOps?: boolean; - /** Ensure the test case does not "leak" resources - ie. the resource table - * after the test has exactly the same contents as before the test. Defaults - * to true. */ - sanitizeResources?: boolean; - } - - /** Register a test which will be run when `deno test` is used on the command - * line and the containing module looks like a test module. - * `fn` can be async if required. - * ```ts - * import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test({ - * name: "example test", - * fn(): void { - * assertEquals("world", "world"); - * }, - * }); - * - * Deno.test({ - * name: "example ignored test", - * ignore: Deno.build.os === "windows", - * fn(): void { - * // This test is ignored only on Windows machines - * }, - * }); - * - * Deno.test({ - * name: "example async test", - * async fn() { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * } - * }); - * ``` - */ - export function test(t: TestDefinition): void; - - /** Register a test which will be run when `deno test` is used on the command - * line and the containing module looks like a test module. - * `fn` can be async if required. - * - * ```ts - * import {assert, fail, assertEquals} from "https://deno.land/std/testing/asserts.ts"; - * - * Deno.test("My test description", ():void => { - * assertEquals("hello", "hello"); - * }); - * - * Deno.test("My async test description", async ():Promise<void> => { - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello_world.txt"); - * assertEquals(decoder.decode(data), "Hello world"); - * }); - * ``` - * */ - export function test(name: string, fn: () => void | Promise<void>): void; - - /** Exit the Deno process with optional exit code. If no exit code is supplied - * then Deno will exit with return code of 0. - * - * ```ts - * Deno.exit(5); - * ``` - */ - export function exit(code?: number): never; - - export const env: { - /** Retrieve the value of an environment variable. Returns undefined if that - * key doesn't exist. - * - * ```ts - * console.log(Deno.env.get("HOME")); // e.g. outputs "/home/alice" - * console.log(Deno.env.get("MADE_UP_VAR")); // outputs "Undefined" - * ``` - * Requires `allow-env` permission. */ - get(key: string): string | undefined; - - /** Set the value of an environment variable. - * - * ```ts - * Deno.env.set("SOME_VAR", "Value")); - * Deno.env.get("SOME_VAR"); // outputs "Value" - * ``` - * - * Requires `allow-env` permission. */ - set(key: string, value: string): void; - - /** Delete the value of an environment variable. - * - * ```ts - * Deno.env.set("SOME_VAR", "Value")); - * Deno.env.delete("SOME_VAR"); // outputs "Undefined" - * ``` - * - * Requires `allow-env` permission. */ - delete(key: string): void; - - /** Returns a snapshot of the environment variables at invocation. - * - * ```ts - * Deno.env.set("TEST_VAR", "A"); - * const myEnv = Deno.env.toObject(); - * console.log(myEnv.SHELL); - * Deno.env.set("TEST_VAR", "B"); - * console.log(myEnv.TEST_VAR); // outputs "A" - * ``` - * - * Requires `allow-env` permission. */ - toObject(): { [index: string]: string }; - }; - - /** - * Returns the path to the current deno executable. - * - * ```ts - * console.log(Deno.execPath()); // e.g. "/home/alice/.local/bin/deno" - * ``` - * - * Requires `allow-read` permission. - */ - export function execPath(): string; - - /** - * Change the current working directory to the specified path. - * - * ```ts - * Deno.chdir("/home/userA"); - * Deno.chdir("../userB"); - * Deno.chdir("C:\\Program Files (x86)\\Java"); - * ``` - * - * Throws `Deno.errors.NotFound` if directory not found. - * Throws `Deno.errors.PermissionDenied` if the user does not have access - * rights - * - * Requires --allow-read. - */ - export function chdir(directory: string): void; - - /** - * Return a string representing the current working directory. - * - * If the current directory can be reached via multiple paths (due to symbolic - * links), `cwd()` may return any one of them. - * - * ```ts - * const currentWorkingDirectory = Deno.cwd(); - * ``` - * - * Throws `Deno.errors.NotFound` if directory not available. - * - * Requires --allow-read - */ - export function cwd(): string; - - export enum SeekMode { - Start = 0, - Current = 1, - End = 2, - } - - export interface Reader { - /** Reads up to `p.byteLength` bytes into `p`. It resolves to the number of - * bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error - * encountered. Even if `read()` resolves to `n` < `p.byteLength`, it may - * use all of `p` as scratch space during the call. If some data is - * available but not `p.byteLength` bytes, `read()` conventionally resolves - * to what is available instead of waiting for more. - * - * When `read()` encounters end-of-file condition, it resolves to EOF - * (`null`). - * - * When `read()` encounters an error, it rejects with an error. - * - * Callers should always process the `n` > `0` bytes returned before - * considering the EOF (`null`). Doing so correctly handles I/O errors that - * happen after reading some bytes and also both of the allowed EOF - * behaviors. - * - * Implementations should not retain a reference to `p`. - * - * Use Deno.iter() to turn a Reader into an AsyncIterator. - */ - read(p: Uint8Array): Promise<number | null>; - } - - export interface ReaderSync { - /** Reads up to `p.byteLength` bytes into `p`. It resolves to the number - * of bytes read (`0` < `n` <= `p.byteLength`) and rejects if any error - * encountered. Even if `read()` returns `n` < `p.byteLength`, it may use - * all of `p` as scratch space during the call. If some data is available - * but not `p.byteLength` bytes, `read()` conventionally returns what is - * available instead of waiting for more. - * - * When `readSync()` encounters end-of-file condition, it returns EOF - * (`null`). - * - * When `readSync()` encounters an error, it throws with an error. - * - * Callers should always process the `n` > `0` bytes returned before - * considering the EOF (`null`). Doing so correctly handles I/O errors that happen - * after reading some bytes and also both of the allowed EOF behaviors. - * - * Implementations should not retain a reference to `p`. - * - * Use Deno.iterSync() to turn a ReaderSync into an Iterator. - */ - readSync(p: Uint8Array): number | null; - } - - export interface Writer { - /** Writes `p.byteLength` bytes from `p` to the underlying data stream. It - * resolves to the number of bytes written from `p` (`0` <= `n` <= - * `p.byteLength`) or reject with the error encountered that caused the - * write to stop early. `write()` must reject with a non-null error if - * would resolve to `n` < `p.byteLength`. `write()` must not modify the - * slice data, even temporarily. - * - * Implementations should not retain a reference to `p`. - */ - write(p: Uint8Array): Promise<number>; - } - - export interface WriterSync { - /** Writes `p.byteLength` bytes from `p` to the underlying data - * stream. It returns the number of bytes written from `p` (`0` <= `n` - * <= `p.byteLength`) and any error encountered that caused the write to - * stop early. `writeSync()` must throw a non-null error if it returns `n` < - * `p.byteLength`. `writeSync()` must not modify the slice data, even - * temporarily. - * - * Implementations should not retain a reference to `p`. - */ - writeSync(p: Uint8Array): number; - } - - export interface Closer { - close(): void; - } - - export interface Seeker { - /** Seek sets the offset for the next `read()` or `write()` to offset, - * interpreted according to `whence`: `Start` means relative to the - * start of the file, `Current` means relative to the current offset, - * and `End` means relative to the end. Seek resolves to the new offset - * relative to the start of the file. - * - * Seeking to an offset before the start of the file is an error. Seeking to - * any positive offset is legal, but the behavior of subsequent I/O - * operations on the underlying object is implementation-dependent. - * It returns the number of cursor position. - */ - seek(offset: number, whence: SeekMode): Promise<number>; - } - - export interface SeekerSync { - /** Seek sets the offset for the next `readSync()` or `writeSync()` to - * offset, interpreted according to `whence`: `Start` means relative - * to the start of the file, `Current` means relative to the current - * offset, and `End` means relative to the end. - * - * Seeking to an offset before the start of the file is an error. Seeking to - * any positive offset is legal, but the behavior of subsequent I/O - * operations on the underlying object is implementation-dependent. - */ - seekSync(offset: number, whence: SeekMode): number; - } - - /** Copies from `src` to `dst` until either EOF (`null`) is read from `src` or - * an error occurs. It resolves to the number of bytes copied or rejects with - * the first error encountered while copying. - * - * ```ts - * const source = await Deno.open("my_file.txt"); - * const buffer = new Deno.Buffer() - * const bytesCopied1 = await Deno.copy(source, Deno.stdout); - * const bytesCopied2 = await Deno.copy(source, buffer); - * ``` - * - * @param src The source to copy from - * @param dst The destination to copy to - * @param options Can be used to tune size of the buffer. Default size is 32kB - */ - export function copy( - src: Reader, - dst: Writer, - options?: { - bufSize?: number; - }, - ): Promise<number>; - - /** Turns a Reader, `r`, into an async iterator. - * - * ```ts - * let f = await Deno.open("/etc/passwd"); - * for await (const chunk of Deno.iter(f)) { - * console.log(chunk); - * } - * f.close(); - * ``` - * - * Second argument can be used to tune size of a buffer. - * Default size of the buffer is 32kB. - * - * ```ts - * let f = await Deno.open("/etc/passwd"); - * const iter = Deno.iter(f, { - * bufSize: 1024 * 1024 - * }); - * for await (const chunk of iter) { - * console.log(chunk); - * } - * f.close(); - * ``` - * - * Iterator uses an internal buffer of fixed size for efficiency; it returns - * a view on that buffer on each iteration. It is therefore caller's - * responsibility to copy contents of the buffer if needed; otherwise the - * next iteration will overwrite contents of previously returned chunk. - */ - export function iter( - r: Reader, - options?: { - bufSize?: number; - }, - ): AsyncIterableIterator<Uint8Array>; - - /** Turns a ReaderSync, `r`, into an iterator. - * - * ```ts - * let f = Deno.openSync("/etc/passwd"); - * for (const chunk of Deno.iterSync(f)) { - * console.log(chunk); - * } - * f.close(); - * ``` - * - * Second argument can be used to tune size of a buffer. - * Default size of the buffer is 32kB. - * - * ```ts - * let f = await Deno.open("/etc/passwd"); - * const iter = Deno.iterSync(f, { - * bufSize: 1024 * 1024 - * }); - * for (const chunk of iter) { - * console.log(chunk); - * } - * f.close(); - * ``` - * - * Iterator uses an internal buffer of fixed size for efficiency; it returns - * a view on that buffer on each iteration. It is therefore caller's - * responsibility to copy contents of the buffer if needed; otherwise the - * next iteration will overwrite contents of previously returned chunk. - */ - export function iterSync( - r: ReaderSync, - options?: { - bufSize?: number; - }, - ): IterableIterator<Uint8Array>; - - /** Synchronously open a file and return an instance of `Deno.File`. The - * file does not need to previously exist if using the `create` or `createNew` - * open options. It is the callers responsibility to close the file when finished - * with it. - * - * ```ts - * const file = Deno.openSync("/foo/bar.txt", { read: true, write: true }); - * // Do work with file - * Deno.close(file.rid); - * ``` - * - * Requires `allow-read` and/or `allow-write` permissions depending on options. - */ - export function openSync(path: string | URL, options?: OpenOptions): File; - - /** Open a file and resolve to an instance of `Deno.File`. The - * file does not need to previously exist if using the `create` or `createNew` - * open options. It is the callers responsibility to close the file when finished - * with it. - * - * ```ts - * const file = await Deno.open("/foo/bar.txt", { read: true, write: true }); - * // Do work with file - * Deno.close(file.rid); - * ``` - * - * Requires `allow-read` and/or `allow-write` permissions depending on options. - */ - export function open( - path: string | URL, - options?: OpenOptions, - ): Promise<File>; - - /** Creates a file if none exists or truncates an existing file and returns - * an instance of `Deno.File`. - * - * ```ts - * const file = Deno.createSync("/foo/bar.txt"); - * ``` - * - * Requires `allow-read` and `allow-write` permissions. - */ - export function createSync(path: string | URL): File; - - /** Creates a file if none exists or truncates an existing file and resolves to - * an instance of `Deno.File`. - * - * ```ts - * const file = await Deno.create("/foo/bar.txt"); - * ``` - * - * Requires `allow-read` and `allow-write` permissions. - */ - export function create(path: string | URL): Promise<File>; - - /** Synchronously read from a resource ID (`rid`) into an array buffer (`buffer`). - * - * Returns either the number of bytes read during the operation or EOF - * (`null`) if there was nothing more to read. - * - * It is possible for a read to successfully return with `0` bytes. This does - * not indicate EOF. - * - * This function is one of the lowest level APIs and most users should not - * work with this directly, but rather use Deno.readAllSync() instead. - * - * **It is not guaranteed that the full buffer will be read in a single call.** - * - * ```ts - * // if "/foo/bar.txt" contains the text "hello world": - * const file = Deno.openSync("/foo/bar.txt"); - * const buf = new Uint8Array(100); - * const numberOfBytesRead = Deno.readSync(file.rid, buf); // 11 bytes - * const text = new TextDecoder().decode(buf); // "hello world" - * Deno.close(file.rid); - * ``` - */ - export function readSync(rid: number, buffer: Uint8Array): number | null; - - /** Read from a resource ID (`rid`) into an array buffer (`buffer`). - * - * Resolves to either the number of bytes read during the operation or EOF - * (`null`) if there was nothing more to read. - * - * It is possible for a read to successfully return with `0` bytes. This does - * not indicate EOF. - * - * This function is one of the lowest level APIs and most users should not - * work with this directly, but rather use Deno.readAll() instead. - * - * **It is not guaranteed that the full buffer will be read in a single call.** - * - * ```ts - * // if "/foo/bar.txt" contains the text "hello world": - * const file = await Deno.open("/foo/bar.txt"); - * const buf = new Uint8Array(100); - * const numberOfBytesRead = await Deno.read(file.rid, buf); // 11 bytes - * const text = new TextDecoder().decode(buf); // "hello world" - * Deno.close(file.rid); - * ``` - */ - export function read(rid: number, buffer: Uint8Array): Promise<number | null>; - - /** Synchronously write to the resource ID (`rid`) the contents of the array - * buffer (`data`). - * - * Returns the number of bytes written. This function is one of the lowest - * level APIs and most users should not work with this directly, but rather use - * Deno.writeAllSync() instead. - * - * **It is not guaranteed that the full buffer will be written in a single - * call.** - * - * ```ts - * const encoder = new TextEncoder(); - * const data = encoder.encode("Hello world"); - * const file = Deno.openSync("/foo/bar.txt", {write: true}); - * const bytesWritten = Deno.writeSync(file.rid, data); // 11 - * Deno.close(file.rid); - * ``` - */ - export function writeSync(rid: number, data: Uint8Array): number; - - /** Write to the resource ID (`rid`) the contents of the array buffer (`data`). - * - * Resolves to the number of bytes written. This function is one of the lowest - * level APIs and most users should not work with this directly, but rather use - * Deno.writeAll() instead. - * - * **It is not guaranteed that the full buffer will be written in a single - * call.** - * - * ```ts - * const encoder = new TextEncoder(); - * const data = encoder.encode("Hello world"); - * const file = await Deno.open("/foo/bar.txt", { write: true }); - * const bytesWritten = await Deno.write(file.rid, data); // 11 - * Deno.close(file.rid); - * ``` - */ - export function write(rid: number, data: Uint8Array): Promise<number>; - - /** Synchronously seek a resource ID (`rid`) to the given `offset` under mode - * given by `whence`. The new position within the resource (bytes from the - * start) is returned. - * - * ```ts - * const file = Deno.openSync('hello.txt', {read: true, write: true, truncate: true, create: true}); - * Deno.writeSync(file.rid, new TextEncoder().encode("Hello world")); - * // advance cursor 6 bytes - * const cursorPosition = Deno.seekSync(file.rid, 6, Deno.SeekMode.Start); - * console.log(cursorPosition); // 6 - * const buf = new Uint8Array(100); - * file.readSync(buf); - * console.log(new TextDecoder().decode(buf)); // "world" - * ``` - * - * The seek modes work as follows: - * - * ```ts - * // Given file.rid pointing to file with "Hello world", which is 11 bytes long: - * // Seek 6 bytes from the start of the file - * console.log(Deno.seekSync(file.rid, 6, Deno.SeekMode.Start)); // "6" - * // Seek 2 more bytes from the current position - * console.log(Deno.seekSync(file.rid, 2, Deno.SeekMode.Current)); // "8" - * // Seek backwards 2 bytes from the end of the file - * console.log(Deno.seekSync(file.rid, -2, Deno.SeekMode.End)); // "9" (e.g. 11-2) - * ``` - */ - export function seekSync( - rid: number, - offset: number, - whence: SeekMode, - ): number; - - /** Seek a resource ID (`rid`) to the given `offset` under mode given by `whence`. - * The call resolves to the new position within the resource (bytes from the start). - * - * ```ts - * const file = await Deno.open('hello.txt', {read: true, write: true, truncate: true, create: true}); - * await Deno.write(file.rid, new TextEncoder().encode("Hello world")); - * // advance cursor 6 bytes - * const cursorPosition = await Deno.seek(file.rid, 6, Deno.SeekMode.Start); - * console.log(cursorPosition); // 6 - * const buf = new Uint8Array(100); - * await file.read(buf); - * console.log(new TextDecoder().decode(buf)); // "world" - * ``` - * - * The seek modes work as follows: - * - * ```ts - * // Given file.rid pointing to file with "Hello world", which is 11 bytes long: - * // Seek 6 bytes from the start of the file - * console.log(await Deno.seek(file.rid, 6, Deno.SeekMode.Start)); // "6" - * // Seek 2 more bytes from the current position - * console.log(await Deno.seek(file.rid, 2, Deno.SeekMode.Current)); // "8" - * // Seek backwards 2 bytes from the end of the file - * console.log(await Deno.seek(file.rid, -2, Deno.SeekMode.End)); // "9" (e.g. 11-2) - * ``` - */ - export function seek( - rid: number, - offset: number, - whence: SeekMode, - ): Promise<number>; - - /** Close the given resource ID (rid) which has been previously opened, such - * as via opening or creating a file. Closing a file when you are finished - * with it is important to avoid leaking resources. - * - * ```ts - * const file = await Deno.open("my_file.txt"); - * // do work with "file" object - * Deno.close(file.rid); - * ```` - */ - export function close(rid: number): void; - - /** The Deno abstraction for reading and writing files. */ - export class File - implements - Reader, - ReaderSync, - Writer, - WriterSync, - Seeker, - SeekerSync, - Closer { - readonly rid: number; - constructor(rid: number); - write(p: Uint8Array): Promise<number>; - writeSync(p: Uint8Array): number; - read(p: Uint8Array): Promise<number | null>; - readSync(p: Uint8Array): number | null; - seek(offset: number, whence: SeekMode): Promise<number>; - seekSync(offset: number, whence: SeekMode): number; - close(): void; - } - - /** A handle for `stdin`. */ - export const stdin: Reader & ReaderSync & Closer & { rid: number }; - /** A handle for `stdout`. */ - export const stdout: Writer & WriterSync & Closer & { rid: number }; - /** A handle for `stderr`. */ - export const stderr: Writer & WriterSync & Closer & { rid: number }; - - export interface OpenOptions { - /** Sets the option for read access. This option, when `true`, means that the - * file should be read-able if opened. */ - read?: boolean; - /** Sets the option for write access. This option, when `true`, means that - * the file should be write-able if opened. If the file already exists, - * any write calls on it will overwrite its contents, by default without - * truncating it. */ - write?: boolean; - /**Sets the option for the append mode. This option, when `true`, means that - * writes will append to a file instead of overwriting previous contents. - * Note that setting `{ write: true, append: true }` has the same effect as - * setting only `{ append: true }`. */ - append?: boolean; - /** Sets the option for truncating a previous file. If a file is - * successfully opened with this option set it will truncate the file to `0` - * size if it already exists. The file must be opened with write access - * for truncate to work. */ - truncate?: boolean; - /** Sets the option to allow creating a new file, if one doesn't already - * exist at the specified path. Requires write or append access to be - * used. */ - create?: boolean; - /** Defaults to `false`. If set to `true`, no file, directory, or symlink is - * allowed to exist at the target location. Requires write or append - * access to be used. When createNew is set to `true`, create and truncate - * are ignored. */ - createNew?: boolean; - /** Permissions to use if creating the file (defaults to `0o666`, before - * the process's umask). - * Ignored on Windows. */ - mode?: number; - } - - /** - * - * Check if a given resource id (`rid`) is a TTY. - * - * ```ts - * // This example is system and context specific - * const nonTTYRid = Deno.openSync("my_file.txt").rid; - * const ttyRid = Deno.openSync("/dev/tty6").rid; - * console.log(Deno.isatty(nonTTYRid)); // false - * console.log(Deno.isatty(ttyRid)); // true - * Deno.close(nonTTYRid); - * Deno.close(ttyRid); - * ``` - */ - export function isatty(rid: number): boolean; - - /** A variable-sized buffer of bytes with `read()` and `write()` methods. - * - * Deno.Buffer is almost always used with some I/O like files and sockets. It - * allows one to buffer up a download from a socket. Buffer grows and shrinks - * as necessary. - * - * Deno.Buffer is NOT the same thing as Node's Buffer. Node's Buffer was - * created in 2009 before JavaScript had the concept of ArrayBuffers. It's - * simply a non-standard ArrayBuffer. - * - * ArrayBuffer is a fixed memory allocation. Deno.Buffer is implemented on top - * of ArrayBuffer. - * - * Based on [Go Buffer](https://golang.org/pkg/bytes/#Buffer). */ - export class Buffer implements Reader, ReaderSync, Writer, WriterSync { - constructor(ab?: ArrayBuffer); - /** Returns a slice holding the unread portion of the buffer. - * - * The slice is valid for use only until the next buffer modification (that - * is, only until the next call to a method like `read()`, `write()`, - * `reset()`, or `truncate()`). If `options.copy` is false the slice aliases the buffer content at - * least until the next buffer modification, so immediate changes to the - * slice will affect the result of future reads. - * @param options Defaults to `{ copy: true }` - */ - bytes(options?: { copy?: boolean }): Uint8Array; - /** Returns whether the unread portion of the buffer is empty. */ - empty(): boolean; - /** A read only number of bytes of the unread portion of the buffer. */ - readonly length: number; - /** The read only capacity of the buffer's underlying byte slice, that is, - * the total space allocated for the buffer's data. */ - readonly capacity: number; - /** Discards all but the first `n` unread bytes from the buffer but - * continues to use the same allocated storage. It throws if `n` is - * negative or greater than the length of the buffer. */ - truncate(n: number): void; - /** Resets the buffer to be empty, but it retains the underlying storage for - * use by future writes. `.reset()` is the same as `.truncate(0)`. */ - reset(): void; - /** Reads the next `p.length` bytes from the buffer or until the buffer is - * drained. Returns the number of bytes read. If the buffer has no data to - * return, the return is EOF (`null`). */ - readSync(p: Uint8Array): number | null; - /** Reads the next `p.length` bytes from the buffer or until the buffer is - * drained. Resolves to the number of bytes read. If the buffer has no - * data to return, resolves to EOF (`null`). - * - * NOTE: This methods reads bytes sychronously; it's provided for - * compatibility with `Reader` interfaces. - */ - read(p: Uint8Array): Promise<number | null>; - writeSync(p: Uint8Array): number; - /** NOTE: This methods writes bytes sychronously; it's provided for - * compatibility with `Writer` interface. */ - write(p: Uint8Array): Promise<number>; - /** Grows the buffer's capacity, if necessary, to guarantee space for - * another `n` bytes. After `.grow(n)`, at least `n` bytes can be written to - * the buffer without another allocation. If `n` is negative, `.grow()` will - * throw. If the buffer can't grow it will throw an error. - * - * Based on Go Lang's - * [Buffer.Grow](https://golang.org/pkg/bytes/#Buffer.Grow). */ - grow(n: number): void; - /** Reads data from `r` until EOF (`null`) and appends it to the buffer, - * growing the buffer as needed. It resolves to the number of bytes read. - * If the buffer becomes too large, `.readFrom()` will reject with an error. - * - * Based on Go Lang's - * [Buffer.ReadFrom](https://golang.org/pkg/bytes/#Buffer.ReadFrom). */ - readFrom(r: Reader): Promise<number>; - /** Reads data from `r` until EOF (`null`) and appends it to the buffer, - * growing the buffer as needed. It returns the number of bytes read. If the - * buffer becomes too large, `.readFromSync()` will throw an error. - * - * Based on Go Lang's - * [Buffer.ReadFrom](https://golang.org/pkg/bytes/#Buffer.ReadFrom). */ - readFromSync(r: ReaderSync): number; - } - - /** Read Reader `r` until EOF (`null`) and resolve to the content as - * Uint8Array`. - * - * ```ts - * // Example from stdin - * const stdinContent = await Deno.readAll(Deno.stdin); - * - * // Example from file - * const file = await Deno.open("my_file.txt", {read: true}); - * const myFileContent = await Deno.readAll(file); - * Deno.close(file.rid); - * - * // Example from buffer - * const myData = new Uint8Array(100); - * // ... fill myData array with data - * const reader = new Deno.Buffer(myData.buffer as ArrayBuffer); - * const bufferContent = await Deno.readAll(reader); - * ``` - */ - export function readAll(r: Reader): Promise<Uint8Array>; - - /** Synchronously reads Reader `r` until EOF (`null`) and returns the content - * as `Uint8Array`. - * - * ```ts - * // Example from stdin - * const stdinContent = Deno.readAllSync(Deno.stdin); - * - * // Example from file - * const file = Deno.openSync("my_file.txt", {read: true}); - * const myFileContent = Deno.readAllSync(file); - * Deno.close(file.rid); - * - * // Example from buffer - * const myData = new Uint8Array(100); - * // ... fill myData array with data - * const reader = new Deno.Buffer(myData.buffer as ArrayBuffer); - * const bufferContent = Deno.readAllSync(reader); - * ``` - */ - export function readAllSync(r: ReaderSync): Uint8Array; - - /** Write all the content of the array buffer (`arr`) to the writer (`w`). - * - * ```ts - * // Example writing to stdout - * const contentBytes = new TextEncoder().encode("Hello World"); - * await Deno.writeAll(Deno.stdout, contentBytes); - * - * // Example writing to file - * const contentBytes = new TextEncoder().encode("Hello World"); - * const file = await Deno.open('test.file', {write: true}); - * await Deno.writeAll(file, contentBytes); - * Deno.close(file.rid); - * - * // Example writing to buffer - * const contentBytes = new TextEncoder().encode("Hello World"); - * const writer = new Deno.Buffer(); - * await Deno.writeAll(writer, contentBytes); - * console.log(writer.bytes().length); // 11 - * ``` - */ - export function writeAll(w: Writer, arr: Uint8Array): Promise<void>; - - /** Synchronously write all the content of the array buffer (`arr`) to the - * writer (`w`). - * - * ```ts - * // Example writing to stdout - * const contentBytes = new TextEncoder().encode("Hello World"); - * Deno.writeAllSync(Deno.stdout, contentBytes); - * - * // Example writing to file - * const contentBytes = new TextEncoder().encode("Hello World"); - * const file = Deno.openSync('test.file', {write: true}); - * Deno.writeAllSync(file, contentBytes); - * Deno.close(file.rid); - * - * // Example writing to buffer - * const contentBytes = new TextEncoder().encode("Hello World"); - * const writer = new Deno.Buffer(); - * Deno.writeAllSync(writer, contentBytes); - * console.log(writer.bytes().length); // 11 - * ``` - */ - export function writeAllSync(w: WriterSync, arr: Uint8Array): void; - - export interface MkdirOptions { - /** Defaults to `false`. If set to `true`, means that any intermediate - * directories will also be created (as with the shell command `mkdir -p`). - * Intermediate directories are created with the same permissions. - * When recursive is set to `true`, succeeds silently (without changing any - * permissions) if a directory already exists at the path, or if the path - * is a symlink to an existing directory. */ - recursive?: boolean; - /** Permissions to use when creating the directory (defaults to `0o777`, - * before the process's umask). - * Ignored on Windows. */ - mode?: number; - } - - /** Synchronously creates a new directory with the specified path. - * - * ```ts - * Deno.mkdirSync("new_dir"); - * Deno.mkdirSync("nested/directories", { recursive: true }); - * Deno.mkdirSync("restricted_access_dir", { mode: 0o700 }); - * ``` - * - * Defaults to throwing error if the directory already exists. - * - * Requires `allow-write` permission. */ - export function mkdirSync(path: string | URL, options?: MkdirOptions): void; - - /** Creates a new directory with the specified path. - * - * ```ts - * await Deno.mkdir("new_dir"); - * await Deno.mkdir("nested/directories", { recursive: true }); - * await Deno.mkdir("restricted_access_dir", { mode: 0o700 }); - * ``` - * - * Defaults to throwing error if the directory already exists. - * - * Requires `allow-write` permission. */ - export function mkdir( - path: string | URL, - options?: MkdirOptions, - ): Promise<void>; - - export interface MakeTempOptions { - /** Directory where the temporary directory should be created (defaults to - * the env variable TMPDIR, or the system's default, usually /tmp). - * - * Note that if the passed `dir` is relative, the path returned by - * makeTempFile() and makeTempDir() will also be relative. Be mindful of - * this when changing working directory. */ - dir?: string; - /** String that should precede the random portion of the temporary - * directory's name. */ - prefix?: string; - /** String that should follow the random portion of the temporary - * directory's name. */ - suffix?: string; - } - - /** Synchronously creates a new temporary directory in the default directory - * for temporary files (see also `Deno.dir("temp")`), unless `dir` is specified. - * Other optional options include prefixing and suffixing the directory name - * with `prefix` and `suffix` respectively. - * - * The full path to the newly created directory is returned. - * - * Multiple programs calling this function simultaneously will create different - * directories. It is the caller's responsibility to remove the directory when - * no longer needed. - * - * ```ts - * const tempDirName0 = Deno.makeTempDirSync(); // e.g. /tmp/2894ea76 - * const tempDirName1 = Deno.makeTempDirSync({ prefix: 'my_temp' }); // e.g. /tmp/my_temp339c944d - * ``` - * - * Requires `allow-write` permission. */ - // TODO(ry) Doesn't check permissions. - export function makeTempDirSync(options?: MakeTempOptions): string; - - /** Creates a new temporary directory in the default directory for temporary - * files (see also `Deno.dir("temp")`), unless `dir` is specified. Other - * optional options include prefixing and suffixing the directory name with - * `prefix` and `suffix` respectively. - * - * This call resolves to the full path to the newly created directory. - * - * Multiple programs calling this function simultaneously will create different - * directories. It is the caller's responsibility to remove the directory when - * no longer needed. - * - * ```ts - * const tempDirName0 = await Deno.makeTempDir(); // e.g. /tmp/2894ea76 - * const tempDirName1 = await Deno.makeTempDir({ prefix: 'my_temp' }); // e.g. /tmp/my_temp339c944d - * ``` - * - * Requires `allow-write` permission. */ - // TODO(ry) Doesn't check permissions. - export function makeTempDir(options?: MakeTempOptions): Promise<string>; - - /** Synchronously creates a new temporary file in the default directory for - * temporary files (see also `Deno.dir("temp")`), unless `dir` is specified. - * Other optional options include prefixing and suffixing the directory name - * with `prefix` and `suffix` respectively. - * - * The full path to the newly created file is returned. - * - * Multiple programs calling this function simultaneously will create different - * files. It is the caller's responsibility to remove the file when no longer - * needed. - * - * ```ts - * const tempFileName0 = Deno.makeTempFileSync(); // e.g. /tmp/419e0bf2 - * const tempFileName1 = Deno.makeTempFileSync({ prefix: 'my_temp' }); // e.g. /tmp/my_temp754d3098 - * ``` - * - * Requires `allow-write` permission. */ - export function makeTempFileSync(options?: MakeTempOptions): string; - - /** Creates a new temporary file in the default directory for temporary - * files (see also `Deno.dir("temp")`), unless `dir` is specified. Other - * optional options include prefixing and suffixing the directory name with - * `prefix` and `suffix` respectively. - * - * This call resolves to the full path to the newly created file. - * - * Multiple programs calling this function simultaneously will create different - * files. It is the caller's responsibility to remove the file when no longer - * needed. - * - * ```ts - * const tmpFileName0 = await Deno.makeTempFile(); // e.g. /tmp/419e0bf2 - * const tmpFileName1 = await Deno.makeTempFile({ prefix: 'my_temp' }); // e.g. /tmp/my_temp754d3098 - * ``` - * - * Requires `allow-write` permission. */ - export function makeTempFile(options?: MakeTempOptions): Promise<string>; - - /** Synchronously changes the permission of a specific file/directory of - * specified path. Ignores the process's umask. - * - * ```ts - * Deno.chmodSync("/path/to/file", 0o666); - * ``` - * - * For a full description, see [chmod](#chmod) - * - * NOTE: This API currently throws on Windows - * - * Requires `allow-write` permission. */ - export function chmodSync(path: string | URL, mode: number): void; - - /** Changes the permission of a specific file/directory of specified path. - * Ignores the process's umask. - * - * ```ts - * await Deno.chmod("/path/to/file", 0o666); - * ``` - * - * The mode is a sequence of 3 octal numbers. The first/left-most number - * specifies the permissions for the owner. The second number specifies the - * permissions for the group. The last/right-most number specifies the - * permissions for others. For example, with a mode of 0o764, the owner (7) can - * read/write/execute, the group (6) can read/write and everyone else (4) can - * read only. - * - * | Number | Description | - * | ------ | ----------- | - * | 7 | read, write, and execute | - * | 6 | read and write | - * | 5 | read and execute | - * | 4 | read only | - * | 3 | write and execute | - * | 2 | write only | - * | 1 | execute only | - * | 0 | no permission | - * - * NOTE: This API currently throws on Windows - * - * Requires `allow-write` permission. */ - export function chmod(path: string | URL, mode: number): Promise<void>; - - /** Synchronously change owner of a regular file or directory. This functionality - * is not available on Windows. - * - * ```ts - * Deno.chownSync("myFile.txt", 1000, 1002); - * ``` - * - * Requires `allow-write` permission. - * - * Throws Error (not implemented) if executed on Windows - * - * @param path path to the file - * @param uid user id (UID) of the new owner, or `null` for no change - * @param gid group id (GID) of the new owner, or `null` for no change - */ - export function chownSync( - path: string | URL, - uid: number | null, - gid: number | null, - ): void; - - /** Change owner of a regular file or directory. This functionality - * is not available on Windows. - * - * ```ts - * await Deno.chown("myFile.txt", 1000, 1002); - * ``` - * - * Requires `allow-write` permission. - * - * Throws Error (not implemented) if executed on Windows - * - * @param path path to the file - * @param uid user id (UID) of the new owner, or `null` for no change - * @param gid group id (GID) of the new owner, or `null` for no change - */ - export function chown( - path: string | URL, - uid: number | null, - gid: number | null, - ): Promise<void>; - - export interface RemoveOptions { - /** Defaults to `false`. If set to `true`, path will be removed even if - * it's a non-empty directory. */ - recursive?: boolean; - } - - /** Synchronously removes the named file or directory. - * - * ```ts - * Deno.removeSync("/path/to/empty_dir/or/file"); - * Deno.removeSync("/path/to/populated_dir/or/file", { recursive: true }); - * ``` - * - * Throws error if permission denied, path not found, or path is a non-empty - * directory and the `recursive` option isn't set to `true`. - * - * Requires `allow-write` permission. */ - export function removeSync(path: string | URL, options?: RemoveOptions): void; - - /** Removes the named file or directory. - * - * ```ts - * await Deno.remove("/path/to/empty_dir/or/file"); - * await Deno.remove("/path/to/populated_dir/or/file", { recursive: true }); - * ``` - * - * Throws error if permission denied, path not found, or path is a non-empty - * directory and the `recursive` option isn't set to `true`. - * - * Requires `allow-write` permission. */ - export function remove( - path: string | URL, - options?: RemoveOptions, - ): Promise<void>; - - /** Synchronously renames (moves) `oldpath` to `newpath`. Paths may be files or - * directories. If `newpath` already exists and is not a directory, - * `renameSync()` replaces it. OS-specific restrictions may apply when - * `oldpath` and `newpath` are in different directories. - * - * ```ts - * Deno.renameSync("old/path", "new/path"); - * ``` - * - * On Unix, this operation does not follow symlinks at either path. - * - * It varies between platforms when the operation throws errors, and if so what - * they are. It's always an error to rename anything to a non-empty directory. - * - * Requires `allow-read` and `allow-write` permissions. */ - export function renameSync(oldpath: string, newpath: string): void; - - /** Renames (moves) `oldpath` to `newpath`. Paths may be files or directories. - * If `newpath` already exists and is not a directory, `rename()` replaces it. - * OS-specific restrictions may apply when `oldpath` and `newpath` are in - * different directories. - * - * ```ts - * await Deno.rename("old/path", "new/path"); - * ``` - * - * On Unix, this operation does not follow symlinks at either path. - * - * It varies between platforms when the operation throws errors, and if so what - * they are. It's always an error to rename anything to a non-empty directory. - * - * Requires `allow-read` and `allow-write` permission. */ - export function rename(oldpath: string, newpath: string): Promise<void>; - - /** Synchronously reads and returns the entire contents of a file as utf8 encoded string - * encoded string. Reading a directory returns an empty string. - * - * ```ts - * const data = Deno.readTextFileSync("hello.txt"); - * console.log(data); - * ``` - * - * Requires `allow-read` permission. */ - export function readTextFileSync(path: string | URL): string; - - /** Asynchronously reads and returns the entire contents of a file as a utf8 - * encoded string. Reading a directory returns an empty data array. - * - * ```ts - * const data = await Deno.readTextFile("hello.txt"); - * console.log(data); - * ``` - * - * Requires `allow-read` permission. */ - export function readTextFile(path: string | URL): Promise<string>; - - /** Synchronously reads and returns the entire contents of a file as an array - * of bytes. `TextDecoder` can be used to transform the bytes to string if - * required. Reading a directory returns an empty data array. - * - * ```ts - * const decoder = new TextDecoder("utf-8"); - * const data = Deno.readFileSync("hello.txt"); - * console.log(decoder.decode(data)); - * ``` - * - * Requires `allow-read` permission. */ - export function readFileSync(path: string | URL): Uint8Array; - - /** Reads and resolves to the entire contents of a file as an array of bytes. - * `TextDecoder` can be used to transform the bytes to string if required. - * Reading a directory returns an empty data array. - * - * ```ts - * const decoder = new TextDecoder("utf-8"); - * const data = await Deno.readFile("hello.txt"); - * console.log(decoder.decode(data)); - * ``` - * - * Requires `allow-read` permission. */ - export function readFile(path: string | URL): Promise<Uint8Array>; - - /** A FileInfo describes a file and is returned by `stat`, `lstat`, - * `statSync`, `lstatSync`. */ - export interface FileInfo { - /** True if this is info for a regular file. Mutually exclusive to - * `FileInfo.isDirectory` and `FileInfo.isSymlink`. */ - isFile: boolean; - /** True if this is info for a regular directory. Mutually exclusive to - * `FileInfo.isFile` and `FileInfo.isSymlink`. */ - isDirectory: boolean; - /** True if this is info for a symlink. Mutually exclusive to - * `FileInfo.isFile` and `FileInfo.isDirectory`. */ - isSymlink: boolean; - /** The size of the file, in bytes. */ - size: number; - /** The last modification time of the file. This corresponds to the `mtime` - * field from `stat` on Linux/Mac OS and `ftLastWriteTime` on Windows. This - * may not be available on all platforms. */ - mtime: Date | null; - /** The last access time of the file. This corresponds to the `atime` - * field from `stat` on Unix and `ftLastAccessTime` on Windows. This may not - * be available on all platforms. */ - atime: Date | null; - /** The creation time of the file. This corresponds to the `birthtime` - * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may - * not be available on all platforms. */ - birthtime: Date | null; - /** ID of the device containing the file. - * - * _Linux/Mac OS only._ */ - dev: number | null; - /** Inode number. - * - * _Linux/Mac OS only._ */ - ino: number | null; - /** **UNSTABLE**: Match behavior with Go on Windows for `mode`. - * - * The underlying raw `st_mode` bits that contain the standard Unix - * permissions for this file/directory. */ - mode: number | null; - /** Number of hard links pointing to this file. - * - * _Linux/Mac OS only._ */ - nlink: number | null; - /** User ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - uid: number | null; - /** Group ID of the owner of this file. - * - * _Linux/Mac OS only._ */ - gid: number | null; - /** Device ID of this file. - * - * _Linux/Mac OS only._ */ - rdev: number | null; - /** Blocksize for filesystem I/O. - * - * _Linux/Mac OS only._ */ - blksize: number | null; - /** Number of blocks allocated to the file, in 512-byte units. - * - * _Linux/Mac OS only._ */ - blocks: number | null; - } - - /** Returns absolute normalized path, with symbolic links resolved. - * - * ```ts - * // e.g. given /home/alice/file.txt and current directory /home/alice - * Deno.symlinkSync("file.txt", "symlink_file.txt"); - * const realPath = Deno.realPathSync("./file.txt"); - * const realSymLinkPath = Deno.realPathSync("./symlink_file.txt"); - * console.log(realPath); // outputs "/home/alice/file.txt" - * console.log(realSymLinkPath); // outputs "/home/alice/file.txt" - * ``` - * - * Requires `allow-read` permission for the target path. - * Also requires `allow-read` permission for the CWD if the target path is - * relative.*/ - export function realPathSync(path: string): string; - - /** Resolves to the absolute normalized path, with symbolic links resolved. - * - * ```ts - * // e.g. given /home/alice/file.txt and current directory /home/alice - * await Deno.symlink("file.txt", "symlink_file.txt"); - * const realPath = await Deno.realPath("./file.txt"); - * const realSymLinkPath = await Deno.realPath("./symlink_file.txt"); - * console.log(realPath); // outputs "/home/alice/file.txt" - * console.log(realSymLinkPath); // outputs "/home/alice/file.txt" - * ``` - * - * Requires `allow-read` permission for the target path. - * Also requires `allow-read` permission for the CWD if the target path is - * relative.*/ - export function realPath(path: string): Promise<string>; - - export interface DirEntry { - name: string; - isFile: boolean; - isDirectory: boolean; - isSymlink: boolean; - } - - /** Synchronously reads the directory given by `path` and returns an iterable - * of `Deno.DirEntry`. - * - * ```ts - * for (const dirEntry of Deno.readDirSync("/")) { - * console.log(dirEntry.name); - * } - * ``` - * - * Throws error if `path` is not a directory. - * - * Requires `allow-read` permission. */ - export function readDirSync(path: string | URL): Iterable<DirEntry>; - - /** Reads the directory given by `path` and returns an async iterable of - * `Deno.DirEntry`. - * - * ```ts - * for await (const dirEntry of Deno.readDir("/")) { - * console.log(dirEntry.name); - * } - * ``` - * - * Throws error if `path` is not a directory. - * - * Requires `allow-read` permission. */ - export function readDir(path: string | URL): AsyncIterable<DirEntry>; - - /** Synchronously copies the contents and permissions of one file to another - * specified path, by default creating a new file if needed, else overwriting. - * Fails if target path is a directory or is unwritable. - * - * ```ts - * Deno.copyFileSync("from.txt", "to.txt"); - * ``` - * - * Requires `allow-read` permission on fromPath. - * Requires `allow-write` permission on toPath. */ - export function copyFileSync( - fromPath: string | URL, - toPath: string | URL, - ): void; - - /** Copies the contents and permissions of one file to another specified path, - * by default creating a new file if needed, else overwriting. Fails if target - * path is a directory or is unwritable. - * - * ```ts - * await Deno.copyFile("from.txt", "to.txt"); - * ``` - * - * Requires `allow-read` permission on fromPath. - * Requires `allow-write` permission on toPath. */ - export function copyFile( - fromPath: string | URL, - toPath: string | URL, - ): Promise<void>; - - /** Returns the full path destination of the named symbolic link. - * - * ```ts - * Deno.symlinkSync("./test.txt", "./test_link.txt"); - * const target = Deno.readLinkSync("./test_link.txt"); // full path of ./test.txt - * ``` - * - * Throws TypeError if called with a hard link - * - * Requires `allow-read` permission. */ - export function readLinkSync(path: string): string; - - /** Resolves to the full path destination of the named symbolic link. - * - * ```ts - * await Deno.symlink("./test.txt", "./test_link.txt"); - * const target = await Deno.readLink("./test_link.txt"); // full path of ./test.txt - * ``` - * - * Throws TypeError if called with a hard link - * - * Requires `allow-read` permission. */ - export function readLink(path: string): Promise<string>; - - /** Resolves to a `Deno.FileInfo` for the specified `path`. If `path` is a - * symlink, information for the symlink will be returned instead of what it - * points to. - * - * ```ts - * import { assert } from "https://deno.land/std/testing/asserts.ts"; - * const fileInfo = await Deno.lstat("hello.txt"); - * assert(fileInfo.isFile); - * ``` - * - * Requires `allow-read` permission. */ - export function lstat(path: string | URL): Promise<FileInfo>; - - /** Synchronously returns a `Deno.FileInfo` for the specified `path`. If - * `path` is a symlink, information for the symlink will be returned instead of - * what it points to.. - * - * ```ts - * const fileInfo = Deno.lstatSync("hello.txt"); - * assert(fileInfo.isFile); - * ``` - * - * Requires `allow-read` permission. */ - export function lstatSync(path: string | URL): FileInfo; - - /** Resolves to a `Deno.FileInfo` for the specified `path`. Will always - * follow symlinks. - * - * ```ts - * import { assert } from "https://deno.land/std/testing/asserts.ts"; - * const fileInfo = await Deno.stat("hello.txt"); - * assert(fileInfo.isFile); - * ``` - * - * Requires `allow-read` permission. */ - export function stat(path: string | URL): Promise<FileInfo>; - - /** Synchronously returns a `Deno.FileInfo` for the specified `path`. Will - * always follow symlinks. - * - * ```ts - * import { assert } from "https://deno.land/std/testing/asserts.ts"; - * const fileInfo = Deno.statSync("hello.txt"); - * assert(fileInfo.isFile); - * ``` - * - * Requires `allow-read` permission. */ - export function statSync(path: string | URL): FileInfo; - - /** Options for writing to a file. */ - export interface WriteFileOptions { - /** Defaults to `false`. If set to `true`, will append to a file instead of - * overwriting previous contents. */ - append?: boolean; - /** Sets the option to allow creating a new file, if one doesn't already - * exist at the specified path (defaults to `true`). */ - create?: boolean; - /** Permissions always applied to file. */ - mode?: number; - } - - /** Synchronously write `data` to the given `path`, by default creating a new - * file if needed, else overwriting. - * - * ```ts - * const encoder = new TextEncoder(); - * const data = encoder.encode("Hello world\n"); - * Deno.writeFileSync("hello1.txt", data); // overwrite "hello1.txt" or create it - * Deno.writeFileSync("hello2.txt", data, {create: false}); // only works if "hello2.txt" exists - * Deno.writeFileSync("hello3.txt", data, {mode: 0o777}); // set permissions on new file - * Deno.writeFileSync("hello4.txt", data, {append: true}); // add data to the end of the file - * ``` - * - * Requires `allow-write` permission, and `allow-read` if `options.create` is - * `false`. - */ - export function writeFileSync( - path: string | URL, - data: Uint8Array, - options?: WriteFileOptions, - ): void; - - /** Write `data` to the given `path`, by default creating a new file if needed, - * else overwriting. - * - * ```ts - * const encoder = new TextEncoder(); - * const data = encoder.encode("Hello world\n"); - * await Deno.writeFile("hello1.txt", data); // overwrite "hello1.txt" or create it - * await Deno.writeFile("hello2.txt", data, {create: false}); // only works if "hello2.txt" exists - * await Deno.writeFile("hello3.txt", data, {mode: 0o777}); // set permissions on new file - * await Deno.writeFile("hello4.txt", data, {append: true}); // add data to the end of the file - * ``` - * - * Requires `allow-write` permission, and `allow-read` if `options.create` is `false`. - */ - export function writeFile( - path: string | URL, - data: Uint8Array, - options?: WriteFileOptions, - ): Promise<void>; - - /** Synchronously write string `data` to the given `path`, by default creating a new file if needed, - * else overwriting. - * - * ```ts - * await Deno.writeTextFileSync("hello1.txt", "Hello world\n"); // overwrite "hello1.txt" or create it - * ``` - * - * Requires `allow-write` permission, and `allow-read` if `options.create` is `false`. - */ - export function writeTextFileSync( - path: string | URL, - data: string, - options?: WriteFileOptions, - ): void; - - /** Asynchronously write string `data` to the given `path`, by default creating a new file if needed, - * else overwriting. - * - * ```ts - * await Deno.writeTextFile("hello1.txt", "Hello world\n"); // overwrite "hello1.txt" or create it - * ``` - * - * Requires `allow-write` permission, and `allow-read` if `options.create` is `false`. - */ - export function writeTextFile( - path: string | URL, - data: string, - options?: WriteFileOptions, - ): Promise<void>; - - /** Synchronously truncates or extends the specified file, to reach the - * specified `len`. If `len` is not specified then the entire file contents - * are truncated. - * - * ```ts - * // truncate the entire file - * Deno.truncateSync("my_file.txt"); - * - * // truncate part of the file - * const file = Deno.makeTempFileSync(); - * Deno.writeFileSync(file, new TextEncoder().encode("Hello World")); - * Deno.truncateSync(file, 7); - * const data = Deno.readFileSync(file); - * console.log(new TextDecoder().decode(data)); - * ``` - * - * Requires `allow-write` permission. */ - export function truncateSync(name: string, len?: number): void; - - /** Truncates or extends the specified file, to reach the specified `len`. If - * `len` is not specified then the entire file contents are truncated. - * - * ```ts - * // truncate the entire file - * await Deno.truncate("my_file.txt"); - * - * // truncate part of the file - * const file = await Deno.makeTempFile(); - * await Deno.writeFile(file, new TextEncoder().encode("Hello World")); - * await Deno.truncate(file, 7); - * const data = await Deno.readFile(file); - * console.log(new TextDecoder().decode(data)); // "Hello W" - * ``` - * - * Requires `allow-write` permission. */ - export function truncate(name: string, len?: number): Promise<void>; - - export interface NetAddr { - transport: "tcp" | "udp"; - hostname: string; - port: number; - } - - export interface UnixAddr { - transport: "unix" | "unixpacket"; - path: string; - } - - export type Addr = NetAddr | UnixAddr; - - /** A generic network listener for stream-oriented protocols. */ - export interface Listener extends AsyncIterable<Conn> { - /** Waits for and resolves to the next connection to the `Listener`. */ - accept(): Promise<Conn>; - /** Close closes the listener. Any pending accept promises will be rejected - * with errors. */ - close(): void; - /** Return the address of the `Listener`. */ - readonly addr: Addr; - - /** Return the rid of the `Listener`. */ - readonly rid: number; - - [Symbol.asyncIterator](): AsyncIterableIterator<Conn>; - } - - export interface Conn extends Reader, Writer, Closer { - /** The local address of the connection. */ - readonly localAddr: Addr; - /** The remote address of the connection. */ - readonly remoteAddr: Addr; - /** The resource ID of the connection. */ - readonly rid: number; - /** Shuts down (`shutdown(2)`) the writing side of the TCP connection. Most - * callers should just use `close()`. - * - * **Unstable** because of lack of testing and because Deno.shutdown is also - * unstable. - * */ - closeWrite(): void; - } - - export interface ListenOptions { - /** The port to listen on. */ - port: number; - /** A literal IP address or host name that can be resolved to an IP address. - * If not specified, defaults to `0.0.0.0`. */ - hostname?: string; - } - - /** Listen announces on the local transport address. - * - * ```ts - * const listener1 = Deno.listen({ port: 80 }) - * const listener2 = Deno.listen({ hostname: "192.0.2.1", port: 80 }) - * const listener3 = Deno.listen({ hostname: "[2001:db8::1]", port: 80 }); - * const listener4 = Deno.listen({ hostname: "golang.org", port: 80, transport: "tcp" }); - * ``` - * - * Requires `allow-net` permission. */ - export function listen( - options: ListenOptions & { transport?: "tcp" }, - ): Listener; - - export interface ListenTlsOptions extends ListenOptions { - /** Server certificate file. */ - certFile: string; - /** Server public key file. */ - keyFile: string; - - transport?: "tcp"; - } - - /** Listen announces on the local transport address over TLS (transport layer - * security). - * - * ```ts - * const lstnr = Deno.listenTls({ port: 443, certFile: "./server.crt", keyFile: "./server.key" }); - * ``` - * - * Requires `allow-net` permission. */ - export function listenTls(options: ListenTlsOptions): Listener; - - export interface ConnectOptions { - /** The port to connect to. */ - port: number; - /** A literal IP address or host name that can be resolved to an IP address. - * If not specified, defaults to `127.0.0.1`. */ - hostname?: string; - transport?: "tcp"; - } - - /** - * Connects to the hostname (default is "127.0.0.1") and port on the named - * transport (default is "tcp"), and resolves to the connection (`Conn`). - * - * ```ts - * const conn1 = await Deno.connect({ port: 80 }); - * const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 }); - * const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 }); - * const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" }); - * ``` - * - * Requires `allow-net` permission for "tcp". */ - export function connect(options: ConnectOptions): Promise<Conn>; - - export interface ConnectTlsOptions { - /** The port to connect to. */ - port: number; - /** A literal IP address or host name that can be resolved to an IP address. - * If not specified, defaults to `127.0.0.1`. */ - hostname?: string; - /** Server certificate file. */ - certFile?: string; - } - - /** Establishes a secure connection over TLS (transport layer security) using - * an optional cert file, hostname (default is "127.0.0.1") and port. The - * cert file is optional and if not included Mozilla's root certificates will - * be used (see also https://github.com/ctz/webpki-roots for specifics) - * - * ```ts - * const conn1 = await Deno.connectTls({ port: 80 }); - * const conn2 = await Deno.connectTls({ certFile: "./certs/my_custom_root_CA.pem", hostname: "192.0.2.1", port: 80 }); - * const conn3 = await Deno.connectTls({ hostname: "[2001:db8::1]", port: 80 }); - * const conn4 = await Deno.connectTls({ certFile: "./certs/my_custom_root_CA.pem", hostname: "golang.org", port: 80}); - * ``` - * - * Requires `allow-net` permission. - */ - export function connectTls(options: ConnectTlsOptions): Promise<Conn>; - - 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; - } - - /** Receive metrics from the privileged side of Deno. This is primarily used - * in the development of Deno. 'Ops', also called 'bindings', are the go-between - * between Deno JavaScript and Deno Rust. - * - * > console.table(Deno.metrics()) - * ┌─────────────────────────┬────────┐ - * │ (index) │ Values │ - * ├─────────────────────────┼────────┤ - * │ opsDispatched │ 3 │ - * │ opsDispatchedSync │ 2 │ - * │ opsDispatchedAsync │ 1 │ - * │ opsDispatchedAsyncUnref │ 0 │ - * │ opsCompleted │ 3 │ - * │ opsCompletedSync │ 2 │ - * │ opsCompletedAsync │ 1 │ - * │ opsCompletedAsyncUnref │ 0 │ - * │ bytesSentControl │ 73 │ - * │ bytesSentData │ 0 │ - * │ bytesReceived │ 375 │ - * └─────────────────────────┴────────┘ - */ - export function metrics(): Metrics; - - interface ResourceMap { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [rid: number]: any; - } - - /** Returns a map of open resource ids (rid) along with their string - * representations. This is an internal API and as such resource - * representation has `any` type; that means it can change any time. - * - * ```ts - * console.log(Deno.resources()); - * // { 0: "stdin", 1: "stdout", 2: "stderr" } - * Deno.openSync('../test.file'); - * console.log(Deno.resources()); - * // { 0: "stdin", 1: "stdout", 2: "stderr", 3: "fsFile" } - * ``` - */ - export function resources(): ResourceMap; - - export interface FsEvent { - kind: "any" | "access" | "create" | "modify" | "remove"; - paths: string[]; - } - - /** Watch for file system events against one or more `paths`, which can be files - * or directories. These paths must exist already. One user action (e.g. - * `touch test.file`) can generate multiple file system events. Likewise, - * one user action can result in multiple file paths in one event (e.g. `mv - * old_name.txt new_name.txt`). Recursive option is `true` by default and, - * for directories, will watch the specified directory and all sub directories. - * Note that the exact ordering of the events can vary between operating systems. - * - * ```ts - * const watcher = Deno.watchFs("/"); - * for await (const event of watcher) { - * console.log(">>>> event", event); - * // { kind: "create", paths: [ "/foo.txt" ] } - * } - *``` - * - * Requires `allow-read` permission. - */ - export function watchFs( - paths: string | string[], - options?: { recursive: boolean }, - ): AsyncIterableIterator<FsEvent>; - - 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; - /** Resolves to the current status of the process. */ - status(): Promise<ProcessStatus>; - /** Buffer the stdout until EOF and return it as `Uint8Array`. - * - * You must set stdout to `"piped"` when creating the process. - * - * This calls `close()` on stdout after its done. */ - output(): Promise<Uint8Array>; - /** Buffer the stderr until EOF and return it as `Uint8Array`. - * - * You must set stderr to `"piped"` when creating the process. - * - * This calls `close()` on stderr after its done. */ - stderrOutput(): Promise<Uint8Array>; - close(): void; - - /** **UNSTABLE**: The `signo` argument may change to require the Deno.Signal - * enum. - * - * Send a signal to process. This functionality currently only works on - * Linux and Mac OS. - */ - kill(signo: number): void; - } - - export type ProcessStatus = - | { - success: true; - code: 0; - signal?: undefined; - } - | { - success: false; - code: number; - signal?: number; - }; - - export interface RunOptions { - /** Arguments to pass. Note, the first element needs to be a path to the - * binary */ - cmd: string[]; - cwd?: string; - env?: { - [key: string]: string; - }; - stdout?: "inherit" | "piped" | "null" | number; - stderr?: "inherit" | "piped" | "null" | number; - stdin?: "inherit" | "piped" | "null" | number; - } - - /** Spawns new subprocess. RunOptions must contain at a minimum the `opt.cmd`, - * an array of program arguments, the first of which is the binary. - * - * ```ts - * const p = Deno.run({ - * cmd: ["echo", "hello"], - * }); - * ``` - * - * Subprocess uses same working directory as parent process unless `opt.cwd` - * is specified. - * - * Environmental variables for subprocess can be specified using `opt.env` - * mapping. - * - * By default subprocess inherits stdio of parent process. To change that - * `opt.stdout`, `opt.stderr` and `opt.stdin` can be specified independently - - * they can be set to either an rid of open file or set to "inherit" "piped" - * or "null": - * - * `"inherit"` The default if unspecified. The child inherits from the - * corresponding parent descriptor. - * - * `"piped"` A new pipe should be arranged to connect the parent and child - * sub-processes. - * - * `"null"` This stream will be ignored. This is the equivalent of attaching - * the stream to `/dev/null`. - * - * Details of the spawned process are returned. - * - * Requires `allow-run` permission. */ - export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>; - - export interface InspectOptions { - /** Traversal depth for nested objects. Defaults to 4. */ - depth?: number; - /** Sort Object, Set and Map entries by key. Defaults to false. */ - sorted?: boolean; - /** Add a trailing comma for multiline collections. Defaults to false. */ - trailingComma?: boolean; - /** Try to fit more than one entry of a collection on the same line. - * Defaults to true. */ - compact?: boolean; - /** The maximum number of iterable entries to print. Defaults to 100. */ - iterableLimit?: number; - } - - /** Converts the input into a string that has the same format as printed by - * `console.log()`. - * - * ```ts - * const obj = {}; - * obj.propA = 10; - * obj.propB = "hello"; - * const objAsString = Deno.inspect(obj); // { propA: 10, propB: "hello" } - * console.log(obj); // prints same value as objAsString, e.g. { propA: 10, propB: "hello" } - * ``` - * - * You can also register custom inspect functions, via the `customInspect` Deno - * symbol on objects, to control and customize the output. - * - * ```ts - * class A { - * x = 10; - * y = "hello"; - * [Deno.customInspect](): string { - * return "x=" + this.x + ", y=" + this.y; - * } - * } - * ``` - * - * const inStringFormat = Deno.inspect(new A()); // "x=10, y=hello" - * console.log(inStringFormat); // prints "x=10, y=hello" - * - * Finally, you can also specify the depth to which it will format. - * - * Deno.inspect({a: {b: {c: {d: 'hello'}}}}, {depth: 2}); // { a: { b: [Object] } } - * - */ - export function inspect(value: unknown, options?: InspectOptions): string; - - /** Build related information. */ - export const build: { - /** The LLVM target triple */ - target: string; - /** Instruction set architecture */ - arch: "x86_64"; - /** Operating system */ - os: "darwin" | "linux" | "windows"; - /** Computer vendor */ - vendor: string; - /** Optional environment */ - env?: string; - }; - - interface Version { - deno: string; - v8: string; - typescript: string; - } - /** Version related information. */ - export const version: Version; - - /** Returns the script arguments to the program. If for example we run a - * program: - * - * deno run --allow-read https://deno.land/std/examples/cat.ts /etc/passwd - * - * Then `Deno.args` will contain: - * - * [ "/etc/passwd" ] - */ - export const args: string[]; - - /** A symbol which can be used as a key for a custom method which will be - * called when `Deno.inspect()` is called, or when the object is logged to - * the console. */ - export const customInspect: unique symbol; -} diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts deleted file mode 100644 index c77f1ea0e..000000000 --- a/cli/js/lib.deno.shared_globals.d.ts +++ /dev/null @@ -1,1657 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, no-var */ - -/// <reference no-default-lib="true" /> -/// <reference lib="esnext" /> - -// This follows the WebIDL at: https://webassembly.github.io/spec/js-api/ -// and: https://webassembly.github.io/spec/web-api/ -declare namespace WebAssembly { - interface WebAssemblyInstantiatedSource { - module: Module; - instance: Instance; - } - - /** Compiles a `WebAssembly.Module` from WebAssembly binary code. This - * function is useful if it is necessary to a compile a module before it can - * be instantiated (otherwise, the `WebAssembly.instantiate()` function - * should be used). */ - function compile(bufferSource: BufferSource): Promise<Module>; - - /** Compiles a `WebAssembly.Module` directly from a streamed underlying - * source. This function is useful if it is necessary to a compile a module - * before it can be instantiated (otherwise, the - * `WebAssembly.instantiateStreaming()` function should be used). */ - function compileStreaming(source: Promise<Response>): Promise<Module>; - - /** Takes the WebAssembly binary code, in the form of a typed array or - * `ArrayBuffer`, and performs both compilation and instantiation in one step. - * The returned `Promise` resolves to both a compiled `WebAssembly.Module` and - * its first `WebAssembly.Instance`. */ - function instantiate( - bufferSource: BufferSource, - importObject?: object, - ): Promise<WebAssemblyInstantiatedSource>; - - /** Takes an already-compiled `WebAssembly.Module` and returns a `Promise` - * that resolves to an `Instance` of that `Module`. This overload is useful if - * the `Module` has already been compiled. */ - function instantiate( - module: Module, - importObject?: object, - ): Promise<Instance>; - - /** Compiles and instantiates a WebAssembly module directly from a streamed - * underlying source. This is the most efficient, optimized way to load wasm - * code. */ - function instantiateStreaming( - source: Promise<Response>, - importObject?: object, - ): Promise<WebAssemblyInstantiatedSource>; - - /** Validates a given typed array of WebAssembly binary code, returning - * whether the bytes form a valid wasm module (`true`) or not (`false`). */ - function validate(bufferSource: BufferSource): boolean; - - type ImportExportKind = "function" | "table" | "memory" | "global"; - - interface ModuleExportDescriptor { - name: string; - kind: ImportExportKind; - } - interface ModuleImportDescriptor { - module: string; - name: string; - kind: ImportExportKind; - } - - class Module { - constructor(bufferSource: BufferSource); - - /** Given a `Module` and string, returns a copy of the contents of all - * custom sections in the module with the given string name. */ - static customSections( - moduleObject: Module, - sectionName: string, - ): ArrayBuffer; - - /** Given a `Module`, returns an array containing descriptions of all the - * declared exports. */ - static exports(moduleObject: Module): ModuleExportDescriptor[]; - - /** Given a `Module`, returns an array containing descriptions of all the - * declared imports. */ - static imports(moduleObject: Module): ModuleImportDescriptor[]; - } - - class Instance<T extends object = { [key: string]: any }> { - constructor(module: Module, importObject?: object); - - /** An object containing as its members all the functions exported from the - * WebAssembly module instance, to allow them to be accessed and used by - * JavaScript. */ - readonly exports: T; - } - - interface MemoryDescriptor { - initial: number; - maximum?: number; - } - - class Memory { - constructor(descriptor: MemoryDescriptor); - - /** An accessor property that returns the buffer contained in the memory. */ - readonly buffer: ArrayBuffer; - - /** Increases the size of the memory instance by a specified number of - * WebAssembly pages (each one is 64KB in size). */ - grow(delta: number): number; - } - - type TableKind = "anyfunc"; - - interface TableDescriptor { - element: TableKind; - initial: number; - maximum?: number; - } - - class Table { - constructor(descriptor: TableDescriptor); - - /** Returns the length of the table, i.e. the number of elements. */ - readonly length: number; - - /** Accessor function — gets the element stored at a given index. */ - get(index: number): (...args: any[]) => any; - - /** Increases the size of the Table instance by a specified number of - * elements. */ - grow(delta: number): number; - - /** Sets an element stored at a given index to a given value. */ - set(index: number, value: (...args: any[]) => any): void; - } - - type ValueType = "i32" | "i64" | "f32" | "f64"; - - interface GlobalDescriptor { - value: ValueType; - mutable?: boolean; - } - - /** Represents a global variable instance, accessible from both JavaScript and - * importable/exportable across one or more `WebAssembly.Module` instances. - * This allows dynamic linking of multiple modules. */ - class Global { - constructor(descriptor: GlobalDescriptor, value?: any); - - /** Old-style method that returns the value contained inside the global - * variable. */ - valueOf(): any; - - /** The value contained inside the global variable — this can be used to - * directly set and get the global's value. */ - value: any; - } - - /** Indicates an error during WebAssembly decoding or validation */ - class CompileError extends Error { - constructor(message: string, fileName?: string, lineNumber?: string); - } - - /** Indicates an error during module instantiation (besides traps from the - * start function). */ - class LinkError extends Error { - constructor(message: string, fileName?: string, lineNumber?: string); - } - - /** Is thrown whenever WebAssembly specifies a trap. */ - class RuntimeError extends Error { - constructor(message: string, fileName?: string, lineNumber?: string); - } -} - -/** Sets a timer which executes a function once after the timer expires. Returns - * an id which may be used to cancel the timeout. - * - * setTimeout(() => { console.log('hello'); }, 500); - */ -declare function setTimeout( - /** callback function to execute when timer expires */ - cb: (...args: any[]) => void, - /** delay in ms */ - delay?: number, - /** arguments passed to callback function */ - ...args: any[] -): number; - -/** Repeatedly calls a function , with a fixed time delay between each call. - * - * // Outputs 'hello' to the console every 500ms - * setInterval(() => { console.log('hello'); }, 500); - */ -declare function setInterval( - /** callback function to execute when timer expires */ - cb: (...args: any[]) => void, - /** delay in ms */ - delay?: number, - /** arguments passed to callback function */ - ...args: any[] -): number; - -/** Cancels a timed, repeating action which was previously started by a call - * to `setInterval()` - * - * const id = setInterval(()= > {console.log('hello');}, 500); - * ... - * clearInterval(id); - */ -declare function clearInterval(id?: number): void; - -/** Cancels a scheduled action initiated by `setTimeout()` - * - * const id = setTimeout(()= > {console.log('hello');}, 500); - * ... - * clearTimeout(id); - */ -declare function clearTimeout(id?: number): void; - -interface VoidFunction { - (): void; -} - -/** A microtask is a short function which is executed after the function or - * module which created it exits and only if the JavaScript execution stack is - * empty, but before returning control to the event loop being used to drive the - * script's execution environment. This event loop may be either the main event - * loop or the event loop driving a web worker. - * - * queueMicrotask(() => { console.log('This event loop stack is complete'); }); - */ -declare function queueMicrotask(func: VoidFunction): void; - -declare var console: Console; -declare var crypto: Crypto; - -/** Registers an event listener in the global scope, which will be called - * synchronously whenever the event `type` is dispatched. - * - * addEventListener('unload', () => { console.log('All finished!'); }); - * ... - * dispatchEvent(new Event('unload')); - */ -declare function addEventListener( - type: string, - callback: EventListenerOrEventListenerObject | null, - options?: boolean | AddEventListenerOptions | undefined, -): void; - -/** Dispatches an event in the global scope, synchronously invoking any - * registered event listeners for this event in the appropriate order. Returns - * false if event is cancelable and at least one of the event handlers which - * handled this event called Event.preventDefault(). Otherwise it returns true. - * - * dispatchEvent(new Event('unload')); - */ -declare function dispatchEvent(event: Event): boolean; - -/** Remove a previously registered event listener from the global scope - * - * const lstnr = () => { console.log('hello'); }; - * addEventListener('load', lstnr); - * removeEventListener('load', lstnr); - */ -declare function removeEventListener( - type: string, - callback: EventListenerOrEventListenerObject | null, - options?: boolean | EventListenerOptions | undefined, -): void; - -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, - thisArg?: any, - ): void; -} - -interface ReadableStreamReadDoneResult<T> { - done: true; - value?: T; -} - -interface ReadableStreamReadValueResult<T> { - done: false; - value: T; -} - -type ReadableStreamReadResult<T> = - | ReadableStreamReadValueResult<T> - | ReadableStreamReadDoneResult<T>; - -interface ReadableStreamDefaultReader<R = any> { - readonly closed: Promise<void>; - cancel(reason?: any): Promise<void>; - read(): Promise<ReadableStreamReadResult<R>>; - releaseLock(): void; -} - -interface ReadableStreamReader<R = any> { - cancel(): Promise<void>; - read(): Promise<ReadableStreamReadResult<R>>; - releaseLock(): void; -} - -interface ReadableByteStreamControllerCallback { - (controller: ReadableByteStreamController): void | PromiseLike<void>; -} - -interface UnderlyingByteSource { - autoAllocateChunkSize?: number; - cancel?: ReadableStreamErrorCallback; - pull?: ReadableByteStreamControllerCallback; - start?: ReadableByteStreamControllerCallback; - type: "bytes"; -} - -interface UnderlyingSource<R = any> { - cancel?: ReadableStreamErrorCallback; - pull?: ReadableStreamDefaultControllerCallback<R>; - start?: ReadableStreamDefaultControllerCallback<R>; - type?: undefined; -} - -interface ReadableStreamErrorCallback { - (reason: any): void | PromiseLike<void>; -} - -interface ReadableStreamDefaultControllerCallback<R> { - (controller: ReadableStreamDefaultController<R>): void | PromiseLike<void>; -} - -interface ReadableStreamDefaultController<R = any> { - readonly desiredSize: number | null; - close(): void; - enqueue(chunk: R): void; - error(error?: any): void; -} - -interface ReadableByteStreamController { - readonly byobRequest: undefined; - readonly desiredSize: number | null; - close(): void; - enqueue(chunk: ArrayBufferView): void; - error(error?: any): void; -} - -interface PipeOptions { - preventAbort?: boolean; - preventCancel?: boolean; - preventClose?: boolean; - signal?: AbortSignal; -} - -interface QueuingStrategySizeCallback<T = any> { - (chunk: T): number; -} - -interface QueuingStrategy<T = any> { - highWaterMark?: number; - size?: QueuingStrategySizeCallback<T>; -} - -/** This Streams API interface provides a built-in byte length queuing strategy - * that can be used when constructing streams. */ -declare class CountQueuingStrategy implements QueuingStrategy { - constructor(options: { highWaterMark: number }); - highWaterMark: number; - size(chunk: any): 1; -} - -declare class ByteLengthQueuingStrategy - implements QueuingStrategy<ArrayBufferView> { - constructor(options: { highWaterMark: number }); - highWaterMark: number; - size(chunk: ArrayBufferView): number; -} - -/** This Streams API interface represents a readable stream of byte data. The - * Fetch API offers a concrete instance of a ReadableStream through the body - * property of a Response object. */ -interface ReadableStream<R = any> { - readonly locked: boolean; - cancel(reason?: any): Promise<void>; - getIterator(options?: { preventCancel?: boolean }): AsyncIterableIterator<R>; - // getReader(options: { mode: "byob" }): ReadableStreamBYOBReader; - getReader(): ReadableStreamDefaultReader<R>; - pipeThrough<T>( - { - writable, - readable, - }: { - writable: WritableStream<R>; - readable: ReadableStream<T>; - }, - options?: PipeOptions, - ): ReadableStream<T>; - pipeTo(dest: WritableStream<R>, options?: PipeOptions): Promise<void>; - tee(): [ReadableStream<R>, ReadableStream<R>]; - [Symbol.asyncIterator](options?: { - preventCancel?: boolean; - }): AsyncIterableIterator<R>; -} - -declare var ReadableStream: { - prototype: ReadableStream; - new ( - underlyingSource: UnderlyingByteSource, - strategy?: { highWaterMark?: number; size?: undefined }, - ): ReadableStream<Uint8Array>; - new <R = any>( - underlyingSource?: UnderlyingSource<R>, - strategy?: QueuingStrategy<R>, - ): ReadableStream<R>; -}; - -interface WritableStreamDefaultControllerCloseCallback { - (): void | PromiseLike<void>; -} - -interface WritableStreamDefaultControllerStartCallback { - (controller: WritableStreamDefaultController): void | PromiseLike<void>; -} - -interface WritableStreamDefaultControllerWriteCallback<W> { - (chunk: W, controller: WritableStreamDefaultController): - | void - | PromiseLike< - void - >; -} - -interface WritableStreamErrorCallback { - (reason: any): void | PromiseLike<void>; -} - -interface UnderlyingSink<W = any> { - abort?: WritableStreamErrorCallback; - close?: WritableStreamDefaultControllerCloseCallback; - start?: WritableStreamDefaultControllerStartCallback; - type?: undefined; - write?: WritableStreamDefaultControllerWriteCallback<W>; -} - -/** This Streams API interface provides a standard abstraction for writing - * streaming data to a destination, known as a sink. This object comes with - * built-in backpressure and queuing. */ -declare class WritableStream<W = any> { - constructor( - underlyingSink?: UnderlyingSink<W>, - strategy?: QueuingStrategy<W>, - ); - readonly locked: boolean; - abort(reason?: any): Promise<void>; - close(): Promise<void>; - getWriter(): WritableStreamDefaultWriter<W>; -} - -/** This Streams API interface represents a controller allowing control of a - * WritableStream's state. When constructing a WritableStream, the underlying - * sink is given a corresponding WritableStreamDefaultController instance to - * manipulate. */ -interface WritableStreamDefaultController { - error(error?: any): void; -} - -/** This Streams API interface is the object returned by - * WritableStream.getWriter() and once created locks the < writer to the - * WritableStream ensuring that no other streams can write to the underlying - * sink. */ -interface WritableStreamDefaultWriter<W = any> { - readonly closed: Promise<void>; - readonly desiredSize: number | null; - readonly ready: Promise<void>; - abort(reason?: any): Promise<void>; - close(): Promise<void>; - releaseLock(): void; - write(chunk: W): Promise<void>; -} - -declare class TransformStream<I = any, O = any> { - constructor( - transformer?: Transformer<I, O>, - writableStrategy?: QueuingStrategy<I>, - readableStrategy?: QueuingStrategy<O>, - ); - readonly readable: ReadableStream<O>; - readonly writable: WritableStream<I>; -} - -interface TransformStreamDefaultController<O = any> { - readonly desiredSize: number | null; - enqueue(chunk: O): void; - error(reason?: any): void; - terminate(): void; -} - -interface Transformer<I = any, O = any> { - flush?: TransformStreamDefaultControllerCallback<O>; - readableType?: undefined; - start?: TransformStreamDefaultControllerCallback<O>; - transform?: TransformStreamDefaultControllerTransformCallback<I, O>; - writableType?: undefined; -} - -interface TransformStreamDefaultControllerCallback<O> { - (controller: TransformStreamDefaultController<O>): void | PromiseLike<void>; -} - -interface TransformStreamDefaultControllerTransformCallback<I, O> { - ( - chunk: I, - controller: TransformStreamDefaultController<O>, - ): void | PromiseLike<void>; -} - -interface DOMStringList { - /** Returns the number of strings in strings. */ - readonly length: number; - /** Returns true if strings contains string, and false otherwise. */ - contains(string: string): boolean; - /** Returns the string with index index from strings. */ - item(index: number): string | null; - [index: number]: string; -} - -declare class DOMException extends Error { - constructor(message?: string, name?: string); - readonly name: string; - readonly message: string; -} - -type BufferSource = ArrayBufferView | ArrayBuffer; -type BlobPart = BufferSource | Blob | string; - -interface BlobPropertyBag { - type?: string; - ending?: "transparent" | "native"; -} - -/** A file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system. */ -interface Blob { - readonly size: number; - readonly type: string; - arrayBuffer(): Promise<ArrayBuffer>; - slice(start?: number, end?: number, contentType?: string): Blob; - stream(): ReadableStream; - text(): Promise<string>; -} - -declare const Blob: { - prototype: Blob; - new (blobParts?: BlobPart[], options?: BlobPropertyBag): Blob; -}; - -interface FilePropertyBag extends BlobPropertyBag { - lastModified?: number; -} - -/** Provides information about files and allows JavaScript in a web page to - * access their content. */ -interface File extends Blob { - readonly lastModified: number; - readonly name: string; -} - -declare const File: { - prototype: File; - new (fileBits: BlobPart[], fileName: string, options?: FilePropertyBag): File; -}; - -declare const isConsoleInstance: unique symbol; - -declare class Console { - indentLevel: number; - [isConsoleInstance]: boolean; - /** Writes the arguments to stdout */ - log: (...args: unknown[]) => void; - /** Writes the arguments to stdout */ - debug: (...args: unknown[]) => void; - /** Writes the arguments to stdout */ - info: (...args: unknown[]) => void; - /** Writes the properties of the supplied `obj` to stdout */ - dir: ( - obj: unknown, - options?: Partial<{ - depth: number; - indentLevel: number; - }>, - ) => void; - - /** From MDN: - * Displays an interactive tree of the descendant elements of - * the specified XML/HTML element. If it is not possible to display - * as an element the JavaScript Object view is shown instead. - * The output is presented as a hierarchical listing of expandable - * nodes that let you see the contents of child nodes. - * - * Since we write to stdout, we can't display anything interactive - * we just fall back to `console.dir`. - */ - dirxml: ( - obj: unknown, - options?: Partial<{ - showHidden: boolean; - depth: number; - colors: boolean; - indentLevel: number; - }>, - ) => void; - - /** Writes the arguments to stdout */ - warn: (...args: unknown[]) => void; - /** Writes the arguments to stdout */ - error: (...args: unknown[]) => void; - /** Writes an error message to stdout if the assertion is `false`. If the - * assertion is `true`, nothing happens. - * - * ref: https://console.spec.whatwg.org/#assert - */ - assert: (condition?: boolean, ...args: unknown[]) => void; - count: (label?: string) => void; - countReset: (label?: string) => void; - table: (data: unknown, properties?: string[] | undefined) => void; - time: (label?: string) => void; - timeLog: (label?: string, ...args: unknown[]) => void; - timeEnd: (label?: string) => void; - group: (...label: unknown[]) => void; - groupCollapsed: (...label: unknown[]) => void; - groupEnd: () => void; - clear: () => void; - trace: (...args: unknown[]) => void; - static [Symbol.hasInstance](instance: Console): boolean; -} - -declare interface Crypto { - readonly subtle: null; - getRandomValues< - T extends - | Int8Array - | Int16Array - | Int32Array - | Uint8Array - | Uint16Array - | Uint32Array - | Uint8ClampedArray - | Float32Array - | Float64Array - | DataView - | null, - >( - array: T, - ): T; -} - -type FormDataEntryValue = File | string; - -/** Provides a way to easily construct a set of key/value pairs representing - * form fields and their values, which can then be easily sent using the - * XMLHttpRequest.send() method. It uses the same format a form would use if the - * encoding type were set to "multipart/form-data". */ -interface FormData extends DomIterable<string, FormDataEntryValue> { - append(name: string, value: string | Blob, fileName?: string): void; - delete(name: string): void; - get(name: string): FormDataEntryValue | null; - getAll(name: string): FormDataEntryValue[]; - has(name: string): boolean; - set(name: string, value: string | Blob, fileName?: string): void; -} - -declare const FormData: { - prototype: FormData; - // TODO(ry) FormData constructor is non-standard. - // new(form?: HTMLFormElement): FormData; - new (): FormData; -}; - -interface Body { - /** A simple getter used to expose a `ReadableStream` of the body contents. */ - readonly body: ReadableStream<Uint8Array> | null; - /** Stores a `Boolean` that declares whether the body has been used in a - * response yet. - */ - readonly bodyUsed: boolean; - /** Takes a `Response` stream and reads it to completion. It returns a promise - * that resolves with an `ArrayBuffer`. - */ - arrayBuffer(): Promise<ArrayBuffer>; - /** Takes a `Response` stream and reads it to completion. It returns a promise - * that resolves with a `Blob`. - */ - blob(): Promise<Blob>; - /** Takes a `Response` stream and reads it to completion. It returns a promise - * that resolves with a `FormData` object. - */ - formData(): Promise<FormData>; - /** Takes a `Response` stream and reads it to completion. It returns a promise - * that resolves with the result of parsing the body text as JSON. - */ - json(): Promise<any>; - /** Takes a `Response` stream and reads it to completion. It returns a promise - * that resolves with a `USVString` (text). - */ - text(): Promise<string>; -} - -type HeadersInit = Headers | string[][] | Record<string, string>; - -/** This Fetch API interface allows you to perform various actions on HTTP - * request and response headers. These actions include retrieving, setting, - * adding to, and removing. A Headers object has an associated header list, - * which is initially empty and consists of zero or more name and value pairs. - * You can add to this using methods like append() (see Examples.) In all - * methods of this interface, header names are matched by case-insensitive byte - * sequence. */ -interface Headers { - append(name: string, value: string): void; - delete(name: string): void; - get(name: string): string | null; - has(name: string): boolean; - set(name: string, value: string): void; - forEach( - callbackfn: (value: string, key: string, parent: Headers) => void, - thisArg?: any, - ): void; -} - -interface Headers extends DomIterable<string, string> { - /** Appends a new value onto an existing header inside a `Headers` object, or - * adds the header if it does not already exist. - */ - append(name: string, value: string): void; - /** Deletes a header from a `Headers` object. */ - delete(name: string): void; - /** Returns an iterator allowing to go through all key/value pairs - * contained in this Headers object. The both the key and value of each pairs - * are ByteString objects. - */ - entries(): IterableIterator<[string, string]>; - /** Returns a `ByteString` sequence of all the values of a header within a - * `Headers` object with a given name. - */ - get(name: string): string | null; - /** Returns a boolean stating whether a `Headers` object contains a certain - * header. - */ - has(name: string): boolean; - /** Returns an iterator allowing to go through all keys contained in - * this Headers object. The keys are ByteString objects. - */ - keys(): IterableIterator<string>; - /** Sets a new value for an existing header inside a Headers object, or adds - * the header if it does not already exist. - */ - set(name: string, value: string): void; - /** Returns an iterator allowing to go through all values contained in - * this Headers object. The values are ByteString objects. - */ - values(): IterableIterator<string>; - forEach( - callbackfn: (value: string, key: string, parent: this) => void, - thisArg?: any, - ): void; - /** The Symbol.iterator well-known symbol specifies the default - * iterator for this Headers object - */ - [Symbol.iterator](): IterableIterator<[string, string]>; -} - -declare const Headers: { - prototype: Headers; - new (init?: HeadersInit): Headers; -}; - -type RequestInfo = Request | string; -type RequestCache = - | "default" - | "force-cache" - | "no-cache" - | "no-store" - | "only-if-cached" - | "reload"; -type RequestCredentials = "include" | "omit" | "same-origin"; -type RequestMode = "cors" | "navigate" | "no-cors" | "same-origin"; -type RequestRedirect = "error" | "follow" | "manual"; -type ReferrerPolicy = - | "" - | "no-referrer" - | "no-referrer-when-downgrade" - | "origin" - | "origin-when-cross-origin" - | "same-origin" - | "strict-origin" - | "strict-origin-when-cross-origin" - | "unsafe-url"; -type BodyInit = - | Blob - | BufferSource - | FormData - | URLSearchParams - | ReadableStream<Uint8Array> - | string; -type RequestDestination = - | "" - | "audio" - | "audioworklet" - | "document" - | "embed" - | "font" - | "image" - | "manifest" - | "object" - | "paintworklet" - | "report" - | "script" - | "sharedworker" - | "style" - | "track" - | "video" - | "worker" - | "xslt"; - -interface RequestInit { - /** - * A BodyInit object or null to set request's body. - */ - body?: BodyInit | null; - /** - * A string indicating how the request will interact with the browser's cache - * to set request's cache. - */ - cache?: RequestCache; - /** - * A string indicating whether credentials will be sent with the request - * always, never, or only when sent to a same-origin URL. Sets request's - * credentials. - */ - credentials?: RequestCredentials; - /** - * A Headers object, an object literal, or an array of two-item arrays to set - * request's headers. - */ - headers?: HeadersInit; - /** - * A cryptographic hash of the resource to be fetched by request. Sets - * request's integrity. - */ - integrity?: string; - /** - * A boolean to set request's keepalive. - */ - keepalive?: boolean; - /** - * A string to set request's method. - */ - method?: string; - /** - * A string to indicate whether the request will use CORS, or will be - * restricted to same-origin URLs. Sets request's mode. - */ - mode?: RequestMode; - /** - * A string indicating whether request follows redirects, results in an error - * upon encountering a redirect, or returns the redirect (in an opaque - * fashion). Sets request's redirect. - */ - redirect?: RequestRedirect; - /** - * A string whose value is a same-origin URL, "about:client", or the empty - * string, to set request's referrer. - */ - referrer?: string; - /** - * A referrer policy to set request's referrerPolicy. - */ - referrerPolicy?: ReferrerPolicy; - /** - * An AbortSignal to set request's signal. - */ - signal?: AbortSignal | null; - /** - * Can only be null. Used to disassociate request from any Window. - */ - window?: any; -} - -/** This Fetch API interface represents a resource request. */ -interface Request extends Body { - /** - * Returns the cache mode associated with request, which is a string - * indicating how the request will interact with the browser's cache when - * fetching. - */ - readonly cache: RequestCache; - /** - * Returns the credentials mode associated with request, which is a string - * indicating whether credentials will be sent with the request always, never, - * or only when sent to a same-origin URL. - */ - readonly credentials: RequestCredentials; - /** - * Returns the kind of resource requested by request, e.g., "document" or "script". - */ - readonly destination: RequestDestination; - /** - * Returns a Headers object consisting of the headers associated with request. - * Note that headers added in the network layer by the user agent will not be - * accounted for in this object, e.g., the "Host" header. - */ - readonly headers: Headers; - /** - * Returns request's subresource integrity metadata, which is a cryptographic - * hash of the resource being fetched. Its value consists of multiple hashes - * separated by whitespace. [SRI] - */ - readonly integrity: string; - /** - * Returns a boolean indicating whether or not request is for a history - * navigation (a.k.a. back-forward navigation). - */ - readonly isHistoryNavigation: boolean; - /** - * Returns a boolean indicating whether or not request is for a reload - * navigation. - */ - readonly isReloadNavigation: boolean; - /** - * Returns a boolean indicating whether or not request can outlive the global - * in which it was created. - */ - readonly keepalive: boolean; - /** - * Returns request's HTTP method, which is "GET" by default. - */ - readonly method: string; - /** - * Returns the mode associated with request, which is a string indicating - * whether the request will use CORS, or will be restricted to same-origin - * URLs. - */ - readonly mode: RequestMode; - /** - * Returns the redirect mode associated with request, which is a string - * indicating how redirects for the request will be handled during fetching. A - * request will follow redirects by default. - */ - readonly redirect: RequestRedirect; - /** - * Returns the referrer of request. Its value can be a same-origin URL if - * explicitly set in init, the empty string to indicate no referrer, and - * "about:client" when defaulting to the global's default. This is used during - * fetching to determine the value of the `Referer` header of the request - * being made. - */ - readonly referrer: string; - /** - * Returns the referrer policy associated with request. This is used during - * fetching to compute the value of the request's referrer. - */ - readonly referrerPolicy: ReferrerPolicy; - /** - * Returns the signal associated with request, which is an AbortSignal object - * indicating whether or not request has been aborted, and its abort event - * handler. - */ - readonly signal: AbortSignal; - /** - * Returns the URL of request as a string. - */ - readonly url: string; - clone(): Request; -} - -declare const Request: { - prototype: Request; - new (input: RequestInfo, init?: RequestInit): Request; -}; - -interface ResponseInit { - headers?: HeadersInit; - status?: number; - statusText?: string; -} - -type ResponseType = - | "basic" - | "cors" - | "default" - | "error" - | "opaque" - | "opaqueredirect"; - -/** This Fetch API interface represents the response to a request. */ -interface Response extends Body { - readonly headers: Headers; - readonly ok: boolean; - readonly redirected: boolean; - readonly status: number; - readonly statusText: string; - readonly trailer: Promise<Headers>; - readonly type: ResponseType; - readonly url: string; - clone(): Response; -} - -declare const Response: { - prototype: Response; - new (body?: BodyInit | null, init?: ResponseInit): Response; - error(): Response; - redirect(url: string, status?: number): Response; -}; - -/** Fetch a resource from the network. It returns a Promise that resolves to the - * Response to that request, whether it is successful or not. - * - * const response = await fetch("http://my.json.host/data.json"); - * console.log(response.status); // e.g. 200 - * console.log(response.statusText); // e.g. "OK" - * const jsonData = await response.json(); - */ -declare function fetch( - input: Request | URL | string, - init?: RequestInit, -): Promise<Response>; - -/** Decodes a string of data which has been encoded using base-64 encoding. - * - * console.log(atob("aGVsbG8gd29ybGQ=")); // outputs 'hello world' - */ -declare function atob(s: string): string; - -/** Creates a base-64 ASCII encoded string from the input string. - * - * console.log(btoa("hello world")); // outputs "aGVsbG8gd29ybGQ=" - */ -declare function btoa(s: string): string; - -declare class TextDecoder { - /** Returns encoding's name, lowercased. */ - readonly encoding: string; - /** Returns `true` if error mode is "fatal", and `false` otherwise. */ - readonly fatal: boolean; - /** Returns `true` if ignore BOM flag is set, and `false` otherwise. */ - readonly ignoreBOM = false; - constructor( - label?: string, - options?: { fatal?: boolean; ignoreBOM?: boolean }, - ); - /** Returns the result of running encoding's decoder. */ - decode(input?: BufferSource, options?: { stream?: false }): string; - readonly [Symbol.toStringTag]: string; -} - -declare class TextEncoder { - /** Returns "utf-8". */ - readonly encoding = "utf-8"; - /** Returns the result of running UTF-8's encoder. */ - encode(input?: string): Uint8Array; - encodeInto( - input: string, - dest: Uint8Array, - ): { read: number; written: number }; - readonly [Symbol.toStringTag]: string; -} - -interface URLSearchParams { - /** Appends a specified key/value pair as a new search parameter. - * - * ```ts - * let searchParams = new URLSearchParams(); - * searchParams.append('name', 'first'); - * searchParams.append('name', 'second'); - * ``` - */ - append(name: string, value: string): void; - - /** Deletes the given search parameter and its associated value, - * from the list of all search parameters. - * - * ```ts - * let searchParams = new URLSearchParams([['name', 'value']]); - * searchParams.delete('name'); - * ``` - */ - delete(name: string): void; - - /** Returns all the values associated with a given search parameter - * as an array. - * - * ```ts - * searchParams.getAll('name'); - * ``` - */ - getAll(name: string): string[]; - - /** Returns the first value associated to the given search parameter. - * - * ```ts - * searchParams.get('name'); - * ``` - */ - get(name: string): string | null; - - /** Returns a Boolean that indicates whether a parameter with the - * specified name exists. - * - * ```ts - * searchParams.has('name'); - * ``` - */ - has(name: string): boolean; - - /** Sets the value associated with a given search parameter to the - * given value. If there were several matching values, this method - * deletes the others. If the search parameter doesn't exist, this - * method creates it. - * - * ```ts - * searchParams.set('name', 'value'); - * ``` - */ - set(name: string, value: string): void; - - /** Sort all key/value pairs contained in this object in place and - * return undefined. The sort order is according to Unicode code - * points of the keys. - * - * ```ts - * searchParams.sort(); - * ``` - */ - sort(): void; - - /** Calls a function for each element contained in this object in - * place and return undefined. Optionally accepts an object to use - * as this when executing callback as second argument. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * params.forEach((value, key, parent) => { - * console.log(value, key, parent); - * }); - * ``` - * - */ - forEach( - callbackfn: (value: string, key: string, parent: this) => void, - thisArg?: any, - ): void; - - /** Returns an iterator allowing to go through all keys contained - * in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const key of params.keys()) { - * console.log(key); - * } - * ``` - */ - keys(): IterableIterator<string>; - - /** Returns an iterator allowing to go through all values contained - * in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const value of params.values()) { - * console.log(value); - * } - * ``` - */ - values(): IterableIterator<string>; - - /** Returns an iterator allowing to go through all key/value - * pairs contained in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const [key, value] of params.entries()) { - * console.log(key, value); - * } - * ``` - */ - entries(): IterableIterator<[string, string]>; - - /** Returns an iterator allowing to go through all key/value - * pairs contained in this object. - * - * ```ts - * const params = new URLSearchParams([["a", "b"], ["c", "d"]]); - * for (const [key, value] of params) { - * console.log(key, value); - * } - * ``` - */ - [Symbol.iterator](): IterableIterator<[string, string]>; - - /** Returns a query string suitable for use in a URL. - * - * ```ts - * searchParams.toString(); - * ``` - */ - toString(): string; -} - -declare const URLSearchParams: { - prototype: URLSearchParams; - new ( - init?: string[][] | Record<string, string> | string | URLSearchParams, - ): URLSearchParams; - toString(): string; -}; - -/** The URL interface represents an object providing static methods used for creating object URLs. */ -interface URL { - hash: string; - host: string; - hostname: string; - href: string; - toString(): string; - readonly origin: string; - password: string; - pathname: string; - port: string; - protocol: string; - search: string; - readonly searchParams: URLSearchParams; - username: string; - toJSON(): string; -} - -declare const URL: { - prototype: URL; - new (url: string, base?: string | URL): URL; - createObjectURL(object: any): string; - revokeObjectURL(url: string): void; -}; - -interface MessageEventInit extends EventInit { - data?: any; - origin?: string; - lastEventId?: string; -} - -declare class MessageEvent extends Event { - readonly data: any; - readonly origin: string; - readonly lastEventId: string; - constructor(type: string, eventInitDict?: MessageEventInit); -} - -interface ErrorEventInit extends EventInit { - message?: string; - filename?: string; - lineno?: number; - colno?: number; - error?: any; -} - -declare class ErrorEvent extends Event { - readonly message: string; - readonly filename: string; - readonly lineno: number; - readonly colno: number; - readonly error: any; - constructor(type: string, eventInitDict?: ErrorEventInit); -} - -interface PostMessageOptions { - transfer?: any[]; -} - -declare class Worker extends EventTarget { - onerror?: (e: ErrorEvent) => void; - onmessage?: (e: MessageEvent) => void; - onmessageerror?: (e: MessageEvent) => void; - constructor( - specifier: string, - options?: { - type?: "classic" | "module"; - name?: string; - /** UNSTABLE: New API. Expect many changes; most likely this - * field will be made into an object for more granular - * configuration of worker thread (permissions, import map, etc.). - * - * Set to `true` to make `Deno` namespace and all of its methods - * available to worker thread. - * - * Currently worker inherits permissions from main thread (permissions - * given using `--allow-*` flags). - * Configurable permissions are on the roadmap to be implemented. - * - * Example: - * - * ```ts - * // mod.ts - * const worker = new Worker( - * new URL("deno_worker.ts", import.meta.url).href, - * { type: "module", deno: true } - * ); - * worker.postMessage({ cmd: "readFile", fileName: "./log.txt" }); - * - * // deno_worker.ts - * - * - * self.onmessage = async function (e) { - * const { cmd, fileName } = e.data; - * if (cmd !== "readFile") { - * throw new Error("Invalid command"); - * } - * const buf = await Deno.readFile(fileName); - * const fileContents = new TextDecoder().decode(buf); - * console.log(fileContents); - * } - * ``` - * - * // log.txt - * hello world - * hello world 2 - * - * // run program - * $ deno run --allow-read mod.ts - * hello world - * hello world2 - * - */ - deno?: boolean; - }, - ); - postMessage(message: any, transfer: ArrayBuffer[]): void; - postMessage(message: any, options?: PostMessageOptions): void; - terminate(): void; -} - -declare type PerformanceEntryList = PerformanceEntry[]; - -declare interface Performance { - /** Removes the stored timestamp with the associated name. */ - clearMarks(markName?: string): void; - - /** Removes stored timestamp with the associated name. */ - clearMeasures(measureName?: string): void; - - getEntries(): PerformanceEntryList; - getEntriesByName(name: string, type?: string): PerformanceEntryList; - getEntriesByType(type: string): PerformanceEntryList; - - /** Stores a timestamp with the associated name (a "mark"). */ - mark(markName: string, options?: PerformanceMarkOptions): PerformanceMark; - - /** Stores the `DOMHighResTimeStamp` duration between two marks along with the - * associated name (a "measure"). */ - measure( - measureName: string, - options?: PerformanceMeasureOptions, - ): PerformanceMeasure; - /** Stores the `DOMHighResTimeStamp` duration between two marks along with the - * associated name (a "measure"). */ - measure( - measureName: string, - startMark?: string, - endMark?: string, - ): PerformanceMeasure; - - /** Returns a current time from Deno's start in milliseconds. - * - * Use the permission flag `--allow-hrtime` return a precise value. - * - * ```ts - * const t = performance.now(); - * console.log(`${t} ms since start!`); - * ``` - */ - now(): number; -} - -declare const Performance: { - prototype: Performance; - new (): Performance; -}; - -declare const performance: Performance; - -declare interface PerformanceMarkOptions { - /** Metadata to be included in the mark. */ - detail?: any; - - /** Timestamp to be used as the mark time. */ - startTime?: number; -} - -declare interface PerformanceMeasureOptions { - /** Metadata to be included in the measure. */ - detail?: any; - - /** Timestamp to be used as the start time or string to be used as start - * mark.*/ - start?: string | number; - - /** Duration between the start and end times. */ - duration?: number; - - /** Timestamp to be used as the end time or string to be used as end mark. */ - end?: string | number; -} - -/** Encapsulates a single performance metric that is part of the performance - * timeline. A performance entry can be directly created by making a performance - * mark or measure (for example by calling the `.mark()` method) at an explicit - * point in an application. */ -declare class PerformanceEntry { - readonly duration: number; - readonly entryType: string; - readonly name: string; - readonly startTime: number; - toJSON(): any; -} - -/** `PerformanceMark` is an abstract interface for `PerformanceEntry` objects - * with an entryType of `"mark"`. Entries of this type are created by calling - * `performance.mark()` to add a named `DOMHighResTimeStamp` (the mark) to the - * performance timeline. */ -declare class PerformanceMark extends PerformanceEntry { - readonly detail: any; - readonly entryType: "mark"; - constructor(name: string, options?: PerformanceMarkOptions); -} - -/** `PerformanceMeasure` is an abstract interface for `PerformanceEntry` objects - * with an entryType of `"measure"`. Entries of this type are created by calling - * `performance.measure()` to add a named `DOMHighResTimeStamp` (the measure) - * between two marks to the performance timeline. */ -declare class PerformanceMeasure extends PerformanceEntry { - readonly detail: any; - readonly entryType: "measure"; -} - -interface EventInit { - bubbles?: boolean; - cancelable?: boolean; - composed?: boolean; -} - -/** An event which takes place in the DOM. */ -declare class Event { - constructor(type: string, eventInitDict?: EventInit); - /** Returns true or false depending on how event was initialized. True if - * event goes through its target's ancestors in reverse tree order, and - * false otherwise. */ - readonly bubbles: boolean; - cancelBubble: boolean; - /** Returns true or false depending on how event was initialized. Its return - * value does not always carry meaning, but true can indicate that part of the - * operation during which event was dispatched, can be canceled by invoking - * the preventDefault() method. */ - readonly cancelable: boolean; - /** Returns true or false depending on how event was initialized. True if - * event invokes listeners past a ShadowRoot node that is the root of its - * target, and false otherwise. */ - readonly composed: boolean; - /** Returns the object whose event listener's callback is currently being - * invoked. */ - readonly currentTarget: EventTarget | null; - /** Returns true if preventDefault() was invoked successfully to indicate - * cancellation, and false otherwise. */ - readonly defaultPrevented: boolean; - /** Returns the event's phase, which is one of NONE, CAPTURING_PHASE, - * AT_TARGET, and BUBBLING_PHASE. */ - readonly eventPhase: number; - /** Returns true if event was dispatched by the user agent, and false - * otherwise. */ - readonly isTrusted: boolean; - /** Returns the object to which event is dispatched (its target). */ - readonly target: EventTarget | null; - /** Returns the event's timestamp as the number of milliseconds measured - * relative to the time origin. */ - readonly timeStamp: number; - /** Returns the type of event, e.g. "click", "hashchange", or "submit". */ - readonly type: string; - /** Returns the invocation target objects of event's path (objects on which - * listeners will be invoked), except for any nodes in shadow trees of which - * the shadow root's mode is "closed" that are not reachable from event's - * currentTarget. */ - composedPath(): EventTarget[]; - /** If invoked when the cancelable attribute value is true, and while - * executing a listener for the event with passive set to false, signals to - * the operation that caused event to be dispatched that it needs to be - * canceled. */ - preventDefault(): void; - /** Invoking this method prevents event from reaching any registered event - * listeners after the current one finishes running and, when dispatched in a - * tree, also prevents event from reaching any other objects. */ - stopImmediatePropagation(): void; - /** When dispatched in a tree, invoking this method prevents event from - * reaching any objects other than the current object. */ - stopPropagation(): void; - readonly AT_TARGET: number; - readonly BUBBLING_PHASE: number; - readonly CAPTURING_PHASE: number; - readonly NONE: number; - static readonly AT_TARGET: number; - static readonly BUBBLING_PHASE: number; - static readonly CAPTURING_PHASE: number; - static readonly NONE: number; -} - -/** - * EventTarget is a DOM interface implemented by objects that can receive events - * and may have listeners for them. - */ -declare class EventTarget { - /** Appends an event listener for events whose type attribute value is type. - * The callback argument sets the callback that will be invoked when the event - * is dispatched. - * - * The options argument sets listener-specific options. For compatibility this - * can be a boolean, in which case the method behaves exactly as if the value - * was specified as options's capture. - * - * When set to true, options's capture prevents callback from being invoked - * when the event's eventPhase attribute value is BUBBLING_PHASE. When false - * (or not present), callback will not be invoked when event's eventPhase - * attribute value is CAPTURING_PHASE. Either way, callback will be invoked if - * event's eventPhase attribute value is AT_TARGET. - * - * When set to true, options's passive indicates that the callback will not - * cancel the event by invoking preventDefault(). This is used to enable - * performance optimizations described in § 2.8 Observing event listeners. - * - * When set to true, options's once indicates that the callback will only be - * invoked once after which the event listener will be removed. - * - * The event listener is appended to target's event listener list and is not - * appended if it has the same type, callback, and capture. */ - addEventListener( - type: string, - listener: EventListenerOrEventListenerObject | null, - options?: boolean | AddEventListenerOptions, - ): void; - /** Dispatches a synthetic event event to target and returns true if either - * event's cancelable attribute value is false or its preventDefault() method - * was not invoked, and false otherwise. */ - dispatchEvent(event: Event): boolean; - /** Removes the event listener in target's event listener list with the same - * type, callback, and options. */ - removeEventListener( - type: string, - callback: EventListenerOrEventListenerObject | null, - options?: EventListenerOptions | boolean, - ): void; - [Symbol.toStringTag]: string; -} - -interface EventListener { - (evt: Event): void | Promise<void>; -} - -interface EventListenerObject { - handleEvent(evt: Event): void | Promise<void>; -} - -declare type EventListenerOrEventListenerObject = - | EventListener - | EventListenerObject; - -interface AddEventListenerOptions extends EventListenerOptions { - once?: boolean; - passive?: boolean; -} - -interface EventListenerOptions { - capture?: boolean; -} - -/** Events measuring progress of an underlying process, like an HTTP request - * (for an XMLHttpRequest, or the loading of the underlying resource of an - * <img>, <audio>, <video>, <style> or <link>). */ -interface ProgressEvent<T extends EventTarget = EventTarget> extends Event { - readonly lengthComputable: boolean; - readonly loaded: number; - readonly target: T | null; - readonly total: number; -} - -interface CustomEventInit<T = any> extends EventInit { - detail?: T; -} - -declare class CustomEvent<T = any> extends Event { - constructor(typeArg: string, eventInitDict?: CustomEventInit<T>); - /** Returns any custom data event was created with. Typically used for - * synthetic events. */ - readonly detail: T; -} - -/** A controller object that allows you to abort one or more DOM requests as and - * when desired. */ -declare class AbortController { - /** Returns the AbortSignal object associated with this object. */ - readonly signal: AbortSignal; - /** Invoking this method will set this object's AbortSignal's aborted flag and - * signal to any observers that the associated activity is to be aborted. */ - abort(): void; -} - -interface AbortSignalEventMap { - abort: Event; -} - -/** A signal object that allows you to communicate with a DOM request (such as a - * Fetch) and abort it if required via an AbortController object. */ -interface AbortSignal extends EventTarget { - /** Returns true if this AbortSignal's AbortController has signaled to abort, - * and false otherwise. */ - readonly aborted: boolean; - onabort: ((this: AbortSignal, ev: Event) => any) | null; - addEventListener<K extends keyof AbortSignalEventMap>( - type: K, - listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, - options?: boolean | AddEventListenerOptions, - ): void; - addEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | AddEventListenerOptions, - ): void; - removeEventListener<K extends keyof AbortSignalEventMap>( - type: K, - listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, - options?: boolean | EventListenerOptions, - ): void; - removeEventListener( - type: string, - listener: EventListenerOrEventListenerObject, - options?: boolean | EventListenerOptions, - ): void; -} - -declare const AbortSignal: { - prototype: AbortSignal; - new (): AbortSignal; -}; - -interface ErrorConstructor { - /** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */ - // eslint-disable-next-line @typescript-eslint/ban-types - captureStackTrace(error: Object, constructor?: Function): void; - // TODO(nayeemrmn): Support `Error.prepareStackTrace()`. We currently use this - // internally in a way that makes it unavailable for users. -} diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts deleted file mode 100644 index d23536c42..000000000 --- a/cli/js/lib.deno.unstable.d.ts +++ /dev/null @@ -1,1217 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -/// <reference no-default-lib="true" /> -/// <reference lib="deno.ns" /> - -declare namespace Deno { - /** - * **UNSTABLE**: New API, yet to be vetted. This API is under consideration to - * determine if permissions are required to call it. - * - * Retrieve the process umask. If `mask` is provided, sets the process umask. - * This call always returns what the umask was before the call. - * - * ```ts - * console.log(Deno.umask()); // e.g. 18 (0o022) - * const prevUmaskValue = Deno.umask(0o077); // e.g. 18 (0o022) - * console.log(Deno.umask()); // e.g. 63 (0o077) - * ``` - * - * NOTE: This API is not implemented on Windows - */ - export function umask(mask?: number): number; - - /** **UNSTABLE**: This API needs a security review. - * - * Synchronously creates `newpath` as a hard link to `oldpath`. - * - * ```ts - * Deno.linkSync("old/name", "new/name"); - * ``` - * - * Requires `allow-read` and `allow-write` permissions. */ - export function linkSync(oldpath: string, newpath: string): void; - - /** **UNSTABLE**: This API needs a security review. - * - * Creates `newpath` as a hard link to `oldpath`. - * - * ```ts - * await Deno.link("old/name", "new/name"); - * ``` - * - * Requires `allow-read` and `allow-write` permissions. */ - export function link(oldpath: string, newpath: string): Promise<void>; - - /** **UNSTABLE**: New API, yet to be vetted. - * - * Gets the size of the console as columns/rows. - * - * ```ts - * const { columns, rows } = await Deno.consoleSize(Deno.stdout.rid); - * ``` - */ - export function consoleSize( - rid: number, - ): { - columns: number; - rows: number; - }; - - export type SymlinkOptions = { - type: "file" | "dir"; - }; - - /** **UNSTABLE**: This API needs a security review. - * - * Creates `newpath` as a symbolic link to `oldpath`. - * - * The options.type parameter can be set to `file` or `dir`. This argument is only - * available on Windows and ignored on other platforms. - * - * ```ts - * Deno.symlinkSync("old/name", "new/name"); - * ``` - * - * Requires `allow-write` permission. */ - export function symlinkSync( - oldpath: string, - newpath: string, - options?: SymlinkOptions, - ): void; - - /** **UNSTABLE**: This API needs a security review. - * - * Creates `newpath` as a symbolic link to `oldpath`. - * - * The options.type parameter can be set to `file` or `dir`. This argument is only - * available on Windows and ignored on other platforms. - * - * ```ts - * await Deno.symlink("old/name", "new/name"); - * ``` - * - * Requires `allow-write` permission. */ - export function symlink( - oldpath: string, - newpath: string, - options?: SymlinkOptions, - ): Promise<void>; - - /** **Unstable** There are questions around which permission this needs. And - * maybe should be renamed (loadAverage?) - * - * Returns an array containing the 1, 5, and 15 minute load averages. The - * load average is a measure of CPU and IO utilization of the last one, five, - * and 15 minute periods expressed as a fractional number. Zero means there - * is no load. On Windows, the three values are always the same and represent - * the current load, not the 1, 5 and 15 minute load averages. - * - * ```ts - * console.log(Deno.loadavg()); // e.g. [ 0.71, 0.44, 0.44 ] - * ``` - * - * Requires `allow-env` permission. - */ - export function loadavg(): number[]; - - /** **Unstable** new API. yet to be vetted. Under consideration to possibly move to - * Deno.build or Deno.versions and if it should depend sys-info, which may not - * be desireable. - * - * Returns the release version of the Operating System. - * - * ```ts - * console.log(Deno.osRelease()); - * ``` - * - * Requires `allow-env` permission. - * - */ - export function osRelease(): string; - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Open and initialize a plugin. - * - * ```ts - * const rid = Deno.openPlugin("./path/to/some/plugin.so"); - * const opId = Deno.core.ops()["some_op"]; - * const response = Deno.core.dispatch(opId, new Uint8Array([1,2,3,4])); - * console.log(`Response from plugin ${response}`); - * ``` - * - * Requires `allow-plugin` permission. - * - * The plugin system is not stable and will change in the future, hence the - * lack of docs. For now take a look at the example - * https://github.com/denoland/deno/tree/master/test_plugin - */ - export function openPlugin(filename: string): number; - - /** The log category for a diagnostic message. */ - 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 { - /** A string message summarizing the diagnostic. */ - message: string; - /** An ordered array of further diagnostics. */ - messageChain?: DiagnosticMessageChain; - /** Information related to the diagnostic. This is present when there is a - * suggestion or other additional diagnostic information */ - relatedInformation?: DiagnosticItem[]; - /** The text of the source line related to the diagnostic. */ - sourceLine?: string; - /** The line number that is related to the diagnostic. */ - lineNumber?: number; - /** The name of the script resource related to the diagnostic. */ - scriptResourceName?: string; - /** The start position related to the diagnostic. */ - startPosition?: number; - /** The end position related to the diagnostic. */ - endPosition?: number; - /** The category of the diagnostic. */ - category: DiagnosticCategory; - /** A number identifier. */ - code: number; - /** The the start column of the sourceLine related to the diagnostic. */ - startColumn?: number; - /** The end column of the sourceLine related to the diagnostic. */ - endColumn?: number; - } - - export interface Diagnostic { - /** An array of diagnostic items. */ - items: DiagnosticItem[]; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Format an array of diagnostic items and return them as a single string in a - * user friendly format. - * - * ```ts - * const [diagnostics, result] = Deno.compile("file_with_compile_issues.ts"); - * console.table(diagnostics); // Prints raw diagnostic data - * console.log(Deno.formatDiagnostics(diagnostics)); // User friendly output of diagnostics - * ``` - * - * @param items An array of diagnostic items to format - */ - export function formatDiagnostics(items: DiagnosticItem[]): string; - - /** **UNSTABLE**: new API, yet to be vetted. - * - * A specific subset TypeScript compiler options that can be supported by the - * Deno TypeScript compiler. */ - export interface CompilerOptions { - /** Allow JavaScript files to be compiled. Defaults to `true`. */ - allowJs?: boolean; - /** Allow default imports from modules with no default export. This does not - * affect code emit, just typechecking. Defaults to `false`. */ - allowSyntheticDefaultImports?: boolean; - /** Allow accessing UMD globals from modules. Defaults to `false`. */ - allowUmdGlobalAccess?: boolean; - /** Do not report errors on unreachable code. Defaults to `false`. */ - allowUnreachableCode?: boolean; - /** Do not report errors on unused labels. Defaults to `false` */ - allowUnusedLabels?: boolean; - /** Parse in strict mode and emit `"use strict"` for each source file. - * Defaults to `true`. */ - alwaysStrict?: boolean; - /** Base directory to resolve non-relative module names. Defaults to - * `undefined`. */ - baseUrl?: string; - /** Report errors in `.js` files. Use in conjunction with `allowJs`. Defaults - * to `false`. */ - checkJs?: boolean; - /** Generates corresponding `.d.ts` file. Defaults to `false`. */ - declaration?: boolean; - /** Output directory for generated declaration files. */ - declarationDir?: string; - /** Generates a source map for each corresponding `.d.ts` file. Defaults to - * `false`. */ - declarationMap?: boolean; - /** Provide full support for iterables in `for..of`, spread and - * destructuring when targeting ES5 or ES3. Defaults to `false`. */ - downlevelIteration?: boolean; - /** Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. - * Defaults to `false`. */ - emitBOM?: boolean; - /** Only emit `.d.ts` declaration files. Defaults to `false`. */ - emitDeclarationOnly?: boolean; - /** Emit design-type metadata for decorated declarations in source. See issue - * [microsoft/TypeScript#2577](https://github.com/Microsoft/TypeScript/issues/2577) - * for details. Defaults to `false`. */ - emitDecoratorMetadata?: boolean; - /** Emit `__importStar` and `__importDefault` helpers for runtime babel - * ecosystem compatibility and enable `allowSyntheticDefaultImports` for type - * system compatibility. Defaults to `true`. */ - esModuleInterop?: boolean; - /** Enables experimental support for ES decorators. Defaults to `false`. */ - experimentalDecorators?: boolean; - /** Emit a single file with source maps instead of having a separate file. - * Defaults to `false`. */ - inlineSourceMap?: boolean; - /** Emit the source alongside the source maps within a single file; requires - * `inlineSourceMap` or `sourceMap` to be set. Defaults to `false`. */ - inlineSources?: boolean; - /** Perform additional checks to ensure that transpile only would be safe. - * Defaults to `false`. */ - isolatedModules?: boolean; - /** Support JSX in `.tsx` files: `"react"`, `"preserve"`, `"react-native"`. - * Defaults to `"react"`. */ - jsx?: "react" | "preserve" | "react-native"; - /** Specify the JSX factory function to use when targeting react JSX emit, - * e.g. `React.createElement` or `h`. Defaults to `React.createElement`. */ - jsxFactory?: string; - /** Resolve keyof to string valued property names only (no numbers or - * symbols). Defaults to `false`. */ - keyofStringsOnly?: string; - /** Emit class fields with ECMAScript-standard semantics. Defaults to `false`. - * Does not apply to `"esnext"` target. */ - useDefineForClassFields?: boolean; - /** List of library files to be included in the compilation. If omitted, - * then the Deno main runtime libs are used. */ - lib?: string[]; - /** The locale to use to show error messages. */ - locale?: string; - /** Specifies the location where debugger should locate map files instead of - * generated locations. Use this flag if the `.map` files will be located at - * run-time in a different location than the `.js` files. The location - * specified will be embedded in the source map to direct the debugger where - * the map files will be located. Defaults to `undefined`. */ - mapRoot?: string; - /** Specify the module format for the emitted code. Defaults to - * `"esnext"`. */ - module?: - | "none" - | "commonjs" - | "amd" - | "system" - | "umd" - | "es6" - | "es2015" - | "esnext"; - /** Do not generate custom helper functions like `__extends` in compiled - * output. Defaults to `false`. */ - noEmitHelpers?: boolean; - /** Report errors for fallthrough cases in switch statement. Defaults to - * `false`. */ - noFallthroughCasesInSwitch?: boolean; - /** Raise error on expressions and declarations with an implied any type. - * Defaults to `true`. */ - noImplicitAny?: boolean; - /** Report an error when not all code paths in function return a value. - * Defaults to `false`. */ - noImplicitReturns?: boolean; - /** Raise error on `this` expressions with an implied `any` type. Defaults to - * `true`. */ - noImplicitThis?: boolean; - /** Do not emit `"use strict"` directives in module output. Defaults to - * `false`. */ - noImplicitUseStrict?: boolean; - /** Do not add triple-slash references or module import targets to the list of - * compiled files. Defaults to `false`. */ - noResolve?: boolean; - /** Disable strict checking of generic signatures in function types. Defaults - * to `false`. */ - noStrictGenericChecks?: boolean; - /** Report errors on unused locals. Defaults to `false`. */ - noUnusedLocals?: boolean; - /** Report errors on unused parameters. Defaults to `false`. */ - noUnusedParameters?: boolean; - /** Redirect output structure to the directory. This only impacts - * `Deno.compile` and only changes the emitted file names. Defaults to - * `undefined`. */ - outDir?: string; - /** List of path mapping entries for module names to locations relative to the - * `baseUrl`. Defaults to `undefined`. */ - paths?: Record<string, string[]>; - /** Do not erase const enum declarations in generated code. Defaults to - * `false`. */ - preserveConstEnums?: boolean; - /** Remove all comments except copy-right header comments beginning with - * `/*!`. Defaults to `true`. */ - removeComments?: boolean; - /** Include modules imported with `.json` extension. Defaults to `true`. */ - resolveJsonModule?: boolean; - /** Specifies the root directory of input files. Only use to control the - * output directory structure with `outDir`. Defaults to `undefined`. */ - rootDir?: string; - /** List of _root_ folders whose combined content represent the structure of - * the project at runtime. Defaults to `undefined`. */ - rootDirs?: string[]; - /** Generates corresponding `.map` file. Defaults to `false`. */ - sourceMap?: boolean; - /** Specifies the location where debugger should locate TypeScript files - * instead of source locations. Use this flag if the sources will be located - * at run-time in a different location than that at design-time. The location - * specified will be embedded in the sourceMap to direct the debugger where - * the source files will be located. Defaults to `undefined`. */ - sourceRoot?: string; - /** Enable all strict type checking options. Enabling `strict` enables - * `noImplicitAny`, `noImplicitThis`, `alwaysStrict`, `strictBindCallApply`, - * `strictNullChecks`, `strictFunctionTypes` and - * `strictPropertyInitialization`. Defaults to `true`. */ - strict?: boolean; - /** Enable stricter checking of the `bind`, `call`, and `apply` methods on - * functions. Defaults to `true`. */ - strictBindCallApply?: boolean; - /** Disable bivariant parameter checking for function types. Defaults to - * `true`. */ - strictFunctionTypes?: boolean; - /** Ensure non-undefined class properties are initialized in the constructor. - * This option requires `strictNullChecks` be enabled in order to take effect. - * Defaults to `true`. */ - strictPropertyInitialization?: boolean; - /** In strict null checking mode, the `null` and `undefined` values are not in - * the domain of every type and are only assignable to themselves and `any` - * (the one exception being that `undefined` is also assignable to `void`). */ - strictNullChecks?: boolean; - /** Suppress excess property checks for object literals. Defaults to - * `false`. */ - suppressExcessPropertyErrors?: boolean; - /** Suppress `noImplicitAny` errors for indexing objects lacking index - * signatures. */ - suppressImplicitAnyIndexErrors?: boolean; - /** Specify ECMAScript target version. Defaults to `esnext`. */ - target?: - | "es3" - | "es5" - | "es6" - | "es2015" - | "es2016" - | "es2017" - | "es2018" - | "es2019" - | "es2020" - | "esnext"; - /** List of names of type definitions to include. Defaults to `undefined`. - * - * The type definitions are resolved according to the normal Deno resolution - * irrespective of if sources are provided on the call. Like other Deno - * modules, there is no "magical" resolution. For example: - * - * ```ts - * Deno.compile( - * "./foo.js", - * undefined, - * { - * types: [ "./foo.d.ts", "https://deno.land/x/example/types.d.ts" ] - * } - * ); - * ``` - */ - types?: string[]; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * The results of a transpile only command, where the `source` contains the - * emitted source, and `map` optionally contains the source map. */ - export interface TranspileOnlyResult { - source: string; - map?: string; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Takes a set of TypeScript sources and resolves to a map where the key was - * the original file name provided in sources and the result contains the - * `source` and optionally the `map` from the transpile operation. This does no - * type checking and validation, it effectively "strips" the types from the - * file. - * - * ```ts - * const results = await Deno.transpileOnly({ - * "foo.ts": `const foo: string = "foo";` - * }); - * ``` - * - * @param sources A map where the key is the filename and the value is the text - * to transpile. The filename is only used in the transpile and - * not resolved, for example to fill in the source name in the - * source map. - * @param options An option object of options to send to the compiler. This is - * a subset of ts.CompilerOptions which can be supported by Deno. - * Many of the options related to type checking and emitting - * type declaration files will have no impact on the output. - */ - export function transpileOnly( - sources: Record<string, string>, - options?: CompilerOptions, - ): Promise<Record<string, TranspileOnlyResult>>; - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Takes a root module name, and optionally a record set of sources. Resolves - * with a compiled set of modules and possibly diagnostics if the compiler - * encountered any issues. If just a root name is provided, the modules - * will be resolved as if the root module had been passed on the command line. - * - * If sources are passed, all modules will be resolved out of this object, where - * the key is the module name and the value is the content. The extension of - * the module name will be used to determine the media type of the module. - * - * ```ts - * const [ maybeDiagnostics1, output1 ] = await Deno.compile("foo.ts"); - * - * const [ maybeDiagnostics2, output2 ] = await Deno.compile("/foo.ts", { - * "/foo.ts": `export * from "./bar.ts";`, - * "/bar.ts": `export const bar = "bar";` - * }); - * ``` - * - * @param rootName The root name of the module which will be used as the - * "starting point". If no `sources` is specified, Deno will - * resolve the module externally as if the `rootName` had been - * specified on the command line. - * @param sources An optional key/value map of sources to be used when resolving - * modules, where the key is the module name, and the value is - * the source content. The extension of the key will determine - * the media type of the file when processing. If supplied, - * Deno will not attempt to resolve any modules externally. - * @param options An optional object of options to send to the compiler. This is - * a subset of ts.CompilerOptions which can be supported by Deno. - */ - export function compile( - rootName: string, - sources?: Record<string, string>, - options?: CompilerOptions, - ): Promise<[DiagnosticItem[] | undefined, Record<string, string>]>; - - /** **UNSTABLE**: new API, yet to be vetted. - * - * `bundle()` is part the compiler API. A full description of this functionality - * can be found in the [manual](https://deno.land/manual/runtime/compiler_apis#denobundle). - * - * Takes a root module name, and optionally a record set of sources. Resolves - * with a single JavaScript string (and bundle diagnostics if issues arise with - * the bundling) that is like the output of a `deno bundle` command. If just - * a root name is provided, the modules will be resolved as if the root module - * had been passed on the command line. - * - * If sources are passed, all modules will be resolved out of this object, where - * the key is the module name and the value is the content. The extension of the - * module name will be used to determine the media type of the module. - * - * ```ts - * // equivalent to "deno bundle foo.ts" from the command line - * const [ maybeDiagnostics1, output1 ] = await Deno.bundle("foo.ts"); - * - * const [ maybeDiagnostics2, output2 ] = await Deno.bundle("/foo.ts", { - * "/foo.ts": `export * from "./bar.ts";`, - * "/bar.ts": `export const bar = "bar";` - * }); - * ``` - * - * @param rootName The root name of the module which will be used as the - * "starting point". If no `sources` is specified, Deno will - * resolve the module externally as if the `rootName` had been - * specified on the command line. - * @param sources An optional key/value map of sources to be used when resolving - * modules, where the key is the module name, and the value is - * the source content. The extension of the key will determine - * the media type of the file when processing. If supplied, - * Deno will not attempt to resolve any modules externally. - * @param options An optional object of options to send to the compiler. This is - * a subset of ts.CompilerOptions which can be supported by Deno. - */ - export function bundle( - rootName: string, - sources?: Record<string, string>, - options?: CompilerOptions, - ): Promise<[DiagnosticItem[] | undefined, string]>; - - /** **UNSTABLE**: Should not have same name as `window.location` type. */ - interface Location { - /** The full url for the module, e.g. `file://some/file.ts` or - * `https://some/file.ts`. */ - fileName: string; - /** The line number in the file. It is assumed to be 1-indexed. */ - lineNumber: number; - /** The column number in the file. It is assumed to be 1-indexed. */ - columnNumber: number; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Given a current location in a module, lookup the source location and return - * it. - * - * When Deno transpiles code, it keep source maps of the transpiled code. This - * function can be used to lookup the original location. This is - * automatically done when accessing the `.stack` of an error, or when an - * uncaught error is logged. This function can be used to perform the lookup - * for creating better error handling. - * - * **Note:** `line` and `column` are 1 indexed, which matches display - * expectations, but is not typical of most index numbers in Deno. - * - * An example: - * - * ```ts - * const orig = Deno.applySourceMap({ - * fileName: "file://my/module.ts", - * lineNumber: 5, - * columnNumber: 15 - * }); - * console.log(`${orig.filename}:${orig.line}:${orig.column}`); - * ``` - */ - export function applySourceMap(location: Location): Location; - - 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, - } - 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, - } - - /** **UNSTABLE**: Further changes required to make platform independent. - * - * Signals numbers. This is platform dependent. */ - export const Signal: typeof MacOSSignal | typeof LinuxSignal; - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Represents the stream of signals, implements both `AsyncIterator` and - * `PromiseLike`. */ - export class SignalStream - implements AsyncIterableIterator<void>, PromiseLike<void> { - constructor(signal: typeof Deno.Signal); - then<T, S>( - f: (v: void) => T | Promise<T>, - g?: (v: void) => S | Promise<S>, - ): Promise<T | S>; - next(): Promise<IteratorResult<void>>; - [Symbol.asyncIterator](): AsyncIterableIterator<void>; - dispose(): void; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Returns the stream of the given signal number. You can use it as an async - * iterator. - * - * ```ts - * for await (const _ of Deno.signal(Deno.Signal.SIGTERM)) { - * console.log("got SIGTERM!"); - * } - * ``` - * - * You can also use it as a promise. In this case you can only receive the - * first one. - * - * ```ts - * await Deno.signal(Deno.Signal.SIGTERM); - * console.log("SIGTERM received!") - * ``` - * - * If you want to stop receiving the signals, you can use `.dispose()` method - * of the signal stream object. - * - * ```ts - * const sig = Deno.signal(Deno.Signal.SIGTERM); - * setTimeout(() => { sig.dispose(); }, 5000); - * for await (const _ of sig) { - * console.log("SIGTERM!") - * } - * ``` - * - * The above for-await loop exits after 5 seconds when `sig.dispose()` is - * called. - * - * NOTE: This functionality is not yet implemented on Windows. - */ - export function signal(signo: number): SignalStream; - - /** **UNSTABLE**: new API, yet to be vetted. */ - export const signals: { - /** Returns the stream of SIGALRM signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGALRM)`. */ - alarm: () => SignalStream; - /** Returns the stream of SIGCHLD signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGCHLD)`. */ - child: () => SignalStream; - /** Returns the stream of SIGHUP signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGHUP)`. */ - hungup: () => SignalStream; - /** Returns the stream of SIGINT signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGINT)`. */ - interrupt: () => SignalStream; - /** Returns the stream of SIGIO signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGIO)`. */ - io: () => SignalStream; - /** Returns the stream of SIGPIPE signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGPIPE)`. */ - pipe: () => SignalStream; - /** Returns the stream of SIGQUIT signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGQUIT)`. */ - quit: () => SignalStream; - /** Returns the stream of SIGTERM signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGTERM)`. */ - terminate: () => SignalStream; - /** Returns the stream of SIGUSR1 signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGUSR1)`. */ - userDefined1: () => SignalStream; - /** Returns the stream of SIGUSR2 signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGUSR2)`. */ - userDefined2: () => SignalStream; - /** Returns the stream of SIGWINCH signals. - * - * This method is the shorthand for `Deno.signal(Deno.Signal.SIGWINCH)`. */ - windowChange: () => SignalStream; - }; - - /** **UNSTABLE**: new API, yet to be vetted - * - * Set TTY to be under raw mode or not. In raw mode, characters are read and - * returned as is, without being processed. All special processing of - * characters by the terminal is disabled, including echoing input characters. - * Reading from a TTY device in raw mode is faster than reading from a TTY - * device in canonical mode. - * - * ```ts - * Deno.setRaw(myTTY.rid, true); - * ``` - */ - export function setRaw(rid: number, mode: boolean): void; - - /** **UNSTABLE**: needs investigation into high precision time. - * - * Synchronously changes the access (`atime`) and modification (`mtime`) times - * of a file system object referenced by `path`. Given times are either in - * seconds (UNIX epoch time) or as `Date` objects. - * - * ```ts - * Deno.utimeSync("myfile.txt", 1556495550, new Date()); - * ``` - * - * Requires `allow-write` permission. */ - export function utimeSync( - path: string, - atime: number | Date, - mtime: number | Date, - ): void; - - /** **UNSTABLE**: needs investigation into high precision time. - * - * Changes the access (`atime`) and modification (`mtime`) times of a file - * system object referenced by `path`. Given times are either in seconds - * (UNIX epoch time) or as `Date` objects. - * - * ```ts - * await Deno.utime("myfile.txt", 1556495550, new Date()); - * ``` - * - * Requires `allow-write` permission. */ - export function utime( - path: string, - atime: number | Date, - mtime: number | Date, - ): Promise<void>; - - /** **UNSTABLE**: Under consideration to remove `ShutdownMode` entirely. - * - * Corresponds to `SHUT_RD`, `SHUT_WR`, `SHUT_RDWR` on POSIX-like systems. - * - * See: http://man7.org/linux/man-pages/man2/shutdown.2.html */ - export enum ShutdownMode { - Read = 0, - Write, - ReadWrite, // TODO(ry) panics on ReadWrite. - } - - /** **UNSTABLE**: Both the `how` parameter and `ShutdownMode` enum are under - * consideration for removal. - * - * Shutdown socket send and receive operations. - * - * Matches behavior of POSIX shutdown(3). - * - * ```ts - * const listener = Deno.listen({ port: 80 }); - * const conn = await listener.accept(); - * Deno.shutdown(conn.rid, Deno.ShutdownMode.Write); - * ``` - */ - export function shutdown(rid: number, how: ShutdownMode): Promise<void>; - - /** **UNSTABLE**: new API, yet to be vetted. - * - * A generic transport listener for message-oriented protocols. */ - export interface DatagramConn extends AsyncIterable<[Uint8Array, Addr]> { - /** **UNSTABLE**: new API, yet to be vetted. - * - * Waits for and resolves to the next message to the `UDPConn`. */ - receive(p?: Uint8Array): Promise<[Uint8Array, Addr]>; - /** UNSTABLE: new API, yet to be vetted. - * - * Sends a message to the target. */ - send(p: Uint8Array, addr: Addr): Promise<number>; - /** UNSTABLE: new API, yet to be vetted. - * - * Close closes the socket. Any pending message promises will be rejected - * with errors. */ - close(): void; - /** Return the address of the `UDPConn`. */ - readonly addr: Addr; - [Symbol.asyncIterator](): AsyncIterableIterator<[Uint8Array, Addr]>; - } - - export interface UnixListenOptions { - /** A Path to the Unix Socket. */ - path: string; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Listen announces on the local transport address. - * - * ```ts - * const listener = Deno.listen({ path: "/foo/bar.sock", transport: "unix" }) - * ``` - * - * Requires `allow-read` and `allow-write` permission. */ - export function listen( - options: UnixListenOptions & { transport: "unix" }, - ): Listener; - - /** **UNSTABLE**: new API, yet to be vetted - * - * Listen announces on the local transport address. - * - * ```ts - * const listener1 = Deno.listenDatagram({ - * port: 80, - * transport: "udp" - * }); - * const listener2 = Deno.listenDatagram({ - * hostname: "golang.org", - * port: 80, - * transport: "udp" - * }); - * ``` - * - * Requires `allow-net` permission. */ - export function listenDatagram( - options: ListenOptions & { transport: "udp" }, - ): DatagramConn; - - /** **UNSTABLE**: new API, yet to be vetted - * - * Listen announces on the local transport address. - * - * ```ts - * const listener = Deno.listenDatagram({ - * address: "/foo/bar.sock", - * transport: "unixpacket" - * }); - * ``` - * - * Requires `allow-read` and `allow-write` permission. */ - export function listenDatagram( - options: UnixListenOptions & { transport: "unixpacket" }, - ): DatagramConn; - - export interface UnixConnectOptions { - transport: "unix"; - path: string; - } - - /** **UNSTABLE**: The unix socket transport is unstable as a new API yet to - * be vetted. The TCP transport is considered stable. - * - * Connects to the hostname (default is "127.0.0.1") and port on the named - * transport (default is "tcp"), and resolves to the connection (`Conn`). - * - * ```ts - * const conn1 = await Deno.connect({ port: 80 }); - * const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 }); - * const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 }); - * const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" }); - * const conn5 = await Deno.connect({ path: "/foo/bar.sock", transport: "unix" }); - * ``` - * - * Requires `allow-net` permission for "tcp" and `allow-read` for "unix". */ - export function connect( - options: ConnectOptions | UnixConnectOptions, - ): Promise<Conn>; - - export interface StartTlsOptions { - /** A literal IP address or host name that can be resolved to an IP address. - * If not specified, defaults to `127.0.0.1`. */ - hostname?: string; - /** Server certificate file. */ - certFile?: string; - } - - /** **UNSTABLE**: new API, yet to be vetted. - * - * Start TLS handshake from an existing connection using - * an optional cert file, hostname (default is "127.0.0.1"). The - * cert file is optional and if not included Mozilla's root certificates will - * be used (see also https://github.com/ctz/webpki-roots for specifics) - * Using this function requires that the other end of the connection is - * prepared for TLS handshake. - * - * ```ts - * const conn = await Deno.connect({ port: 80, hostname: "127.0.0.1" }); - * const tlsConn = await Deno.startTls(conn, { certFile: "./certs/my_custom_root_CA.pem", hostname: "127.0.0.1", port: 80 }); - * ``` - * - * Requires `allow-net` permission. - */ - export function startTls( - conn: Conn, - options?: StartTlsOptions, - ): Promise<Conn>; - - /** **UNSTABLE**: The `signo` argument may change to require the Deno.Signal - * enum. - * - * Send a signal to process under given `pid`. This functionality currently - * only works on Linux and Mac OS. - * - * If `pid` is negative, the signal will be sent to the process group - * identified by `pid`. - * - * const p = Deno.run({ - * cmd: ["python", "-c", "from time import sleep; sleep(10000)"] - * }); - * - * Deno.kill(p.pid, Deno.Signal.SIGINT); - * - * Requires `allow-run` permission. */ - export function kill(pid: number, signo: number): void; - - /** The name of a "powerful feature" which needs permission. - * - * See: https://w3c.github.io/permissions/#permission-registry - * - * Note that the definition of `PermissionName` in the above spec is swapped - * out for a set of Deno permissions which are not web-compatible. */ - export type PermissionName = - | "run" - | "read" - | "write" - | "net" - | "env" - | "plugin" - | "hrtime"; - - /** The current status of the permission. - * - * See: https://w3c.github.io/permissions/#status-of-a-permission */ - 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"; - /** Optional url associated with this descriptor. - * - * If specified: must be a valid url. Expected format: <scheme>://<host_or_ip>[:port][/path] - * If the scheme is unknown, callers should specify some scheme, such as x:// na:// unknown:// - * - * See: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml */ - url?: string; - } - - export interface EnvPermissionDescriptor { - name: "env"; - } - - export interface PluginPermissionDescriptor { - name: "plugin"; - } - - export interface HrtimePermissionDescriptor { - name: "hrtime"; - } - - /** Permission descriptors which define a permission and can be queried, - * requested, or revoked. - * - * See: https://w3c.github.io/permissions/#permission-descriptor */ - export type PermissionDescriptor = - | RunPermissionDescriptor - | ReadPermissionDescriptor - | WritePermissionDescriptor - | NetPermissionDescriptor - | EnvPermissionDescriptor - | PluginPermissionDescriptor - | HrtimePermissionDescriptor; - - export class Permissions { - /** Resolves to the current status of a permission. - * - * ```ts - * const status = await Deno.permissions.query({ name: "read", path: "/etc" }); - * if (status.state === "granted") { - * data = await Deno.readFile("/etc/passwd"); - * } - * ``` - */ - query(desc: PermissionDescriptor): Promise<PermissionStatus>; - - /** Revokes a permission, and resolves to the state of the permission. - * - * const status = await Deno.permissions.revoke({ name: "run" }); - * assert(status.state !== "granted") - */ - revoke(desc: PermissionDescriptor): Promise<PermissionStatus>; - - /** Requests the permission, and resolves to the state of the permission. - * - * ```ts - * const status = await Deno.permissions.request({ name: "env" }); - * if (status.state === "granted") { - * console.log(Deno.dir("home"); - * } else { - * console.log("'env' permission is denied."); - * } - * ``` - */ - request(desc: PermissionDescriptor): Promise<PermissionStatus>; - } - - /** **UNSTABLE**: Under consideration to move to `navigator.permissions` to - * match web API. It could look like `navigator.permissions.query({ name: Deno.symbols.read })`. - */ - export const permissions: Permissions; - - /** see: https://w3c.github.io/permissions/#permissionstatus */ - export class PermissionStatus { - state: PermissionState; - constructor(state: PermissionState); - } - - /** **UNSTABLE**: New API, yet to be vetted. Additional consideration is still - * necessary around the permissions required. - * - * Get the `hostname` of the machine the Deno process is running on. - * - * ```ts - * console.log(Deno.hostname()); - * ``` - * - * Requires `allow-env` permission. - */ - export function hostname(): string; - - /** **UNSTABLE**: The URL of the file that was originally executed from the command-line. */ - export const mainModule: string; - - /** **UNSTABLE**: new API, yet to be vetted. - * Synchronously truncates or extends the specified file stream, to reach the - * specified `len`. If `len` is not specified then the entire file contents - * are truncated. - * - * ```ts - * // truncate the entire file - * const file = Deno.open("my_file.txt", { read: true, write: true, truncate: true, create: true }); - * Deno.ftruncateSync(file.rid); - * - * // truncate part of the file - * const file = Deno.open("my_file.txt", { read: true, write: true, create: true }); - * Deno.write(file.rid, new TextEncoder().encode("Hello World")); - * Deno.ftruncateSync(file.rid, 7); - * const data = new Uint8Array(32); - * Deno.readSync(file.rid, data); - * console.log(new TextDecoder().decode(data)); // Hello W - * ``` - */ - export function ftruncateSync(rid: number, len?: number): void; - - /** **UNSTABLE**: new API, yet to be vetted. - * Truncates or extends the specified file stream, to reach the specified `len`. If - * `len` is not specified then the entire file contents are truncated. - * - * ```ts - * // truncate the entire file - * const file = Deno.open("my_file.txt", { read: true, write: true, create: true }); - * await Deno.ftruncate(file.rid); - * - * // truncate part of the file - * const file = Deno.open("my_file.txt", { read: true, write: true, create: true }); - * await Deno.write(file.rid, new TextEncoder().encode("Hello World")); - * await Deno.ftruncate(file.rid, 7); - * const data = new Uint8Array(32); - * await Deno.read(file.rid, data); - * console.log(new TextDecoder().decode(data)); // Hello W - * ``` - */ - export function ftruncate(rid: number, len?: number): Promise<void>; - - /* **UNSTABLE**: New API, yet to be vetted. - * Synchronously flushes any pending data operations of the given file stream to disk. - * ```ts - * const file = Deno.openSync("my_file.txt", { read: true, write: true, create: true }); - * Deno.writeSync(file.rid, new TextEncoder().encode("Hello World")); - * Deno.fdatasyncSync(file.rid); - * console.log(new TextDecoder().decode(Deno.readFileSync("my_file.txt"))); // Hello World - * ``` - */ - export function fdatasyncSync(rid: number): void; - - /** **UNSTABLE**: New API, yet to be vetted. - * Flushes any pending data operations of the given file stream to disk. - * ```ts - * const file = await Deno.open("my_file.txt", { read: true, write: true, create: true }); - * await Deno.write(file.rid, new TextEncoder().encode("Hello World")); - * await Deno.fdatasync(file.rid); - * console.log(new TextDecoder().decode(await Deno.readFile("my_file.txt"))); // Hello World - * ``` - */ - export function fdatasync(rid: number): Promise<void>; - - /** **UNSTABLE**: New API, yet to be vetted. - * Synchronously flushes any pending data and metadata operations of the given file stream to disk. - * ```ts - * const file = Deno.openSync("my_file.txt", { read: true, write: true, create: true }); - * Deno.writeSync(file.rid, new TextEncoder().encode("Hello World")); - * Deno.ftruncateSync(file.rid, 1); - * Deno.fsyncSync(file.rid); - * console.log(new TextDecoder().decode(Deno.readFileSync("my_file.txt"))); // H - * ``` - */ - export function fsyncSync(rid: number): void; - - /** **UNSTABLE**: New API, yet to be vetted. - * Flushes any pending data and metadata operations of the given file stream to disk. - * ```ts - * const file = await Deno.open("my_file.txt", { read: true, write: true, create: true }); - * await Deno.write(file.rid, new TextEncoder().encode("Hello World")); - * await Deno.ftruncate(file.rid, 1); - * await Deno.fsync(file.rid); - * console.log(new TextDecoder().decode(await Deno.readFile("my_file.txt"))); // H - * ``` - */ - export function fsync(rid: number): Promise<void>; - - /** **UNSTABLE**: New API, yet to be vetted. - * Synchronously returns a `Deno.FileInfo` for the given file stream. - * - * ```ts - * const file = Deno.openSync("file.txt", { read: true }); - * const fileInfo = Deno.fstatSync(file.rid); - * assert(fileInfo.isFile); - * ``` - */ - export function fstatSync(rid: number): FileInfo; - - /** **UNSTABLE**: New API, yet to be vetted. - * Returns a `Deno.FileInfo` for the given file stream. - * - * ```ts - * const file = await Deno.open("file.txt", { read: true }); - * const fileInfo = await Deno.fstat(file.rid); - * assert(fileInfo.isFile); - * ``` - */ - export function fstat(rid: number): Promise<FileInfo>; - - /** **UNSTABLE**: New API, yet to be vetted. - * The pid of the current process's parent. - */ - export const ppid: number; -} diff --git a/cli/js/lib.deno.window.d.ts b/cli/js/lib.deno.window.d.ts deleted file mode 100644 index 61c5abf8a..000000000 --- a/cli/js/lib.deno.window.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -/* eslint-disable @typescript-eslint/no-explicit-any */ - -/// <reference no-default-lib="true" /> -/// <reference lib="deno.ns" /> -/// <reference lib="deno.shared_globals" /> -/// <reference lib="esnext" /> - -declare interface Window extends EventTarget { - readonly window: Window & typeof globalThis; - readonly self: Window & typeof globalThis; - onload: ((this: Window, ev: Event) => any) | null; - onunload: ((this: Window, ev: Event) => any) | null; - close: () => void; - readonly closed: boolean; - Deno: typeof Deno; -} - -declare const window: Window & typeof globalThis; -declare const self: Window & typeof globalThis; -declare const onload: ((this: Window, ev: Event) => any) | null; -declare const onunload: ((this: Window, ev: Event) => any) | null; - -/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/cli/js/lib.deno.worker.d.ts b/cli/js/lib.deno.worker.d.ts deleted file mode 100644 index 95aa16139..000000000 --- a/cli/js/lib.deno.worker.d.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any */ - -/// <reference no-default-lib="true" /> -/// <reference lib="deno.ns" /> -/// <reference lib="deno.shared_globals" /> -/// <reference lib="esnext" /> - -declare interface DedicatedWorkerGlobalScope { - self: DedicatedWorkerGlobalScope & typeof globalThis; - onmessage: (e: MessageEvent) => void; - onmessageerror: (e: MessageEvent) => void; - onerror: undefined | typeof onerror; - name: typeof __workerMain.name; - close: typeof __workerMain.close; - postMessage: typeof __workerMain.postMessage; - Deno: typeof Deno; -} - -declare const self: DedicatedWorkerGlobalScope & typeof globalThis; -declare let onmessage: ((e: { data: any }) => Promise<void> | void) | undefined; -declare let onerror: - | (( - msg: string, - source: string, - lineno: number, - colno: number, - e: Event, - ) => boolean | void) - | undefined; -declare const close: typeof __workerMain.close; -declare const name: typeof __workerMain.name; -declare const postMessage: typeof __workerMain.postMessage; - -declare namespace __workerMain { - export let onmessage: (e: { data: any }) => void; - export function postMessage(data: any): void; - export function close(): void; - export const name: string; -} - -/* eslint-enable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any */ diff --git a/cli/js/main.ts b/cli/js/main.ts deleted file mode 100644 index 4646f4cc2..000000000 --- a/cli/js/main.ts +++ /dev/null @@ -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, - }, -}); diff --git a/cli/js/net.ts b/cli/js/net.ts deleted file mode 100644 index 07feb89fe..000000000 --- a/cli/js/net.ts +++ /dev/null @@ -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!); -} diff --git a/cli/js/net_unstable.ts b/cli/js/net_unstable.ts deleted file mode 100644 index cedb68b23..000000000 --- a/cli/js/net_unstable.ts +++ /dev/null @@ -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); - } -} diff --git a/cli/js/ops/dispatch_json.ts b/cli/js/ops/dispatch_json.ts deleted file mode 100644 index cf6f5c095..000000000 --- a/cli/js/ops/dispatch_json.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/dispatch_minimal.ts b/cli/js/ops/dispatch_minimal.ts deleted file mode 100644 index cc1d97e20..000000000 --- a/cli/js/ops/dispatch_minimal.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/errors.ts b/cli/js/ops/errors.ts deleted file mode 100644 index 002ca699e..000000000 --- a/cli/js/ops/errors.ts +++ /dev/null @@ -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, - }; -} diff --git a/cli/js/ops/fetch.ts b/cli/js/ops/fetch.ts deleted file mode 100644 index e349b9de5..000000000 --- a/cli/js/ops/fetch.ts +++ /dev/null @@ -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] : [])); -} diff --git a/cli/js/ops/fs/chmod.ts b/cli/js/ops/fs/chmod.ts deleted file mode 100644 index a2236935b..000000000 --- a/cli/js/ops/fs/chmod.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/chown.ts b/cli/js/ops/fs/chown.ts deleted file mode 100644 index 054b61f6c..000000000 --- a/cli/js/ops/fs/chown.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/copy_file.ts b/cli/js/ops/fs/copy_file.ts deleted file mode 100644 index d2d2d5688..000000000 --- a/cli/js/ops/fs/copy_file.ts +++ /dev/null @@ -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), - }); -} diff --git a/cli/js/ops/fs/dir.ts b/cli/js/ops/fs/dir.ts deleted file mode 100644 index dbf468c62..000000000 --- a/cli/js/ops/fs/dir.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/link.ts b/cli/js/ops/fs/link.ts deleted file mode 100644 index 05ff358ef..000000000 --- a/cli/js/ops/fs/link.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/make_temp.ts b/cli/js/ops/fs/make_temp.ts deleted file mode 100644 index 3996744d1..000000000 --- a/cli/js/ops/fs/make_temp.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/fs/mkdir.ts b/cli/js/ops/fs/mkdir.ts deleted file mode 100644 index 790b2ad05..000000000 --- a/cli/js/ops/fs/mkdir.ts +++ /dev/null @@ -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)); -} diff --git a/cli/js/ops/fs/open.ts b/cli/js/ops/fs/open.ts deleted file mode 100644 index f2cad5988..000000000 --- a/cli/js/ops/fs/open.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/read_dir.ts b/cli/js/ops/fs/read_dir.ts deleted file mode 100644 index 6ffe6116e..000000000 --- a/cli/js/ops/fs/read_dir.ts +++ /dev/null @@ -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; - }, - }; -} diff --git a/cli/js/ops/fs/read_link.ts b/cli/js/ops/fs/read_link.ts deleted file mode 100644 index 33fef7e36..000000000 --- a/cli/js/ops/fs/read_link.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/real_path.ts b/cli/js/ops/fs/real_path.ts deleted file mode 100644 index c424d99bc..000000000 --- a/cli/js/ops/fs/real_path.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/remove.ts b/cli/js/ops/fs/remove.ts deleted file mode 100644 index 24e23986c..000000000 --- a/cli/js/ops/fs/remove.ts +++ /dev/null @@ -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, - }); -} diff --git a/cli/js/ops/fs/rename.ts b/cli/js/ops/fs/rename.ts deleted file mode 100644 index f0789d3eb..000000000 --- a/cli/js/ops/fs/rename.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/seek.ts b/cli/js/ops/fs/seek.ts deleted file mode 100644 index 4f97514ed..000000000 --- a/cli/js/ops/fs/seek.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/stat.ts b/cli/js/ops/fs/stat.ts deleted file mode 100644 index f444190fd..000000000 --- a/cli/js/ops/fs/stat.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/fs/symlink.ts b/cli/js/ops/fs/symlink.ts deleted file mode 100644 index d96e05f24..000000000 --- a/cli/js/ops/fs/symlink.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/sync.ts b/cli/js/ops/fs/sync.ts deleted file mode 100644 index 7f208b8bd..000000000 --- a/cli/js/ops/fs/sync.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/truncate.ts b/cli/js/ops/fs/truncate.ts deleted file mode 100644 index d18e5d9d9..000000000 --- a/cli/js/ops/fs/truncate.ts +++ /dev/null @@ -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) }); -} diff --git a/cli/js/ops/fs/umask.ts b/cli/js/ops/fs/umask.ts deleted file mode 100644 index fbc94091e..000000000 --- a/cli/js/ops/fs/umask.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/fs/utime.ts b/cli/js/ops/fs/utime.ts deleted file mode 100644 index bbc023ae9..000000000 --- a/cli/js/ops/fs/utime.ts +++ /dev/null @@ -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), - }); -} diff --git a/cli/js/ops/fs_events.ts b/cli/js/ops/fs_events.ts deleted file mode 100644 index ffe19b4d7..000000000 --- a/cli/js/ops/fs_events.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/get_random_values.ts b/cli/js/ops/get_random_values.ts deleted file mode 100644 index 5a45a79d7..000000000 --- a/cli/js/ops/get_random_values.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/ops/idna.ts b/cli/js/ops/idna.ts deleted file mode 100644 index 59a9af030..000000000 --- a/cli/js/ops/idna.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/io.ts b/cli/js/ops/io.ts deleted file mode 100644 index 355a09ae0..000000000 --- a/cli/js/ops/io.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/ops/net.ts b/cli/js/ops/net.ts deleted file mode 100644 index 1dfa92bd1..000000000 --- a/cli/js/ops/net.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/os.ts b/cli/js/ops/os.ts deleted file mode 100644 index 50234ee4b..000000000 --- a/cli/js/ops/os.ts +++ /dev/null @@ -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"); -} diff --git a/cli/js/ops/permissions.ts b/cli/js/ops/permissions.ts deleted file mode 100644 index 74b9ba0f0..000000000 --- a/cli/js/ops/permissions.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/ops/plugins.ts b/cli/js/ops/plugins.ts deleted file mode 100644 index 787fd799b..000000000 --- a/cli/js/ops/plugins.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/process.ts b/cli/js/ops/process.ts deleted file mode 100644 index 86a0c9a71..000000000 --- a/cli/js/ops/process.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/repl.ts b/cli/js/ops/repl.ts deleted file mode 100644 index 1781aa089..000000000 --- a/cli/js/ops/repl.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/resources.ts b/cli/js/ops/resources.ts deleted file mode 100644 index ffcdb553e..000000000 --- a/cli/js/ops/resources.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/runtime.ts b/cli/js/ops/runtime.ts deleted file mode 100644 index 09208df6d..000000000 --- a/cli/js/ops/runtime.ts +++ /dev/null @@ -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"); -} diff --git a/cli/js/ops/runtime_compiler.ts b/cli/js/ops/runtime_compiler.ts deleted file mode 100644 index ed439de4a..000000000 --- a/cli/js/ops/runtime_compiler.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/signal.ts b/cli/js/ops/signal.ts deleted file mode 100644 index 15093a3c4..000000000 --- a/cli/js/ops/signal.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/timers.ts b/cli/js/ops/timers.ts deleted file mode 100644 index 2fdbd6851..000000000 --- a/cli/js/ops/timers.ts +++ /dev/null @@ -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"); -} diff --git a/cli/js/ops/tls.ts b/cli/js/ops/tls.ts deleted file mode 100644 index 291fe3dd9..000000000 --- a/cli/js/ops/tls.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/ops/tty.ts b/cli/js/ops/tty.ts deleted file mode 100644 index f9da7bd0d..000000000 --- a/cli/js/ops/tty.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/ops/web_worker.ts b/cli/js/ops/web_worker.ts deleted file mode 100644 index 329323e2e..000000000 --- a/cli/js/ops/web_worker.ts +++ /dev/null @@ -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"); -} diff --git a/cli/js/ops/worker_host.ts b/cli/js/ops/worker_host.ts deleted file mode 100644 index d5adfc3d5..000000000 --- a/cli/js/ops/worker_host.ts +++ /dev/null @@ -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 }); -} diff --git a/cli/js/permissions.ts b/cli/js/permissions.ts deleted file mode 100644 index ab0612ad4..000000000 --- a/cli/js/permissions.ts +++ /dev/null @@ -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(); diff --git a/cli/js/process.ts b/cli/js/process.ts deleted file mode 100644 index 0844dd8fd..000000000 --- a/cli/js/process.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/rbtree.ts b/cli/js/rbtree.ts deleted file mode 100644 index fbade97b7..000000000 --- a/cli/js/rbtree.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/read_file.ts b/cli/js/read_file.ts deleted file mode 100644 index a90ad47fb..000000000 --- a/cli/js/read_file.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/read_text_file.ts b/cli/js/read_text_file.ts deleted file mode 100644 index 02c9fe611..000000000 --- a/cli/js/read_text_file.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/repl.ts b/cli/js/repl.ts deleted file mode 100644 index 9f2693de6..000000000 --- a/cli/js/repl.ts +++ /dev/null @@ -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); - } - } - } - } -} diff --git a/cli/js/runtime.ts b/cli/js/runtime.ts deleted file mode 100644 index a260dfebe..000000000 --- a/cli/js/runtime.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/runtime_main.ts b/cli/js/runtime_main.ts deleted file mode 100644 index 2983fd47f..000000000 --- a/cli/js/runtime_main.ts +++ /dev/null @@ -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(); - } -} diff --git a/cli/js/runtime_worker.ts b/cli/js/runtime_worker.ts deleted file mode 100644 index 9904ab012..000000000 --- a/cli/js/runtime_worker.ts +++ /dev/null @@ -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); - } -} diff --git a/cli/js/signals.ts b/cli/js/signals.ts deleted file mode 100644 index a29bac0d7..000000000 --- a/cli/js/signals.ts +++ /dev/null @@ -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); - } -} diff --git a/cli/js/testing.ts b/cli/js/testing.ts deleted file mode 100644 index accbb81ee..000000000 --- a/cli/js/testing.ts +++ /dev/null @@ -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); diff --git a/cli/js/tls.ts b/cli/js/tls.ts deleted file mode 100644 index f266a16ea..000000000 --- a/cli/js/tls.ts +++ /dev/null @@ -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!); -} diff --git a/cli/js/ts_global.d.ts b/cli/js/ts_global.d.ts deleted file mode 100644 index a32e8b620..000000000 --- a/cli/js/ts_global.d.ts +++ /dev/null @@ -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; - } - } -} diff --git a/cli/js/util.ts b/cli/js/util.ts deleted file mode 100644 index f1aefb601..000000000 --- a/cli/js/util.ts +++ /dev/null @@ -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); diff --git a/cli/js/version.ts b/cli/js/version.ts deleted file mode 100644 index 30157af04..000000000 --- a/cli/js/version.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/web/README.md b/cli/js/web/README.md deleted file mode 100644 index 01672fe76..000000000 --- a/cli/js/web/README.md +++ /dev/null @@ -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). diff --git a/cli/js/web/abort_controller.ts b/cli/js/web/abort_controller.ts deleted file mode 100644 index 376376092..000000000 --- a/cli/js/web/abort_controller.ts +++ /dev/null @@ -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, -}); diff --git a/cli/js/web/abort_signal.ts b/cli/js/web/abort_signal.ts deleted file mode 100644 index b741d6534..000000000 --- a/cli/js/web/abort_signal.ts +++ /dev/null @@ -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, -}); diff --git a/cli/js/web/base64.ts b/cli/js/web/base64.ts deleted file mode 100644 index 6f2459b92..000000000 --- a/cli/js/web/base64.ts +++ /dev/null @@ -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(""); -} diff --git a/cli/js/web/blob.ts b/cli/js/web/blob.ts deleted file mode 100644 index 7034da723..000000000 --- a/cli/js/web/blob.ts +++ /dev/null @@ -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 }; diff --git a/cli/js/web/body.ts b/cli/js/web/body.ts deleted file mode 100644 index a7a120ad6..000000000 --- a/cli/js/web/body.ts +++ /dev/null @@ -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}`, - ); - } -} diff --git a/cli/js/web/console.ts b/cli/js/web/console.ts deleted file mode 100644 index 181cdb664..000000000 --- a/cli/js/web/console.ts +++ /dev/null @@ -1,1072 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { isInvalidDate, isTypedArray, TypedArray } from "./util.ts"; -import { cliTable } from "./console_table.ts"; -import { exposeForTest } from "../internals.ts"; -import { PromiseState } from "./promise.ts"; -import { - stripColor, - yellow, - dim, - cyan, - red, - green, - magenta, - bold, -} from "../colors.ts"; - -type ConsoleContext = Set<unknown>; - -export interface InspectOptions { - depth?: number; - indentLevel?: number; - sorted?: boolean; - trailingComma?: boolean; - compact?: boolean; - iterableLimit?: number; -} - -const DEFAULT_INSPECT_OPTIONS: Required<InspectOptions> = { - depth: 4, - indentLevel: 0, - sorted: false, - trailingComma: false, - compact: true, - iterableLimit: 100, -}; - -const DEFAULT_INDENT = " "; // Default indent string - -const LINE_BREAKING_LENGTH = 80; -const MIN_GROUP_LENGTH = 6; -const STR_ABBREVIATE_SIZE = 100; -// Char codes -const CHAR_PERCENT = 37; /* % */ -const CHAR_LOWERCASE_S = 115; /* s */ -const CHAR_LOWERCASE_D = 100; /* d */ -const CHAR_LOWERCASE_I = 105; /* i */ -const CHAR_LOWERCASE_F = 102; /* f */ -const CHAR_LOWERCASE_O = 111; /* o */ -const CHAR_UPPERCASE_O = 79; /* O */ -const CHAR_LOWERCASE_C = 99; /* c */ - -const PROMISE_STRING_BASE_LENGTH = 12; - -export class CSI { - static kClear = "\x1b[1;1H"; - static kClearScreenDown = "\x1b[0J"; -} - -/* eslint-disable @typescript-eslint/no-use-before-define */ - -function getClassInstanceName(instance: unknown): string { - if (typeof instance !== "object") { - return ""; - } - if (!instance) { - return ""; - } - - const proto = Object.getPrototypeOf(instance); - if (proto && proto.constructor) { - return proto.constructor.name; // could be "Object" or "Array" - } - - return ""; -} - -function inspectFunction(value: Function, _ctx: ConsoleContext): string { - // Might be Function/AsyncFunction/GeneratorFunction - const cstrName = Object.getPrototypeOf(value).constructor.name; - if (value.name && value.name !== "anonymous") { - // from MDN spec - return `[${cstrName}: ${value.name}]`; - } - return `[${cstrName}]`; -} - -interface InspectIterableOptions<T> { - typeName: string; - displayName: string; - delims: [string, string]; - entryHandler: ( - entry: [unknown, T], - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, - next: () => IteratorResult<[unknown, T], unknown>, - ) => string; - group: boolean; - sort: boolean; -} -type IterableEntries<T> = Iterable<T> & { - entries(): IterableIterator<[unknown, T]>; -}; -function inspectIterable<T>( - value: IterableEntries<T>, - ctx: ConsoleContext, - level: number, - options: InspectIterableOptions<T>, - inspectOptions: Required<InspectOptions>, -): string { - if (level >= inspectOptions.depth) { - return cyan(`[${options.typeName}]`); - } - ctx.add(value); - - const entries: string[] = []; - - const iter = value.entries(); - let entriesLength = 0; - const next = (): IteratorResult<[unknown, T], unknown> => { - return iter.next(); - }; - for (const el of iter) { - if (entriesLength < inspectOptions.iterableLimit) { - entries.push( - options.entryHandler( - el, - ctx, - level + 1, - inspectOptions, - next.bind(iter), - ), - ); - } - entriesLength++; - } - ctx.delete(value); - - if (options.sort) { - entries.sort(); - } - - if (entriesLength > inspectOptions.iterableLimit) { - const nmore = entriesLength - inspectOptions.iterableLimit; - entries.push(`... ${nmore} more items`); - } - - const iPrefix = `${options.displayName ? options.displayName + " " : ""}`; - - const initIndentation = `\n${DEFAULT_INDENT.repeat(level + 1)}`; - const entryIndentation = `,\n${DEFAULT_INDENT.repeat(level + 1)}`; - const closingIndentation = `${inspectOptions.trailingComma ? "," : ""}\n${ - DEFAULT_INDENT.repeat(level) - }`; - - let iContent: string; - if (options.group && entries.length > MIN_GROUP_LENGTH) { - const groups = groupEntries(entries, level, value); - iContent = `${initIndentation}${ - groups.join(entryIndentation) - }${closingIndentation}`; - } else { - iContent = entries.length === 0 ? "" : ` ${entries.join(", ")} `; - if ( - stripColor(iContent).length > LINE_BREAKING_LENGTH || - !inspectOptions.compact - ) { - iContent = `${initIndentation}${ - entries.join(entryIndentation) - }${closingIndentation}`; - } - } - - return `${iPrefix}${options.delims[0]}${iContent}${options.delims[1]}`; -} - -// Ported from Node.js -// Copyright Node.js contributors. All rights reserved. -function groupEntries<T>( - entries: string[], - level: number, - value: Iterable<T>, - iterableLimit = 100, -): string[] { - let totalLength = 0; - let maxLength = 0; - let entriesLength = entries.length; - if (iterableLimit < entriesLength) { - // This makes sure the "... n more items" part is not taken into account. - entriesLength--; - } - const separatorSpace = 2; // Add 1 for the space and 1 for the separator. - const dataLen = new Array(entriesLength); - // Calculate the total length of all output entries and the individual max - // entries length of all output entries. - // IN PROGRESS: Colors are being taken into account. - for (let i = 0; i < entriesLength; i++) { - // Taking colors into account: removing the ANSI color - // codes from the string before measuring its length - const len = stripColor(entries[i]).length; - dataLen[i] = len; - totalLength += len + separatorSpace; - if (maxLength < len) maxLength = len; - } - // Add two to `maxLength` as we add a single whitespace character plus a comma - // in-between two entries. - const actualMax = maxLength + separatorSpace; - // Check if at least three entries fit next to each other and prevent grouping - // of arrays that contains entries of very different length (i.e., if a single - // entry is longer than 1/5 of all other entries combined). Otherwise the - // space in-between small entries would be enormous. - if ( - actualMax * 3 + (level + 1) < LINE_BREAKING_LENGTH && - (totalLength / actualMax > 5 || maxLength <= 6) - ) { - const approxCharHeights = 2.5; - const averageBias = Math.sqrt(actualMax - totalLength / entries.length); - const biasedMax = Math.max(actualMax - 3 - averageBias, 1); - // Dynamically check how many columns seem possible. - const columns = Math.min( - // Ideally a square should be drawn. We expect a character to be about 2.5 - // times as high as wide. This is the area formula to calculate a square - // which contains n rectangles of size `actualMax * approxCharHeights`. - // Divide that by `actualMax` to receive the correct number of columns. - // The added bias increases the columns for short entries. - Math.round( - Math.sqrt(approxCharHeights * biasedMax * entriesLength) / biasedMax, - ), - // Do not exceed the breakLength. - Math.floor((LINE_BREAKING_LENGTH - (level + 1)) / actualMax), - // Limit the columns to a maximum of fifteen. - 15, - ); - // Return with the original output if no grouping should happen. - if (columns <= 1) { - return entries; - } - const tmp = []; - const maxLineLength = []; - for (let i = 0; i < columns; i++) { - let lineMaxLength = 0; - for (let j = i; j < entries.length; j += columns) { - if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j]; - } - lineMaxLength += separatorSpace; - maxLineLength[i] = lineMaxLength; - } - let order: "padStart" | "padEnd" = "padStart"; - if (value !== undefined) { - for (let i = 0; i < entries.length; i++) { - /* eslint-disable @typescript-eslint/no-explicit-any */ - if ( - typeof (value as any)[i] !== "number" && - typeof (value as any)[i] !== "bigint" - ) { - order = "padEnd"; - break; - } - /* eslint-enable */ - } - } - // Each iteration creates a single line of grouped entries. - for (let i = 0; i < entriesLength; i += columns) { - // The last lines may contain less entries than columns. - const max = Math.min(i + columns, entriesLength); - let str = ""; - let j = i; - for (; j < max - 1; j++) { - // In future, colors should be taken here into the account - const padding = maxLineLength[j - i]; - str += `${entries[j]}, `[order](padding, " "); - } - if (order === "padStart") { - const padding = maxLineLength[j - i] + - entries[j].length - - dataLen[j] - - separatorSpace; - str += entries[j].padStart(padding, " "); - } else { - str += entries[j]; - } - tmp.push(str); - } - if (iterableLimit < entries.length) { - tmp.push(entries[entriesLength]); - } - entries = tmp; - } - return entries; -} - -function inspectValue( - value: unknown, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - switch (typeof value) { - case "string": - return value; - case "number": // Numbers are yellow - // Special handling of -0 - return yellow(Object.is(value, -0) ? "-0" : `${value}`); - case "boolean": // booleans are yellow - return yellow(String(value)); - case "undefined": // undefined is dim - return dim(String(value)); - case "symbol": // Symbols are green - return green(String(value)); - case "bigint": // Bigints are yellow - return yellow(`${value}n`); - case "function": // Function string is cyan - return cyan(inspectFunction(value as Function, ctx)); - case "object": // null is bold - if (value === null) { - return bold("null"); - } - - if (ctx.has(value)) { - // Circular string is cyan - return cyan("[Circular]"); - } - - return inspectObject(value, ctx, level, inspectOptions); - default: - // Not implemented is red - return red("[Not Implemented]"); - } -} - -// We can match Node's quoting behavior exactly by swapping the double quote and -// single quote in this array. That would give preference to single quotes. -// However, we prefer double quotes as the default. -const QUOTES = ['"', "'", "`"]; - -/** Surround the string in quotes. - * - * The quote symbol is chosen by taking the first of the `QUOTES` array which - * does not occur in the string. If they all occur, settle with `QUOTES[0]`. - * - * Insert a backslash before any occurrence of the chosen quote symbol and - * before any backslash. */ -function quoteString(string: string): string { - const quote = QUOTES.find((c) => !string.includes(c)) ?? QUOTES[0]; - const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g"); - return `${quote}${string.replace(escapePattern, "\\")}${quote}`; -} - -// Print strings when they are inside of arrays or objects with quotes -function inspectValueWithQuotes( - value: unknown, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - switch (typeof value) { - case "string": - const trunc = value.length > STR_ABBREVIATE_SIZE - ? value.slice(0, STR_ABBREVIATE_SIZE) + "..." - : value; - return green(quoteString(trunc)); // Quoted strings are green - default: - return inspectValue(value, ctx, level, inspectOptions); - } -} - -function inspectArray( - value: unknown[], - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - const options: InspectIterableOptions<unknown> = { - typeName: "Array", - displayName: "", - delims: ["[", "]"], - entryHandler: (entry, ctx, level, inspectOptions, next): string => { - const [index, val] = entry as [number, unknown]; - let i = index; - if (!value.hasOwnProperty(i)) { - i++; - while (!value.hasOwnProperty(i) && i < value.length) { - next(); - i++; - } - const emptyItems = i - index; - const ending = emptyItems > 1 ? "s" : ""; - return dim(`<${emptyItems} empty item${ending}>`); - } else { - return inspectValueWithQuotes(val, ctx, level, inspectOptions); - } - }, - group: inspectOptions.compact, - sort: false, - }; - return inspectIterable(value, ctx, level, options, inspectOptions); -} - -function inspectTypedArray( - typedArrayName: string, - value: TypedArray, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - const valueLength = value.length; - const options: InspectIterableOptions<unknown> = { - typeName: typedArrayName, - displayName: `${typedArrayName}(${valueLength})`, - delims: ["[", "]"], - entryHandler: (entry, ctx, level, inspectOptions): string => { - const val = entry[1]; - return inspectValueWithQuotes(val, ctx, level + 1, inspectOptions); - }, - group: inspectOptions.compact, - sort: false, - }; - return inspectIterable(value, ctx, level, options, inspectOptions); -} - -function inspectSet( - value: Set<unknown>, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - const options: InspectIterableOptions<unknown> = { - typeName: "Set", - displayName: "Set", - delims: ["{", "}"], - entryHandler: (entry, ctx, level, inspectOptions): string => { - const val = entry[1]; - return inspectValueWithQuotes(val, ctx, level + 1, inspectOptions); - }, - group: false, - sort: inspectOptions.sorted, - }; - return inspectIterable(value, ctx, level, options, inspectOptions); -} - -function inspectMap( - value: Map<unknown, unknown>, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - const options: InspectIterableOptions<[unknown]> = { - typeName: "Map", - displayName: "Map", - delims: ["{", "}"], - entryHandler: (entry, ctx, level, inspectOptions): string => { - const [key, val] = entry; - return `${ - inspectValueWithQuotes( - key, - ctx, - level + 1, - inspectOptions, - ) - } => ${inspectValueWithQuotes(val, ctx, level + 1, inspectOptions)}`; - }, - group: false, - sort: inspectOptions.sorted, - }; - return inspectIterable( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - value as any, - ctx, - level, - options, - inspectOptions, - ); -} - -function inspectWeakSet(): string { - return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color -} - -function inspectWeakMap(): string { - return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color -} - -function inspectDate(value: Date): string { - // without quotes, ISO format, in magenta like before - return magenta(isInvalidDate(value) ? "Invalid Date" : value.toISOString()); -} - -function inspectRegExp(value: RegExp): string { - return red(value.toString()); // RegExps are red -} - -/* eslint-disable @typescript-eslint/ban-types */ - -function inspectStringObject(value: String): string { - return cyan(`[String: "${value.toString()}"]`); // wrappers are in cyan -} - -function inspectBooleanObject(value: Boolean): string { - return cyan(`[Boolean: ${value.toString()}]`); // wrappers are in cyan -} - -function inspectNumberObject(value: Number): string { - return cyan(`[Number: ${value.toString()}]`); // wrappers are in cyan -} - -/* eslint-enable @typescript-eslint/ban-types */ - -function inspectPromise( - value: Promise<unknown>, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - const [state, result] = Deno.core.getPromiseDetails(value); - - if (state === PromiseState.Pending) { - return `Promise { ${cyan("<pending>")} }`; - } - - const prefix = state === PromiseState.Fulfilled - ? "" - : `${red("<rejected>")} `; - - const str = `${prefix}${ - inspectValueWithQuotes( - result, - ctx, - level + 1, - inspectOptions, - ) - }`; - - if (str.length + PROMISE_STRING_BASE_LENGTH > LINE_BREAKING_LENGTH) { - return `Promise {\n${DEFAULT_INDENT.repeat(level + 1)}${str}\n}`; - } - - return `Promise { ${str} }`; -} - -// TODO: Proxy - -function inspectRawObject( - value: Record<string, unknown>, - ctx: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - if (level >= inspectOptions.depth) { - return cyan("[Object]"); // wrappers are in cyan - } - ctx.add(value); - - let baseString: string; - - let shouldShowDisplayName = false; - let displayName = (value as { [Symbol.toStringTag]: string })[ - Symbol.toStringTag - ]; - if (!displayName) { - displayName = getClassInstanceName(value); - } - if (displayName && displayName !== "Object" && displayName !== "anonymous") { - shouldShowDisplayName = true; - } - - const entries: string[] = []; - const stringKeys = Object.keys(value); - const symbolKeys = Object.getOwnPropertySymbols(value); - if (inspectOptions.sorted) { - stringKeys.sort(); - symbolKeys.sort((s1, s2) => - (s1.description ?? "").localeCompare(s2.description ?? "") - ); - } - - for (const key of stringKeys) { - entries.push( - `${key}: ${ - inspectValueWithQuotes( - value[key], - ctx, - level + 1, - inspectOptions, - ) - }`, - ); - } - for (const key of symbolKeys) { - entries.push( - `${key.toString()}: ${ - inspectValueWithQuotes( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - value[key as any], - ctx, - level + 1, - inspectOptions, - ) - }`, - ); - } - // Making sure color codes are ignored when calculating the total length - const totalLength = entries.length + level + - stripColor(entries.join("")).length; - - ctx.delete(value); - - if (entries.length === 0) { - baseString = "{}"; - } else if (totalLength > LINE_BREAKING_LENGTH || !inspectOptions.compact) { - const entryIndent = DEFAULT_INDENT.repeat(level + 1); - const closingIndent = DEFAULT_INDENT.repeat(level); - baseString = `{\n${entryIndent}${entries.join(`,\n${entryIndent}`)}${ - inspectOptions.trailingComma ? "," : "" - }\n${closingIndent}}`; - } else { - baseString = `{ ${entries.join(", ")} }`; - } - - if (shouldShowDisplayName) { - baseString = `${displayName} ${baseString}`; - } - - return baseString; -} - -function inspectObject( - value: {}, - consoleContext: ConsoleContext, - level: number, - inspectOptions: Required<InspectOptions>, -): string { - if (customInspect in value && typeof value[customInspect] === "function") { - try { - return String(value[customInspect]!()); - } catch {} - } - if (value instanceof Error) { - return String(value.stack); - } else if (Array.isArray(value)) { - return inspectArray(value, consoleContext, level, inspectOptions); - } else if (value instanceof Number) { - return inspectNumberObject(value); - } else if (value instanceof Boolean) { - return inspectBooleanObject(value); - } else if (value instanceof String) { - return inspectStringObject(value); - } else if (value instanceof Promise) { - return inspectPromise(value, consoleContext, level, inspectOptions); - } else if (value instanceof RegExp) { - return inspectRegExp(value); - } else if (value instanceof Date) { - return inspectDate(value); - } else if (value instanceof Set) { - return inspectSet(value, consoleContext, level, inspectOptions); - } else if (value instanceof Map) { - return inspectMap(value, consoleContext, level, inspectOptions); - } else if (value instanceof WeakSet) { - return inspectWeakSet(); - } else if (value instanceof WeakMap) { - return inspectWeakMap(); - } else if (isTypedArray(value)) { - return inspectTypedArray( - Object.getPrototypeOf(value).constructor.name, - value, - consoleContext, - level, - inspectOptions, - ); - } else { - // Otherwise, default object formatting - return inspectRawObject(value, consoleContext, level, inspectOptions); - } -} - -export function inspectArgs( - args: unknown[], - inspectOptions: InspectOptions = {}, -): string { - const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions }; - const first = args[0]; - let a = 0; - let str = ""; - let join = ""; - - if (typeof first === "string") { - let tempStr: string; - let lastPos = 0; - - for (let i = 0; i < first.length - 1; i++) { - if (first.charCodeAt(i) === CHAR_PERCENT) { - const nextChar = first.charCodeAt(++i); - if (a + 1 !== args.length) { - switch (nextChar) { - case CHAR_LOWERCASE_S: - // format as a string - tempStr = String(args[++a]); - break; - case CHAR_LOWERCASE_D: - case CHAR_LOWERCASE_I: - // format as an integer - const tempInteger = args[++a]; - if (typeof tempInteger === "bigint") { - tempStr = `${tempInteger}n`; - } else if (typeof tempInteger === "symbol") { - tempStr = "NaN"; - } else { - tempStr = `${parseInt(String(tempInteger), 10)}`; - } - break; - case CHAR_LOWERCASE_F: - // format as a floating point value - const tempFloat = args[++a]; - if (typeof tempFloat === "symbol") { - tempStr = "NaN"; - } else { - tempStr = `${parseFloat(String(tempFloat))}`; - } - break; - case CHAR_LOWERCASE_O: - case CHAR_UPPERCASE_O: - // format as an object - tempStr = inspectValue( - args[++a], - new Set<unknown>(), - 0, - rInspectOptions, - ); - break; - case CHAR_PERCENT: - str += first.slice(lastPos, i); - lastPos = i + 1; - continue; - case CHAR_LOWERCASE_C: - // TODO: applies CSS style rules to the output string as specified - continue; - default: - // any other character is not a correct placeholder - continue; - } - - if (lastPos !== i - 1) { - str += first.slice(lastPos, i - 1); - } - - str += tempStr; - lastPos = i + 1; - } else if (nextChar === CHAR_PERCENT) { - str += first.slice(lastPos, i); - lastPos = i + 1; - } - } - } - - if (lastPos !== 0) { - a++; - join = " "; - if (lastPos < first.length) { - str += first.slice(lastPos); - } - } - } - - while (a < args.length) { - const value = args[a]; - str += join; - if (typeof value === "string") { - str += value; - } else { - // use default maximum depth for null or undefined argument - str += inspectValue(value, new Set<unknown>(), 0, rInspectOptions); - } - join = " "; - a++; - } - - if (rInspectOptions.indentLevel > 0) { - const groupIndent = DEFAULT_INDENT.repeat(rInspectOptions.indentLevel); - if (str.indexOf("\n") !== -1) { - str = str.replace(/\n/g, `\n${groupIndent}`); - } - str = groupIndent + str; - } - - return str; -} - -type PrintFunc = (x: string, isErr?: boolean) => void; - -const countMap = new Map<string, number>(); -const timerMap = new Map<string, number>(); -const isConsoleInstance = Symbol("isConsoleInstance"); - -export class Console { - readonly #printFunc: PrintFunc; - indentLevel: number; - [isConsoleInstance] = false; - - constructor(printFunc: PrintFunc) { - this.#printFunc = printFunc; - this.indentLevel = 0; - this[isConsoleInstance] = true; - - // ref https://console.spec.whatwg.org/#console-namespace - // For historical web-compatibility reasons, the namespace object for - // console must have as its [[Prototype]] an empty object, created as if - // by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%. - const console = Object.create({}) as Console; - Object.assign(console, this); - return console; - } - - log = (...args: unknown[]): void => { - this.#printFunc( - inspectArgs(args, { - indentLevel: this.indentLevel, - }) + "\n", - false, - ); - }; - - debug = this.log; - info = this.log; - - dir = (obj: unknown, options: InspectOptions = {}): void => { - this.#printFunc(inspectArgs([obj], options) + "\n", false); - }; - - dirxml = this.dir; - - warn = (...args: unknown[]): void => { - this.#printFunc( - inspectArgs(args, { - indentLevel: this.indentLevel, - }) + "\n", - true, - ); - }; - - error = this.warn; - - assert = (condition = false, ...args: unknown[]): void => { - if (condition) { - return; - } - - if (args.length === 0) { - this.error("Assertion failed"); - return; - } - - const [first, ...rest] = args; - - if (typeof first === "string") { - this.error(`Assertion failed: ${first}`, ...rest); - return; - } - - this.error(`Assertion failed:`, ...args); - }; - - count = (label = "default"): void => { - label = String(label); - - if (countMap.has(label)) { - const current = countMap.get(label) || 0; - countMap.set(label, current + 1); - } else { - countMap.set(label, 1); - } - - this.info(`${label}: ${countMap.get(label)}`); - }; - - countReset = (label = "default"): void => { - label = String(label); - - if (countMap.has(label)) { - countMap.set(label, 0); - } else { - this.warn(`Count for '${label}' does not exist`); - } - }; - - table = (data: unknown, properties?: string[]): void => { - if (properties !== undefined && !Array.isArray(properties)) { - throw new Error( - "The 'properties' argument must be of type Array. " + - "Received type string", - ); - } - - if (data === null || typeof data !== "object") { - return this.log(data); - } - - const objectValues: { [key: string]: string[] } = {}; - const indexKeys: string[] = []; - const values: string[] = []; - - const stringifyValue = (value: unknown): string => - inspectValueWithQuotes(value, new Set<unknown>(), 0, { - ...DEFAULT_INSPECT_OPTIONS, - depth: 1, - }); - const toTable = (header: string[], body: string[][]): void => - this.log(cliTable(header, body)); - const createColumn = (value: unknown, shift?: number): string[] => [ - ...(shift ? [...new Array(shift)].map((): string => "") : []), - stringifyValue(value), - ]; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let resultData: any; - const isSet = data instanceof Set; - const isMap = data instanceof Map; - const valuesKey = "Values"; - const indexKey = isSet || isMap ? "(iter idx)" : "(idx)"; - - if (data instanceof Set) { - resultData = [...data]; - } else if (data instanceof Map) { - let idx = 0; - resultData = {}; - - data.forEach((v: unknown, k: unknown): void => { - resultData[idx] = { Key: k, Values: v }; - idx++; - }); - } else { - resultData = data!; - } - - let hasPrimitives = false; - Object.keys(resultData).forEach((k, idx): void => { - const value: unknown = resultData[k]!; - const primitive = value === null || - (typeof value !== "function" && typeof value !== "object"); - if (properties === undefined && primitive) { - hasPrimitives = true; - values.push(stringifyValue(value)); - } else { - const valueObj = (value as { [key: string]: unknown }) || {}; - const keys = properties || Object.keys(valueObj); - for (const k of keys) { - if (primitive || !valueObj.hasOwnProperty(k)) { - if (objectValues[k]) { - // fill with blanks for idx to avoid misplacing from later values - objectValues[k].push(""); - } - } else { - if (objectValues[k]) { - objectValues[k].push(stringifyValue(valueObj[k])); - } else { - objectValues[k] = createColumn(valueObj[k], idx); - } - } - } - values.push(""); - } - - indexKeys.push(k); - }); - - const headerKeys = Object.keys(objectValues); - const bodyValues = Object.values(objectValues); - const header = [ - indexKey, - ...(properties || [...headerKeys, !isMap && hasPrimitives && valuesKey]), - ].filter(Boolean) as string[]; - const body = [indexKeys, ...bodyValues, values]; - - toTable(header, body); - }; - - time = (label = "default"): void => { - label = String(label); - - if (timerMap.has(label)) { - this.warn(`Timer '${label}' already exists`); - return; - } - - timerMap.set(label, Date.now()); - }; - - timeLog = (label = "default", ...args: unknown[]): void => { - label = String(label); - - if (!timerMap.has(label)) { - this.warn(`Timer '${label}' does not exists`); - return; - } - - const startTime = timerMap.get(label) as number; - const duration = Date.now() - startTime; - - this.info(`${label}: ${duration}ms`, ...args); - }; - - timeEnd = (label = "default"): void => { - label = String(label); - - if (!timerMap.has(label)) { - this.warn(`Timer '${label}' does not exists`); - return; - } - - const startTime = timerMap.get(label) as number; - timerMap.delete(label); - const duration = Date.now() - startTime; - - this.info(`${label}: ${duration}ms`); - }; - - group = (...label: unknown[]): void => { - if (label.length > 0) { - this.log(...label); - } - this.indentLevel += 2; - }; - - groupCollapsed = this.group; - - groupEnd = (): void => { - if (this.indentLevel > 0) { - this.indentLevel -= 2; - } - }; - - clear = (): void => { - this.indentLevel = 0; - this.#printFunc(CSI.kClear, false); - this.#printFunc(CSI.kClearScreenDown, false); - }; - - trace = (...args: unknown[]): void => { - const message = inspectArgs(args, { indentLevel: 0 }); - const err = { - name: "Trace", - message, - }; - Error.captureStackTrace(err, this.trace); - this.error((err as Error).stack); - }; - - static [Symbol.hasInstance](instance: Console): boolean { - return instance[isConsoleInstance]; - } -} - -export const customInspect = Symbol("Deno.customInspect"); - -export function inspect( - value: unknown, - inspectOptions: InspectOptions = {}, -): string { - if (typeof value === "string") { - return value; - } else { - return inspectValue(value, new Set<unknown>(), 0, { - ...DEFAULT_INSPECT_OPTIONS, - ...inspectOptions, - // TODO(nayeemrmn): Indent level is not supported. - indentLevel: 0, - }); - } -} - -// Expose these fields to internalObject for tests. -exposeForTest("Console", Console); -exposeForTest("inspectArgs", inspectArgs); diff --git a/cli/js/web/console_table.ts b/cli/js/web/console_table.ts deleted file mode 100644 index 42667d998..000000000 --- a/cli/js/web/console_table.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/web/custom_event.ts b/cli/js/web/custom_event.ts deleted file mode 100644 index dad89f650..000000000 --- a/cli/js/web/custom_event.ts +++ /dev/null @@ -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, -}); diff --git a/cli/js/web/decode_utf8.ts b/cli/js/web/decode_utf8.ts deleted file mode 100644 index ca190134c..000000000 --- a/cli/js/web/decode_utf8.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/web/dom_exception.ts b/cli/js/web/dom_exception.ts deleted file mode 100644 index 5e7d5ee6f..000000000 --- a/cli/js/web/dom_exception.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -export class DOMExceptionImpl extends Error implements DOMException { - readonly #name: string; - - constructor(message = "", name = "Error") { - super(message); - this.#name = name; - } - - get name(): string { - return this.#name; - } -} diff --git a/cli/js/web/dom_file.ts b/cli/js/web/dom_file.ts deleted file mode 100644 index 907337e59..000000000 --- a/cli/js/web/dom_file.ts +++ /dev/null @@ -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; - } -} diff --git a/cli/js/web/dom_iterable.ts b/cli/js/web/dom_iterable.ts deleted file mode 100644 index 7e26a12a4..000000000 --- a/cli/js/web/dom_iterable.ts +++ /dev/null @@ -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); diff --git a/cli/js/web/dom_types.d.ts b/cli/js/web/dom_types.d.ts deleted file mode 100644 index b8636b7d1..000000000 --- a/cli/js/web/dom_types.d.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/web/dom_util.ts b/cli/js/web/dom_util.ts deleted file mode 100644 index 4b9ce3f50..000000000 --- a/cli/js/web/dom_util.ts +++ /dev/null @@ -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; -} diff --git a/cli/js/web/error_event.ts b/cli/js/web/error_event.ts deleted file mode 100644 index c04a49545..000000000 --- a/cli/js/web/error_event.ts +++ /dev/null @@ -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", -]); diff --git a/cli/js/web/event.ts b/cli/js/web/event.ts deleted file mode 100644 index d22d41c29..000000000 --- a/cli/js/web/event.ts +++ /dev/null @@ -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", -]); diff --git a/cli/js/web/event_target.ts b/cli/js/web/event_target.ts deleted file mode 100644 index 82935dd9c..000000000 --- a/cli/js/web/event_target.ts +++ /dev/null @@ -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", -]); diff --git a/cli/js/web/fetch.ts b/cli/js/web/fetch.ts deleted file mode 100644 index 4fe525cde..000000000 --- a/cli/js/web/fetch.ts +++ /dev/null @@ -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); -} diff --git a/cli/js/web/fetch/multipart.ts b/cli/js/web/fetch/multipart.ts deleted file mode 100644 index f30975e5e..000000000 --- a/cli/js/web/fetch/multipart.ts +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { Buffer } from "../../buffer.ts"; -import { bytesSymbol } from "../blob.ts"; -import { DomFileImpl } from "../dom_file.ts"; -import { DenoBlob } from "../blob.ts"; -import { TextEncoder, TextDecoder } from "../text_encoding.ts"; -import { getHeaderValueParams } from "../util.ts"; - -const decoder = new TextDecoder(); -const encoder = new TextEncoder(); -const CR = "\r".charCodeAt(0); -const LF = "\n".charCodeAt(0); - -interface MultipartHeaders { - headers: Headers; - disposition: Map<string, string>; -} - -export class MultipartBuilder { - readonly boundary: string; - readonly writer = new Buffer(); - constructor(readonly formData: FormData, boundary?: string) { - this.boundary = boundary ?? this.#createBoundary(); - } - - getContentType(): string { - return `multipart/form-data; boundary=${this.boundary}`; - } - - getBody(): Uint8Array { - for (const [fieldName, fieldValue] of this.formData.entries()) { - if (fieldValue instanceof DomFileImpl) { - this.#writeFile(fieldName, fieldValue); - } else this.#writeField(fieldName, fieldValue as string); - } - - this.writer.writeSync(encoder.encode(`\r\n--${this.boundary}--`)); - - return this.writer.bytes(); - } - - #createBoundary = (): string => { - return ( - "----------" + - Array.from(Array(32)) - .map(() => Math.random().toString(36)[2] || 0) - .join("") - ); - }; - - #writeHeaders = (headers: string[][]): void => { - let buf = this.writer.empty() ? "" : "\r\n"; - - buf += `--${this.boundary}\r\n`; - for (const [key, value] of headers) { - buf += `${key}: ${value}\r\n`; - } - buf += `\r\n`; - - this.writer.write(encoder.encode(buf)); - }; - - #writeFileHeaders = ( - field: string, - filename: string, - type?: string, - ): void => { - const headers = [ - [ - "Content-Disposition", - `form-data; name="${field}"; filename="${filename}"`, - ], - ["Content-Type", type || "application/octet-stream"], - ]; - return this.#writeHeaders(headers); - }; - - #writeFieldHeaders = (field: string): void => { - const headers = [["Content-Disposition", `form-data; name="${field}"`]]; - return this.#writeHeaders(headers); - }; - - #writeField = (field: string, value: string): void => { - this.#writeFieldHeaders(field); - this.writer.writeSync(encoder.encode(value)); - }; - - #writeFile = (field: string, value: DomFileImpl): void => { - this.#writeFileHeaders(field, value.name, value.type); - this.writer.writeSync(value[bytesSymbol]); - }; -} - -export class MultipartParser { - readonly boundary: string; - readonly boundaryChars: Uint8Array; - readonly body: Uint8Array; - constructor(body: Uint8Array, boundary: string) { - if (!boundary) { - throw new TypeError("multipart/form-data must provide a boundary"); - } - - this.boundary = `--${boundary}`; - this.body = body; - this.boundaryChars = encoder.encode(this.boundary); - } - - #parseHeaders = (headersText: string): MultipartHeaders => { - const headers = new Headers(); - const rawHeaders = headersText.split("\r\n"); - for (const rawHeader of rawHeaders) { - const sepIndex = rawHeader.indexOf(":"); - if (sepIndex < 0) { - continue; // Skip this header - } - const key = rawHeader.slice(0, sepIndex); - const value = rawHeader.slice(sepIndex + 1); - headers.set(key, value); - } - - return { - headers, - disposition: getHeaderValueParams( - headers.get("Content-Disposition") ?? "", - ), - }; - }; - - parse(): FormData { - const formData = new FormData(); - let headerText = ""; - let boundaryIndex = 0; - let state = 0; - let fileStart = 0; - - for (let i = 0; i < this.body.length; i++) { - const byte = this.body[i]; - const prevByte = this.body[i - 1]; - const isNewLine = byte === LF && prevByte === CR; - - if (state === 1 || state === 2 || state == 3) { - headerText += String.fromCharCode(byte); - } - if (state === 0 && isNewLine) { - state = 1; - } else if (state === 1 && isNewLine) { - state = 2; - const headersDone = this.body[i + 1] === CR && this.body[i + 2] === LF; - - if (headersDone) { - state = 3; - } - } else if (state === 2 && isNewLine) { - state = 3; - } else if (state === 3 && isNewLine) { - state = 4; - fileStart = i + 1; - } else if (state === 4) { - if (this.boundaryChars[boundaryIndex] !== byte) { - boundaryIndex = 0; - } else { - boundaryIndex++; - } - - if (boundaryIndex >= this.boundary.length) { - const { headers, disposition } = this.#parseHeaders(headerText); - const content = this.body.subarray(fileStart, i - boundaryIndex - 1); - // https://fetch.spec.whatwg.org/#ref-for-dom-body-formdata - const filename = disposition.get("filename"); - const name = disposition.get("name"); - - state = 5; - // Reset - boundaryIndex = 0; - headerText = ""; - - if (!name) { - continue; // Skip, unknown name - } - - if (filename) { - const blob = new DenoBlob([content], { - type: headers.get("Content-Type") || "application/octet-stream", - }); - formData.append(name, blob, filename); - } else { - formData.append(name, decoder.decode(content)); - } - } - } else if (state === 5 && isNewLine) { - state = 1; - } - } - - return formData; - } -} diff --git a/cli/js/web/form_data.ts b/cli/js/web/form_data.ts deleted file mode 100644 index 1a0622638..000000000 --- a/cli/js/web/form_data.ts +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import * as blob from "./blob.ts"; -import * as domFile from "./dom_file.ts"; -import { DomIterableMixin } from "./dom_iterable.ts"; -import { requiredArguments } from "./util.ts"; - -const dataSymbol = Symbol("data"); - -class FormDataBase { - [dataSymbol]: Array<[string, FormDataEntryValue]> = []; - - append(name: string, value: string): void; - append(name: string, value: domFile.DomFileImpl): void; - append(name: string, value: blob.DenoBlob, filename?: string): void; - append( - name: string, - value: string | blob.DenoBlob | domFile.DomFileImpl, - filename?: string, - ): void { - requiredArguments("FormData.append", arguments.length, 2); - name = String(name); - if (value instanceof domFile.DomFileImpl) { - this[dataSymbol].push([name, value]); - } else if (value instanceof blob.DenoBlob) { - const dfile = new domFile.DomFileImpl([value], filename || "blob", { - type: value.type, - }); - this[dataSymbol].push([name, dfile]); - } else { - this[dataSymbol].push([name, String(value)]); - } - } - - delete(name: string): void { - requiredArguments("FormData.delete", arguments.length, 1); - name = String(name); - let i = 0; - while (i < this[dataSymbol].length) { - if (this[dataSymbol][i][0] === name) { - this[dataSymbol].splice(i, 1); - } else { - i++; - } - } - } - - getAll(name: string): FormDataEntryValue[] { - requiredArguments("FormData.getAll", arguments.length, 1); - name = String(name); - const values = []; - for (const entry of this[dataSymbol]) { - if (entry[0] === name) { - values.push(entry[1]); - } - } - - return values; - } - - get(name: string): FormDataEntryValue | null { - requiredArguments("FormData.get", arguments.length, 1); - name = String(name); - for (const entry of this[dataSymbol]) { - if (entry[0] === name) { - return entry[1]; - } - } - - return null; - } - - has(name: string): boolean { - requiredArguments("FormData.has", arguments.length, 1); - name = String(name); - return this[dataSymbol].some((entry): boolean => entry[0] === name); - } - - set(name: string, value: string): void; - set(name: string, value: domFile.DomFileImpl): void; - set(name: string, value: blob.DenoBlob, filename?: string): void; - set( - name: string, - value: string | blob.DenoBlob | domFile.DomFileImpl, - filename?: string, - ): void { - requiredArguments("FormData.set", arguments.length, 2); - name = String(name); - - // If there are any entries in the context object’s entry list whose name - // is name, replace the first such entry with entry and remove the others - let found = false; - let i = 0; - while (i < this[dataSymbol].length) { - if (this[dataSymbol][i][0] === name) { - if (!found) { - if (value instanceof domFile.DomFileImpl) { - this[dataSymbol][i][1] = value; - } else if (value instanceof blob.DenoBlob) { - this[dataSymbol][i][1] = new domFile.DomFileImpl( - [value], - filename || "blob", - { - type: value.type, - }, - ); - } else { - this[dataSymbol][i][1] = String(value); - } - found = true; - } else { - this[dataSymbol].splice(i, 1); - continue; - } - } - i++; - } - - // Otherwise, append entry to the context object’s entry list. - if (!found) { - if (value instanceof domFile.DomFileImpl) { - this[dataSymbol].push([name, value]); - } else if (value instanceof blob.DenoBlob) { - const dfile = new domFile.DomFileImpl([value], filename || "blob", { - type: value.type, - }); - this[dataSymbol].push([name, dfile]); - } else { - this[dataSymbol].push([name, String(value)]); - } - } - } - - get [Symbol.toStringTag](): string { - return "FormData"; - } -} - -export class FormDataImpl extends DomIterableMixin< - string, - FormDataEntryValue, - typeof FormDataBase ->(FormDataBase, dataSymbol) {} - -Object.defineProperty(FormDataImpl, "name", { - value: "FormData", - configurable: true, -}); diff --git a/cli/js/web/headers.ts b/cli/js/web/headers.ts deleted file mode 100644 index d75f87adc..000000000 --- a/cli/js/web/headers.ts +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { DomIterableMixin } from "./dom_iterable.ts"; -import { requiredArguments } from "./util.ts"; -import { customInspect } from "./console.ts"; - -// From node-fetch -// Copyright (c) 2016 David Frank. MIT License. -const invalidTokenRegex = /[^\^_`a-zA-Z\-0-9!#$%&'*+.|~]/; -const invalidHeaderCharRegex = /[^\t\x20-\x7e\x80-\xff]/; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isHeaders(value: any): value is Headers { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - return value instanceof Headers; -} - -const headersData = Symbol("headers data"); - -// TODO: headerGuard? Investigate if it is needed -// node-fetch did not implement this but it is in the spec -function normalizeParams(name: string, value?: string): string[] { - name = String(name).toLowerCase(); - value = String(value).trim(); - return [name, value]; -} - -// The following name/value validations are copied from -// https://github.com/bitinn/node-fetch/blob/master/src/headers.js -// Copyright (c) 2016 David Frank. MIT License. -function validateName(name: string): void { - if (invalidTokenRegex.test(name) || name === "") { - throw new TypeError(`${name} is not a legal HTTP header name`); - } -} - -function validateValue(value: string): void { - if (invalidHeaderCharRegex.test(value)) { - throw new TypeError(`${value} is not a legal HTTP header value`); - } -} - -/** Appends a key and value to the header list. - * - * The spec indicates that when a key already exists, the append adds the new - * value onto the end of the existing value. The behaviour of this though - * varies when the key is `set-cookie`. In this case, if the key of the cookie - * already exists, the value is replaced, but if the key of the cookie does not - * exist, and additional `set-cookie` header is added. - * - * The browser specification of `Headers` is written for clients, and not - * servers, and Deno is a server, meaning that it needs to follow the patterns - * expected for servers, of which a `set-cookie` header is expected for each - * unique cookie key, but duplicate cookie keys should not exist. */ -function dataAppend( - data: Array<[string, string]>, - key: string, - value: string, -): void { - for (let i = 0; i < data.length; i++) { - const [dataKey] = data[i]; - if (key === "set-cookie" && dataKey === "set-cookie") { - const [, dataValue] = data[i]; - const [dataCookieKey] = dataValue.split("="); - const [cookieKey] = value.split("="); - if (dataCookieKey === cookieKey) { - data[i][1] = value; - return; - } - } else { - if (dataKey === key) { - data[i][1] += `, ${value}`; - return; - } - } - } - data.push([key, value]); -} - -/** Gets a value of a key in the headers list. - * - * This varies slightly from spec behaviour in that when the key is `set-cookie` - * the value returned will look like a concatenated value, when in fact, if the - * headers were iterated over, each individual `set-cookie` value is a unique - * entry in the headers list. */ -function dataGet( - data: Array<[string, string]>, - key: string, -): string | undefined { - const setCookieValues = []; - for (const [dataKey, value] of data) { - if (dataKey === key) { - if (key === "set-cookie") { - setCookieValues.push(value); - } else { - return value; - } - } - } - if (setCookieValues.length) { - return setCookieValues.join(", "); - } - return undefined; -} - -/** Sets a value of a key in the headers list. - * - * The spec indicates that the value should be replaced if the key already - * exists. The behaviour here varies, where if the key is `set-cookie` the key - * of the cookie is inspected, and if the key of the cookie already exists, - * then the value is replaced. If the key of the cookie is not found, then - * the value of the `set-cookie` is added to the list of headers. - * - * The browser specification of `Headers` is written for clients, and not - * servers, and Deno is a server, meaning that it needs to follow the patterns - * expected for servers, of which a `set-cookie` header is expected for each - * unique cookie key, but duplicate cookie keys should not exist. */ -function dataSet( - data: Array<[string, string]>, - key: string, - value: string, -): void { - for (let i = 0; i < data.length; i++) { - const [dataKey] = data[i]; - if (dataKey === key) { - // there could be multiple set-cookie headers, but all others are unique - if (key === "set-cookie") { - const [, dataValue] = data[i]; - const [dataCookieKey] = dataValue.split("="); - const [cookieKey] = value.split("="); - if (cookieKey === dataCookieKey) { - data[i][1] = value; - return; - } - } else { - data[i][1] = value; - return; - } - } - } - data.push([key, value]); -} - -function dataDelete(data: Array<[string, string]>, key: string): void { - let i = 0; - while (i < data.length) { - const [dataKey] = data[i]; - if (dataKey === key) { - data.splice(i, 1); - } else { - i++; - } - } -} - -function dataHas(data: Array<[string, string]>, key: string): boolean { - for (const [dataKey] of data) { - if (dataKey === key) { - return true; - } - } - return false; -} - -// ref: https://fetch.spec.whatwg.org/#dom-headers -class HeadersBase { - [headersData]: Array<[string, string]>; - - constructor(init?: HeadersInit) { - if (init === null) { - throw new TypeError( - "Failed to construct 'Headers'; The provided value was not valid", - ); - } else if (isHeaders(init)) { - this[headersData] = [...init]; - } else { - this[headersData] = []; - if (Array.isArray(init)) { - for (const tuple of init) { - // If header does not contain exactly two items, - // then throw a TypeError. - // ref: https://fetch.spec.whatwg.org/#concept-headers-fill - requiredArguments( - "Headers.constructor tuple array argument", - tuple.length, - 2, - ); - - this.append(tuple[0], tuple[1]); - } - } else if (init) { - for (const [rawName, rawValue] of Object.entries(init)) { - this.append(rawName, rawValue); - } - } - } - } - - [customInspect](): string { - let length = this[headersData].length; - let output = ""; - for (const [key, value] of this[headersData]) { - const prefix = length === this[headersData].length ? " " : ""; - const postfix = length === 1 ? " " : ", "; - output = output + `${prefix}${key}: ${value}${postfix}`; - length--; - } - return `Headers {${output}}`; - } - - // ref: https://fetch.spec.whatwg.org/#concept-headers-append - append(name: string, value: string): void { - requiredArguments("Headers.append", arguments.length, 2); - const [newname, newvalue] = normalizeParams(name, value); - validateName(newname); - validateValue(newvalue); - dataAppend(this[headersData], newname, newvalue); - } - - delete(name: string): void { - requiredArguments("Headers.delete", arguments.length, 1); - const [newname] = normalizeParams(name); - validateName(newname); - dataDelete(this[headersData], newname); - } - - get(name: string): string | null { - requiredArguments("Headers.get", arguments.length, 1); - const [newname] = normalizeParams(name); - validateName(newname); - return dataGet(this[headersData], newname) ?? null; - } - - has(name: string): boolean { - requiredArguments("Headers.has", arguments.length, 1); - const [newname] = normalizeParams(name); - validateName(newname); - return dataHas(this[headersData], newname); - } - - set(name: string, value: string): void { - requiredArguments("Headers.set", arguments.length, 2); - const [newname, newvalue] = normalizeParams(name, value); - validateName(newname); - validateValue(newvalue); - dataSet(this[headersData], newname, newvalue); - } - - get [Symbol.toStringTag](): string { - return "Headers"; - } -} - -// @internal -export class HeadersImpl extends DomIterableMixin< - string, - string, - typeof HeadersBase ->(HeadersBase, headersData) {} - -Object.defineProperty(HeadersImpl, "name", { - value: "Headers", - configurable: true, -}); diff --git a/cli/js/web/performance.ts b/cli/js/web/performance.ts deleted file mode 100644 index 1acff9f75..000000000 --- a/cli/js/web/performance.ts +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { now as opNow } from "../ops/timers.ts"; -import { customInspect, inspect } from "./console.ts"; -import { cloneValue, setFunctionName } from "./util.ts"; - -let performanceEntries: PerformanceEntryList = []; - -function findMostRecent( - name: string, - type: "mark" | "measure", -): PerformanceEntry | undefined { - return performanceEntries - .slice() - .reverse() - .find((entry) => entry.name === name && entry.entryType === type); -} - -function convertMarkToTimestamp(mark: string | number): number { - if (typeof mark === "string") { - const entry = findMostRecent(mark, "mark"); - if (!entry) { - throw new SyntaxError(`Cannot find mark: "${mark}".`); - } - return entry.startTime; - } - if (mark < 0) { - throw new TypeError("Mark cannot be negative."); - } - return mark; -} - -function filterByNameType( - name?: string, - type?: "mark" | "measure", -): PerformanceEntryList { - return performanceEntries.filter( - (entry) => - (name ? entry.name === name : true) && - (type ? entry.entryType === type : true), - ); -} - -function now(): number { - const res = opNow(); - return res.seconds * 1e3 + res.subsecNanos / 1e6; -} - -export class PerformanceEntryImpl implements PerformanceEntry { - #name: string; - #entryType: string; - #startTime: number; - #duration: number; - - get name(): string { - return this.#name; - } - - get entryType(): string { - return this.#entryType; - } - - get startTime(): number { - return this.#startTime; - } - - get duration(): number { - return this.#duration; - } - - constructor( - name: string, - entryType: string, - startTime: number, - duration: number, - ) { - this.#name = name; - this.#entryType = entryType; - this.#startTime = startTime; - this.#duration = duration; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - toJSON(): any { - return { - name: this.#name, - entryType: this.#entryType, - startTime: this.#startTime, - duration: this.#duration, - }; - } - - [customInspect](): string { - return `${this.constructor.name} { name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`; - } -} - -export class PerformanceMarkImpl extends PerformanceEntryImpl - implements PerformanceMark { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - #detail: any; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get detail(): any { - return this.#detail; - } - - get entryType(): "mark" { - return "mark"; - } - - constructor( - name: string, - { detail = null, startTime = now() }: PerformanceMarkOptions = {}, - ) { - super(name, "mark", startTime, 0); - if (startTime < 0) { - throw new TypeError("startTime cannot be negative"); - } - this.#detail = cloneValue(detail); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - toJSON(): any { - return { - name: this.name, - entryType: this.entryType, - startTime: this.startTime, - duration: this.duration, - detail: this.detail, - }; - } - - [customInspect](): string { - return this.detail - ? `${this.constructor.name} {\n detail: ${ - inspect(this.detail, { depth: 3 }) - },\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}` - : `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`; - } -} - -export class PerformanceMeasureImpl extends PerformanceEntryImpl - implements PerformanceMeasure { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - #detail: any; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get detail(): any { - return this.#detail; - } - - get entryType(): "measure" { - return "measure"; - } - - constructor( - name: string, - startTime: number, - duration: number, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - detail: any = null, - ) { - super(name, "measure", startTime, duration); - this.#detail = cloneValue(detail); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - toJSON(): any { - return { - name: this.name, - entryType: this.entryType, - startTime: this.startTime, - duration: this.duration, - detail: this.detail, - }; - } - - [customInspect](): string { - return this.detail - ? `${this.constructor.name} {\n detail: ${ - inspect(this.detail, { depth: 3 }) - },\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}` - : `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`; - } -} - -export class PerformanceImpl implements Performance { - clearMarks(markName?: string): void { - if (markName == null) { - performanceEntries = performanceEntries.filter( - (entry) => entry.entryType !== "mark", - ); - } else { - performanceEntries = performanceEntries.filter( - (entry) => !(entry.name === markName && entry.entryType === "mark"), - ); - } - } - - clearMeasures(measureName?: string): void { - if (measureName == null) { - performanceEntries = performanceEntries.filter( - (entry) => entry.entryType !== "measure", - ); - } else { - performanceEntries = performanceEntries.filter( - (entry) => - !(entry.name === measureName && entry.entryType === "measure"), - ); - } - } - - getEntries(): PerformanceEntryList { - return filterByNameType(); - } - getEntriesByName( - name: string, - type?: "mark" | "measure", - ): PerformanceEntryList { - return filterByNameType(name, type); - } - getEntriesByType(type: "mark" | "measure"): PerformanceEntryList { - return filterByNameType(undefined, type); - } - - mark( - markName: string, - options: PerformanceMarkOptions = {}, - ): PerformanceMark { - // 3.1.1.1 If the global object is a Window object and markName uses the - // same name as a read only attribute in the PerformanceTiming interface, - // throw a SyntaxError. - not implemented - const entry = new PerformanceMarkImpl(markName, options); - // 3.1.1.7 Queue entry - not implemented - performanceEntries.push(entry); - return entry; - } - - measure( - measureName: string, - options?: PerformanceMeasureOptions, - ): PerformanceMeasure; - measure( - measureName: string, - startMark?: string, - endMark?: string, - ): PerformanceMeasure; - measure( - measureName: string, - startOrMeasureOptions: string | PerformanceMeasureOptions = {}, - endMark?: string, - ): PerformanceMeasure { - if (startOrMeasureOptions && typeof startOrMeasureOptions === "object") { - if (endMark) { - throw new TypeError("Options cannot be passed with endMark."); - } - if ( - !("start" in startOrMeasureOptions) && - !("end" in startOrMeasureOptions) - ) { - throw new TypeError("A start or end mark must be supplied in options."); - } - if ( - "start" in startOrMeasureOptions && - "duration" in startOrMeasureOptions && - "end" in startOrMeasureOptions - ) { - throw new TypeError( - "Cannot specify start, end, and duration together in options.", - ); - } - } - let endTime: number; - if (endMark) { - endTime = convertMarkToTimestamp(endMark); - } else if ( - typeof startOrMeasureOptions === "object" && - "end" in startOrMeasureOptions - ) { - endTime = convertMarkToTimestamp(startOrMeasureOptions.end!); - } else if ( - typeof startOrMeasureOptions === "object" && - "start" in startOrMeasureOptions && - "duration" in startOrMeasureOptions - ) { - const start = convertMarkToTimestamp(startOrMeasureOptions.start!); - const duration = convertMarkToTimestamp(startOrMeasureOptions.duration!); - endTime = start + duration; - } else { - endTime = now(); - } - let startTime: number; - if ( - typeof startOrMeasureOptions === "object" && - "start" in startOrMeasureOptions - ) { - startTime = convertMarkToTimestamp(startOrMeasureOptions.start!); - } else if ( - typeof startOrMeasureOptions === "object" && - "end" in startOrMeasureOptions && - "duration" in startOrMeasureOptions - ) { - const end = convertMarkToTimestamp(startOrMeasureOptions.end!); - const duration = convertMarkToTimestamp(startOrMeasureOptions.duration!); - startTime = end - duration; - } else if (typeof startOrMeasureOptions === "string") { - startTime = convertMarkToTimestamp(startOrMeasureOptions); - } else { - startTime = 0; - } - const entry = new PerformanceMeasureImpl( - measureName, - startTime, - endTime - startTime, - typeof startOrMeasureOptions === "object" - ? startOrMeasureOptions.detail ?? null - : null, - ); - performanceEntries.push(entry); - return entry; - } - - now(): number { - return now(); - } -} - -setFunctionName(PerformanceEntryImpl, "PerformanceEntry"); -setFunctionName(PerformanceMarkImpl, "PerformanceMark"); -setFunctionName(PerformanceMeasureImpl, "PerformanceMeasure"); -setFunctionName(PerformanceImpl, "Performance"); diff --git a/cli/js/web/promise.ts b/cli/js/web/promise.ts deleted file mode 100644 index a24e8ed51..000000000 --- a/cli/js/web/promise.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -export enum PromiseState { - Pending, - Fulfilled, - Rejected, -} - -export type PromiseDetails<T> = [PromiseState, T | undefined]; diff --git a/cli/js/web/request.ts b/cli/js/web/request.ts deleted file mode 100644 index f65b6a363..000000000 --- a/cli/js/web/request.ts +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import * as body from "./body.ts"; -import type * as domTypes from "./dom_types.d.ts"; -import { ReadableStreamImpl } from "./streams/readable_stream.ts"; - -function byteUpperCase(s: string): string { - return String(s).replace(/[a-z]/g, function byteUpperCaseReplace(c): string { - return c.toUpperCase(); - }); -} - -function normalizeMethod(m: string): string { - const u = byteUpperCase(m); - if ( - u === "DELETE" || - u === "GET" || - u === "HEAD" || - u === "OPTIONS" || - u === "POST" || - u === "PUT" - ) { - return u; - } - return m; -} - -export class Request extends body.Body implements domTypes.Request { - public method: string; - public url: string; - public credentials?: "omit" | "same-origin" | "include"; - public headers: Headers; - - constructor(input: domTypes.RequestInfo, init?: domTypes.RequestInit) { - if (arguments.length < 1) { - throw TypeError("Not enough arguments"); - } - - if (!init) { - init = {}; - } - - let b: BodyInit; - - // prefer body from init - if (init.body) { - b = init.body; - } else if (input instanceof Request && input._bodySource) { - if (input.bodyUsed) { - throw TypeError(body.BodyUsedError); - } - b = input._bodySource; - } else if (typeof input === "object" && "body" in input && input.body) { - if (input.bodyUsed) { - throw TypeError(body.BodyUsedError); - } - b = input.body; - } else { - b = ""; - } - - let headers: Headers; - - // prefer headers from init - if (init.headers) { - headers = new Headers(init.headers); - } else if (input instanceof Request) { - headers = input.headers; - } else { - headers = new Headers(); - } - - const contentType = headers.get("content-type") || ""; - super(b, { contentType }); - this.headers = headers; - - // readonly attribute ByteString method; - this.method = "GET"; - - // readonly attribute USVString url; - this.url = ""; - - // readonly attribute RequestCredentials credentials; - this.credentials = "omit"; - - if (input instanceof Request) { - if (input.bodyUsed) { - throw TypeError(body.BodyUsedError); - } - this.method = input.method; - this.url = input.url; - this.headers = new Headers(input.headers); - this.credentials = input.credentials; - this._stream = input._stream; - } else if (typeof input === "string") { - this.url = input; - } - - if (init && "method" in init) { - this.method = normalizeMethod(init.method as string); - } - - if ( - init && - "credentials" in init && - init.credentials && - ["omit", "same-origin", "include"].indexOf(init.credentials) !== -1 - ) { - this.credentials = init.credentials; - } - } - - public clone(): domTypes.Request { - 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 body2 = this._bodySource; - - if (this._bodySource instanceof ReadableStreamImpl) { - const tees = this._bodySource.tee(); - this._stream = this._bodySource = tees[0]; - body2 = tees[1]; - } - - return new Request(this.url, { - body: body2, - method: this.method, - headers: new Headers(headersList), - credentials: this.credentials, - }); - } -} diff --git a/cli/js/web/streams/internals.ts b/cli/js/web/streams/internals.ts deleted file mode 100644 index 06c5e304d..000000000 --- a/cli/js/web/streams/internals.ts +++ /dev/null @@ -1,2405 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// This code closely follows the WHATWG Stream Specification -// See: https://streams.spec.whatwg.org/ -// -// There are some parts that are not fully implemented, and there are some -// comments which point to steps of the specification that are not implemented. - -/* eslint-disable @typescript-eslint/no-explicit-any,require-await */ -import { ReadableByteStreamControllerImpl } from "./readable_byte_stream_controller.ts"; -import { ReadableStreamDefaultControllerImpl } from "./readable_stream_default_controller.ts"; -import { ReadableStreamDefaultReaderImpl } from "./readable_stream_default_reader.ts"; -import { ReadableStreamImpl } from "./readable_stream.ts"; -import * as sym from "./symbols.ts"; -import type { TransformStreamImpl } from "./transform_stream.ts"; -import { TransformStreamDefaultControllerImpl } from "./transform_stream_default_controller.ts"; -import { WritableStreamDefaultControllerImpl } from "./writable_stream_default_controller.ts"; -import { WritableStreamDefaultWriterImpl } from "./writable_stream_default_writer.ts"; -import { WritableStreamImpl } from "./writable_stream.ts"; -import { AbortSignalImpl } from "../abort_signal.ts"; -import { DOMExceptionImpl as DOMException } from "../dom_exception.ts"; -import { cloneValue, setFunctionName } from "../util.ts"; -import { assert, AssertionError } from "../../util.ts"; - -export type AbortAlgorithm = (reason?: any) => PromiseLike<void>; -export interface AbortRequest { - promise: Deferred<void>; - reason?: any; - wasAlreadyErroring: boolean; -} -export interface BufferQueueItem extends Pair<ArrayBuffer | SharedArrayBuffer> { - offset: number; -} -export type CancelAlgorithm = (reason?: any) => PromiseLike<void>; -export type CloseAlgorithm = () => PromiseLike<void>; -type Container<R = any> = { - [sym.queue]: Array<Pair<R> | BufferQueueItem>; - [sym.queueTotalSize]: number; -}; -export type FlushAlgorithm = () => Promise<void>; -export type Pair<R> = { value: R; size: number }; -export type PullAlgorithm = () => PromiseLike<void>; -export type SizeAlgorithm<T> = (chunk: T) => number; -export type StartAlgorithm = () => void | PromiseLike<void>; -export type TransformAlgorithm<I> = (chunk: I) => Promise<void>; -export type WriteAlgorithm<W> = (chunk: W) => Promise<void>; -export interface Deferred<T> { - promise: Promise<T>; - resolve?: (value?: T | PromiseLike<T>) => void; - reject?: (reason?: any) => void; -} - -export interface ReadableStreamGenericReader<R = any> - extends ReadableStreamReader<R> { - [sym.closedPromise]: Deferred<void>; - [sym.forAuthorCode]: boolean; - [sym.ownerReadableStream]: ReadableStreamImpl<R>; - [sym.readRequests]: Array<Deferred<ReadableStreamReadResult<R>>>; -} - -export interface ReadableStreamAsyncIterator<T = any> extends AsyncIterator<T> { - [sym.asyncIteratorReader]: ReadableStreamDefaultReaderImpl<T>; - [sym.preventCancel]: boolean; - return(value?: any | PromiseLike<any>): Promise<IteratorResult<T>>; -} - -export function acquireReadableStreamDefaultReader<T>( - stream: ReadableStreamImpl<T>, - forAuthorCode = false, -): ReadableStreamDefaultReaderImpl<T> { - const reader = new ReadableStreamDefaultReaderImpl(stream); - reader[sym.forAuthorCode] = forAuthorCode; - return reader; -} - -export function acquireWritableStreamDefaultWriter<W>( - stream: WritableStreamImpl<W>, -): WritableStreamDefaultWriterImpl<W> { - return new WritableStreamDefaultWriterImpl(stream); -} - -export function call<F extends (...args: any[]) => any>( - fn: F, - v: ThisType<F>, - args: Parameters<F>, -): ReturnType<F> { - return Function.prototype.apply.call(fn, v, args); -} - -function createAlgorithmFromUnderlyingMethod< - O extends UnderlyingByteSource | UnderlyingSource | Transformer, - P extends keyof O, ->( - underlyingObject: O, - methodName: P, - algoArgCount: 0, - ...extraArgs: any[] -): () => Promise<void>; - -function createAlgorithmFromUnderlyingMethod< - O extends UnderlyingByteSource | UnderlyingSource | Transformer, - P extends keyof O, ->( - underlyingObject: O, - methodName: P, - algoArgCount: 1, - ...extraArgs: any[] -): (arg: any) => Promise<void>; -function createAlgorithmFromUnderlyingMethod< - O extends UnderlyingByteSource | UnderlyingSource | Transformer, - P extends keyof O, ->( - underlyingObject: O, - methodName: P, - algoArgCount: 0 | 1, - ...extraArgs: any[] -): (() => Promise<void>) | ((arg: any) => Promise<void>) { - const method = underlyingObject[methodName]; - if (method) { - if (!isCallable(method)) { - throw new TypeError("method is not callable"); - } - if (algoArgCount === 0) { - return async (): Promise<void> => - call(method, underlyingObject, extraArgs as any); - } else { - return async (arg: any): Promise<void> => { - const fullArgs = [arg, ...extraArgs]; - return call(method, underlyingObject, fullArgs as any); - }; - } - } - return async (): Promise<void> => undefined; -} - -function createReadableStream<T>( - startAlgorithm: StartAlgorithm, - pullAlgorithm: PullAlgorithm, - cancelAlgorithm: CancelAlgorithm, - highWaterMark = 1, - sizeAlgorithm: SizeAlgorithm<T> = (): number => 1, -): ReadableStreamImpl<T> { - highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark); - const stream: ReadableStreamImpl<T> = Object.create( - ReadableStreamImpl.prototype, - ); - initializeReadableStream(stream); - const controller: ReadableStreamDefaultControllerImpl<T> = Object.create( - ReadableStreamDefaultControllerImpl.prototype, - ); - setUpReadableStreamDefaultController( - stream, - controller, - startAlgorithm, - pullAlgorithm, - cancelAlgorithm, - highWaterMark, - sizeAlgorithm, - ); - return stream; -} - -function createWritableStream<W>( - startAlgorithm: StartAlgorithm, - writeAlgorithm: WriteAlgorithm<W>, - closeAlgorithm: CloseAlgorithm, - abortAlgorithm: AbortAlgorithm, - highWaterMark = 1, - sizeAlgorithm: SizeAlgorithm<W> = (): number => 1, -): WritableStreamImpl<W> { - highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark); - const stream = Object.create(WritableStreamImpl.prototype); - initializeWritableStream(stream); - const controller = Object.create( - WritableStreamDefaultControllerImpl.prototype, - ); - setUpWritableStreamDefaultController( - stream, - controller, - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - highWaterMark, - sizeAlgorithm, - ); - return stream; -} - -export function dequeueValue<R>(container: Container<R>): R { - assert(sym.queue in container && sym.queueTotalSize in container); - assert(container[sym.queue].length); - const pair = container[sym.queue].shift()!; - container[sym.queueTotalSize] -= pair.size; - if (container[sym.queueTotalSize] <= 0) { - container[sym.queueTotalSize] = 0; - } - return pair.value as R; -} - -function enqueueValueWithSize<R>( - container: Container<R>, - value: R, - size: number, -): void { - assert(sym.queue in container && sym.queueTotalSize in container); - size = Number(size); - if (!isFiniteNonNegativeNumber(size)) { - throw new RangeError("size must be a finite non-negative number."); - } - container[sym.queue].push({ value, size }); - container[sym.queueTotalSize] += size; -} - -/** Non-spec mechanism to "unwrap" a promise and store it to be resolved - * later. */ -export function getDeferred<T>(): Required<Deferred<T>> { - let resolve: (value?: T | PromiseLike<T>) => void; - let reject: (reason?: any) => void; - const promise = new Promise<T>((res, rej) => { - resolve = res; - reject = rej; - }); - return { promise, resolve: resolve!, reject: reject! }; -} - -export function initializeReadableStream<R>( - stream: ReadableStreamImpl<R>, -): void { - stream[sym.state] = "readable"; - stream[sym.reader] = stream[sym.storedError] = undefined; - stream[sym.disturbed] = false; -} - -export function initializeTransformStream<I, O>( - stream: TransformStreamImpl<I, O>, - startPromise: Promise<void>, - writableHighWaterMark: number, - writableSizeAlgorithm: SizeAlgorithm<I>, - readableHighWaterMark: number, - readableSizeAlgorithm: SizeAlgorithm<O>, -): void { - const startAlgorithm = (): Promise<void> => startPromise; - const writeAlgorithm = (chunk: any): Promise<void> => - transformStreamDefaultSinkWriteAlgorithm(stream, chunk); - const abortAlgorithm = (reason: any): Promise<void> => - transformStreamDefaultSinkAbortAlgorithm(stream, reason); - const closeAlgorithm = (): Promise<void> => - transformStreamDefaultSinkCloseAlgorithm(stream); - stream[sym.writable] = createWritableStream( - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - writableHighWaterMark, - writableSizeAlgorithm, - ); - const pullAlgorithm = (): PromiseLike<void> => - transformStreamDefaultSourcePullAlgorithm(stream); - const cancelAlgorithm = (reason: any): Promise<void> => { - transformStreamErrorWritableAndUnblockWrite(stream, reason); - return Promise.resolve(undefined); - }; - stream[sym.readable] = createReadableStream( - startAlgorithm, - pullAlgorithm, - cancelAlgorithm, - readableHighWaterMark, - readableSizeAlgorithm, - ); - stream[sym.backpressure] = stream[sym.backpressureChangePromise] = undefined; - transformStreamSetBackpressure(stream, true); - Object.defineProperty(stream, sym.transformStreamController, { - value: undefined, - configurable: true, - }); -} - -export function initializeWritableStream<W>( - stream: WritableStreamImpl<W>, -): void { - stream[sym.state] = "writable"; - stream[sym.storedError] = stream[sym.writer] = stream[ - sym.writableStreamController - ] = stream[sym.inFlightWriteRequest] = stream[sym.closeRequest] = stream[ - sym.inFlightCloseRequest - ] = stream[sym.pendingAbortRequest] = undefined; - stream[sym.writeRequests] = []; - stream[sym.backpressure] = false; -} - -export function invokeOrNoop<O extends Record<string, any>, P extends keyof O>( - o: O, - p: P, - ...args: Parameters<O[P]> -): ReturnType<O[P]> | undefined { - assert(o); - const method = o[p]; - if (!method) { - return undefined; - } - return call(method, o, args); -} - -function isCallable(value: unknown): value is (...args: any) => any { - return typeof value === "function"; -} - -export function isDetachedBuffer(value: object): boolean { - return sym.isFakeDetached in value; -} - -function isFiniteNonNegativeNumber(v: unknown): v is number { - return Number.isFinite(v) && (v as number) >= 0; -} - -export function isReadableByteStreamController( - x: unknown, -): x is ReadableByteStreamControllerImpl { - return !( - typeof x !== "object" || - x === null || - !(sym.controlledReadableByteStream in x) - ); -} - -export function isReadableStream(x: unknown): x is ReadableStreamImpl { - return !( - typeof x !== "object" || - x === null || - !(sym.readableStreamController in x) - ); -} - -export function isReadableStreamAsyncIterator( - x: unknown, -): x is ReadableStreamAsyncIterator { - if (typeof x !== "object" || x === null) { - return false; - } - return sym.asyncIteratorReader in x; -} - -export function isReadableStreamDefaultController( - x: unknown, -): x is ReadableStreamDefaultControllerImpl { - return !( - typeof x !== "object" || - x === null || - !(sym.controlledReadableStream in x) - ); -} - -export function isReadableStreamDefaultReader<T>( - x: unknown, -): x is ReadableStreamDefaultReaderImpl<T> { - return !(typeof x !== "object" || x === null || !(sym.readRequests in x)); -} - -export function isReadableStreamLocked(stream: ReadableStreamImpl): boolean { - assert(isReadableStream(stream)); - return !!stream[sym.reader]; -} - -export function isReadableStreamDisturbed(stream: ReadableStream): boolean { - assert(isReadableStream(stream)); - return !!stream[sym.disturbed]; -} - -export function isTransformStream(x: unknown): x is TransformStreamImpl { - return !( - typeof x !== "object" || - x === null || - !(sym.transformStreamController in x) - ); -} - -export function isTransformStreamDefaultController( - x: unknown, -): x is TransformStreamDefaultControllerImpl { - return !( - typeof x !== "object" || - x === null || - !(sym.controlledTransformStream in x) - ); -} - -export function isUnderlyingByteSource( - underlyingSource: UnderlyingByteSource | UnderlyingSource, -): underlyingSource is UnderlyingByteSource { - const { type } = underlyingSource; - const typeString = String(type); - return typeString === "bytes"; -} - -export function isWritableStream(x: unknown): x is WritableStreamImpl { - return !( - typeof x !== "object" || - x === null || - !(sym.writableStreamController in x) - ); -} - -export function isWritableStreamDefaultController( - x: unknown, -): x is WritableStreamDefaultControllerImpl<any> { - return !( - typeof x !== "object" || - x === null || - !(sym.controlledWritableStream in x) - ); -} - -export function isWritableStreamDefaultWriter( - x: unknown, -): x is WritableStreamDefaultWriterImpl<any> { - return !( - typeof x !== "object" || - x === null || - !(sym.ownerWritableStream in x) - ); -} - -export function isWritableStreamLocked(stream: WritableStreamImpl): boolean { - assert(isWritableStream(stream)); - return stream[sym.writer] !== undefined; -} - -export function makeSizeAlgorithmFromSizeFunction<T>( - size: QueuingStrategySizeCallback<T> | undefined, -): SizeAlgorithm<T> { - if (size === undefined) { - return (): number => 1; - } - if (typeof size !== "function") { - throw new TypeError("size must be callable."); - } - return (chunk: T): number => { - return size.call(undefined, chunk); - }; -} - -function peekQueueValue<T>(container: Container<T>): T | "close" { - assert(sym.queue in container && sym.queueTotalSize in container); - assert(container[sym.queue].length); - const [pair] = container[sym.queue]; - return pair.value as T; -} - -function readableByteStreamControllerShouldCallPull( - controller: ReadableByteStreamControllerImpl, -): boolean { - const stream = controller[sym.controlledReadableByteStream]; - if ( - stream[sym.state] !== "readable" || - controller[sym.closeRequested] || - !controller[sym.started] - ) { - return false; - } - if ( - readableStreamHasDefaultReader(stream) && - readableStreamGetNumReadRequests(stream) > 0 - ) { - return true; - } - // 3.13.25.6 If ! ReadableStreamHasBYOBReader(stream) is true and ! - // ReadableStreamGetNumReadIntoRequests(stream) > 0, return true. - const desiredSize = readableByteStreamControllerGetDesiredSize(controller); - assert(desiredSize !== null); - return desiredSize > 0; -} - -export function readableByteStreamControllerCallPullIfNeeded( - controller: ReadableByteStreamControllerImpl, -): void { - const shouldPull = readableByteStreamControllerShouldCallPull(controller); - if (!shouldPull) { - return; - } - if (controller[sym.pulling]) { - controller[sym.pullAgain] = true; - return; - } - assert(controller[sym.pullAgain] === false); - controller[sym.pulling] = true; - const pullPromise = controller[sym.pullAlgorithm](); - setPromiseIsHandledToTrue( - pullPromise.then( - () => { - controller[sym.pulling] = false; - if (controller[sym.pullAgain]) { - controller[sym.pullAgain] = false; - readableByteStreamControllerCallPullIfNeeded(controller); - } - }, - (e) => { - readableByteStreamControllerError(controller, e); - }, - ), - ); -} - -export function readableByteStreamControllerClearAlgorithms( - controller: ReadableByteStreamControllerImpl, -): void { - (controller as any)[sym.pullAlgorithm] = undefined; - (controller as any)[sym.cancelAlgorithm] = undefined; -} - -export function readableByteStreamControllerClose( - controller: ReadableByteStreamControllerImpl, -): void { - const stream = controller[sym.controlledReadableByteStream]; - if (controller[sym.closeRequested] || stream[sym.state] !== "readable") { - return; - } - if (controller[sym.queueTotalSize] > 0) { - controller[sym.closeRequested] = true; - return; - } - // 3.13.6.4 If controller.[[pendingPullIntos]] is not empty, (BYOB Support) - readableByteStreamControllerClearAlgorithms(controller); - readableStreamClose(stream); -} - -export function readableByteStreamControllerEnqueue( - controller: ReadableByteStreamControllerImpl, - chunk: ArrayBufferView, -): void { - const stream = controller[sym.controlledReadableByteStream]; - if (controller[sym.closeRequested] || stream[sym.state] !== "readable") { - return; - } - const { buffer, byteOffset, byteLength } = chunk; - const transferredBuffer = transferArrayBuffer(buffer); - if (readableStreamHasDefaultReader(stream)) { - if (readableStreamGetNumReadRequests(stream) === 0) { - readableByteStreamControllerEnqueueChunkToQueue( - controller, - transferredBuffer, - byteOffset, - byteLength, - ); - } else { - assert(controller[sym.queue].length === 0); - const transferredView = new Uint8Array( - transferredBuffer, - byteOffset, - byteLength, - ); - readableStreamFulfillReadRequest(stream, transferredView, false); - } - // 3.13.9.8 Otherwise, if ! ReadableStreamHasBYOBReader(stream) is true - } else { - assert(!isReadableStreamLocked(stream)); - readableByteStreamControllerEnqueueChunkToQueue( - controller, - transferredBuffer, - byteOffset, - byteLength, - ); - } - readableByteStreamControllerCallPullIfNeeded(controller); -} - -function readableByteStreamControllerEnqueueChunkToQueue( - controller: ReadableByteStreamControllerImpl, - buffer: ArrayBuffer | SharedArrayBuffer, - byteOffset: number, - byteLength: number, -): void { - controller[sym.queue].push({ - value: buffer, - offset: byteOffset, - size: byteLength, - }); - controller[sym.queueTotalSize] += byteLength; -} - -export function readableByteStreamControllerError( - controller: ReadableByteStreamControllerImpl, - e: any, -): void { - const stream = controller[sym.controlledReadableByteStream]; - if (stream[sym.state] !== "readable") { - return; - } - // 3.13.11.3 Perform ! ReadableByteStreamControllerClearPendingPullIntos(controller). - resetQueue(controller); - readableByteStreamControllerClearAlgorithms(controller); - readableStreamError(stream, e); -} - -export function readableByteStreamControllerGetDesiredSize( - controller: ReadableByteStreamControllerImpl, -): number | null { - const stream = controller[sym.controlledReadableByteStream]; - const state = stream[sym.state]; - if (state === "errored") { - return null; - } - if (state === "closed") { - return 0; - } - return controller[sym.strategyHWM] - controller[sym.queueTotalSize]; -} - -export function readableByteStreamControllerHandleQueueDrain( - controller: ReadableByteStreamControllerImpl, -): void { - assert( - controller[sym.controlledReadableByteStream][sym.state] === "readable", - ); - if (controller[sym.queueTotalSize] === 0 && controller[sym.closeRequested]) { - readableByteStreamControllerClearAlgorithms(controller); - readableStreamClose(controller[sym.controlledReadableByteStream]); - } else { - readableByteStreamControllerCallPullIfNeeded(controller); - } -} - -export function readableStreamAddReadRequest<R>( - stream: ReadableStreamImpl<R>, -): Promise<ReadableStreamReadResult<R>> { - assert(isReadableStreamDefaultReader(stream[sym.reader])); - assert(stream[sym.state] === "readable"); - const promise = getDeferred<ReadableStreamReadResult<R>>(); - stream[sym.reader]![sym.readRequests].push(promise); - return promise.promise; -} - -export function readableStreamCancel<T>( - stream: ReadableStreamImpl<T>, - reason: any, -): Promise<void> { - stream[sym.disturbed] = true; - if (stream[sym.state] === "closed") { - return Promise.resolve(); - } - if (stream[sym.state] === "errored") { - return Promise.reject(stream[sym.storedError]); - } - readableStreamClose(stream); - return stream[sym.readableStreamController].then( - () => undefined, - ) as Promise<void>; -} - -export function readableStreamClose<T>(stream: ReadableStreamImpl<T>): void { - assert(stream[sym.state] === "readable"); - stream[sym.state] = "closed"; - const reader = stream[sym.reader]; - if (!reader) { - return; - } - if (isReadableStreamDefaultReader<T>(reader)) { - for (const readRequest of reader[sym.readRequests]) { - assert(readRequest.resolve); - readRequest.resolve( - readableStreamCreateReadResult<T>( - undefined, - true, - reader[sym.forAuthorCode], - ), - ); - } - reader[sym.readRequests] = []; - } - const resolve = reader[sym.closedPromise].resolve; - assert(resolve); - resolve(); -} - -export function readableStreamCreateReadResult<T>( - value: T | undefined, - done: boolean, - forAuthorCode: boolean, -): ReadableStreamReadResult<T> { - const prototype = forAuthorCode ? Object.prototype : null; - assert(typeof done === "boolean"); - const obj: ReadableStreamReadResult<T> = Object.create(prototype); - Object.defineProperties(obj, { - value: { value, writable: true, enumerable: true, configurable: true }, - done: { value: done, writable: true, enumerable: true, configurable: true }, - }); - return obj; -} - -export function readableStreamDefaultControllerCallPullIfNeeded<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): void { - const shouldPull = readableStreamDefaultControllerShouldCallPull(controller); - if (!shouldPull) { - return; - } - if (controller[sym.pulling]) { - controller[sym.pullAgain] = true; - return; - } - assert(controller[sym.pullAgain] === false); - controller[sym.pulling] = true; - const pullPromise = controller[sym.pullAlgorithm](); - pullPromise.then( - () => { - controller[sym.pulling] = false; - if (controller[sym.pullAgain]) { - controller[sym.pullAgain] = false; - readableStreamDefaultControllerCallPullIfNeeded(controller); - } - }, - (e) => { - readableStreamDefaultControllerError(controller, e); - }, - ); -} - -export function readableStreamDefaultControllerCanCloseOrEnqueue<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): boolean { - const state = controller[sym.controlledReadableStream][sym.state]; - return !controller[sym.closeRequested] && state === "readable"; -} - -export function readableStreamDefaultControllerClearAlgorithms<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): void { - (controller as any)[sym.pullAlgorithm] = undefined; - (controller as any)[sym.cancelAlgorithm] = undefined; - (controller as any)[sym.strategySizeAlgorithm] = undefined; -} - -export function readableStreamDefaultControllerClose<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): void { - if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller)) { - return; - } - const stream = controller[sym.controlledReadableStream]; - controller[sym.closeRequested] = true; - if (controller[sym.queue].length === 0) { - readableStreamDefaultControllerClearAlgorithms(controller); - readableStreamClose(stream); - } -} - -export function readableStreamDefaultControllerEnqueue<T>( - controller: ReadableStreamDefaultControllerImpl<T>, - chunk: T, -): void { - if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller)) { - return; - } - const stream = controller[sym.controlledReadableStream]; - if ( - isReadableStreamLocked(stream) && - readableStreamGetNumReadRequests(stream) > 0 - ) { - readableStreamFulfillReadRequest(stream, chunk, false); - } else { - try { - const chunkSize = controller[sym.strategySizeAlgorithm](chunk); - enqueueValueWithSize(controller, chunk, chunkSize); - } catch (err) { - readableStreamDefaultControllerError(controller, err); - throw err; - } - } - readableStreamDefaultControllerCallPullIfNeeded(controller); -} - -export function readableStreamDefaultControllerGetDesiredSize<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): number | null { - const stream = controller[sym.controlledReadableStream]; - const state = stream[sym.state]; - if (state === "errored") { - return null; - } - if (state === "closed") { - return 0; - } - return controller[sym.strategyHWM] - controller[sym.queueTotalSize]; -} - -export function readableStreamDefaultControllerError<T>( - controller: ReadableStreamDefaultControllerImpl<T>, - e: any, -): void { - const stream = controller[sym.controlledReadableStream]; - if (stream[sym.state] !== "readable") { - return; - } - resetQueue(controller); - readableStreamDefaultControllerClearAlgorithms(controller); - readableStreamError(stream, e); -} - -function readableStreamDefaultControllerHasBackpressure<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): boolean { - return readableStreamDefaultControllerShouldCallPull(controller); -} - -function readableStreamDefaultControllerShouldCallPull<T>( - controller: ReadableStreamDefaultControllerImpl<T>, -): boolean { - const stream = controller[sym.controlledReadableStream]; - if ( - !readableStreamDefaultControllerCanCloseOrEnqueue(controller) || - controller[sym.started] === false - ) { - return false; - } - if ( - isReadableStreamLocked(stream) && - readableStreamGetNumReadRequests(stream) > 0 - ) { - return true; - } - const desiredSize = readableStreamDefaultControllerGetDesiredSize(controller); - assert(desiredSize !== null); - return desiredSize > 0; -} - -export function readableStreamDefaultReaderRead<R>( - reader: ReadableStreamDefaultReaderImpl<R>, -): Promise<ReadableStreamReadResult<R>> { - const stream = reader[sym.ownerReadableStream]; - assert(stream); - stream[sym.disturbed] = true; - if (stream[sym.state] === "closed") { - return Promise.resolve( - readableStreamCreateReadResult<R>( - undefined, - true, - reader[sym.forAuthorCode], - ), - ); - } - if (stream[sym.state] === "errored") { - return Promise.reject(stream[sym.storedError]); - } - assert(stream[sym.state] === "readable"); - return (stream[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl)[sym.pullSteps](); -} - -export function readableStreamError(stream: ReadableStreamImpl, e: any): void { - assert(isReadableStream(stream)); - assert(stream[sym.state] === "readable"); - stream[sym.state] = "errored"; - stream[sym.storedError] = e; - const reader = stream[sym.reader]; - if (reader === undefined) { - return; - } - if (isReadableStreamDefaultReader(reader)) { - for (const readRequest of reader[sym.readRequests]) { - assert(readRequest.reject); - readRequest.reject(e); - readRequest.reject = undefined; - readRequest.resolve = undefined; - } - reader[sym.readRequests] = []; - } - // 3.5.6.8 Otherwise, support BYOB Reader - reader[sym.closedPromise].reject!(e); - reader[sym.closedPromise].reject = undefined; - reader[sym.closedPromise].resolve = undefined; - setPromiseIsHandledToTrue(reader[sym.closedPromise].promise); -} - -export function readableStreamFulfillReadRequest<R>( - stream: ReadableStreamImpl<R>, - chunk: R, - done: boolean, -): void { - const reader = stream[sym.reader]!; - const readRequest = reader[sym.readRequests].shift()!; - assert(readRequest.resolve); - readRequest.resolve( - readableStreamCreateReadResult(chunk, done, reader[sym.forAuthorCode]), - ); -} - -export function readableStreamGetNumReadRequests( - stream: ReadableStreamImpl, -): number { - return stream[sym.reader]?.[sym.readRequests].length ?? 0; -} - -export function readableStreamHasDefaultReader( - stream: ReadableStreamImpl, -): boolean { - const reader = stream[sym.reader]; - return !(reader === undefined || !isReadableStreamDefaultReader(reader)); -} - -export function readableStreamPipeTo<T>( - source: ReadableStreamImpl<T>, - dest: WritableStreamImpl<T>, - preventClose: boolean, - preventAbort: boolean, - preventCancel: boolean, - signal: AbortSignalImpl | undefined, -): Promise<void> { - assert(isReadableStream(source)); - assert(isWritableStream(dest)); - assert( - typeof preventClose === "boolean" && - typeof preventAbort === "boolean" && - typeof preventCancel === "boolean", - ); - assert(signal === undefined || signal instanceof AbortSignalImpl); - assert(!isReadableStreamLocked(source)); - assert(!isWritableStreamLocked(dest)); - const reader = acquireReadableStreamDefaultReader(source); - const writer = acquireWritableStreamDefaultWriter(dest); - source[sym.disturbed] = true; - let shuttingDown = false; - const promise = getDeferred<void>(); - let abortAlgorithm: () => void; - if (signal) { - abortAlgorithm = (): void => { - const error = new DOMException("Abort signal received.", "AbortSignal"); - const actions: Array<() => Promise<void>> = []; - if (!preventAbort) { - actions.push(() => { - if (dest[sym.state] === "writable") { - return writableStreamAbort(dest, error); - } else { - return Promise.resolve(undefined); - } - }); - } - if (!preventCancel) { - actions.push(() => { - if (source[sym.state] === "readable") { - return readableStreamCancel(source, error); - } else { - return Promise.resolve(undefined); - } - }); - } - shutdownWithAction( - () => Promise.all(actions.map((action) => action())), - true, - error, - ); - }; - if (signal.aborted) { - abortAlgorithm(); - return promise.promise; - } - signal.addEventListener("abort", abortAlgorithm); - } - - let currentWrite = Promise.resolve(); - - // At this point, the spec becomes non-specific and vague. Most of the rest - // of this code is based on the reference implementation that is part of the - // specification. This is why the functions are only scoped to this function - // to ensure they don't leak into the spec compliant parts. - - function isOrBecomesClosed( - stream: ReadableStreamImpl | WritableStreamImpl, - promise: Promise<void>, - action: () => void, - ): void { - if (stream[sym.state] === "closed") { - action(); - } else { - setPromiseIsHandledToTrue(promise.then(action)); - } - } - - function isOrBecomesErrored( - stream: ReadableStreamImpl | WritableStreamImpl, - promise: Promise<void>, - action: (error: any) => void, - ): void { - if (stream[sym.state] === "errored") { - action(stream[sym.storedError]); - } else { - setPromiseIsHandledToTrue(promise.catch((error) => action(error))); - } - } - - function finalize(isError?: boolean, error?: any): void { - writableStreamDefaultWriterRelease(writer); - readableStreamReaderGenericRelease(reader); - - if (signal) { - signal.removeEventListener("abort", abortAlgorithm); - } - if (isError) { - promise.reject(error); - } else { - promise.resolve(); - } - } - - function waitForWritesToFinish(): Promise<void> { - const oldCurrentWrite = currentWrite; - return currentWrite.then(() => - oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : undefined - ); - } - - function shutdownWithAction( - action: () => Promise<any>, - originalIsError?: boolean, - originalError?: any, - ): void { - function doTheRest(): void { - setPromiseIsHandledToTrue( - action().then( - () => finalize(originalIsError, originalError), - (newError) => finalize(true, newError), - ), - ); - } - - if (shuttingDown) { - return; - } - shuttingDown = true; - - if ( - dest[sym.state] === "writable" && - writableStreamCloseQueuedOrInFlight(dest) === false - ) { - setPromiseIsHandledToTrue(waitForWritesToFinish().then(doTheRest)); - } else { - doTheRest(); - } - } - - function shutdown(isError: boolean, error?: any): void { - if (shuttingDown) { - return; - } - shuttingDown = true; - - if ( - dest[sym.state] === "writable" && - !writableStreamCloseQueuedOrInFlight(dest) - ) { - setPromiseIsHandledToTrue( - waitForWritesToFinish().then(() => finalize(isError, error)), - ); - } - finalize(isError, error); - } - - function pipeStep(): Promise<boolean> { - if (shuttingDown) { - return Promise.resolve(true); - } - return writer[sym.readyPromise].promise.then(() => { - return readableStreamDefaultReaderRead(reader).then(({ value, done }) => { - if (done === true) { - return true; - } - currentWrite = writableStreamDefaultWriterWrite( - writer, - value!, - ).then(undefined, () => {}); - return false; - }); - }); - } - - function pipeLoop(): Promise<void> { - return new Promise((resolveLoop, rejectLoop) => { - function next(done: boolean): void { - if (done) { - resolveLoop(undefined); - } else { - setPromiseIsHandledToTrue(pipeStep().then(next, rejectLoop)); - } - } - next(false); - }); - } - - isOrBecomesErrored( - source, - reader[sym.closedPromise].promise, - (storedError) => { - if (!preventAbort) { - shutdownWithAction( - () => writableStreamAbort(dest, storedError), - true, - storedError, - ); - } else { - shutdown(true, storedError); - } - }, - ); - - isOrBecomesErrored(dest, writer[sym.closedPromise].promise, (storedError) => { - if (!preventCancel) { - shutdownWithAction( - () => readableStreamCancel(source, storedError), - true, - storedError, - ); - } else { - shutdown(true, storedError); - } - }); - - isOrBecomesClosed(source, reader[sym.closedPromise].promise, () => { - if (!preventClose) { - shutdownWithAction(() => - writableStreamDefaultWriterCloseWithErrorPropagation(writer) - ); - } - }); - - if ( - writableStreamCloseQueuedOrInFlight(dest) || - dest[sym.state] === "closed" - ) { - const destClosed = new TypeError( - "The destination writable stream closed before all data could be piped to it.", - ); - if (!preventCancel) { - shutdownWithAction( - () => readableStreamCancel(source, destClosed), - true, - destClosed, - ); - } else { - shutdown(true, destClosed); - } - } - - setPromiseIsHandledToTrue(pipeLoop()); - return promise.promise; -} - -export function readableStreamReaderGenericCancel<R = any>( - reader: ReadableStreamGenericReader<R>, - reason: any, -): Promise<void> { - const stream = reader[sym.ownerReadableStream]; - assert(stream); - return readableStreamCancel(stream, reason); -} - -export function readableStreamReaderGenericInitialize<R = any>( - reader: ReadableStreamGenericReader<R>, - stream: ReadableStreamImpl<R>, -): void { - reader[sym.forAuthorCode] = true; - reader[sym.ownerReadableStream] = stream; - stream[sym.reader] = reader; - if (stream[sym.state] === "readable") { - reader[sym.closedPromise] = getDeferred(); - } else if (stream[sym.state] === "closed") { - reader[sym.closedPromise] = { promise: Promise.resolve() }; - } else { - assert(stream[sym.state] === "errored"); - reader[sym.closedPromise] = { - promise: Promise.reject(stream[sym.storedError]), - }; - setPromiseIsHandledToTrue(reader[sym.closedPromise].promise); - } -} - -export function readableStreamReaderGenericRelease<R = any>( - reader: ReadableStreamGenericReader<R>, -): void { - assert(reader[sym.ownerReadableStream]); - assert(reader[sym.ownerReadableStream][sym.reader] === reader); - const closedPromise = reader[sym.closedPromise]; - if (reader[sym.ownerReadableStream][sym.state] === "readable") { - assert(closedPromise.reject); - closedPromise.reject(new TypeError("ReadableStream state is readable.")); - } else { - closedPromise.promise = Promise.reject(new TypeError("Reading is closed.")); - delete closedPromise.reject; - delete closedPromise.resolve; - } - setPromiseIsHandledToTrue(closedPromise.promise); - reader[sym.ownerReadableStream][sym.reader] = undefined; - (reader as any)[sym.ownerReadableStream] = undefined; -} - -export function readableStreamTee<T>( - stream: ReadableStreamImpl<T>, - cloneForBranch2: boolean, -): [ReadableStreamImpl<T>, ReadableStreamImpl<T>] { - assert(isReadableStream(stream)); - assert(typeof cloneForBranch2 === "boolean"); - const reader = acquireReadableStreamDefaultReader(stream); - let reading = false; - let canceled1 = false; - let canceled2 = false; - let reason1: any = undefined; - let reason2: any = undefined; - /* eslint-disable prefer-const */ - let branch1: ReadableStreamImpl<T>; - let branch2: ReadableStreamImpl<T>; - /* eslint-enable prefer-const */ - const cancelPromise = getDeferred<void>(); - const pullAlgorithm = (): PromiseLike<void> => { - if (reading) { - return Promise.resolve(); - } - reading = true; - const readPromise = readableStreamDefaultReaderRead(reader).then( - (result) => { - reading = false; - assert(typeof result === "object"); - const { done } = result; - assert(typeof done === "boolean"); - if (done) { - if (!canceled1) { - readableStreamDefaultControllerClose( - branch1[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl, - ); - } - if (!canceled2) { - readableStreamDefaultControllerClose( - branch2[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl, - ); - } - return; - } - const { value } = result; - const value1 = value!; - let value2 = value!; - if (!canceled2 && cloneForBranch2) { - value2 = cloneValue(value2); - } - if (!canceled1) { - readableStreamDefaultControllerEnqueue( - branch1[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl, - value1, - ); - } - if (!canceled2) { - readableStreamDefaultControllerEnqueue( - branch2[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl, - value2, - ); - } - }, - ); - setPromiseIsHandledToTrue(readPromise); - return Promise.resolve(); - }; - const cancel1Algorithm = (reason?: any): PromiseLike<void> => { - canceled1 = true; - reason1 = reason; - if (canceled2) { - const compositeReason = [reason1, reason2]; - const cancelResult = readableStreamCancel(stream, compositeReason); - cancelPromise.resolve(cancelResult); - } - return cancelPromise.promise; - }; - const cancel2Algorithm = (reason?: any): PromiseLike<void> => { - canceled2 = true; - reason2 = reason; - if (canceled1) { - const compositeReason = [reason1, reason2]; - const cancelResult = readableStreamCancel(stream, compositeReason); - cancelPromise.resolve(cancelResult); - } - return cancelPromise.promise; - }; - const startAlgorithm = (): void => undefined; - branch1 = createReadableStream( - startAlgorithm, - pullAlgorithm, - cancel1Algorithm, - ); - branch2 = createReadableStream( - startAlgorithm, - pullAlgorithm, - cancel2Algorithm, - ); - setPromiseIsHandledToTrue( - reader[sym.closedPromise].promise.catch((r) => { - readableStreamDefaultControllerError( - branch1[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl, - r, - ); - readableStreamDefaultControllerError( - branch2[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl, - r, - ); - }), - ); - return [branch1, branch2]; -} - -export function resetQueue<R>(container: Container<R>): void { - assert(sym.queue in container && sym.queueTotalSize in container); - container[sym.queue] = []; - container[sym.queueTotalSize] = 0; -} - -/** An internal function which mimics the behavior of setting the promise to - * handled in JavaScript. In this situation, an assertion failure, which - * shouldn't happen will get thrown, instead of swallowed. */ -export function setPromiseIsHandledToTrue(promise: PromiseLike<unknown>): void { - promise.then(undefined, (e) => { - if (e && e instanceof AssertionError) { - queueMicrotask(() => { - throw e; - }); - } - }); -} - -function setUpReadableByteStreamController( - stream: ReadableStreamImpl, - controller: ReadableByteStreamControllerImpl, - startAlgorithm: StartAlgorithm, - pullAlgorithm: PullAlgorithm, - cancelAlgorithm: CancelAlgorithm, - highWaterMark: number, - autoAllocateChunkSize: number | undefined, -): void { - assert(stream[sym.readableStreamController] === undefined); - if (autoAllocateChunkSize !== undefined) { - assert(Number.isInteger(autoAllocateChunkSize)); - assert(autoAllocateChunkSize >= 0); - } - controller[sym.controlledReadableByteStream] = stream; - controller[sym.pulling] = controller[sym.pullAgain] = false; - controller[sym.byobRequest] = undefined; - controller[sym.queue] = []; - controller[sym.queueTotalSize] = 0; - controller[sym.closeRequested] = controller[sym.started] = false; - controller[sym.strategyHWM] = validateAndNormalizeHighWaterMark( - highWaterMark, - ); - controller[sym.pullAlgorithm] = pullAlgorithm; - controller[sym.cancelAlgorithm] = cancelAlgorithm; - controller[sym.autoAllocateChunkSize] = autoAllocateChunkSize; - // 3.13.26.12 Set controller.[[pendingPullIntos]] to a new empty List. - stream[sym.readableStreamController] = controller; - const startResult = startAlgorithm(); - const startPromise = Promise.resolve(startResult); - setPromiseIsHandledToTrue( - startPromise.then( - () => { - controller[sym.started] = true; - assert(!controller[sym.pulling]); - assert(!controller[sym.pullAgain]); - readableByteStreamControllerCallPullIfNeeded(controller); - }, - (r) => { - readableByteStreamControllerError(controller, r); - }, - ), - ); -} - -export function setUpReadableByteStreamControllerFromUnderlyingSource( - stream: ReadableStreamImpl, - underlyingByteSource: UnderlyingByteSource, - highWaterMark: number, -): void { - assert(underlyingByteSource); - const controller: ReadableByteStreamControllerImpl = Object.create( - ReadableByteStreamControllerImpl.prototype, - ); - const startAlgorithm: StartAlgorithm = () => { - return invokeOrNoop(underlyingByteSource, "start", controller); - }; - const pullAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingByteSource, - "pull", - 0, - controller, - ); - setFunctionName(pullAlgorithm, "[[pullAlgorithm]]"); - const cancelAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingByteSource, - "cancel", - 1, - ); - setFunctionName(cancelAlgorithm, "[[cancelAlgorithm]]"); - // 3.13.27.6 Let autoAllocateChunkSize be ? GetV(underlyingByteSource, "autoAllocateChunkSize"). - const autoAllocateChunkSize = undefined; - setUpReadableByteStreamController( - stream, - controller, - startAlgorithm, - pullAlgorithm, - cancelAlgorithm, - highWaterMark, - autoAllocateChunkSize, - ); -} - -function setUpReadableStreamDefaultController<T>( - stream: ReadableStreamImpl<T>, - controller: ReadableStreamDefaultControllerImpl<T>, - startAlgorithm: StartAlgorithm, - pullAlgorithm: PullAlgorithm, - cancelAlgorithm: CancelAlgorithm, - highWaterMark: number, - sizeAlgorithm: SizeAlgorithm<T>, -): void { - assert(stream[sym.readableStreamController] === undefined); - controller[sym.controlledReadableStream] = stream; - controller[sym.queue] = []; - controller[sym.queueTotalSize] = 0; - controller[sym.started] = controller[sym.closeRequested] = controller[ - sym.pullAgain - ] = controller[sym.pulling] = false; - controller[sym.strategySizeAlgorithm] = sizeAlgorithm; - controller[sym.strategyHWM] = highWaterMark; - controller[sym.pullAlgorithm] = pullAlgorithm; - controller[sym.cancelAlgorithm] = cancelAlgorithm; - stream[sym.readableStreamController] = controller; - const startResult = startAlgorithm(); - const startPromise = Promise.resolve(startResult); - setPromiseIsHandledToTrue( - startPromise.then( - () => { - controller[sym.started] = true; - assert(controller[sym.pulling] === false); - assert(controller[sym.pullAgain] === false); - readableStreamDefaultControllerCallPullIfNeeded(controller); - }, - (r) => { - readableStreamDefaultControllerError(controller, r); - }, - ), - ); -} - -export function setUpReadableStreamDefaultControllerFromUnderlyingSource<T>( - stream: ReadableStreamImpl<T>, - underlyingSource: UnderlyingSource<T>, - highWaterMark: number, - sizeAlgorithm: SizeAlgorithm<T>, -): void { - assert(underlyingSource); - const controller: ReadableStreamDefaultControllerImpl<T> = Object.create( - ReadableStreamDefaultControllerImpl.prototype, - ); - const startAlgorithm: StartAlgorithm = (): void | PromiseLike<void> => - invokeOrNoop(underlyingSource, "start", controller); - const pullAlgorithm: PullAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingSource, - "pull", - 0, - controller, - ); - setFunctionName(pullAlgorithm, "[[pullAlgorithm]]"); - const cancelAlgorithm: CancelAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingSource, - "cancel", - 1, - ); - setFunctionName(cancelAlgorithm, "[[cancelAlgorithm]]"); - setUpReadableStreamDefaultController( - stream, - controller, - startAlgorithm, - pullAlgorithm, - cancelAlgorithm, - highWaterMark, - sizeAlgorithm, - ); -} - -function setUpTransformStreamDefaultController<I, O>( - stream: TransformStreamImpl<I, O>, - controller: TransformStreamDefaultControllerImpl<I, O>, - transformAlgorithm: TransformAlgorithm<I>, - flushAlgorithm: FlushAlgorithm, -): void { - assert(isTransformStream(stream)); - assert(stream[sym.transformStreamController] === undefined); - controller[sym.controlledTransformStream] = stream; - stream[sym.transformStreamController] = controller; - controller[sym.transformAlgorithm] = transformAlgorithm; - controller[sym.flushAlgorithm] = flushAlgorithm; -} - -export function setUpTransformStreamDefaultControllerFromTransformer<I, O>( - stream: TransformStreamImpl<I, O>, - transformer: Transformer<I, O>, -): void { - assert(transformer); - const controller = Object.create( - TransformStreamDefaultControllerImpl.prototype, - ) as TransformStreamDefaultControllerImpl<I, O>; - let transformAlgorithm: TransformAlgorithm<I> = (chunk) => { - try { - transformStreamDefaultControllerEnqueue( - controller, - // it defaults to no tranformation, so I is assumed to be O - (chunk as unknown) as O, - ); - } catch (e) { - return Promise.reject(e); - } - return Promise.resolve(); - }; - const transformMethod = transformer.transform; - if (transformMethod) { - if (typeof transformMethod !== "function") { - throw new TypeError("tranformer.transform must be callable."); - } - transformAlgorithm = async (chunk): Promise<void> => - call(transformMethod, transformer, [chunk, controller]); - } - const flushAlgorithm = createAlgorithmFromUnderlyingMethod( - transformer, - "flush", - 0, - controller, - ); - setUpTransformStreamDefaultController( - stream, - controller, - transformAlgorithm, - flushAlgorithm, - ); -} - -function setUpWritableStreamDefaultController<W>( - stream: WritableStreamImpl<W>, - controller: WritableStreamDefaultControllerImpl<W>, - startAlgorithm: StartAlgorithm, - writeAlgorithm: WriteAlgorithm<W>, - closeAlgorithm: CloseAlgorithm, - abortAlgorithm: AbortAlgorithm, - highWaterMark: number, - sizeAlgorithm: SizeAlgorithm<W>, -): void { - assert(isWritableStream(stream)); - assert(stream[sym.writableStreamController] === undefined); - controller[sym.controlledWritableStream] = stream; - stream[sym.writableStreamController] = controller; - controller[sym.queue] = []; - controller[sym.queueTotalSize] = 0; - controller[sym.started] = false; - controller[sym.strategySizeAlgorithm] = sizeAlgorithm; - controller[sym.strategyHWM] = highWaterMark; - controller[sym.writeAlgorithm] = writeAlgorithm; - controller[sym.closeAlgorithm] = closeAlgorithm; - controller[sym.abortAlgorithm] = abortAlgorithm; - const backpressure = writableStreamDefaultControllerGetBackpressure( - controller, - ); - writableStreamUpdateBackpressure(stream, backpressure); - const startResult = startAlgorithm(); - const startPromise = Promise.resolve(startResult); - setPromiseIsHandledToTrue( - startPromise.then( - () => { - assert( - stream[sym.state] === "writable" || stream[sym.state] === "erroring", - ); - controller[sym.started] = true; - writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, - (r) => { - assert( - stream[sym.state] === "writable" || stream[sym.state] === "erroring", - ); - controller[sym.started] = true; - writableStreamDealWithRejection(stream, r); - }, - ), - ); -} - -export function setUpWritableStreamDefaultControllerFromUnderlyingSink<W>( - stream: WritableStreamImpl<W>, - underlyingSink: UnderlyingSink<W>, - highWaterMark: number, - sizeAlgorithm: SizeAlgorithm<W>, -): void { - assert(underlyingSink); - const controller = Object.create( - WritableStreamDefaultControllerImpl.prototype, - ); - const startAlgorithm = (): void | PromiseLike<void> => { - return invokeOrNoop(underlyingSink, "start", controller); - }; - const writeAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingSink, - "write", - 1, - controller, - ); - setFunctionName(writeAlgorithm, "[[writeAlgorithm]]"); - const closeAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingSink, - "close", - 0, - ); - setFunctionName(closeAlgorithm, "[[closeAlgorithm]]"); - const abortAlgorithm = createAlgorithmFromUnderlyingMethod( - underlyingSink, - "abort", - 1, - ); - setFunctionName(abortAlgorithm, "[[abortAlgorithm]]"); - setUpWritableStreamDefaultController( - stream, - controller, - startAlgorithm, - writeAlgorithm, - closeAlgorithm, - abortAlgorithm, - highWaterMark, - sizeAlgorithm, - ); -} - -function transformStreamDefaultControllerClearAlgorithms<I, O>( - controller: TransformStreamDefaultControllerImpl<I, O>, -): void { - (controller as any)[sym.transformAlgorithm] = undefined; - (controller as any)[sym.flushAlgorithm] = undefined; -} - -export function transformStreamDefaultControllerEnqueue<I, O>( - controller: TransformStreamDefaultControllerImpl<I, O>, - chunk: O, -): void { - const stream = controller[sym.controlledTransformStream]; - const readableController = stream[sym.readable][ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl<O>; - if (!readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) { - throw new TypeError( - "TransformStream's readable controller cannot be closed or enqueued.", - ); - } - try { - readableStreamDefaultControllerEnqueue(readableController, chunk); - } catch (e) { - transformStreamErrorWritableAndUnblockWrite(stream, e); - throw stream[sym.readable][sym.storedError]; - } - const backpressure = readableStreamDefaultControllerHasBackpressure( - readableController, - ); - if (backpressure) { - transformStreamSetBackpressure(stream, true); - } -} - -export function transformStreamDefaultControllerError<I, O>( - controller: TransformStreamDefaultControllerImpl<I, O>, - e: any, -): void { - transformStreamError(controller[sym.controlledTransformStream], e); -} - -function transformStreamDefaultControllerPerformTransform<I, O>( - controller: TransformStreamDefaultControllerImpl<I, O>, - chunk: I, -): Promise<void> { - const transformPromise = controller[sym.transformAlgorithm](chunk); - return transformPromise.then(undefined, (r) => { - transformStreamError(controller[sym.controlledTransformStream], r); - throw r; - }); -} - -function transformStreamDefaultSinkAbortAlgorithm<I, O>( - stream: TransformStreamImpl<I, O>, - reason: any, -): Promise<void> { - transformStreamError(stream, reason); - return Promise.resolve(undefined); -} - -function transformStreamDefaultSinkCloseAlgorithm<I, O>( - stream: TransformStreamImpl<I, O>, -): Promise<void> { - const readable = stream[sym.readable]; - const controller = stream[sym.transformStreamController]; - const flushPromise = controller[sym.flushAlgorithm](); - transformStreamDefaultControllerClearAlgorithms(controller); - return flushPromise.then( - () => { - if (readable[sym.state] === "errored") { - throw readable[sym.storedError]; - } - const readableController = readable[ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl<O>; - if ( - readableStreamDefaultControllerCanCloseOrEnqueue(readableController) - ) { - readableStreamDefaultControllerClose(readableController); - } - }, - (r) => { - transformStreamError(stream, r); - throw readable[sym.storedError]; - }, - ); -} - -function transformStreamDefaultSinkWriteAlgorithm<I, O>( - stream: TransformStreamImpl<I, O>, - chunk: I, -): Promise<void> { - assert(stream[sym.writable][sym.state] === "writable"); - const controller = stream[sym.transformStreamController]; - if (stream[sym.backpressure]) { - const backpressureChangePromise = stream[sym.backpressureChangePromise]; - assert(backpressureChangePromise); - return backpressureChangePromise.promise.then(() => { - const writable = stream[sym.writable]; - const state = writable[sym.state]; - if (state === "erroring") { - throw writable[sym.storedError]; - } - assert(state === "writable"); - return transformStreamDefaultControllerPerformTransform( - controller, - chunk, - ); - }); - } - return transformStreamDefaultControllerPerformTransform(controller, chunk); -} - -function transformStreamDefaultSourcePullAlgorithm<I, O>( - stream: TransformStreamImpl<I, O>, -): Promise<void> { - assert(stream[sym.backpressure] === true); - assert(stream[sym.backpressureChangePromise] !== undefined); - transformStreamSetBackpressure(stream, false); - return stream[sym.backpressureChangePromise]!.promise; -} - -function transformStreamError<I, O>( - stream: TransformStreamImpl<I, O>, - e: any, -): void { - readableStreamDefaultControllerError( - stream[sym.readable][ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl<O>, - e, - ); - transformStreamErrorWritableAndUnblockWrite(stream, e); -} - -export function transformStreamDefaultControllerTerminate<I, O>( - controller: TransformStreamDefaultControllerImpl<I, O>, -): void { - const stream = controller[sym.controlledTransformStream]; - const readableController = stream[sym.readable][ - sym.readableStreamController - ] as ReadableStreamDefaultControllerImpl<O>; - readableStreamDefaultControllerClose(readableController); - const error = new TypeError("TransformStream is closed."); - transformStreamErrorWritableAndUnblockWrite(stream, error); -} - -function transformStreamErrorWritableAndUnblockWrite<I, O>( - stream: TransformStreamImpl<I, O>, - e: any, -): void { - transformStreamDefaultControllerClearAlgorithms( - stream[sym.transformStreamController], - ); - writableStreamDefaultControllerErrorIfNeeded( - stream[sym.writable][sym.writableStreamController]!, - e, - ); - if (stream[sym.backpressure]) { - transformStreamSetBackpressure(stream, false); - } -} - -function transformStreamSetBackpressure<I, O>( - stream: TransformStreamImpl<I, O>, - backpressure: boolean, -): void { - assert(stream[sym.backpressure] !== backpressure); - if (stream[sym.backpressureChangePromise] !== undefined) { - stream[sym.backpressureChangePromise]!.resolve!(undefined); - } - stream[sym.backpressureChangePromise] = getDeferred<void>(); - stream[sym.backpressure] = backpressure; -} - -function transferArrayBuffer(buffer: ArrayBuffer): ArrayBuffer { - assert(!isDetachedBuffer(buffer)); - const transferredIshVersion = buffer.slice(0); - - Object.defineProperty(buffer, "byteLength", { - get(): number { - return 0; - }, - }); - (buffer as any)[sym.isFakeDetached] = true; - - return transferredIshVersion; -} - -export function validateAndNormalizeHighWaterMark( - highWaterMark: number, -): number { - highWaterMark = Number(highWaterMark); - if (Number.isNaN(highWaterMark) || highWaterMark < 0) { - throw new RangeError( - `highWaterMark must be a positive number or Infinity. Received: ${highWaterMark}.`, - ); - } - return highWaterMark; -} - -export function writableStreamAbort<W>( - stream: WritableStreamImpl<W>, - reason: any, -): Promise<void> { - const state = stream[sym.state]; - if (state === "closed" || state === "errored") { - return Promise.resolve(undefined); - } - if (stream[sym.pendingAbortRequest]) { - return stream[sym.pendingAbortRequest]!.promise.promise; - } - assert(state === "writable" || state === "erroring"); - let wasAlreadyErroring = false; - if (state === "erroring") { - wasAlreadyErroring = true; - reason = undefined; - } - const promise = getDeferred<void>(); - stream[sym.pendingAbortRequest] = { promise, reason, wasAlreadyErroring }; - - if (wasAlreadyErroring === false) { - writableStreamStartErroring(stream, reason); - } - return promise.promise; -} - -function writableStreamAddWriteRequest<W>( - stream: WritableStreamImpl<W>, -): Promise<void> { - assert(isWritableStream(stream)); - assert(stream[sym.state] === "writable"); - const promise = getDeferred<void>(); - stream[sym.writeRequests].push(promise); - return promise.promise; -} - -export function writableStreamClose<W>( - stream: WritableStreamImpl<W>, -): Promise<void> { - const state = stream[sym.state]; - if (state === "closed" || state === "errored") { - return Promise.reject( - new TypeError( - "Cannot close an already closed or errored WritableStream.", - ), - ); - } - assert(!writableStreamCloseQueuedOrInFlight(stream)); - const promise = getDeferred<void>(); - stream[sym.closeRequest] = promise; - const writer = stream[sym.writer]; - if (writer && stream[sym.backpressure] && state === "writable") { - writer[sym.readyPromise].resolve!(); - writer[sym.readyPromise].resolve = undefined; - writer[sym.readyPromise].reject = undefined; - } - writableStreamDefaultControllerClose(stream[sym.writableStreamController]!); - return promise.promise; -} - -export function writableStreamCloseQueuedOrInFlight<W>( - stream: WritableStreamImpl<W>, -): boolean { - return !( - stream[sym.closeRequest] === undefined && - stream[sym.inFlightCloseRequest] === undefined - ); -} - -function writableStreamDealWithRejection<W>( - stream: WritableStreamImpl<W>, - error: any, -): void { - const state = stream[sym.state]; - if (state === "writable") { - writableStreamStartErroring(stream, error); - return; - } - assert(state === "erroring"); - writableStreamFinishErroring(stream); -} - -function writableStreamDefaultControllerAdvanceQueueIfNeeded<W>( - controller: WritableStreamDefaultControllerImpl<W>, -): void { - const stream = controller[sym.controlledWritableStream]; - if (!controller[sym.started]) { - return; - } - if (stream[sym.inFlightWriteRequest]) { - return; - } - const state = stream[sym.state]; - assert(state !== "closed" && state !== "errored"); - if (state === "erroring") { - writableStreamFinishErroring(stream); - return; - } - if (!controller[sym.queue].length) { - return; - } - const writeRecord = peekQueueValue(controller); - if (writeRecord === "close") { - writableStreamDefaultControllerProcessClose(controller); - } else { - writableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk); - } -} - -export function writableStreamDefaultControllerClearAlgorithms<W>( - controller: WritableStreamDefaultControllerImpl<W>, -): void { - (controller as any)[sym.writeAlgorithm] = undefined; - (controller as any)[sym.closeAlgorithm] = undefined; - (controller as any)[sym.abortAlgorithm] = undefined; - (controller as any)[sym.strategySizeAlgorithm] = undefined; -} - -function writableStreamDefaultControllerClose<W>( - controller: WritableStreamDefaultControllerImpl<W>, -): void { - enqueueValueWithSize(controller, "close", 0); - writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); -} - -export function writableStreamDefaultControllerError<W>( - controller: WritableStreamDefaultControllerImpl<W>, - error: any, -): void { - const stream = controller[sym.controlledWritableStream]; - assert(stream[sym.state] === "writable"); - writableStreamDefaultControllerClearAlgorithms(controller); - writableStreamStartErroring(stream, error); -} - -function writableStreamDefaultControllerErrorIfNeeded<W>( - controller: WritableStreamDefaultControllerImpl<W>, - error: any, -): void { - if (controller[sym.controlledWritableStream][sym.state] === "writable") { - writableStreamDefaultControllerError(controller, error); - } -} - -function writableStreamDefaultControllerGetBackpressure<W>( - controller: WritableStreamDefaultControllerImpl<W>, -): boolean { - const desiredSize = writableStreamDefaultControllerGetDesiredSize(controller); - return desiredSize <= 0; -} - -function writableStreamDefaultControllerGetChunkSize<W>( - controller: WritableStreamDefaultControllerImpl<W>, - chunk: W, -): number { - let returnValue: number; - try { - returnValue = controller[sym.strategySizeAlgorithm](chunk); - } catch (e) { - writableStreamDefaultControllerErrorIfNeeded(controller, e); - return 1; - } - return returnValue; -} - -function writableStreamDefaultControllerGetDesiredSize<W>( - controller: WritableStreamDefaultControllerImpl<W>, -): number { - return controller[sym.strategyHWM] - controller[sym.queueTotalSize]; -} - -function writableStreamDefaultControllerProcessClose<W>( - controller: WritableStreamDefaultControllerImpl<W>, -): void { - const stream = controller[sym.controlledWritableStream]; - writableStreamMarkCloseRequestInFlight(stream); - dequeueValue(controller); - assert(controller[sym.queue].length === 0); - const sinkClosePromise = controller[sym.closeAlgorithm](); - writableStreamDefaultControllerClearAlgorithms(controller); - setPromiseIsHandledToTrue( - sinkClosePromise.then( - () => { - writableStreamFinishInFlightClose(stream); - }, - (reason) => { - writableStreamFinishInFlightCloseWithError(stream, reason); - }, - ), - ); -} - -function writableStreamDefaultControllerProcessWrite<W>( - controller: WritableStreamDefaultControllerImpl<W>, - chunk: W, -): void { - const stream = controller[sym.controlledWritableStream]; - writableStreamMarkFirstWriteRequestInFlight(stream); - const sinkWritePromise = controller[sym.writeAlgorithm](chunk); - setPromiseIsHandledToTrue( - sinkWritePromise.then( - () => { - writableStreamFinishInFlightWrite(stream); - const state = stream[sym.state]; - assert(state === "writable" || state === "erroring"); - dequeueValue(controller); - if ( - !writableStreamCloseQueuedOrInFlight(stream) && - state === "writable" - ) { - const backpressure = writableStreamDefaultControllerGetBackpressure( - controller, - ); - writableStreamUpdateBackpressure(stream, backpressure); - } - writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, - (reason) => { - if (stream[sym.state] === "writable") { - writableStreamDefaultControllerClearAlgorithms(controller); - } - writableStreamFinishInFlightWriteWithError(stream, reason); - }, - ), - ); -} - -function writableStreamDefaultControllerWrite<W>( - controller: WritableStreamDefaultControllerImpl<W>, - chunk: W, - chunkSize: number, -): void { - const writeRecord = { chunk }; - try { - enqueueValueWithSize(controller, writeRecord, chunkSize); - } catch (e) { - writableStreamDefaultControllerErrorIfNeeded(controller, e); - return; - } - const stream = controller[sym.controlledWritableStream]; - if ( - !writableStreamCloseQueuedOrInFlight(stream) && - stream[sym.state] === "writable" - ) { - const backpressure = writableStreamDefaultControllerGetBackpressure( - controller, - ); - writableStreamUpdateBackpressure(stream, backpressure); - } - writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); -} - -export function writableStreamDefaultWriterAbort<W>( - writer: WritableStreamDefaultWriterImpl<W>, - reason: any, -): Promise<void> { - const stream = writer[sym.ownerWritableStream]; - assert(stream); - return writableStreamAbort(stream, reason); -} - -export function writableStreamDefaultWriterClose<W>( - writer: WritableStreamDefaultWriterImpl<W>, -): Promise<void> { - const stream = writer[sym.ownerWritableStream]; - assert(stream); - return writableStreamClose(stream); -} - -function writableStreamDefaultWriterCloseWithErrorPropagation<W>( - writer: WritableStreamDefaultWriterImpl<W>, -): Promise<void> { - const stream = writer[sym.ownerWritableStream]; - assert(stream); - const state = stream[sym.state]; - if (writableStreamCloseQueuedOrInFlight(stream) || state === "closed") { - return Promise.resolve(); - } - if (state === "errored") { - return Promise.reject(stream[sym.storedError]); - } - assert(state === "writable" || state === "erroring"); - return writableStreamDefaultWriterClose(writer); -} - -function writableStreamDefaultWriterEnsureClosePromiseRejected<W>( - writer: WritableStreamDefaultWriterImpl<W>, - error: any, -): void { - if (writer[sym.closedPromise].reject) { - writer[sym.closedPromise].reject!(error); - } else { - writer[sym.closedPromise] = { - promise: Promise.reject(error), - }; - } - setPromiseIsHandledToTrue(writer[sym.closedPromise].promise); -} - -function writableStreamDefaultWriterEnsureReadyPromiseRejected<W>( - writer: WritableStreamDefaultWriterImpl<W>, - error: any, -): void { - if (writer[sym.readyPromise].reject) { - writer[sym.readyPromise].reject!(error); - writer[sym.readyPromise].reject = undefined; - writer[sym.readyPromise].resolve = undefined; - } else { - writer[sym.readyPromise] = { - promise: Promise.reject(error), - }; - } - setPromiseIsHandledToTrue(writer[sym.readyPromise].promise); -} - -export function writableStreamDefaultWriterWrite<W>( - writer: WritableStreamDefaultWriterImpl<W>, - chunk: W, -): Promise<void> { - const stream = writer[sym.ownerWritableStream]; - assert(stream); - const controller = stream[sym.writableStreamController]; - assert(controller); - const chunkSize = writableStreamDefaultControllerGetChunkSize( - controller, - chunk, - ); - if (stream !== writer[sym.ownerWritableStream]) { - return Promise.reject("Writer has incorrect WritableStream."); - } - const state = stream[sym.state]; - if (state === "errored") { - return Promise.reject(stream[sym.storedError]); - } - if (writableStreamCloseQueuedOrInFlight(stream) || state === "closed") { - return Promise.reject(new TypeError("The stream is closed or closing.")); - } - if (state === "erroring") { - return Promise.reject(stream[sym.storedError]); - } - assert(state === "writable"); - const promise = writableStreamAddWriteRequest(stream); - writableStreamDefaultControllerWrite(controller, chunk, chunkSize); - return promise; -} - -export function writableStreamDefaultWriterGetDesiredSize<W>( - writer: WritableStreamDefaultWriterImpl<W>, -): number | null { - const stream = writer[sym.ownerWritableStream]; - const state = stream[sym.state]; - if (state === "errored" || state === "erroring") { - return null; - } - if (state === "closed") { - return 0; - } - return writableStreamDefaultControllerGetDesiredSize( - stream[sym.writableStreamController]!, - ); -} - -export function writableStreamDefaultWriterRelease<W>( - writer: WritableStreamDefaultWriterImpl<W>, -): void { - const stream = writer[sym.ownerWritableStream]; - assert(stream); - assert(stream[sym.writer] === writer); - const releasedError = new TypeError( - "Writer was released and can no longer be used to monitor the stream's closedness.", - ); - writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); - writableStreamDefaultWriterEnsureClosePromiseRejected(writer, releasedError); - stream[sym.writer] = undefined; - (writer as any)[sym.ownerWritableStream] = undefined; -} - -function writableStreamFinishErroring<W>(stream: WritableStreamImpl<W>): void { - assert(stream[sym.state] === "erroring"); - assert(!writableStreamHasOperationMarkedInFlight(stream)); - stream[sym.state] = "errored"; - stream[sym.writableStreamController]![sym.errorSteps](); - const storedError = stream[sym.storedError]; - for (const writeRequest of stream[sym.writeRequests]) { - assert(writeRequest.reject); - writeRequest.reject(storedError); - } - stream[sym.writeRequests] = []; - if (!stream[sym.pendingAbortRequest]) { - writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - const abortRequest = stream[sym.pendingAbortRequest]; - assert(abortRequest); - stream[sym.pendingAbortRequest] = undefined; - if (abortRequest.wasAlreadyErroring) { - assert(abortRequest.promise.reject); - abortRequest.promise.reject(storedError); - writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - const promise = stream[sym.writableStreamController]; - setPromiseIsHandledToTrue( - promise.then( - () => { - assert(abortRequest.promise.resolve); - abortRequest.promise.resolve(); - writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }, - (reason) => { - assert(abortRequest.promise.reject); - abortRequest.promise.reject(reason); - writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }, - ), - ); -} - -function writableStreamFinishInFlightClose<W>( - stream: WritableStreamImpl<W>, -): void { - assert(stream[sym.inFlightCloseRequest]); - stream[sym.inFlightCloseRequest]?.resolve!(); - stream[sym.inFlightCloseRequest] = undefined; - const state = stream[sym.state]; - assert(state === "writable" || state === "erroring"); - if (state === "erroring") { - stream[sym.storedError] = undefined; - if (stream[sym.pendingAbortRequest]) { - stream[sym.pendingAbortRequest]!.promise.resolve!(); - stream[sym.pendingAbortRequest] = undefined; - } - } - stream[sym.state] = "closed"; - const writer = stream[sym.writer]; - if (writer) { - writer[sym.closedPromise].resolve!(); - } - assert(stream[sym.pendingAbortRequest] === undefined); - assert(stream[sym.storedError] === undefined); -} - -function writableStreamFinishInFlightCloseWithError<W>( - stream: WritableStreamImpl<W>, - error: any, -): void { - assert(stream[sym.inFlightCloseRequest]); - stream[sym.inFlightCloseRequest]?.reject!(error); - stream[sym.inFlightCloseRequest] = undefined; - assert(stream[sym.state] === "writable" || stream[sym.state] === "erroring"); - if (stream[sym.pendingAbortRequest]) { - stream[sym.pendingAbortRequest]?.promise.reject!(error); - stream[sym.pendingAbortRequest] = undefined; - } - writableStreamDealWithRejection(stream, error); -} - -function writableStreamFinishInFlightWrite<W>( - stream: WritableStreamImpl<W>, -): void { - assert(stream[sym.inFlightWriteRequest]); - stream[sym.inFlightWriteRequest]!.resolve(); - stream[sym.inFlightWriteRequest] = undefined; -} - -function writableStreamFinishInFlightWriteWithError<W>( - stream: WritableStreamImpl<W>, - error: any, -): void { - assert(stream[sym.inFlightWriteRequest]); - stream[sym.inFlightWriteRequest]!.reject!(error); - stream[sym.inFlightWriteRequest] = undefined; - assert(stream[sym.state] === "writable" || stream[sym.state] === "erroring"); - writableStreamDealWithRejection(stream, error); -} - -function writableStreamHasOperationMarkedInFlight<W>( - stream: WritableStreamImpl<W>, -): boolean { - return !( - stream[sym.inFlightWriteRequest] === undefined && - stream[sym.inFlightCloseRequest] === undefined - ); -} - -function writableStreamMarkCloseRequestInFlight<W>( - stream: WritableStreamImpl<W>, -): void { - assert(stream[sym.inFlightCloseRequest] === undefined); - assert(stream[sym.closeRequest] !== undefined); - stream[sym.inFlightCloseRequest] = stream[sym.closeRequest]; - stream[sym.closeRequest] = undefined; -} - -function writableStreamMarkFirstWriteRequestInFlight<W>( - stream: WritableStreamImpl<W>, -): void { - assert(stream[sym.inFlightWriteRequest] === undefined); - assert(stream[sym.writeRequests].length); - const writeRequest = stream[sym.writeRequests].shift(); - stream[sym.inFlightWriteRequest] = writeRequest; -} - -function writableStreamRejectCloseAndClosedPromiseIfNeeded<W>( - stream: WritableStreamImpl<W>, -): void { - assert(stream[sym.state] === "errored"); - if (stream[sym.closeRequest]) { - assert(stream[sym.inFlightCloseRequest] === undefined); - stream[sym.closeRequest]!.reject!(stream[sym.storedError]); - stream[sym.closeRequest] = undefined; - } - const writer = stream[sym.writer]; - if (writer) { - writer[sym.closedPromise].reject!(stream[sym.storedError]); - setPromiseIsHandledToTrue(writer[sym.closedPromise].promise); - } -} - -function writableStreamStartErroring<W>( - stream: WritableStreamImpl<W>, - reason: any, -): void { - assert(stream[sym.storedError] === undefined); - assert(stream[sym.state] === "writable"); - const controller = stream[sym.writableStreamController]; - assert(controller); - stream[sym.state] = "erroring"; - stream[sym.storedError] = reason; - const writer = stream[sym.writer]; - if (writer) { - writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); - } - if ( - !writableStreamHasOperationMarkedInFlight(stream) && - controller[sym.started] - ) { - writableStreamFinishErroring(stream); - } -} - -function writableStreamUpdateBackpressure<W>( - stream: WritableStreamImpl<W>, - backpressure: boolean, -): void { - assert(stream[sym.state] === "writable"); - assert(!writableStreamCloseQueuedOrInFlight(stream)); - const writer = stream[sym.writer]; - if (writer && backpressure !== stream[sym.backpressure]) { - if (backpressure) { - writer[sym.readyPromise] = getDeferred(); - } else { - assert(backpressure === false); - writer[sym.readyPromise].resolve!(); - writer[sym.readyPromise].resolve = undefined; - writer[sym.readyPromise].reject = undefined; - } - } - stream[sym.backpressure] = backpressure; -} - -/* eslint-enable */ diff --git a/cli/js/web/streams/queuing_strategy.ts b/cli/js/web/streams/queuing_strategy.ts deleted file mode 100644 index 818f0d51b..000000000 --- a/cli/js/web/streams/queuing_strategy.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -export class CountQueuingStrategyImpl implements CountQueuingStrategy { - highWaterMark: number; - - constructor({ highWaterMark }: { highWaterMark: number }) { - this.highWaterMark = highWaterMark; - } - - size(): 1 { - return 1; - } - - [customInspect](): string { - return `${this.constructor.name} { highWaterMark: ${ - String(this.highWaterMark) - }, size: f }`; - } -} - -Object.defineProperty(CountQueuingStrategyImpl.prototype, "size", { - enumerable: true, -}); - -setFunctionName(CountQueuingStrategyImpl, "CountQueuingStrategy"); - -export class ByteLengthQueuingStrategyImpl - implements ByteLengthQueuingStrategy { - highWaterMark: number; - - constructor({ highWaterMark }: { highWaterMark: number }) { - this.highWaterMark = highWaterMark; - } - - size(chunk: ArrayBufferView): number { - return chunk.byteLength; - } - - [customInspect](): string { - return `${this.constructor.name} { highWaterMark: ${ - String(this.highWaterMark) - }, size: f }`; - } -} - -Object.defineProperty(ByteLengthQueuingStrategyImpl.prototype, "size", { - enumerable: true, -}); - -setFunctionName(CountQueuingStrategyImpl, "CountQueuingStrategy"); diff --git a/cli/js/web/streams/readable_byte_stream_controller.ts b/cli/js/web/streams/readable_byte_stream_controller.ts deleted file mode 100644 index eb4374604..000000000 --- a/cli/js/web/streams/readable_byte_stream_controller.ts +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - BufferQueueItem, - CancelAlgorithm, - isDetachedBuffer, - isReadableByteStreamController, - PullAlgorithm, - resetQueue, - readableByteStreamControllerCallPullIfNeeded, - readableByteStreamControllerClearAlgorithms, - readableByteStreamControllerClose, - readableByteStreamControllerEnqueue, - readableByteStreamControllerError, - readableByteStreamControllerGetDesiredSize, - readableByteStreamControllerHandleQueueDrain, - readableStreamAddReadRequest, - readableStreamHasDefaultReader, - readableStreamGetNumReadRequests, - readableStreamCreateReadResult, -} from "./internals.ts"; -import type { ReadableStreamImpl } from "./readable_stream.ts"; -import * as sym from "./symbols.ts"; -import { assert } from "../../util.ts"; -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -export class ReadableByteStreamControllerImpl - implements ReadableByteStreamController { - [sym.autoAllocateChunkSize]: number | undefined; - [sym.byobRequest]: undefined; - [sym.cancelAlgorithm]: CancelAlgorithm; - [sym.closeRequested]: boolean; - [sym.controlledReadableByteStream]: ReadableStreamImpl<Uint8Array>; - [sym.pullAgain]: boolean; - [sym.pullAlgorithm]: PullAlgorithm; - [sym.pulling]: boolean; - [sym.queue]: BufferQueueItem[]; - [sym.queueTotalSize]: number; - [sym.started]: boolean; - [sym.strategyHWM]: number; - - private constructor() { - throw new TypeError( - "ReadableByteStreamController's constructor cannot be called.", - ); - } - - get byobRequest(): undefined { - return undefined; - } - - get desiredSize(): number | null { - if (!isReadableByteStreamController(this)) { - throw new TypeError("Invalid ReadableByteStreamController."); - } - return readableByteStreamControllerGetDesiredSize(this); - } - - close(): void { - if (!isReadableByteStreamController(this)) { - throw new TypeError("Invalid ReadableByteStreamController."); - } - if (this[sym.closeRequested]) { - throw new TypeError("Closed already requested."); - } - if (this[sym.controlledReadableByteStream][sym.state] !== "readable") { - throw new TypeError( - "ReadableByteStreamController's stream is not in a readable state.", - ); - } - readableByteStreamControllerClose(this); - } - - enqueue(chunk: ArrayBufferView): void { - if (!isReadableByteStreamController(this)) { - throw new TypeError("Invalid ReadableByteStreamController."); - } - if (this[sym.closeRequested]) { - throw new TypeError("Closed already requested."); - } - if (this[sym.controlledReadableByteStream][sym.state] !== "readable") { - throw new TypeError( - "ReadableByteStreamController's stream is not in a readable state.", - ); - } - if (!ArrayBuffer.isView(chunk)) { - throw new TypeError( - "You can only enqueue array buffer views when using a ReadableByteStreamController", - ); - } - if (isDetachedBuffer(chunk.buffer)) { - throw new TypeError("Cannot enqueue a view onto a detached ArrayBuffer"); - } - readableByteStreamControllerEnqueue(this, chunk); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - error(error?: any): void { - if (!isReadableByteStreamController(this)) { - throw new TypeError("Invalid ReadableByteStreamController."); - } - readableByteStreamControllerError(this, error); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [sym.cancelSteps](reason: any): PromiseLike<void> { - // 3.11.5.1.1 If this.[[pendingPullIntos]] is not empty, - resetQueue(this); - const result = this[sym.cancelAlgorithm](reason); - readableByteStreamControllerClearAlgorithms(this); - return result; - } - - [sym.pullSteps](): Promise<ReadableStreamReadResult<Uint8Array>> { - const stream = this[sym.controlledReadableByteStream]; - assert(readableStreamHasDefaultReader(stream)); - if (this[sym.queueTotalSize] > 0) { - assert(readableStreamGetNumReadRequests(stream) === 0); - const entry = this[sym.queue].shift(); - assert(entry); - this[sym.queueTotalSize] -= entry.size; - readableByteStreamControllerHandleQueueDrain(this); - const view = new Uint8Array(entry.value, entry.offset, entry.size); - return Promise.resolve( - readableStreamCreateReadResult( - view, - false, - stream[sym.reader]![sym.forAuthorCode], - ), - ); - } - // 3.11.5.2.5 If autoAllocateChunkSize is not undefined, - const promise = readableStreamAddReadRequest(stream); - readableByteStreamControllerCallPullIfNeeded(this); - return promise; - } - - [customInspect](): string { - return `${this.constructor.name} { byobRequest: ${ - String(this.byobRequest) - }, desiredSize: ${String(this.desiredSize)} }`; - } -} - -setFunctionName( - ReadableByteStreamControllerImpl, - "ReadableByteStreamController", -); diff --git a/cli/js/web/streams/readable_stream.ts b/cli/js/web/streams/readable_stream.ts deleted file mode 100644 index 086535bd2..000000000 --- a/cli/js/web/streams/readable_stream.ts +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - acquireReadableStreamDefaultReader, - initializeReadableStream, - isReadableStream, - isReadableStreamLocked, - isUnderlyingByteSource, - isWritableStream, - isWritableStreamLocked, - makeSizeAlgorithmFromSizeFunction, - setPromiseIsHandledToTrue, - readableStreamCancel, - ReadableStreamGenericReader, - readableStreamPipeTo, - readableStreamTee, - setUpReadableByteStreamControllerFromUnderlyingSource, - setUpReadableStreamDefaultControllerFromUnderlyingSource, - validateAndNormalizeHighWaterMark, -} from "./internals.ts"; -import type { ReadableByteStreamControllerImpl } from "./readable_byte_stream_controller.ts"; -import { ReadableStreamAsyncIteratorPrototype } from "./readable_stream_async_iterator.ts"; -import type { ReadableStreamDefaultControllerImpl } from "./readable_stream_default_controller.ts"; -import * as sym from "./symbols.ts"; -import { customInspect } from "../console.ts"; -import { AbortSignalImpl } from "../abort_signal.ts"; -import { setFunctionName } from "../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export class ReadableStreamImpl<R = any> implements ReadableStream<R> { - [sym.disturbed]: boolean; - [sym.readableStreamController]: - | ReadableStreamDefaultControllerImpl<R> - | ReadableByteStreamControllerImpl; - [sym.reader]: ReadableStreamGenericReader<R> | undefined; - [sym.state]: "readable" | "closed" | "errored"; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [sym.storedError]: any; - - constructor( - underlyingSource: UnderlyingByteSource | UnderlyingSource<R> = {}, - strategy: - | { - highWaterMark?: number; - size?: undefined; - } - | QueuingStrategy<R> = {}, - ) { - initializeReadableStream(this); - const { size } = strategy; - let { highWaterMark } = strategy; - const { type } = underlyingSource; - - if (isUnderlyingByteSource(underlyingSource)) { - if (size !== undefined) { - throw new RangeError( - `When underlying source is "bytes", strategy.size must be undefined.`, - ); - } - highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark ?? 0); - setUpReadableByteStreamControllerFromUnderlyingSource( - this, - underlyingSource, - highWaterMark, - ); - } else if (type === undefined) { - const sizeAlgorithm = makeSizeAlgorithmFromSizeFunction(size); - highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark ?? 1); - setUpReadableStreamDefaultControllerFromUnderlyingSource( - this, - underlyingSource, - highWaterMark, - sizeAlgorithm, - ); - } else { - throw new RangeError( - `Valid values for underlyingSource are "bytes" or undefined. Received: "${type}".`, - ); - } - } - - get locked(): boolean { - if (!isReadableStream(this)) { - throw new TypeError("Invalid ReadableStream."); - } - return isReadableStreamLocked(this); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - cancel(reason?: any): Promise<void> { - if (!isReadableStream(this)) { - return Promise.reject(new TypeError("Invalid ReadableStream.")); - } - if (isReadableStreamLocked(this)) { - return Promise.reject( - new TypeError("Cannot cancel a locked ReadableStream."), - ); - } - return readableStreamCancel(this, reason); - } - - getIterator({ - preventCancel, - }: { preventCancel?: boolean } = {}): AsyncIterableIterator<R> { - if (!isReadableStream(this)) { - throw new TypeError("Invalid ReadableStream."); - } - const reader = acquireReadableStreamDefaultReader(this); - const iterator = Object.create(ReadableStreamAsyncIteratorPrototype); - iterator[sym.asyncIteratorReader] = reader; - iterator[sym.preventCancel] = Boolean(preventCancel); - return iterator; - } - - getReader({ mode }: { mode?: string } = {}): ReadableStreamDefaultReader<R> { - if (!isReadableStream(this)) { - throw new TypeError("Invalid ReadableStream."); - } - if (mode === undefined) { - return acquireReadableStreamDefaultReader(this, true); - } - mode = String(mode); - // 3.2.5.4.4 If mode is "byob", return ? AcquireReadableStreamBYOBReader(this, true). - throw new RangeError(`Unsupported mode "${mode}"`); - } - - pipeThrough<T>( - { - writable, - readable, - }: { - writable: WritableStream<R>; - readable: ReadableStream<T>; - }, - { preventClose, preventAbort, preventCancel, signal }: PipeOptions = {}, - ): ReadableStream<T> { - if (!isReadableStream(this)) { - throw new TypeError("Invalid ReadableStream."); - } - if (!isWritableStream(writable)) { - throw new TypeError("writable is not a valid WritableStream."); - } - if (!isReadableStream(readable)) { - throw new TypeError("readable is not a valid ReadableStream."); - } - preventClose = Boolean(preventClose); - preventAbort = Boolean(preventAbort); - preventCancel = Boolean(preventCancel); - if (signal && !(signal instanceof AbortSignalImpl)) { - throw new TypeError("Invalid signal."); - } - if (isReadableStreamLocked(this)) { - throw new TypeError("ReadableStream is locked."); - } - if (isWritableStreamLocked(writable)) { - throw new TypeError("writable is locked."); - } - const promise = readableStreamPipeTo( - this, - writable, - preventClose, - preventAbort, - preventCancel, - signal, - ); - setPromiseIsHandledToTrue(promise); - return readable; - } - - pipeTo( - dest: WritableStream<R>, - { preventClose, preventAbort, preventCancel, signal }: PipeOptions = {}, - ): Promise<void> { - if (!isReadableStream(this)) { - return Promise.reject(new TypeError("Invalid ReadableStream.")); - } - if (!isWritableStream(dest)) { - return Promise.reject( - new TypeError("dest is not a valid WritableStream."), - ); - } - preventClose = Boolean(preventClose); - preventAbort = Boolean(preventAbort); - preventCancel = Boolean(preventCancel); - if (signal && !(signal instanceof AbortSignalImpl)) { - return Promise.reject(new TypeError("Invalid signal.")); - } - if (isReadableStreamLocked(this)) { - return Promise.reject(new TypeError("ReadableStream is locked.")); - } - if (isWritableStreamLocked(dest)) { - return Promise.reject(new TypeError("dest is locked.")); - } - return readableStreamPipeTo( - this, - dest, - preventClose, - preventAbort, - preventCancel, - signal, - ); - } - - tee(): [ReadableStreamImpl<R>, ReadableStreamImpl<R>] { - if (!isReadableStream(this)) { - throw new TypeError("Invalid ReadableStream."); - } - return readableStreamTee(this, false); - } - - [customInspect](): string { - return `${this.constructor.name} { locked: ${String(this.locked)} }`; - } - - [Symbol.asyncIterator]( - options: { - preventCancel?: boolean; - } = {}, - ): AsyncIterableIterator<R> { - return this.getIterator(options); - } -} - -setFunctionName(ReadableStreamImpl, "ReadableStream"); diff --git a/cli/js/web/streams/readable_stream_async_iterator.ts b/cli/js/web/streams/readable_stream_async_iterator.ts deleted file mode 100644 index c6b9759a5..000000000 --- a/cli/js/web/streams/readable_stream_async_iterator.ts +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import * as sym from "./symbols.ts"; -import { - isReadableStreamAsyncIterator, - ReadableStreamAsyncIterator, - readableStreamCreateReadResult, - readableStreamReaderGenericCancel, - readableStreamReaderGenericRelease, - readableStreamDefaultReaderRead, -} from "./internals.ts"; -import { assert } from "../../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const AsyncIteratorPrototype: AsyncIterableIterator<any> = Object - .getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype); - -export const ReadableStreamAsyncIteratorPrototype: ReadableStreamAsyncIterator = - Object.setPrototypeOf({ - next( - this: ReadableStreamAsyncIterator, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ): Promise<ReadableStreamReadResult<any>> { - if (!isReadableStreamAsyncIterator(this)) { - return Promise.reject( - new TypeError("invalid ReadableStreamAsyncIterator."), - ); - } - const reader = this[sym.asyncIteratorReader]; - if (!reader[sym.ownerReadableStream]) { - return Promise.reject( - new TypeError("reader owner ReadableStream is undefined."), - ); - } - return readableStreamDefaultReaderRead(reader).then((result) => { - assert(typeof result === "object"); - const { done } = result; - assert(typeof done === "boolean"); - if (done) { - readableStreamReaderGenericRelease(reader); - } - const { value } = result; - return readableStreamCreateReadResult(value, done, true); - }); - }, - return( - this: ReadableStreamAsyncIterator, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - value?: any | PromiseLike<any>, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ): Promise<ReadableStreamReadResult<any>> { - if (!isReadableStreamAsyncIterator(this)) { - return Promise.reject( - new TypeError("invalid ReadableStreamAsyncIterator."), - ); - } - const reader = this[sym.asyncIteratorReader]; - if (!reader[sym.ownerReadableStream]) { - return Promise.reject( - new TypeError("reader owner ReadableStream is undefined."), - ); - } - if (reader[sym.readRequests].length) { - return Promise.reject( - new TypeError("reader has outstanding read requests."), - ); - } - if (!this[sym.preventCancel]) { - const result = readableStreamReaderGenericCancel(reader, value); - readableStreamReaderGenericRelease(reader); - return result.then(() => - readableStreamCreateReadResult(value, true, true) - ); - } - readableStreamReaderGenericRelease(reader); - return Promise.resolve( - readableStreamCreateReadResult(value, true, true), - ); - }, - }, AsyncIteratorPrototype); diff --git a/cli/js/web/streams/readable_stream_default_controller.ts b/cli/js/web/streams/readable_stream_default_controller.ts deleted file mode 100644 index 8536712b9..000000000 --- a/cli/js/web/streams/readable_stream_default_controller.ts +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - CancelAlgorithm, - dequeueValue, - isReadableStreamDefaultController, - Pair, - PullAlgorithm, - readableStreamAddReadRequest, - readableStreamClose, - readableStreamCreateReadResult, - readableStreamDefaultControllerCallPullIfNeeded, - readableStreamDefaultControllerCanCloseOrEnqueue, - readableStreamDefaultControllerClearAlgorithms, - readableStreamDefaultControllerClose, - readableStreamDefaultControllerEnqueue, - readableStreamDefaultControllerError, - readableStreamDefaultControllerGetDesiredSize, - resetQueue, - SizeAlgorithm, -} from "./internals.ts"; -import type { ReadableStreamImpl } from "./readable_stream.ts"; -import * as sym from "./symbols.ts"; -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export class ReadableStreamDefaultControllerImpl<R = any> - implements ReadableStreamDefaultController<R> { - [sym.cancelAlgorithm]: CancelAlgorithm; - [sym.closeRequested]: boolean; - [sym.controlledReadableStream]: ReadableStreamImpl<R>; - [sym.pullAgain]: boolean; - [sym.pullAlgorithm]: PullAlgorithm; - [sym.pulling]: boolean; - [sym.queue]: Array<Pair<R>>; - [sym.queueTotalSize]: number; - [sym.started]: boolean; - [sym.strategyHWM]: number; - [sym.strategySizeAlgorithm]: SizeAlgorithm<R>; - - private constructor() { - throw new TypeError( - "ReadableStreamDefaultController's constructor cannot be called.", - ); - } - - get desiredSize(): number | null { - if (!isReadableStreamDefaultController(this)) { - throw new TypeError("Invalid ReadableStreamDefaultController."); - } - return readableStreamDefaultControllerGetDesiredSize(this); - } - - close(): void { - if (!isReadableStreamDefaultController(this)) { - throw new TypeError("Invalid ReadableStreamDefaultController."); - } - if (!readableStreamDefaultControllerCanCloseOrEnqueue(this)) { - throw new TypeError( - "ReadableStreamDefaultController cannot close or enqueue.", - ); - } - readableStreamDefaultControllerClose(this); - } - - enqueue(chunk: R): void { - if (!isReadableStreamDefaultController(this)) { - throw new TypeError("Invalid ReadableStreamDefaultController."); - } - if (!readableStreamDefaultControllerCanCloseOrEnqueue(this)) { - throw new TypeError("ReadableSteamController cannot enqueue."); - } - return readableStreamDefaultControllerEnqueue(this, chunk); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - error(error?: any): void { - if (!isReadableStreamDefaultController(this)) { - throw new TypeError("Invalid ReadableStreamDefaultController."); - } - readableStreamDefaultControllerError(this, error); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [sym.cancelSteps](reason?: any): PromiseLike<void> { - resetQueue(this); - const result = this[sym.cancelAlgorithm](reason); - readableStreamDefaultControllerClearAlgorithms(this); - return result; - } - - [sym.pullSteps](): Promise<ReadableStreamReadResult<R>> { - const stream = this[sym.controlledReadableStream]; - if (this[sym.queue].length) { - const chunk = dequeueValue<R>(this); - if (this[sym.closeRequested] && this[sym.queue].length === 0) { - readableStreamDefaultControllerClearAlgorithms(this); - readableStreamClose(stream); - } else { - readableStreamDefaultControllerCallPullIfNeeded(this); - } - return Promise.resolve( - readableStreamCreateReadResult( - chunk, - false, - stream[sym.reader]![sym.forAuthorCode], - ), - ); - } - const pendingPromise = readableStreamAddReadRequest(stream); - readableStreamDefaultControllerCallPullIfNeeded(this); - return pendingPromise; - } - - [customInspect](): string { - return `${this.constructor.name} { desiredSize: ${ - String(this.desiredSize) - } }`; - } -} - -setFunctionName( - ReadableStreamDefaultControllerImpl, - "ReadableStreamDefaultController", -); diff --git a/cli/js/web/streams/readable_stream_default_reader.ts b/cli/js/web/streams/readable_stream_default_reader.ts deleted file mode 100644 index 88260effb..000000000 --- a/cli/js/web/streams/readable_stream_default_reader.ts +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - Deferred, - isReadableStream, - isReadableStreamDefaultReader, - isReadableStreamLocked, - readableStreamDefaultReaderRead, - readableStreamReaderGenericCancel, - readableStreamReaderGenericInitialize, - readableStreamReaderGenericRelease, -} from "./internals.ts"; -import type { ReadableStreamImpl } from "./readable_stream.ts"; -import * as sym from "./symbols.ts"; -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export class ReadableStreamDefaultReaderImpl<R = any> - implements ReadableStreamDefaultReader<R> { - [sym.closedPromise]: Deferred<void>; - [sym.forAuthorCode]: boolean; - [sym.ownerReadableStream]: ReadableStreamImpl<R>; - [sym.readRequests]: Array<Deferred<ReadableStreamReadResult<R>>>; - - constructor(stream: ReadableStream<R>) { - if (!isReadableStream(stream)) { - throw new TypeError("stream is not a ReadableStream."); - } - if (isReadableStreamLocked(stream)) { - throw new TypeError("stream is locked."); - } - readableStreamReaderGenericInitialize(this, stream); - this[sym.readRequests] = []; - } - - get closed(): Promise<void> { - if (!isReadableStreamDefaultReader(this)) { - return Promise.reject( - new TypeError("Invalid ReadableStreamDefaultReader."), - ); - } - return ( - this[sym.closedPromise].promise ?? - Promise.reject(new TypeError("Invalid reader.")) - ); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - cancel(reason?: any): Promise<void> { - if (!isReadableStreamDefaultReader(this)) { - return Promise.reject( - new TypeError("Invalid ReadableStreamDefaultReader."), - ); - } - if (!this[sym.ownerReadableStream]) { - return Promise.reject(new TypeError("Invalid reader.")); - } - return readableStreamReaderGenericCancel(this, reason); - } - - read(): Promise<ReadableStreamReadResult<R>> { - if (!isReadableStreamDefaultReader(this)) { - return Promise.reject( - new TypeError("Invalid ReadableStreamDefaultReader."), - ); - } - if (!this[sym.ownerReadableStream]) { - return Promise.reject(new TypeError("Invalid reader.")); - } - return readableStreamDefaultReaderRead(this); - } - - releaseLock(): void { - if (!isReadableStreamDefaultReader(this)) { - throw new TypeError("Invalid ReadableStreamDefaultReader."); - } - if (this[sym.ownerReadableStream] === undefined) { - return; - } - if (this[sym.readRequests].length) { - throw new TypeError("Cannot release lock with pending read requests."); - } - readableStreamReaderGenericRelease(this); - } - - [customInspect](): string { - return `${this.constructor.name} { closed: Promise }`; - } -} - -setFunctionName(ReadableStreamDefaultReaderImpl, "ReadableStreamDefaultReader"); diff --git a/cli/js/web/streams/symbols.ts b/cli/js/web/streams/symbols.ts deleted file mode 100644 index 82d668598..000000000 --- a/cli/js/web/streams/symbols.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// The specification refers to internal slots. In most cases, ECMAScript -// Private Fields are not sufficient for these, as they are often accessed -// outside of the class itself and using a WeakMap gets really complex to hide -// this data from the public, therefore we will use unique symbols which are -// not available in the runtime. - -export const abortAlgorithm = Symbol("abortAlgorithm"); -export const abortSteps = Symbol("abortSteps"); -export const asyncIteratorReader = Symbol("asyncIteratorReader"); -export const autoAllocateChunkSize = Symbol("autoAllocateChunkSize"); -export const backpressure = Symbol("backpressure"); -export const backpressureChangePromise = Symbol("backpressureChangePromise"); -export const byobRequest = Symbol("byobRequest"); -export const cancelAlgorithm = Symbol("cancelAlgorithm"); -export const cancelSteps = Symbol("cancelSteps"); -export const closeAlgorithm = Symbol("closeAlgorithm"); -export const closedPromise = Symbol("closedPromise"); -export const closeRequest = Symbol("closeRequest"); -export const closeRequested = Symbol("closeRequested"); -export const controlledReadableByteStream = Symbol( - "controlledReadableByteStream", -); -export const controlledReadableStream = Symbol("controlledReadableStream"); -export const controlledTransformStream = Symbol("controlledTransformStream"); -export const controlledWritableStream = Symbol("controlledWritableStream"); -export const disturbed = Symbol("disturbed"); -export const errorSteps = Symbol("errorSteps"); -export const flushAlgorithm = Symbol("flushAlgorithm"); -export const forAuthorCode = Symbol("forAuthorCode"); -export const inFlightWriteRequest = Symbol("inFlightWriteRequest"); -export const inFlightCloseRequest = Symbol("inFlightCloseRequest"); -export const isFakeDetached = Symbol("isFakeDetached"); -export const ownerReadableStream = Symbol("ownerReadableStream"); -export const ownerWritableStream = Symbol("ownerWritableStream"); -export const pendingAbortRequest = Symbol("pendingAbortRequest"); -export const preventCancel = Symbol("preventCancel"); -export const pullAgain = Symbol("pullAgain"); -export const pullAlgorithm = Symbol("pullAlgorithm"); -export const pulling = Symbol("pulling"); -export const pullSteps = Symbol("pullSteps"); -export const queue = Symbol("queue"); -export const queueTotalSize = Symbol("queueTotalSize"); -export const readable = Symbol("readable"); -export const readableStreamController = Symbol("readableStreamController"); -export const reader = Symbol("reader"); -export const readRequests = Symbol("readRequests"); -export const readyPromise = Symbol("readyPromise"); -export const started = Symbol("started"); -export const state = Symbol("state"); -export const storedError = Symbol("storedError"); -export const strategyHWM = Symbol("strategyHWM"); -export const strategySizeAlgorithm = Symbol("strategySizeAlgorithm"); -export const transformAlgorithm = Symbol("transformAlgorithm"); -export const transformStreamController = Symbol("transformStreamController"); -export const writableStreamController = Symbol("writableStreamController"); -export const writeAlgorithm = Symbol("writeAlgorithm"); -export const writable = Symbol("writable"); -export const writer = Symbol("writer"); -export const writeRequests = Symbol("writeRequests"); diff --git a/cli/js/web/streams/transform_stream.ts b/cli/js/web/streams/transform_stream.ts deleted file mode 100644 index f6924aead..000000000 --- a/cli/js/web/streams/transform_stream.ts +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - Deferred, - getDeferred, - initializeTransformStream, - invokeOrNoop, - isTransformStream, - makeSizeAlgorithmFromSizeFunction, - setUpTransformStreamDefaultControllerFromTransformer, - validateAndNormalizeHighWaterMark, -} from "./internals.ts"; -import type { ReadableStreamImpl } from "./readable_stream.ts"; -import * as sym from "./symbols.ts"; -import type { TransformStreamDefaultControllerImpl } from "./transform_stream_default_controller.ts"; -import type { WritableStreamImpl } from "./writable_stream.ts"; -import { customInspect, inspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export class TransformStreamImpl<I = any, O = any> - implements TransformStream<I, O> { - [sym.backpressure]?: boolean; - [sym.backpressureChangePromise]?: Deferred<void>; - [sym.readable]: ReadableStreamImpl<O>; - [sym.transformStreamController]: TransformStreamDefaultControllerImpl<I, O>; - [sym.writable]: WritableStreamImpl<I>; - - constructor( - transformer: Transformer<I, O> = {}, - writableStrategy: QueuingStrategy<I> = {}, - readableStrategy: QueuingStrategy<O> = {}, - ) { - const writableSizeFunction = writableStrategy.size; - let writableHighWaterMark = writableStrategy.highWaterMark; - const readableSizeFunction = readableStrategy.size; - let readableHighWaterMark = readableStrategy.highWaterMark; - const writableType = transformer.writableType; - if (writableType !== undefined) { - throw new RangeError( - `Expected transformer writableType to be undefined, received "${ - String(writableType) - }"`, - ); - } - const writableSizeAlgorithm = makeSizeAlgorithmFromSizeFunction( - writableSizeFunction, - ); - if (writableHighWaterMark === undefined) { - writableHighWaterMark = 1; - } - writableHighWaterMark = validateAndNormalizeHighWaterMark( - writableHighWaterMark, - ); - const readableType = transformer.readableType; - if (readableType !== undefined) { - throw new RangeError( - `Expected transformer readableType to be undefined, received "${ - String(readableType) - }"`, - ); - } - const readableSizeAlgorithm = makeSizeAlgorithmFromSizeFunction( - readableSizeFunction, - ); - if (readableHighWaterMark === undefined) { - readableHighWaterMark = 1; - } - readableHighWaterMark = validateAndNormalizeHighWaterMark( - readableHighWaterMark, - ); - const startPromise = getDeferred<void>(); - initializeTransformStream( - this, - startPromise.promise, - writableHighWaterMark, - writableSizeAlgorithm, - readableHighWaterMark, - readableSizeAlgorithm, - ); - // the brand check expects this, and the brand check occurs in the following - // but the property hasn't been defined. - Object.defineProperty(this, sym.transformStreamController, { - value: undefined, - writable: true, - configurable: true, - }); - setUpTransformStreamDefaultControllerFromTransformer(this, transformer); - const startResult: void | PromiseLike<void> = invokeOrNoop( - transformer, - "start", - this[sym.transformStreamController], - ); - startPromise.resolve(startResult); - } - - get readable(): ReadableStream<O> { - if (!isTransformStream(this)) { - throw new TypeError("Invalid TransformStream."); - } - return this[sym.readable]; - } - - get writable(): WritableStream<I> { - if (!isTransformStream(this)) { - throw new TypeError("Invalid TransformStream."); - } - return this[sym.writable]; - } - - [customInspect](): string { - return `${this.constructor.name} {\n readable: ${ - inspect(this.readable) - }\n writable: ${inspect(this.writable)}\n}`; - } -} - -setFunctionName(TransformStreamImpl, "TransformStream"); diff --git a/cli/js/web/streams/transform_stream_default_controller.ts b/cli/js/web/streams/transform_stream_default_controller.ts deleted file mode 100644 index 54f1e9f2d..000000000 --- a/cli/js/web/streams/transform_stream_default_controller.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - FlushAlgorithm, - isTransformStreamDefaultController, - readableStreamDefaultControllerGetDesiredSize, - TransformAlgorithm, - transformStreamDefaultControllerEnqueue, - transformStreamDefaultControllerError, - transformStreamDefaultControllerTerminate, -} from "./internals.ts"; -import type { ReadableStreamDefaultControllerImpl } from "./readable_stream_default_controller.ts"; -import * as sym from "./symbols.ts"; -import type { TransformStreamImpl } from "./transform_stream.ts"; -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export class TransformStreamDefaultControllerImpl<I = any, O = any> - implements TransformStreamDefaultController<O> { - [sym.controlledTransformStream]: TransformStreamImpl<I, O>; - [sym.flushAlgorithm]: FlushAlgorithm; - [sym.transformAlgorithm]: TransformAlgorithm<I>; - - private constructor() { - throw new TypeError( - "TransformStreamDefaultController's constructor cannot be called.", - ); - } - - get desiredSize(): number | null { - if (!isTransformStreamDefaultController(this)) { - throw new TypeError("Invalid TransformStreamDefaultController."); - } - const readableController = this[sym.controlledTransformStream][ - sym.readable - ][sym.readableStreamController]; - return readableStreamDefaultControllerGetDesiredSize( - readableController as ReadableStreamDefaultControllerImpl<O>, - ); - } - - enqueue(chunk: O): void { - if (!isTransformStreamDefaultController(this)) { - throw new TypeError("Invalid TransformStreamDefaultController."); - } - transformStreamDefaultControllerEnqueue(this, chunk); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - error(reason?: any): void { - if (!isTransformStreamDefaultController(this)) { - throw new TypeError("Invalid TransformStreamDefaultController."); - } - transformStreamDefaultControllerError(this, reason); - } - - terminate(): void { - if (!isTransformStreamDefaultController(this)) { - throw new TypeError("Invalid TransformStreamDefaultController."); - } - transformStreamDefaultControllerTerminate(this); - } - - [customInspect](): string { - return `${this.constructor.name} { desiredSize: ${ - String(this.desiredSize) - } }`; - } -} - -setFunctionName( - TransformStreamDefaultControllerImpl, - "TransformStreamDefaultController", -); diff --git a/cli/js/web/streams/writable_stream.ts b/cli/js/web/streams/writable_stream.ts deleted file mode 100644 index 94bedb941..000000000 --- a/cli/js/web/streams/writable_stream.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - AbortRequest, - acquireWritableStreamDefaultWriter, - Deferred, - initializeWritableStream, - isWritableStream, - isWritableStreamLocked, - makeSizeAlgorithmFromSizeFunction, - setUpWritableStreamDefaultControllerFromUnderlyingSink, - writableStreamAbort, - writableStreamClose, - writableStreamCloseQueuedOrInFlight, - validateAndNormalizeHighWaterMark, -} from "./internals.ts"; -import * as sym from "./symbols.ts"; -import type { WritableStreamDefaultControllerImpl } from "./writable_stream_default_controller.ts"; -import type { WritableStreamDefaultWriterImpl } from "./writable_stream_default_writer.ts"; -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export class WritableStreamImpl<W = any> implements WritableStream<W> { - [sym.backpressure]: boolean; - [sym.closeRequest]?: Deferred<void>; - [sym.inFlightWriteRequest]?: Required<Deferred<void>>; - [sym.inFlightCloseRequest]?: Deferred<void>; - [sym.pendingAbortRequest]?: AbortRequest; - [sym.state]: "writable" | "closed" | "erroring" | "errored"; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [sym.storedError]?: any; - [sym.writableStreamController]?: WritableStreamDefaultControllerImpl<W>; - [sym.writer]?: WritableStreamDefaultWriterImpl<W>; - [sym.writeRequests]: Array<Required<Deferred<void>>>; - - constructor( - underlyingSink: UnderlyingSink = {}, - strategy: QueuingStrategy = {}, - ) { - initializeWritableStream(this); - const size = strategy.size; - let highWaterMark = strategy.highWaterMark ?? 1; - const { type } = underlyingSink; - if (type !== undefined) { - throw new RangeError(`Sink type of "${String(type)}" not supported.`); - } - const sizeAlgorithm = makeSizeAlgorithmFromSizeFunction(size); - highWaterMark = validateAndNormalizeHighWaterMark(highWaterMark); - setUpWritableStreamDefaultControllerFromUnderlyingSink( - this, - underlyingSink, - highWaterMark, - sizeAlgorithm, - ); - } - - get locked(): boolean { - if (!isWritableStream(this)) { - throw new TypeError("Invalid WritableStream."); - } - return isWritableStreamLocked(this); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - abort(reason: any): Promise<void> { - if (!isWritableStream(this)) { - return Promise.reject(new TypeError("Invalid WritableStream.")); - } - if (isWritableStreamLocked(this)) { - return Promise.reject( - new TypeError("Cannot abort a locked WritableStream."), - ); - } - return writableStreamAbort(this, reason); - } - - close(): Promise<void> { - if (!isWritableStream(this)) { - return Promise.reject(new TypeError("Invalid WritableStream.")); - } - if (isWritableStreamLocked(this)) { - return Promise.reject( - new TypeError("Cannot abort a locked WritableStream."), - ); - } - if (writableStreamCloseQueuedOrInFlight(this)) { - return Promise.reject( - new TypeError("Cannot close an already closing WritableStream."), - ); - } - return writableStreamClose(this); - } - - getWriter(): WritableStreamDefaultWriter<W> { - if (!isWritableStream(this)) { - throw new TypeError("Invalid WritableStream."); - } - return acquireWritableStreamDefaultWriter(this); - } - - [customInspect](): string { - return `${this.constructor.name} { locked: ${String(this.locked)} }`; - } -} - -setFunctionName(WritableStreamImpl, "WritableStream"); diff --git a/cli/js/web/streams/writable_stream_default_controller.ts b/cli/js/web/streams/writable_stream_default_controller.ts deleted file mode 100644 index 960060b8f..000000000 --- a/cli/js/web/streams/writable_stream_default_controller.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - AbortAlgorithm, - CloseAlgorithm, - isWritableStreamDefaultController, - Pair, - resetQueue, - SizeAlgorithm, - WriteAlgorithm, - writableStreamDefaultControllerClearAlgorithms, - writableStreamDefaultControllerError, -} from "./internals.ts"; -import * as sym from "./symbols.ts"; -import type { WritableStreamImpl } from "./writable_stream.ts"; -import { customInspect } from "../console.ts"; -import { setFunctionName } from "../util.ts"; - -export class WritableStreamDefaultControllerImpl<W> - implements WritableStreamDefaultController { - [sym.abortAlgorithm]: AbortAlgorithm; - [sym.closeAlgorithm]: CloseAlgorithm; - [sym.controlledWritableStream]: WritableStreamImpl; - [sym.queue]: Array<Pair<{ chunk: W } | "close">>; - [sym.queueTotalSize]: number; - [sym.started]: boolean; - [sym.strategyHWM]: number; - [sym.strategySizeAlgorithm]: SizeAlgorithm<W>; - [sym.writeAlgorithm]: WriteAlgorithm<W>; - - private constructor() { - throw new TypeError( - "WritableStreamDefaultController's constructor cannot be called.", - ); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - error(e: any): void { - if (!isWritableStreamDefaultController(this)) { - throw new TypeError("Invalid WritableStreamDefaultController."); - } - const state = this[sym.controlledWritableStream][sym.state]; - if (state !== "writable") { - return; - } - writableStreamDefaultControllerError(this, e); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [sym.abortSteps](reason: any): PromiseLike<void> { - const result = this[sym.abortAlgorithm](reason); - writableStreamDefaultControllerClearAlgorithms(this); - return result; - } - - [sym.errorSteps](): void { - resetQueue(this); - } - - [customInspect](): string { - return `${this.constructor.name} { }`; - } -} - -setFunctionName( - WritableStreamDefaultControllerImpl, - "WritableStreamDefaultController", -); diff --git a/cli/js/web/streams/writable_stream_default_writer.ts b/cli/js/web/streams/writable_stream_default_writer.ts deleted file mode 100644 index 34e664e95..000000000 --- a/cli/js/web/streams/writable_stream_default_writer.ts +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { - Deferred, - getDeferred, - isWritableStream, - isWritableStreamDefaultWriter, - isWritableStreamLocked, - setPromiseIsHandledToTrue, - writableStreamCloseQueuedOrInFlight, - writableStreamDefaultWriterAbort, - writableStreamDefaultWriterClose, - writableStreamDefaultWriterGetDesiredSize, - writableStreamDefaultWriterRelease, - writableStreamDefaultWriterWrite, -} from "./internals.ts"; -import * as sym from "./symbols.ts"; -import type { WritableStreamImpl } from "./writable_stream.ts"; -import { customInspect } from "../console.ts"; -import { assert } from "../../util.ts"; -import { setFunctionName } from "../util.ts"; - -export class WritableStreamDefaultWriterImpl<W> - implements WritableStreamDefaultWriter<W> { - [sym.closedPromise]: Deferred<void>; - [sym.ownerWritableStream]: WritableStreamImpl<W>; - [sym.readyPromise]: Deferred<void>; - - constructor(stream: WritableStreamImpl<W>) { - if (!isWritableStream(stream)) { - throw new TypeError("Invalid stream."); - } - if (isWritableStreamLocked(stream)) { - throw new TypeError("Cannot create a writer for a locked stream."); - } - this[sym.ownerWritableStream] = stream; - stream[sym.writer] = this; - const state = stream[sym.state]; - if (state === "writable") { - if ( - !writableStreamCloseQueuedOrInFlight(stream) && - stream[sym.backpressure] - ) { - this[sym.readyPromise] = getDeferred(); - } else { - this[sym.readyPromise] = { promise: Promise.resolve() }; - } - this[sym.closedPromise] = getDeferred(); - } else if (state === "erroring") { - this[sym.readyPromise] = { - promise: Promise.reject(stream[sym.storedError]), - }; - setPromiseIsHandledToTrue(this[sym.readyPromise].promise); - this[sym.closedPromise] = getDeferred(); - } else if (state === "closed") { - this[sym.readyPromise] = { promise: Promise.resolve() }; - this[sym.closedPromise] = { promise: Promise.resolve() }; - } else { - assert(state === "errored"); - const storedError = stream[sym.storedError]; - this[sym.readyPromise] = { promise: Promise.reject(storedError) }; - setPromiseIsHandledToTrue(this[sym.readyPromise].promise); - this[sym.closedPromise] = { promise: Promise.reject(storedError) }; - setPromiseIsHandledToTrue(this[sym.closedPromise].promise); - } - } - - get closed(): Promise<void> { - if (!isWritableStreamDefaultWriter(this)) { - return Promise.reject( - new TypeError("Invalid WritableStreamDefaultWriter."), - ); - } - return this[sym.closedPromise].promise; - } - - get desiredSize(): number | null { - if (!isWritableStreamDefaultWriter(this)) { - throw new TypeError("Invalid WritableStreamDefaultWriter."); - } - if (!this[sym.ownerWritableStream]) { - throw new TypeError("WritableStreamDefaultWriter has no owner."); - } - return writableStreamDefaultWriterGetDesiredSize(this); - } - - get ready(): Promise<void> { - if (!isWritableStreamDefaultWriter(this)) { - return Promise.reject( - new TypeError("Invalid WritableStreamDefaultWriter."), - ); - } - return this[sym.readyPromise].promise; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - abort(reason: any): Promise<void> { - if (!isWritableStreamDefaultWriter(this)) { - return Promise.reject( - new TypeError("Invalid WritableStreamDefaultWriter."), - ); - } - if (!this[sym.ownerWritableStream]) { - Promise.reject( - new TypeError("WritableStreamDefaultWriter has no owner."), - ); - } - return writableStreamDefaultWriterAbort(this, reason); - } - - close(): Promise<void> { - if (!isWritableStreamDefaultWriter(this)) { - return Promise.reject( - new TypeError("Invalid WritableStreamDefaultWriter."), - ); - } - const stream = this[sym.ownerWritableStream]; - if (!stream) { - Promise.reject( - new TypeError("WritableStreamDefaultWriter has no owner."), - ); - } - if (writableStreamCloseQueuedOrInFlight(stream)) { - Promise.reject( - new TypeError("Stream is in an invalid state to be closed."), - ); - } - return writableStreamDefaultWriterClose(this); - } - - releaseLock(): void { - if (!isWritableStreamDefaultWriter(this)) { - throw new TypeError("Invalid WritableStreamDefaultWriter."); - } - const stream = this[sym.ownerWritableStream]; - if (!stream) { - return; - } - assert(stream[sym.writer]); - writableStreamDefaultWriterRelease(this); - } - - write(chunk: W): Promise<void> { - if (!isWritableStreamDefaultWriter(this)) { - return Promise.reject( - new TypeError("Invalid WritableStreamDefaultWriter."), - ); - } - if (!this[sym.ownerWritableStream]) { - Promise.reject( - new TypeError("WritableStreamDefaultWriter has no owner."), - ); - } - return writableStreamDefaultWriterWrite(this, chunk); - } - - [customInspect](): string { - return `${this.constructor.name} { closed: Promise, desiredSize: ${ - String(this.desiredSize) - }, ready: Promise }`; - } -} - -setFunctionName(WritableStreamDefaultWriterImpl, "WritableStreamDefaultWriter"); diff --git a/cli/js/web/text_encoding.ts b/cli/js/web/text_encoding.ts deleted file mode 100644 index 97848cb77..000000000 --- a/cli/js/web/text_encoding.ts +++ /dev/null @@ -1,581 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// The following code is based off of text-encoding at: -// https://github.com/inexorabletash/text-encoding -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -import { DOMExceptionImpl as DOMException } from "./dom_exception.ts"; -import * as base64 from "./base64.ts"; -import { decodeUtf8 } from "./decode_utf8.ts"; -import { core } from "../core.ts"; - -const CONTINUE = null; -const END_OF_STREAM = -1; -const FINISHED = -1; - -function decoderError(fatal: boolean): number | never { - if (fatal) { - throw new TypeError("Decoder error."); - } - return 0xfffd; // default code point -} - -function inRange(a: number, min: number, max: number): boolean { - return min <= a && a <= max; -} - -function isASCIIByte(a: number): boolean { - return inRange(a, 0x00, 0x7f); -} - -function stringToCodePoints(input: string): number[] { - const u: number[] = []; - for (const c of input) { - u.push(c.codePointAt(0)!); - } - return u; -} - -class UTF8Encoder implements Encoder { - handler(codePoint: number): "finished" | number[] { - if (codePoint === END_OF_STREAM) { - return "finished"; - } - - if (inRange(codePoint, 0x00, 0x7f)) { - return [codePoint]; - } - - let count: number; - let offset: number; - if (inRange(codePoint, 0x0080, 0x07ff)) { - count = 1; - offset = 0xc0; - } else if (inRange(codePoint, 0x0800, 0xffff)) { - count = 2; - offset = 0xe0; - } else if (inRange(codePoint, 0x10000, 0x10ffff)) { - count = 3; - offset = 0xf0; - } else { - throw TypeError(`Code point out of range: \\x${codePoint.toString(16)}`); - } - - const bytes = [(codePoint >> (6 * count)) + offset]; - - while (count > 0) { - const temp = codePoint >> (6 * (count - 1)); - bytes.push(0x80 | (temp & 0x3f)); - count--; - } - - return bytes; - } -} - -export function atob(s: string): string { - s = String(s); - s = s.replace(/[\t\n\f\r ]/g, ""); - - if (s.length % 4 === 0) { - s = s.replace(/==?$/, ""); - } - - const rem = s.length % 4; - if (rem === 1 || /[^+/0-9A-Za-z]/.test(s)) { - throw new DOMException( - "The string to be decoded is not correctly encoded", - "DataDecodeError", - ); - } - - // base64-js requires length exactly times of 4 - if (rem > 0) { - s = s.padEnd(s.length + (4 - rem), "="); - } - - const byteArray: Uint8Array = base64.toByteArray(s); - let result = ""; - for (let i = 0; i < byteArray.length; i++) { - result += String.fromCharCode(byteArray[i]); - } - return result; -} - -export function btoa(s: string): string { - const byteArray = []; - for (let i = 0; i < s.length; i++) { - const charCode = s[i].charCodeAt(0); - if (charCode > 0xff) { - throw new TypeError( - "The string to be encoded contains characters " + - "outside of the Latin1 range.", - ); - } - byteArray.push(charCode); - } - const result = base64.fromByteArray(Uint8Array.from(byteArray)); - return result; -} - -interface DecoderOptions { - fatal?: boolean; - ignoreBOM?: boolean; -} - -interface Decoder { - handler(stream: Stream, byte: number): number | null; -} - -interface Encoder { - handler(codePoint: number): "finished" | number[]; -} - -class SingleByteDecoder implements Decoder { - readonly #index: number[]; - readonly #fatal: boolean; - - constructor( - index: number[], - { ignoreBOM = false, fatal = false }: DecoderOptions = {}, - ) { - if (ignoreBOM) { - throw new TypeError("Ignoring the BOM is available only with utf-8."); - } - this.#fatal = fatal; - this.#index = index; - } - handler(_stream: Stream, byte: number): number { - if (byte === END_OF_STREAM) { - return FINISHED; - } - if (isASCIIByte(byte)) { - return byte; - } - const codePoint = this.#index[byte - 0x80]; - - if (codePoint == null) { - return decoderError(this.#fatal); - } - - return codePoint; - } -} - -// The encodingMap is a hash of labels that are indexed by the conical -// encoding. -const encodingMap: { [key: string]: string[] } = { - "windows-1252": [ - "ansi_x3.4-1968", - "ascii", - "cp1252", - "cp819", - "csisolatin1", - "ibm819", - "iso-8859-1", - "iso-ir-100", - "iso8859-1", - "iso88591", - "iso_8859-1", - "iso_8859-1:1987", - "l1", - "latin1", - "us-ascii", - "windows-1252", - "x-cp1252", - ], - "utf-8": ["unicode-1-1-utf-8", "utf-8", "utf8"], -}; -// We convert these into a Map where every label resolves to its canonical -// encoding type. -const encodings = new Map<string, string>(); -for (const key of Object.keys(encodingMap)) { - const labels = encodingMap[key]; - for (const label of labels) { - encodings.set(label, key); - } -} - -// A map of functions that return new instances of a decoder indexed by the -// encoding type. -const decoders = new Map<string, (options: DecoderOptions) => Decoder>(); - -// Single byte decoders are an array of code point lookups -const encodingIndexes = new Map<string, number[]>(); -// deno-fmt-ignore -encodingIndexes.set("windows-1252", [ - 8364, - 129, - 8218, - 402, - 8222, - 8230, - 8224, - 8225, - 710, - 8240, - 352, - 8249, - 338, - 141, - 381, - 143, - 144, - 8216, - 8217, - 8220, - 8221, - 8226, - 8211, - 8212, - 732, - 8482, - 353, - 8250, - 339, - 157, - 382, - 376, - 160, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 219, - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 251, - 252, - 253, - 254, - 255, -]); -for (const [key, index] of encodingIndexes) { - decoders.set( - key, - (options: DecoderOptions): SingleByteDecoder => { - return new SingleByteDecoder(index, options); - }, - ); -} - -function codePointsToString(codePoints: number[]): string { - let s = ""; - for (const cp of codePoints) { - s += String.fromCodePoint(cp); - } - return s; -} - -class Stream { - #tokens: number[]; - constructor(tokens: number[] | Uint8Array) { - this.#tokens = [...tokens]; - this.#tokens.reverse(); - } - - endOfStream(): boolean { - return !this.#tokens.length; - } - - read(): number { - return !this.#tokens.length ? END_OF_STREAM : this.#tokens.pop()!; - } - - prepend(token: number | number[]): void { - if (Array.isArray(token)) { - while (token.length) { - this.#tokens.push(token.pop()!); - } - } else { - this.#tokens.push(token); - } - } - - push(token: number | number[]): void { - if (Array.isArray(token)) { - while (token.length) { - this.#tokens.unshift(token.shift()!); - } - } else { - this.#tokens.unshift(token); - } - } -} - -export interface TextDecodeOptions { - stream?: false; -} - -export interface TextDecoderOptions { - fatal?: boolean; - ignoreBOM?: boolean; -} - -type EitherArrayBuffer = SharedArrayBuffer | ArrayBuffer; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isEitherArrayBuffer(x: any): x is EitherArrayBuffer { - return x instanceof SharedArrayBuffer || x instanceof ArrayBuffer; -} - -export class TextDecoder { - readonly #encoding: string; - - get encoding(): string { - return this.#encoding; - } - readonly fatal: boolean = false; - readonly ignoreBOM: boolean = false; - - constructor(label = "utf-8", options: TextDecoderOptions = { fatal: false }) { - if (options.ignoreBOM) { - this.ignoreBOM = true; - } - if (options.fatal) { - this.fatal = true; - } - label = String(label).trim().toLowerCase(); - const encoding = encodings.get(label); - if (!encoding) { - throw new RangeError( - `The encoding label provided ('${label}') is invalid.`, - ); - } - if (!decoders.has(encoding) && encoding !== "utf-8") { - throw new TypeError(`Internal decoder ('${encoding}') not found.`); - } - this.#encoding = encoding; - } - - decode( - input?: BufferSource, - options: TextDecodeOptions = { stream: false }, - ): string { - if (options.stream) { - throw new TypeError("Stream not supported."); - } - - let bytes: Uint8Array; - if (input instanceof Uint8Array) { - bytes = input; - } else if (isEitherArrayBuffer(input)) { - bytes = new Uint8Array(input); - } else if ( - typeof input === "object" && - "buffer" in input && - isEitherArrayBuffer(input.buffer) - ) { - bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength); - } else { - bytes = new Uint8Array(0); - } - - // For simple utf-8 decoding "Deno.core.decode" can be used for performance - if ( - this.#encoding === "utf-8" && - this.fatal === false && - this.ignoreBOM === false - ) { - return core.decode(bytes); - } - - // For performance reasons we utilise a highly optimised decoder instead of - // the general decoder. - if (this.#encoding === "utf-8") { - return decodeUtf8(bytes, this.fatal, this.ignoreBOM); - } - - const decoder = decoders.get(this.#encoding)!({ - fatal: this.fatal, - ignoreBOM: this.ignoreBOM, - }); - const inputStream = new Stream(bytes); - const output: number[] = []; - - while (true) { - const result = decoder.handler(inputStream, inputStream.read()); - if (result === FINISHED) { - break; - } - - if (result !== CONTINUE) { - output.push(result); - } - } - - if (output.length > 0 && output[0] === 0xfeff) { - output.shift(); - } - - return codePointsToString(output); - } - - get [Symbol.toStringTag](): string { - return "TextDecoder"; - } -} - -interface TextEncoderEncodeIntoResult { - read: number; - written: number; -} - -export class TextEncoder { - readonly encoding = "utf-8"; - encode(input = ""): Uint8Array { - // Deno.core.encode() provides very efficient utf-8 encoding - if (this.encoding === "utf-8") { - return core.encode(input); - } - - const encoder = new UTF8Encoder(); - const inputStream = new Stream(stringToCodePoints(input)); - const output: number[] = []; - - while (true) { - const result = encoder.handler(inputStream.read()); - if (result === "finished") { - break; - } - output.push(...result); - } - - return new Uint8Array(output); - } - encodeInto(input: string, dest: Uint8Array): TextEncoderEncodeIntoResult { - const encoder = new UTF8Encoder(); - const inputStream = new Stream(stringToCodePoints(input)); - - let written = 0; - let read = 0; - while (true) { - const result = encoder.handler(inputStream.read()); - if (result === "finished") { - break; - } - if (dest.length - written >= result.length) { - read++; - dest.set(result, written); - written += result.length; - if (result.length > 3) { - // increment read a second time if greater than U+FFFF - read++; - } - } else { - break; - } - } - - return { - read, - written, - }; - } - get [Symbol.toStringTag](): string { - return "TextEncoder"; - } -} diff --git a/cli/js/web/timers.ts b/cli/js/web/timers.ts deleted file mode 100644 index 71aef5f85..000000000 --- a/cli/js/web/timers.ts +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { assert } from "../util.ts"; -import { startGlobalTimer, stopGlobalTimer } from "../ops/timers.ts"; -import { RBTree } from "../rbtree.ts"; - -const { console } = globalThis; -const OriginalDate = Date; - -interface Timer { - id: number; - callback: () => void; - delay: number; - due: number; - repeat: boolean; - scheduled: boolean; -} - -// Timeout values > TIMEOUT_MAX are set to 1. -const TIMEOUT_MAX = 2 ** 31 - 1; - -let globalTimeoutDue: number | null = null; - -let nextTimerId = 1; -const idMap = new Map<number, Timer>(); -type DueNode = { due: number; timers: Timer[] }; -const dueTree = new RBTree<DueNode>((a, b) => a.due - b.due); - -function clearGlobalTimeout(): void { - globalTimeoutDue = null; - stopGlobalTimer(); -} - -let pendingEvents = 0; -const pendingFireTimers: Timer[] = []; - -/** Process and run a single ready timer macrotask. - * This function should be registered through Deno.core.setMacrotaskCallback. - * Returns true when all ready macrotasks have been processed, false if more - * ready ones are available. The Isolate future would rely on the return value - * to repeatedly invoke this function until depletion. Multiple invocations - * of this function one at a time ensures newly ready microtasks are processed - * before next macrotask timer callback is invoked. */ -export function handleTimerMacrotask(): boolean { - if (pendingFireTimers.length > 0) { - fire(pendingFireTimers.shift()!); - return pendingFireTimers.length === 0; - } - return true; -} - -async function setGlobalTimeout(due: number, now: number): Promise<void> { - // Since JS and Rust don't use the same clock, pass the time to rust as a - // relative time value. On the Rust side we'll turn that into an absolute - // value again. - const timeout = due - now; - assert(timeout >= 0); - // Send message to the backend. - globalTimeoutDue = due; - pendingEvents++; - // FIXME(bartlomieju): this is problematic, because `clearGlobalTimeout` - // is synchronous. That means that timer is cancelled, but this promise is still pending - // until next turn of event loop. This leads to "leaking of async ops" in tests; - // because `clearTimeout/clearInterval` might be the last statement in test function - // `opSanitizer` will immediately complain that there is pending op going on, unless - // some timeout/defer is put in place to allow promise resolution. - // Ideally `clearGlobalTimeout` doesn't return until this op is resolved, but - // I'm not if that's possible. - await startGlobalTimer(timeout); - pendingEvents--; - // eslint-disable-next-line @typescript-eslint/no-use-before-define - prepareReadyTimers(); -} - -function prepareReadyTimers(): void { - const now = OriginalDate.now(); - // Bail out if we're not expecting the global timer to fire. - if (globalTimeoutDue === null || pendingEvents > 0) { - return; - } - // After firing the timers that are due now, this will hold the first timer - // list that hasn't fired yet. - let nextDueNode: DueNode | null; - while ((nextDueNode = dueTree.min()) !== null && nextDueNode.due <= now) { - dueTree.remove(nextDueNode); - // Fire all the timers in the list. - for (const timer of nextDueNode.timers) { - // With the list dropped, the timer is no longer scheduled. - timer.scheduled = false; - // Place the callback to pending timers to fire. - pendingFireTimers.push(timer); - } - } - setOrClearGlobalTimeout(nextDueNode && nextDueNode.due, now); -} - -function setOrClearGlobalTimeout(due: number | null, now: number): void { - if (due == null) { - clearGlobalTimeout(); - } else { - setGlobalTimeout(due, now); - } -} - -function schedule(timer: Timer, now: number): void { - assert(!timer.scheduled); - assert(now <= timer.due); - // Find or create the list of timers that will fire at point-in-time `due`. - const maybeNewDueNode = { due: timer.due, timers: [] }; - let dueNode = dueTree.find(maybeNewDueNode); - if (dueNode === null) { - dueTree.insert(maybeNewDueNode); - dueNode = maybeNewDueNode; - } - // Append the newly scheduled timer to the list and mark it as scheduled. - dueNode!.timers.push(timer); - timer.scheduled = true; - // If the new timer is scheduled to fire before any timer that existed before, - // update the global timeout to reflect this. - if (globalTimeoutDue === null || globalTimeoutDue > timer.due) { - setOrClearGlobalTimeout(timer.due, now); - } -} - -function unschedule(timer: Timer): void { - // Check if our timer is pending scheduling or pending firing. - // If either is true, they are not in tree, and their idMap entry - // will be deleted soon. Remove it from queue. - let index = -1; - if ((index = pendingFireTimers.indexOf(timer)) >= 0) { - pendingFireTimers.splice(index); - return; - } - // If timer is not in the 2 pending queues and is unscheduled, - // it is not in the tree. - if (!timer.scheduled) { - return; - } - const searchKey = { due: timer.due, timers: [] }; - // Find the list of timers that will fire at point-in-time `due`. - const list = dueTree.find(searchKey)!.timers; - if (list.length === 1) { - // Time timer is the only one in the list. Remove the entire list. - assert(list[0] === timer); - dueTree.remove(searchKey); - // If the unscheduled timer was 'next up', find when the next timer that - // still exists is due, and update the global alarm accordingly. - if (timer.due === globalTimeoutDue) { - const nextDueNode: DueNode | null = dueTree.min(); - setOrClearGlobalTimeout( - nextDueNode && nextDueNode.due, - OriginalDate.now(), - ); - } - } else { - // Multiple timers that are due at the same point in time. - // Remove this timer from the list. - const index = list.indexOf(timer); - assert(index > -1); - list.splice(index, 1); - } -} - -function fire(timer: Timer): void { - // If the timer isn't found in the ID map, that means it has been cancelled - // between the timer firing and the promise callback (this function). - if (!idMap.has(timer.id)) { - return; - } - // Reschedule the timer if it is a repeating one, otherwise drop it. - if (!timer.repeat) { - // One-shot timer: remove the timer from this id-to-timer map. - idMap.delete(timer.id); - } else { - // Interval timer: compute when timer was supposed to fire next. - // However make sure to never schedule the next interval in the past. - const now = OriginalDate.now(); - timer.due = Math.max(now, timer.due + timer.delay); - schedule(timer, now); - } - // Call the user callback. Intermediate assignment is to avoid leaking `this` - // to it, while also keeping the stack trace neat when it shows up in there. - const callback = timer.callback; - callback(); -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type Args = any[]; - -function checkThis(thisArg: unknown): void { - if (thisArg !== null && thisArg !== undefined && thisArg !== globalThis) { - throw new TypeError("Illegal invocation"); - } -} - -function checkBigInt(n: unknown): void { - if (typeof n === "bigint") { - throw new TypeError("Cannot convert a BigInt value to a number"); - } -} - -function setTimer( - cb: (...args: Args) => void, - delay: number, - args: Args, - repeat: boolean, -): number { - // Bind `args` to the callback and bind `this` to globalThis(global). - const callback: () => void = cb.bind(globalThis, ...args); - // In the browser, the delay value must be coercible to an integer between 0 - // and INT32_MAX. Any other value will cause the timer to fire immediately. - // We emulate this behavior. - const now = OriginalDate.now(); - if (delay > TIMEOUT_MAX) { - console.warn( - `${delay} does not fit into` + - " a 32-bit signed integer." + - "\nTimeout duration was set to 1.", - ); - delay = 1; - } - delay = Math.max(0, delay | 0); - - // Create a new, unscheduled timer object. - const timer = { - id: nextTimerId++, - callback, - args, - delay, - due: now + delay, - repeat, - scheduled: false, - }; - // Register the timer's existence in the id-to-timer map. - idMap.set(timer.id, timer); - // Schedule the timer in the due table. - schedule(timer, now); - return timer.id; -} - -export function setTimeout( - this: unknown, - cb: (...args: Args) => void, - delay = 0, - ...args: Args -): number { - checkBigInt(delay); - checkThis(this); - return setTimer(cb, delay, args, false); -} - -export function setInterval( - this: unknown, - cb: (...args: Args) => void, - delay = 0, - ...args: Args -): number { - checkBigInt(delay); - checkThis(this); - return setTimer(cb, delay, args, true); -} - -function clearTimer(id: number): void { - id = Number(id); - const timer = idMap.get(id); - if (timer === undefined) { - // Timer doesn't exist any more or never existed. This is not an error. - return; - } - // Unschedule the timer if it is currently scheduled, and forget about it. - unschedule(timer); - idMap.delete(timer.id); -} - -export function clearTimeout(id = 0): void { - checkBigInt(id); - if (id === 0) { - return; - } - clearTimer(id); -} - -export function clearInterval(id = 0): void { - checkBigInt(id); - if (id === 0) { - return; - } - clearTimer(id); -} diff --git a/cli/js/web/url.ts b/cli/js/web/url.ts deleted file mode 100644 index fabef3329..000000000 --- a/cli/js/web/url.ts +++ /dev/null @@ -1,627 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { build } from "../build.ts"; -import { getRandomValues } from "../ops/get_random_values.ts"; -import { domainToAscii } from "../ops/idna.ts"; -import { customInspect } from "./console.ts"; -import { TextEncoder } from "./text_encoding.ts"; -import { urls } from "./url_search_params.ts"; - -interface URLParts { - protocol: string; - slashes: string; - username: string; - password: string; - hostname: string; - port: string; - path: string; - query: string; - hash: string; -} - -const searchParamsMethods: Array<keyof URLSearchParams> = [ - "append", - "delete", - "set", -]; - -const specialSchemes = ["ftp", "file", "http", "https", "ws", "wss"]; - -// https://url.spec.whatwg.org/#special-scheme -const schemePorts: Record<string, string> = { - ftp: "21", - file: "", - http: "80", - https: "443", - ws: "80", - wss: "443", -}; -const MAX_PORT = 2 ** 16 - 1; - -// Remove the part of the string that matches the pattern and return the -// remainder (RHS) as well as the first captured group of the matched substring -// (LHS). e.g. -// takePattern("https://deno.land:80", /^([a-z]+):[/]{2}/) -// = ["http", "deno.land:80"] -// takePattern("deno.land:80", /^(\[[0-9a-fA-F.:]{2,}\]|[^:]+)/) -// = ["deno.land", "80"] -function takePattern(string: string, pattern: RegExp): [string, string] { - let capture = ""; - const rest = string.replace(pattern, (_, capture_) => { - capture = capture_; - return ""; - }); - return [capture, rest]; -} - -function parse(url: string, isBase = true): URLParts | undefined { - const parts: Partial<URLParts> = {}; - let restUrl; - [parts.protocol, restUrl] = takePattern(url.trim(), /^([a-z]+):/); - if (isBase && parts.protocol == "") { - return undefined; - } - const isSpecial = specialSchemes.includes(parts.protocol); - if (parts.protocol == "file") { - parts.slashes = "//"; - parts.username = ""; - parts.password = ""; - [parts.hostname, restUrl] = takePattern(restUrl, /^[/\\]{2}([^/\\?#]*)/); - parts.port = ""; - if (build.os == "windows" && parts.hostname == "") { - // UNC paths. e.g. "\\\\localhost\\foo\\bar" on Windows should be - // representable as `new URL("file:////localhost/foo/bar")` which is - // equivalent to: `new URL("file://localhost/foo/bar")`. - [parts.hostname, restUrl] = takePattern(restUrl, /^[/\\]{2,}([^/\\?#]*)/); - } - } else { - let restAuthority; - if (isSpecial) { - parts.slashes = "//"; - [restAuthority, restUrl] = takePattern(restUrl, /^[/\\]{2,}([^/\\?#]*)/); - } else { - parts.slashes = restUrl.match(/^[/\\]{2}/) ? "//" : ""; - [restAuthority, restUrl] = takePattern(restUrl, /^[/\\]{2}([^/\\?#]*)/); - } - let restAuthentication; - [restAuthentication, restAuthority] = takePattern(restAuthority, /^(.*)@/); - [parts.username, restAuthentication] = takePattern( - restAuthentication, - /^([^:]*)/, - ); - parts.username = encodeUserinfo(parts.username); - [parts.password] = takePattern(restAuthentication, /^:(.*)/); - parts.password = encodeUserinfo(parts.password); - [parts.hostname, restAuthority] = takePattern( - restAuthority, - /^(\[[0-9a-fA-F.:]{2,}\]|[^:]+)/, - ); - [parts.port] = takePattern(restAuthority, /^:(.*)/); - if (!isValidPort(parts.port)) { - return undefined; - } - if (parts.hostname == "" && isSpecial && isBase) { - return undefined; - } - } - try { - parts.hostname = encodeHostname(parts.hostname, isSpecial); - } catch { - return undefined; - } - [parts.path, restUrl] = takePattern(restUrl, /^([^?#]*)/); - parts.path = encodePathname(parts.path.replace(/\\/g, "/")); - [parts.query, restUrl] = takePattern(restUrl, /^(\?[^#]*)/); - parts.query = encodeSearch(parts.query); - [parts.hash] = takePattern(restUrl, /^(#.*)/); - parts.hash = encodeHash(parts.hash); - return parts as URLParts; -} - -// Based on https://github.com/kelektiv/node-uuid -// TODO(kevinkassimo): Use deno_std version once possible. -function generateUUID(): string { - return "00000000-0000-4000-8000-000000000000".replace(/[0]/g, (): string => - // random integer from 0 to 15 as a hex digit. - (getRandomValues(new Uint8Array(1))[0] % 16).toString(16)); -} - -// Keep it outside of URL to avoid any attempts of access. -export const blobURLMap = new Map<string, Blob>(); - -function isAbsolutePath(path: string): boolean { - return path.startsWith("/"); -} - -// Resolves `.`s and `..`s where possible. -// Preserves repeating and trailing `/`s by design. -// On Windows, drive letter paths will be given a leading slash, and also a -// trailing slash if there are no other components e.g. "C:" -> "/C:/". -function normalizePath(path: string, isFilePath = false): string { - if (build.os == "windows" && isFilePath) { - path = path.replace(/^\/*([A-Za-z]:)(\/|$)/, "/$1/"); - } - const isAbsolute = isAbsolutePath(path); - path = path.replace(/^\//, ""); - const pathSegments = path.split("/"); - - const newPathSegments: string[] = []; - for (let i = 0; i < pathSegments.length; i++) { - const previous = newPathSegments[newPathSegments.length - 1]; - if ( - pathSegments[i] == ".." && - previous != ".." && - (previous != undefined || isAbsolute) - ) { - newPathSegments.pop(); - } else if (pathSegments[i] != ".") { - newPathSegments.push(pathSegments[i]); - } - } - - let newPath = newPathSegments.join("/"); - if (!isAbsolute) { - if (newPathSegments.length == 0) { - newPath = "."; - } - } else { - newPath = `/${newPath}`; - } - return newPath; -} - -// Standard URL basing logic, applied to paths. -function resolvePathFromBase( - path: string, - basePath: string, - isFilePath = false, -): string { - let normalizedPath = normalizePath(path, isFilePath); - let normalizedBasePath = normalizePath(basePath, isFilePath); - - let driveLetterPrefix = ""; - if (build.os == "windows" && isFilePath) { - let driveLetter: string; - let baseDriveLetter: string; - [driveLetter, normalizedPath] = takePattern( - normalizedPath, - /^(\/[A-Za-z]:)(?=\/)/, - ); - [baseDriveLetter, normalizedBasePath] = takePattern( - normalizedBasePath, - /^(\/[A-Za-z]:)(?=\/)/, - ); - driveLetterPrefix = driveLetter || baseDriveLetter; - } - - if (isAbsolutePath(normalizedPath)) { - return `${driveLetterPrefix}${normalizedPath}`; - } - if (!isAbsolutePath(normalizedBasePath)) { - throw new TypeError("Base path must be absolute."); - } - - // Special case. - if (path == "") { - return `${driveLetterPrefix}${normalizedBasePath}`; - } - - // Remove everything after the last `/` in `normalizedBasePath`. - const prefix = normalizedBasePath.replace(/[^\/]*$/, ""); - // If `normalizedPath` ends with `.` or `..`, add a trailing slash. - const suffix = normalizedPath.replace(/(?<=(^|\/)(\.|\.\.))$/, "/"); - - return `${driveLetterPrefix}${normalizePath(prefix + suffix)}`; -} - -function isValidPort(value: string): boolean { - // https://url.spec.whatwg.org/#port-state - if (value === "") return true; - - const port = Number(value); - return Number.isInteger(port) && port >= 0 && port <= MAX_PORT; -} - -/** @internal */ -export const parts = new WeakMap<URL, URLParts>(); - -export class URLImpl implements URL { - #searchParams!: URLSearchParams; - - [customInspect](): string { - const keys = [ - "href", - "origin", - "protocol", - "username", - "password", - "host", - "hostname", - "port", - "pathname", - "hash", - "search", - ]; - const objectString = keys - .map((key: string) => `${key}: "${this[key as keyof this] || ""}"`) - .join(", "); - return `URL { ${objectString} }`; - } - - #updateSearchParams = (): void => { - const searchParams = new URLSearchParams(this.search); - - for (const methodName of searchParamsMethods) { - /* eslint-disable @typescript-eslint/no-explicit-any */ - const method: (...args: any[]) => any = searchParams[methodName]; - searchParams[methodName] = (...args: unknown[]): any => { - method.apply(searchParams, args); - this.search = searchParams.toString(); - }; - /* eslint-enable */ - } - this.#searchParams = searchParams; - - urls.set(searchParams, this); - }; - - get hash(): string { - return parts.get(this)!.hash; - } - - set hash(value: string) { - value = unescape(String(value)); - if (!value) { - parts.get(this)!.hash = ""; - } else { - if (value.charAt(0) !== "#") { - value = `#${value}`; - } - // hashes can contain % and # unescaped - parts.get(this)!.hash = encodeHash(value); - } - } - - get host(): string { - return `${this.hostname}${this.port ? `:${this.port}` : ""}`; - } - - set host(value: string) { - value = String(value); - const url = new URL(`http://${value}`); - parts.get(this)!.hostname = url.hostname; - parts.get(this)!.port = url.port; - } - - get hostname(): string { - return parts.get(this)!.hostname; - } - - set hostname(value: string) { - value = String(value); - try { - const isSpecial = specialSchemes.includes(parts.get(this)!.protocol); - parts.get(this)!.hostname = encodeHostname(value, isSpecial); - } catch {} - } - - get href(): string { - const authentication = this.username || this.password - ? `${this.username}${this.password ? ":" + this.password : ""}@` - : ""; - const host = this.host; - const slashes = host ? "//" : parts.get(this)!.slashes; - let pathname = this.pathname; - if (pathname.charAt(0) != "/" && pathname != "" && host != "") { - pathname = `/${pathname}`; - } - return `${this.protocol}${slashes}${authentication}${host}${pathname}${this.search}${this.hash}`; - } - - set href(value: string) { - value = String(value); - if (value !== this.href) { - const url = new URL(value); - parts.set(this, { ...parts.get(url)! }); - this.#updateSearchParams(); - } - } - - get origin(): string { - if (this.host) { - return `${this.protocol}//${this.host}`; - } - return "null"; - } - - get password(): string { - return parts.get(this)!.password; - } - - set password(value: string) { - value = String(value); - parts.get(this)!.password = encodeUserinfo(value); - } - - get pathname(): string { - let path = parts.get(this)!.path; - if (specialSchemes.includes(parts.get(this)!.protocol)) { - if (path.charAt(0) != "/") { - path = `/${path}`; - } - } - return path; - } - - set pathname(value: string) { - parts.get(this)!.path = encodePathname(String(value)); - } - - get port(): string { - const port = parts.get(this)!.port; - if (schemePorts[parts.get(this)!.protocol] === port) { - return ""; - } - - return port; - } - - set port(value: string) { - if (!isValidPort(value)) { - return; - } - parts.get(this)!.port = value.toString(); - } - - get protocol(): string { - return `${parts.get(this)!.protocol}:`; - } - - set protocol(value: string) { - value = String(value); - if (value) { - if (value.charAt(value.length - 1) === ":") { - value = value.slice(0, -1); - } - parts.get(this)!.protocol = encodeURIComponent(value); - } - } - - get search(): string { - return parts.get(this)!.query; - } - - set search(value: string) { - value = String(value); - const query = value == "" || value.charAt(0) == "?" ? value : `?${value}`; - parts.get(this)!.query = encodeSearch(query); - this.#updateSearchParams(); - } - - get username(): string { - return parts.get(this)!.username; - } - - set username(value: string) { - value = String(value); - parts.get(this)!.username = encodeUserinfo(value); - } - - get searchParams(): URLSearchParams { - return this.#searchParams; - } - - constructor(url: string | URL, base?: string | URL) { - let baseParts: URLParts | undefined; - if (base) { - baseParts = typeof base === "string" ? parse(base) : parts.get(base); - if (baseParts === undefined) { - throw new TypeError("Invalid base URL."); - } - } - - const urlParts = typeof url === "string" - ? parse(url, !baseParts) - : parts.get(url); - if (urlParts == undefined) { - throw new TypeError("Invalid URL."); - } - - if (urlParts.protocol) { - urlParts.path = normalizePath(urlParts.path, urlParts.protocol == "file"); - parts.set(this, urlParts); - } else if (baseParts) { - parts.set(this, { - protocol: baseParts.protocol, - slashes: baseParts.slashes, - username: baseParts.username, - password: baseParts.password, - hostname: baseParts.hostname, - port: baseParts.port, - path: resolvePathFromBase( - urlParts.path, - baseParts.path || "/", - baseParts.protocol == "file", - ), - query: urlParts.query, - hash: urlParts.hash, - }); - } else { - throw new TypeError("Invalid URL."); - } - - this.#updateSearchParams(); - } - - toString(): string { - return this.href; - } - - toJSON(): string { - return this.href; - } - - // TODO(kevinkassimo): implement MediaSource version in the future. - static createObjectURL(b: Blob): string { - const origin = "http://deno-opaque-origin"; - const key = `blob:${origin}/${generateUUID()}`; - blobURLMap.set(key, b); - return key; - } - - static revokeObjectURL(url: string): void { - let urlObject; - try { - urlObject = new URL(url); - } catch { - throw new TypeError("Provided URL string is not valid"); - } - if (urlObject.protocol !== "blob:") { - return; - } - // Origin match check seems irrelevant for now, unless we implement - // persisten storage for per globalThis.location.origin at some point. - blobURLMap.delete(url); - } -} - -function parseIpv4Number(s: string): number { - if (s.match(/^(0[Xx])[0-9A-Za-z]+$/)) { - return Number(s); - } - if (s.match(/^[0-9]+$/)) { - return Number(s.startsWith("0") ? `0o${s}` : s); - } - return NaN; -} - -function parseIpv4(s: string): string { - const parts = s.split("."); - if (parts[parts.length - 1] == "" && parts.length > 1) { - parts.pop(); - } - if (parts.includes("") || parts.length > 4) { - return s; - } - const numbers = parts.map(parseIpv4Number); - if (numbers.includes(NaN)) { - return s; - } - const last = numbers.pop()!; - if (last >= 256 ** (4 - numbers.length) || numbers.find((n) => n >= 256)) { - throw new TypeError("Invalid hostname."); - } - const ipv4 = numbers.reduce((sum, n, i) => sum + n * 256 ** (3 - i), last); - const ipv4Hex = ipv4.toString(16).padStart(8, "0"); - const ipv4HexParts = ipv4Hex.match(/(..)(..)(..)(..)$/)!.slice(1); - return ipv4HexParts.map((s) => String(Number(`0x${s}`))).join("."); -} - -function charInC0ControlSet(c: string): boolean { - return (c >= "\u0000" && c <= "\u001F") || c > "\u007E"; -} - -function charInSearchSet(c: string): boolean { - // deno-fmt-ignore - return charInC0ControlSet(c) || ["\u0020", "\u0022", "\u0023", "\u0027", "\u003C", "\u003E"].includes(c) || c > "\u007E"; -} - -function charInFragmentSet(c: string): boolean { - // deno-fmt-ignore - return charInC0ControlSet(c) || ["\u0020", "\u0022", "\u003C", "\u003E", "\u0060"].includes(c); -} - -function charInPathSet(c: string): boolean { - // deno-fmt-ignore - return charInFragmentSet(c) || ["\u0023", "\u003F", "\u007B", "\u007D"].includes(c); -} - -function charInUserinfoSet(c: string): boolean { - // "\u0027" ("'") seemingly isn't in the spec, but matches Chrome and Firefox. - // deno-fmt-ignore - return charInPathSet(c) || ["\u0027", "\u002F", "\u003A", "\u003B", "\u003D", "\u0040", "\u005B", "\u005C", "\u005D", "\u005E", "\u007C"].includes(c); -} - -function charIsForbiddenInHost(c: string): boolean { - // deno-fmt-ignore - return ["\u0000", "\u0009", "\u000A", "\u000D", "\u0020", "\u0023", "\u0025", "\u002F", "\u003A", "\u003C", "\u003E", "\u003F", "\u0040", "\u005B", "\u005C", "\u005D", "\u005E"].includes(c); -} - -const encoder = new TextEncoder(); - -function encodeChar(c: string): string { - return [...encoder.encode(c)] - .map((n) => `%${n.toString(16)}`) - .join("") - .toUpperCase(); -} - -function encodeUserinfo(s: string): string { - return [...s].map((c) => (charInUserinfoSet(c) ? encodeChar(c) : c)).join(""); -} - -function encodeHostname(s: string, isSpecial = true): string { - // IPv6 parsing. - if (s.startsWith("[") && s.endsWith("]")) { - if (!s.match(/^\[[0-9A-Fa-f.:]{2,}\]$/)) { - throw new TypeError("Invalid hostname."); - } - // IPv6 address compress - return s.toLowerCase().replace(/\b:?(?:0+:?){2,}/, "::"); - } - - let result = s; - - if (!isSpecial) { - // Check against forbidden host code points except for "%". - for (const c of result) { - if (charIsForbiddenInHost(c) && c != "\u0025") { - throw new TypeError("Invalid hostname."); - } - } - - // Percent-encode C0 control set. - result = [...result] - .map((c) => (charInC0ControlSet(c) ? encodeChar(c) : c)) - .join(""); - - return result; - } - - // Percent-decode. - if (result.match(/%(?![0-9A-Fa-f]{2})/) != null) { - throw new TypeError("Invalid hostname."); - } - result = result.replace( - /%(.{2})/g, - (_, hex) => String.fromCodePoint(Number(`0x${hex}`)), - ); - - // IDNA domain to ASCII. - result = domainToAscii(result); - - // Check against forbidden host code points. - for (const c of result) { - if (charIsForbiddenInHost(c)) { - throw new TypeError("Invalid hostname."); - } - } - - // IPv4 parsing. - if (isSpecial) { - result = parseIpv4(result); - } - - return result; -} - -function encodePathname(s: string): string { - return [...s].map((c) => (charInPathSet(c) ? encodeChar(c) : c)).join(""); -} - -function encodeSearch(s: string): string { - return [...s].map((c) => (charInSearchSet(c) ? encodeChar(c) : c)).join(""); -} - -function encodeHash(s: string): string { - return [...s].map((c) => (charInFragmentSet(c) ? encodeChar(c) : c)).join(""); -} diff --git a/cli/js/web/url_search_params.ts b/cli/js/web/url_search_params.ts deleted file mode 100644 index f3e247522..000000000 --- a/cli/js/web/url_search_params.ts +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { parts } from "./url.ts"; -import { isIterable, requiredArguments } from "./util.ts"; - -/** @internal */ -export const urls = new WeakMap<URLSearchParams, URL | null>(); - -export class URLSearchParamsImpl implements URLSearchParams { - readonly #params: Array<[string, string]> = []; - - constructor(init: string | string[][] | Record<string, string> = "") { - if (typeof init === "string") { - this.#handleStringInitialization(init); - return; - } - - if (Array.isArray(init) || isIterable(init)) { - this.#handleArrayInitialization(init); - return; - } - - if (Object(init) !== init) { - return; - } - - if (init instanceof URLSearchParamsImpl) { - this.#params = [...init.#params]; - return; - } - - // Overload: record<USVString, USVString> - for (const key of Object.keys(init)) { - this.#append(key, init[key]); - } - - urls.set(this, null); - } - - #handleStringInitialization = (init: string): void => { - // Overload: USVString - // If init is a string and starts with U+003F (?), - // remove the first code point from init. - if (init.charCodeAt(0) === 0x003f) { - init = init.slice(1); - } - - for (const pair of init.split("&")) { - // Empty params are ignored - if (pair.length === 0) { - continue; - } - const position = pair.indexOf("="); - const name = pair.slice(0, position === -1 ? pair.length : position); - const value = pair.slice(name.length + 1); - this.#append(decodeURIComponent(name), decodeURIComponent(value)); - } - }; - - #handleArrayInitialization = ( - init: string[][] | Iterable<[string, string]>, - ): void => { - // Overload: sequence<sequence<USVString>> - for (const tuple of init) { - // If pair does not contain exactly two items, then throw a TypeError. - if (tuple.length !== 2) { - throw new TypeError( - "URLSearchParams.constructor tuple array argument must only contain pair elements", - ); - } - this.#append(tuple[0], tuple[1]); - } - }; - - #updateSteps = (): void => { - const url = urls.get(this); - if (url == null) { - return; - } - parts.get(url)!.query = this.toString(); - }; - - #append = (name: string, value: string): void => { - this.#params.push([String(name), String(value)]); - }; - - append(name: string, value: string): void { - requiredArguments("URLSearchParams.append", arguments.length, 2); - this.#append(name, value); - this.#updateSteps(); - } - - delete(name: string): void { - requiredArguments("URLSearchParams.delete", arguments.length, 1); - name = String(name); - let i = 0; - while (i < this.#params.length) { - if (this.#params[i][0] === name) { - this.#params.splice(i, 1); - } else { - i++; - } - } - this.#updateSteps(); - } - - getAll(name: string): string[] { - requiredArguments("URLSearchParams.getAll", arguments.length, 1); - name = String(name); - const values = []; - for (const entry of this.#params) { - if (entry[0] === name) { - values.push(entry[1]); - } - } - - return values; - } - - get(name: string): string | null { - requiredArguments("URLSearchParams.get", arguments.length, 1); - name = String(name); - for (const entry of this.#params) { - if (entry[0] === name) { - return entry[1]; - } - } - - return null; - } - - has(name: string): boolean { - requiredArguments("URLSearchParams.has", arguments.length, 1); - name = String(name); - return this.#params.some((entry) => entry[0] === name); - } - - set(name: string, value: string): void { - requiredArguments("URLSearchParams.set", arguments.length, 2); - - // If there are any name-value pairs whose name is name, in list, - // set the value of the first such name-value pair to value - // and remove the others. - name = String(name); - value = String(value); - let found = false; - let i = 0; - while (i < this.#params.length) { - if (this.#params[i][0] === name) { - if (!found) { - this.#params[i][1] = value; - found = true; - i++; - } else { - this.#params.splice(i, 1); - } - } else { - i++; - } - } - - // Otherwise, append a new name-value pair whose name is name - // and value is value, to list. - if (!found) { - this.#append(name, value); - } - - this.#updateSteps(); - } - - sort(): void { - this.#params.sort((a, b) => (a[0] === b[0] ? 0 : a[0] > b[0] ? 1 : -1)); - this.#updateSteps(); - } - - forEach( - callbackfn: (value: string, key: string, parent: this) => void, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - thisArg?: any, - ): void { - requiredArguments("URLSearchParams.forEach", arguments.length, 1); - - if (typeof thisArg !== "undefined") { - callbackfn = callbackfn.bind(thisArg); - } - - for (const [key, value] of this.#params) { - callbackfn(value, key, this); - } - } - - *keys(): IterableIterator<string> { - for (const [key] of this.#params) { - yield key; - } - } - - *values(): IterableIterator<string> { - for (const [, value] of this.#params) { - yield value; - } - } - - *entries(): IterableIterator<[string, string]> { - yield* this.#params; - } - - *[Symbol.iterator](): IterableIterator<[string, string]> { - yield* this.#params; - } - - toString(): string { - return this.#params - .map( - (tuple) => - `${encodeURIComponent(tuple[0])}=${encodeURIComponent(tuple[1])}`, - ) - .join("&"); - } -} diff --git a/cli/js/web/util.ts b/cli/js/web/util.ts deleted file mode 100644 index 3165c37a7..000000000 --- a/cli/js/web/util.ts +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { DOMExceptionImpl as DOMException } from "./dom_exception.ts"; - -export type TypedArray = - | Int8Array - | Uint8Array - | Uint8ClampedArray - | Int16Array - | Uint16Array - | Int32Array - | Uint32Array - | Float32Array - | Float64Array; - -// @internal -export function isTypedArray(x: unknown): x is TypedArray { - return ArrayBuffer.isView(x) && !(x instanceof DataView); -} - -// @internal -export function isInvalidDate(x: Date): boolean { - return isNaN(x.getTime()); -} - -// @internal -export function requiredArguments( - name: string, - length: number, - required: number, -): void { - if (length < required) { - const errMsg = `${name} requires at least ${required} argument${ - required === 1 ? "" : "s" - }, but only ${length} present`; - throw new TypeError(errMsg); - } -} - -// @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, - }); -} - -// @internal -export function hasOwnProperty(obj: unknown, v: PropertyKey): boolean { - if (obj == null) { - return false; - } - return Object.prototype.hasOwnProperty.call(obj, v); -} - -/** Returns whether o is iterable. - * - * @internal */ -export function isIterable<T, P extends keyof T, K extends T[P]>( - o: T, -): o is T & Iterable<[P, K]> { - // checks for null and undefined - if (o == null) { - return false; - } - return ( - typeof ((o as unknown) as Iterable<[P, K]>)[Symbol.iterator] === "function" - ); -} - -const objectCloneMemo = new WeakMap(); - -function cloneArrayBuffer( - srcBuffer: ArrayBufferLike, - srcByteOffset: number, - srcLength: number, - cloneConstructor: ArrayBufferConstructor | SharedArrayBufferConstructor, -): InstanceType<typeof cloneConstructor> { - // this function fudges the return type but SharedArrayBuffer is disabled for a while anyway - return srcBuffer.slice( - srcByteOffset, - srcByteOffset + srcLength, - ) as InstanceType<typeof cloneConstructor>; -} - -/** Clone a value in a similar way to structured cloning. It is similar to a - * StructureDeserialize(StructuredSerialize(...)). */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function cloneValue(value: any): any { - switch (typeof value) { - case "number": - case "string": - case "boolean": - case "undefined": - case "bigint": - return value; - case "object": { - if (objectCloneMemo.has(value)) { - return objectCloneMemo.get(value); - } - if (value === null) { - return value; - } - if (value instanceof Date) { - return new Date(value.valueOf()); - } - if (value instanceof RegExp) { - return new RegExp(value); - } - if (value instanceof SharedArrayBuffer) { - return value; - } - if (value instanceof ArrayBuffer) { - const cloned = cloneArrayBuffer( - value, - 0, - value.byteLength, - ArrayBuffer, - ); - objectCloneMemo.set(value, cloned); - return cloned; - } - if (ArrayBuffer.isView(value)) { - const clonedBuffer = cloneValue(value.buffer) as ArrayBufferLike; - // Use DataViewConstructor type purely for type-checking, can be a - // DataView or TypedArray. They use the same constructor signature, - // only DataView has a length in bytes and TypedArrays use a length in - // terms of elements, so we adjust for that. - let length: number; - if (value instanceof DataView) { - length = value.byteLength; - } else { - length = (value as Uint8Array).length; - } - return new (value.constructor as DataViewConstructor)( - clonedBuffer, - value.byteOffset, - length, - ); - } - if (value instanceof Map) { - const clonedMap = new Map(); - objectCloneMemo.set(value, clonedMap); - value.forEach((v, k) => clonedMap.set(k, cloneValue(v))); - return clonedMap; - } - if (value instanceof Set) { - const clonedSet = new Map(); - objectCloneMemo.set(value, clonedSet); - value.forEach((v, k) => clonedSet.set(k, cloneValue(v))); - return clonedSet; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const clonedObj = {} as Record<string, any>; - objectCloneMemo.set(value, clonedObj); - const sourceKeys = Object.getOwnPropertyNames(value); - for (const key of sourceKeys) { - clonedObj[key] = cloneValue(value[key]); - } - return clonedObj; - } - case "symbol": - case "function": - default: - throw new DOMException("Uncloneable value in stream", "DataCloneError"); - } -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -interface GenericConstructor<T = any> { - prototype: T; -} - -/** A helper function which ensures accessors are enumerable, as they normally - * are not. */ -export function defineEnumerableProps( - Ctor: GenericConstructor, - props: string[], -): void { - for (const prop of props) { - Reflect.defineProperty(Ctor.prototype, prop, { enumerable: true }); - } -} - -// @internal -export function getHeaderValueParams(value: string): Map<string, string> { - const params = new Map(); - // Forced to do so for some Map constructor param mismatch - value - .split(";") - .slice(1) - .map((s): string[] => s.trim().split("=")) - .filter((arr): boolean => arr.length > 1) - .map(([k, v]): [string, string] => [k, v.replace(/^"([^"]*)"$/, "$1")]) - .forEach(([k, v]): Map<string, string> => params.set(k, v)); - return params; -} - -// @internal -export function hasHeaderValueOf(s: string, value: string): boolean { - return new RegExp(`^${value}[\t\s]*;?`).test(s); -} - -/** An internal function which provides a function name for some generated - * functions, so stack traces are a bit more readable. - * - * @internal */ -export function setFunctionName(fn: Function, value: string): void { - Object.defineProperty(fn, "name", { value, configurable: true }); -} diff --git a/cli/js/web/workers.ts b/cli/js/web/workers.ts deleted file mode 100644 index 5fd63477a..000000000 --- a/cli/js/web/workers.ts +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { - createWorker, - hostTerminateWorker, - hostPostMessage, - hostGetMessage, -} from "../ops/worker_host.ts"; -import { log } from "../util.ts"; -import { TextDecoder, TextEncoder } from "./text_encoding.ts"; -/* -import { blobURLMap } from "./web/url.ts"; -*/ -import { ErrorEventImpl as ErrorEvent } from "./error_event.ts"; -import { EventImpl as Event } from "./event.ts"; -import { EventTargetImpl as EventTarget } from "./event_target.ts"; - -const encoder = new TextEncoder(); -const decoder = new TextDecoder(); - -export interface MessageEventInit extends EventInit { - data?: any; - origin?: string; - lastEventId?: string; -} - -export class MessageEvent extends Event { - readonly data: any; - readonly origin: string; - readonly lastEventId: string; - - constructor(type: string, eventInitDict?: MessageEventInit) { - super(type, { - bubbles: eventInitDict?.bubbles ?? false, - cancelable: eventInitDict?.cancelable ?? false, - composed: eventInitDict?.composed ?? false, - }); - - this.data = eventInitDict?.data ?? null; - this.origin = eventInitDict?.origin ?? ""; - this.lastEventId = eventInitDict?.lastEventId ?? ""; - } -} - -function encodeMessage(data: any): Uint8Array { - const dataJson = JSON.stringify(data); - return encoder.encode(dataJson); -} - -function decodeMessage(dataIntArray: Uint8Array): any { - const dataJson = decoder.decode(dataIntArray); - return JSON.parse(dataJson); -} - -interface WorkerHostError { - message: string; - fileName?: string; - lineNumber?: number; - columnNumber?: number; -} - -interface WorkerHostMessage { - type: "terminalError" | "error" | "msg"; - data?: any; - error?: WorkerHostError; -} - -export interface Worker { - onerror?: (e: ErrorEvent) => void; - onmessage?: (e: MessageEvent) => void; - onmessageerror?: (e: MessageEvent) => void; - postMessage(data: any): void; - terminate(): void; -} - -export interface WorkerOptions { - type?: "classic" | "module"; - name?: string; - deno?: boolean; -} - -export class WorkerImpl extends EventTarget implements Worker { - readonly #id: number; - readonly #name: string; - #terminated = false; - - public onerror?: (e: ErrorEvent) => void; - public onmessage?: (e: MessageEvent) => void; - public onmessageerror?: (e: MessageEvent) => void; - - constructor(specifier: string, options?: WorkerOptions) { - super(); - const { type = "classic", name = "unknown" } = options ?? {}; - - if (type !== "module") { - throw new Error( - 'Not yet implemented: only "module" type workers are supported', - ); - } - - this.#name = name; - const hasSourceCode = false; - const sourceCode = decoder.decode(new Uint8Array()); - - /* TODO(bartlomieju): - // Handle blob URL. - if (specifier.startsWith("blob:")) { - hasSourceCode = true; - const b = blobURLMap.get(specifier); - if (!b) { - throw new Error("No Blob associated with the given URL is found"); - } - const blobBytes = blobBytesWeakMap.get(b!); - if (!blobBytes) { - throw new Error("Invalid Blob"); - } - sourceCode = blobBytes!; - } - */ - - const useDenoNamespace = options ? !!options.deno : false; - - const { id } = createWorker( - specifier, - hasSourceCode, - sourceCode, - useDenoNamespace, - options?.name, - ); - this.#id = id; - this.#poll(); - } - - #handleMessage = (msgData: any): void => { - let data; - try { - data = decodeMessage(new Uint8Array(msgData)); - } catch (e) { - const msgErrorEvent = new MessageEvent("messageerror", { - cancelable: false, - data, - }); - if (this.onmessageerror) { - this.onmessageerror(msgErrorEvent); - } - return; - } - - const msgEvent = new MessageEvent("message", { - cancelable: false, - data, - }); - - if (this.onmessage) { - this.onmessage(msgEvent); - } - - this.dispatchEvent(msgEvent); - }; - - #handleError = (e: WorkerHostError): boolean => { - const event = 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, - }); - - let handled = false; - if (this.onerror) { - this.onerror(event); - } - - this.dispatchEvent(event); - if (event.defaultPrevented) { - handled = true; - } - - return handled; - }; - - #poll = async (): Promise<void> => { - while (!this.#terminated) { - const event = (await hostGetMessage(this.#id)) as WorkerHostMessage; - - // If terminate was called then we ignore all messages - if (this.#terminated) { - return; - } - - const type = event.type; - - if (type === "terminalError") { - this.#terminated = true; - if (!this.#handleError(event.error!)) { - throw Error(event.error!.message); - } - continue; - } - - if (type === "msg") { - this.#handleMessage(event.data); - continue; - } - - if (type === "error") { - if (!this.#handleError(event.error!)) { - throw Error(event.error!.message); - } - continue; - } - - if (type === "close") { - log(`Host got "close" message from worker: ${this.#name}`); - this.#terminated = true; - return; - } - - throw new Error(`Unknown worker event: "${type}"`); - } - }; - - postMessage(message: any, transferOrOptions?: any): void { - if (transferOrOptions) { - throw new Error( - "Not yet implemented: `transfer` and `options` are not supported.", - ); - } - - if (this.#terminated) { - return; - } - - hostPostMessage(this.#id, encodeMessage(message)); - } - - terminate(): void { - if (!this.#terminated) { - this.#terminated = true; - hostTerminateWorker(this.#id); - } - } -} diff --git a/cli/js/write_file.ts b/cli/js/write_file.ts deleted file mode 100644 index db5f20238..000000000 --- a/cli/js/write_file.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { stat, statSync } from "./ops/fs/stat.ts"; -import { open, openSync } from "./files.ts"; -import { chmod, chmodSync } from "./ops/fs/chmod.ts"; -import { writeAll, writeAllSync } from "./buffer.ts"; -import { build } from "./build.ts"; - -export interface WriteFileOptions { - append?: boolean; - create?: boolean; - mode?: number; -} - -export function writeFileSync( - path: string | URL, - data: Uint8Array, - options: WriteFileOptions = {}, -): void { - if (options.create !== undefined) { - const create = !!options.create; - if (!create) { - // verify that file exists - statSync(path); - } - } - - const openOptions = !!options.append - ? { write: true, create: true, append: true } - : { write: true, create: true, truncate: true }; - const file = openSync(path, openOptions); - - if ( - options.mode !== undefined && - options.mode !== null && - build.os !== "windows" - ) { - chmodSync(path, options.mode); - } - - writeAllSync(file, data); - file.close(); -} - -export async function writeFile( - path: string | URL, - data: Uint8Array, - options: WriteFileOptions = {}, -): Promise<void> { - if (options.create !== undefined) { - const create = !!options.create; - if (!create) { - // verify that file exists - await stat(path); - } - } - - const openOptions = !!options.append - ? { write: true, create: true, append: true } - : { write: true, create: true, truncate: true }; - const file = await open(path, openOptions); - - if ( - options.mode !== undefined && - options.mode !== null && - build.os !== "windows" - ) { - await chmod(path, options.mode); - } - - await writeAll(file, data); - file.close(); -} diff --git a/cli/js/write_text_file.ts b/cli/js/write_text_file.ts deleted file mode 100644 index 97148c411..000000000 --- a/cli/js/write_text_file.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { writeFileSync, writeFile, WriteFileOptions } from "./write_file.ts"; - -export function writeTextFileSync( - path: string | URL, - data: string, - options: WriteFileOptions = {}, -): void { - const encoder = new TextEncoder(); - return writeFileSync(path, encoder.encode(data), options); -} - -export function writeTextFile( - path: string | URL, - data: string, - options: WriteFileOptions = {}, -): Promise<void> { - const encoder = new TextEncoder(); - return writeFile(path, encoder.encode(data), options); -} |