1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

Merge branch 'master' into v1.1

This commit is contained in:
Ryan Dahl 2020-05-26 13:05:17 -04:00
commit cf081f9b6e
79 changed files with 985 additions and 765 deletions

View file

@ -40,7 +40,7 @@ impl DenoDir {
root,
gen_cache: DiskCache::new(&gen_path),
};
deno_dir.gen_cache.ensure_location()?;
deno_dir.gen_cache.ensure_dir_exists(&gen_path)?;
Ok(deno_dir)
}

View file

@ -31,14 +31,14 @@ impl DiskCache {
}
/// Ensures the location of the cache.
pub fn ensure_location(&self) -> io::Result<()> {
if self.location.is_dir() {
pub fn ensure_dir_exists(&self, path: &Path) -> io::Result<()> {
if path.is_dir() {
return Ok(());
}
fs::create_dir_all(&self.location).map_err(|e| {
fs::create_dir_all(&path).map_err(|e| {
io::Error::new(e.kind(), format!(
"Could not create TypeScript compiler cache location: {:?}\nCheck the permission of the directory.",
self.location
path
))
})
}
@ -129,8 +129,7 @@ impl DiskCache {
pub fn set(&self, filename: &Path, data: &[u8]) -> std::io::Result<()> {
let path = self.location.join(filename);
match path.parent() {
Some(ref parent) => fs::create_dir_all(parent)
.map_err(|e| with_io_context(&e, format!("{:#?}", &path))),
Some(ref parent) => self.ensure_dir_exists(parent),
None => Ok(()),
}?;
deno_fs::write_file(&path, data, 0o666)
@ -154,7 +153,9 @@ mod tests {
let mut cache_path = cache_location.path().to_owned();
cache_path.push("foo");
let cache = DiskCache::new(&cache_path);
cache.ensure_location().expect("Testing expect:");
cache
.ensure_dir_exists(&cache.location)
.expect("Testing expect:");
assert!(cache_path.is_dir());
}
@ -166,7 +167,9 @@ mod tests {
cache_location.push("foo");
assert_eq!(cache_location.is_dir(), false);
let cache = DiskCache::new(&cache_location);
cache.ensure_location().expect("Testing expect:");
cache
.ensure_dir_exists(&cache.location)
.expect("Testing expect:");
assert_eq!(cache_location.is_dir(), true);
}

View file

@ -1,4 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::file_fetcher::map_file_extension;
use crate::op_error::OpError;
use crate::swc_common::comments::CommentKind;
use crate::swc_common::Span;
@ -15,6 +16,7 @@ use deno_core::ModuleSpecifier;
use futures::Future;
use regex::Regex;
use std::collections::HashMap;
use std::path::PathBuf;
use std::pin::Pin;
use super::namespace::NamespaceDef;
@ -57,9 +59,12 @@ impl DocParser {
file_name: &str,
source_code: &str,
) -> Result<ModuleDoc, SwcDiagnosticBuffer> {
self
.ast_parser
.parse_module(file_name, source_code, |parse_result| {
let media_type = map_file_extension(&PathBuf::from(file_name));
self.ast_parser.parse_module(
file_name,
media_type,
source_code,
|parse_result| {
let module = parse_result?;
let doc_entries =
self.get_doc_nodes_for_module_body(module.body.clone());
@ -69,7 +74,8 @@ impl DocParser {
reexports,
};
Ok(module_doc)
})
},
)
}
pub async fn parse(&self, file_name: &str) -> Result<Vec<DocNode>, ErrBox> {

View file

@ -51,7 +51,6 @@ impl GlobalState {
let dir = deno_dir::DenoDir::new(custom_root)?;
let deps_cache_location = dir.root.join("deps");
let http_cache = http_cache::HttpCache::new(&deps_cache_location);
http_cache.ensure_location()?;
let file_fetcher = SourceFileFetcher::new(
http_cache,

View file

@ -113,16 +113,16 @@ impl HttpCache {
}
/// Ensures the location of the cache.
pub fn ensure_location(&self) -> io::Result<()> {
if self.location.is_dir() {
fn ensure_dir_exists(&self, path: &Path) -> io::Result<()> {
if path.is_dir() {
return Ok(());
}
fs::create_dir_all(&self.location).map_err(|e| {
fs::create_dir_all(&path).map_err(|e| {
io::Error::new(
e.kind(),
format!(
"Could not create remote modules cache location: {:?}\nCheck the permission of the directory.",
self.location
path
),
)
})
@ -163,7 +163,7 @@ impl HttpCache {
let parent_filename = cache_filename
.parent()
.expect("Cache filename should have a parent dir");
fs::create_dir_all(parent_filename)?;
self.ensure_dir_exists(parent_filename)?;
// Cache content
deno_fs::write_file(&cache_filename, content, 0o666)?;
@ -187,8 +187,25 @@ mod tests {
let dir = TempDir::new().unwrap();
let mut cache_path = dir.path().to_owned();
cache_path.push("foobar");
// HttpCache should be created lazily on first use:
// when zipping up a local project with no external dependencies
// "$DENO_DIR/deps" is empty. When unzipping such project
// "$DENO_DIR/deps" might not get restored and in situation
// when directory is owned by root we might not be able
// to create that directory. However if it's not needed it
// doesn't make sense to return error in such specific scenarios.
// For more details check issue:
// https://github.com/denoland/deno/issues/5688
let cache = HttpCache::new(&cache_path);
assert!(cache.ensure_location().is_ok());
assert!(!cache.location.exists());
cache
.set(
&Url::parse("http://example.com/foo/bar.js").unwrap(),
HeadersMap::new(),
b"hello world",
)
.expect("Failed to add to cache");
assert!(cache.ensure_dir_exists(&cache.location).is_ok());
assert!(cache_path.is_dir());
}

View file

@ -13,12 +13,6 @@ 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 {
Diagnostic,
DiagnosticCategory,
DiagnosticItem,
DiagnosticMessageChain,
} from "./diagnostics.ts";
export { chdir, cwd } from "./ops/fs/dir.ts";
export { errors } from "./errors.ts";
export {
@ -59,7 +53,7 @@ export {
export { metrics, Metrics } from "./ops/runtime.ts";
export { mkdirSync, mkdir, MkdirOptions } from "./ops/fs/mkdir.ts";
export { connect, listen, Listener, Conn } from "./net.ts";
export { dir, env, exit, execPath } from "./ops/os.ts";
export { env, exit, execPath } from "./ops/os.ts";
export { run, RunOptions, Process, ProcessStatus } from "./process.ts";
export { DirEntry, readDirSync, readDir } from "./ops/fs/read_dir.ts";
export { readFileSync, readFile } from "./read_file.ts";

View file

@ -23,3 +23,9 @@ export {
PermissionStatus,
Permissions,
} from "./permissions.ts";
export {
Diagnostic,
DiagnosticCategory,
DiagnosticItem,
DiagnosticMessageChain,
} from "./diagnostics.ts";

View file

@ -244,19 +244,19 @@ function prepareStackTrace(
}
)
.map((callSite): string => {
// @ts-ignore
// @ts-expect-error
error.__callSiteEvals.push(Object.freeze(evaluateCallSite(callSite)));
const isInternal =
callSite.getFileName()?.startsWith("$deno$") ?? false;
const string = callSiteToString(callSite, isInternal);
// @ts-ignore
// @ts-expect-error
error.__formattedFrames.push(string);
return ` at ${colors.stripColor(string)}`;
})
.join("\n");
// @ts-ignore
// @ts-expect-error
Object.freeze(error.__callSiteEvals);
// @ts-ignore
// @ts-expect-error
Object.freeze(error.__formattedFrames);
return errorString;
}

View file

@ -62,7 +62,7 @@ declare namespace Deno {
*
* Deno.test({
* name: "example ignored test",
* ignore: Deno.build.os === "windows"
* ignore: Deno.build.os === "windows",
* fn(): void {
* // This test is ignored only on Windows machines
* },
@ -73,7 +73,7 @@ declare namespace Deno {
* async fn() {
* const decoder = new TextDecoder("utf-8");
* const data = await Deno.readFile("hello_world.txt");
* assertEquals(decoder.decode(data), "Hello world")
* assertEquals(decoder.decode(data), "Hello world");
* }
* });
* ```
@ -94,7 +94,7 @@ declare namespace Deno {
* 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")
* assertEquals(decoder.decode(data), "Hello world");
* });
* ```
* */
@ -1612,10 +1612,9 @@ declare namespace Deno {
* 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. */
* Requires `allow-net` permission for "tcp". */
export function connect(options: ConnectOptions): Promise<Conn>;
export interface ConnectTlsOptions {
@ -1828,7 +1827,7 @@ declare namespace Deno {
* ```ts
* const obj = {};
* obj.propA = 10;
* obj.propB = "hello"
* 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" }
* ```

View file

@ -922,6 +922,12 @@ declare const Request: {
new (input: RequestInfo, init?: RequestInit): Request;
};
interface ResponseInit {
headers?: HeadersInit;
status?: number;
statusText?: string;
}
type ResponseType =
| "basic"
| "cors"
@ -945,20 +951,7 @@ interface Response extends Body {
declare const Response: {
prototype: Response;
// TODO(#4667) Response constructor is non-standard.
// new(body?: BodyInit | null, init?: ResponseInit): Response;
new (
url: string,
status: number,
statusText: string,
headersList: Array<[string, string]>,
rid: number,
redirected_: boolean,
type_?: null | ResponseType,
body_?: null | Body
): Response;
new (body?: BodyInit | null, init?: ResponseInit): Response;
error(): Response;
redirect(url: string, status?: number): Response;
};

View file

@ -1067,7 +1067,7 @@ declare namespace Deno {
* const conn5 = await Deno.connect({ path: "/foo/bar.sock", transport: "unix" });
* ```
*
* Requires `allow-net` permission for "tcp" and `allow-read` for unix. */
* Requires `allow-net` permission for "tcp" and `allow-read` for "unix". */
export function connect(
options: ConnectOptions | UnixConnectOptions
): Promise<Conn>;

View file

@ -35,7 +35,7 @@ function isRecoverableError(e: Error): boolean {
// Returns `true` if `close()` is called in REPL.
// We should quit the REPL when this function returns `true`.
function isCloseCalled(): boolean {
// @ts-ignore
// @ts-expect-error
return globalThis.closed;
}

View file

@ -30,7 +30,7 @@ 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.
// @ts-ignore
// @ts-expect-error
denoNs[internalSymbol] = internalObject;
let windowIsClosing = false;
@ -71,7 +71,7 @@ export function bootstrapMainRuntime(): void {
throw new Error("Worker runtime already bootstrapped");
}
// Remove bootstrapping methods from global scope
// @ts-ignore
// @ts-expect-error
globalThis.bootstrap = undefined;
log("bootstrapMainRuntime");
hasBootstrapped = true;

View file

@ -33,7 +33,7 @@ import { setSignals } from "./signals.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.
// @ts-ignore
// @ts-expect-error
denoNs[internalSymbol] = internalObject;
const encoder = new TextEncoder();
@ -128,7 +128,7 @@ export function bootstrapWorkerRuntime(
throw new Error("Worker runtime already bootstrapped");
}
// Remove bootstrapping methods from global scope
// @ts-ignore
// @ts-expect-error
globalThis.bootstrap = undefined;
log("bootstrapWorkerRuntime");
hasBootstrapped = true;

View file

@ -333,11 +333,10 @@ async function runTests({
const filterFn = createFilterFn(filter, skip);
const testApi = new TestApi(TEST_REGISTRY, filterFn, failFast);
// @ts-ignore
const originalConsole = globalThis.console;
if (disableLog) {
// @ts-ignore
// @ts-expect-error
globalThis.console = disabledConsole;
}
@ -356,7 +355,6 @@ async function runTests({
}
if (disableLog) {
// @ts-ignore
globalThis.console = originalConsole;
}

View file

@ -2,20 +2,13 @@ import * as blob from "./blob.ts";
import * as encoding from "./text_encoding.ts";
import * as domTypes from "./dom_types.d.ts";
import { ReadableStreamImpl } from "./streams/readable_stream.ts";
import { getHeaderValueParams, hasHeaderValueOf } from "./util.ts";
// only namespace imports work for now, plucking out what we need
const { TextEncoder, TextDecoder } = encoding;
const DenoBlob = blob.DenoBlob;
export type BodySource =
| Blob
| BufferSource
| FormData
| URLSearchParams
| ReadableStream
| string;
function validateBodyType(owner: Body, bodySource: BodySource): boolean {
function validateBodyType(owner: Body, bodySource: BodyInit | null): boolean {
if (
bodySource instanceof Int8Array ||
bodySource instanceof Int16Array ||
@ -58,53 +51,31 @@ function concatenate(...arrays: Uint8Array[]): ArrayBuffer {
return result.buffer as ArrayBuffer;
}
function bufferFromStream(stream: ReadableStreamReader): Promise<ArrayBuffer> {
return new Promise((resolve, reject): void => {
async function bufferFromStream(
stream: ReadableStreamReader
): Promise<ArrayBuffer> {
const parts: Uint8Array[] = [];
const encoder = new TextEncoder();
// recurse
(function pump(): void {
stream
.read()
.then(({ done, value }): void => {
if (done) {
return resolve(concatenate(...parts));
}
while (true) {
const { done, value } = await stream.read();
if (done) break;
if (typeof value === "string") {
parts.push(encoder.encode(value));
} else if (value instanceof ArrayBuffer) {
parts.push(new Uint8Array(value));
} else if (value instanceof Uint8Array) {
parts.push(value);
} else if (!value) {
// noop for undefined
} else {
reject("unhandled type on stream read");
throw new Error("unhandled type on stream read");
}
}
return pump();
})
.catch((err): void => {
reject(err);
});
})();
});
}
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;
}
function hasHeaderValueOf(s: string, value: string): boolean {
return new RegExp(`^${value}[\t\s]*;?`).test(s);
return concatenate(...parts);
}
export const BodyUsedError =
@ -113,7 +84,10 @@ export const BodyUsedError =
export class Body implements domTypes.Body {
protected _stream: ReadableStreamImpl<string | ArrayBuffer> | null;
constructor(protected _bodySource: BodySource, readonly contentType: string) {
constructor(
protected _bodySource: BodyInit | null,
readonly contentType: string
) {
validateBodyType(this, _bodySource);
this._bodySource = _bodySource;
this.contentType = contentType;
@ -126,7 +100,6 @@ export class Body implements domTypes.Body {
}
if (this._bodySource instanceof ReadableStreamImpl) {
// @ts-ignore
this._stream = this._bodySource;
}
if (typeof this._bodySource === "string") {
@ -149,7 +122,9 @@ export class Body implements domTypes.Body {
}
public async blob(): Promise<Blob> {
return new DenoBlob([await this.arrayBuffer()]);
return new DenoBlob([await this.arrayBuffer()], {
type: this.contentType,
});
}
// ref: https://fetch.spec.whatwg.org/#body-mixin
@ -314,7 +289,6 @@ export class Body implements domTypes.Body {
enc.encode(this._bodySource).buffer as ArrayBuffer
);
} else if (this._bodySource instanceof ReadableStreamImpl) {
// @ts-ignore
return bufferFromStream(this._bodySource.getReader());
} else if (this._bodySource instanceof FormData) {
const enc = new TextEncoder();

View file

@ -223,7 +223,7 @@ function groupEntries<T>(
let order = "padStart";
if (value !== undefined) {
for (let i = 0; i < entries.length; i++) {
//@ts-ignore
//@ts-expect-error
if (typeof value[i] !== "number" && typeof value[i] !== "bigint") {
order = "padEnd";
break;
@ -239,7 +239,7 @@ function groupEntries<T>(
for (; j < max - 1; j++) {
// In future, colors should be taken here into the account
const padding = maxLineLength[j - i];
//@ts-ignore
//@ts-expect-error
str += `${entries[j]}, `[order](padding, " ");
}
if (order === "padStart") {
@ -412,7 +412,7 @@ function createMapString(
},
group: false,
};
//@ts-ignore
//@ts-expect-error
return createIterableString(value, ctx, level, maxLevel, printConfig);
}
@ -494,7 +494,7 @@ function createRawObjectString(
let baseString = "";
let shouldShowDisplayName = false;
// @ts-ignore
// @ts-expect-error
let displayName = value[Symbol.toStringTag];
if (!displayName) {
displayName = getClassInstanceName(value);
@ -515,7 +515,7 @@ function createRawObjectString(
for (const key of symbolKeys) {
entries.push(
`${key.toString()}: ${stringifyWithQuotes(
// @ts-ignore
// @ts-expect-error
value[key],
ctx,
level + 1,
@ -949,7 +949,7 @@ export class Console {
name: "Trace",
message,
};
// @ts-ignore
// @ts-expect-error
Error.captureStackTrace(err, this.trace);
this.error((err as Error).stack);
};

View file

@ -305,7 +305,6 @@ export interface Response extends Body {
readonly redirected: boolean;
readonly status: number;
readonly statusText: string;
readonly trailer: Promise<Headers>;
readonly type: ResponseType;
readonly url: string;
clone(): Response;

View file

@ -1,328 +1,76 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assert, createResolvable, notImplemented } from "../util.ts";
import { notImplemented } from "../util.ts";
import { isTypedArray } from "./util.ts";
import * as domTypes from "./dom_types.d.ts";
import { TextDecoder, TextEncoder } from "./text_encoding.ts";
import { DenoBlob, bytesSymbol as blobBytesSymbol } from "./blob.ts";
import * as io from "../io.ts";
import { read } from "../ops/io.ts";
import { close } from "../ops/resources.ts";
import { Buffer } from "../buffer.ts";
import { fetch as opFetch, FetchResponse } from "../ops/fetch.ts";
import * as Body from "./body.ts";
import { DomFileImpl } from "./dom_file.ts";
import { getHeaderValueParams } from "./util.ts";
import { ReadableStreamImpl } from "./streams/readable_stream.ts";
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;
}
function hasHeaderValueOf(s: string, value: string): boolean {
return new RegExp(`^${value}[\t\s]*;?`).test(s);
}
class Body
implements domTypes.Body, ReadableStream<Uint8Array>, io.Reader, io.Closer {
#bodyUsed = false;
#bodyPromise: Promise<ArrayBuffer> | null = null;
#data: ArrayBuffer | null = null;
#rid: number;
readonly locked: boolean = false; // TODO
readonly body: ReadableStream<Uint8Array>;
constructor(rid: number, readonly contentType: string) {
this.#rid = rid;
this.body = this;
}
#bodyBuffer = async (): Promise<ArrayBuffer> => {
assert(this.#bodyPromise == null);
const buf = new Buffer();
try {
const nread = await buf.readFrom(this);
const ui8 = buf.bytes();
assert(ui8.byteLength === nread);
this.#data = ui8.buffer.slice(
ui8.byteOffset,
ui8.byteOffset + nread
) as ArrayBuffer;
assert(this.#data.byteLength === nread);
} finally {
this.close();
}
return this.#data;
};
// eslint-disable-next-line require-await
async arrayBuffer(): Promise<ArrayBuffer> {
// If we've already bufferred the response, just return it.
if (this.#data != null) {
return this.#data;
}
// If there is no _bodyPromise yet, start it.
if (this.#bodyPromise == null) {
this.#bodyPromise = this.#bodyBuffer();
}
return this.#bodyPromise;
}
async blob(): Promise<Blob> {
const arrayBuffer = await this.arrayBuffer();
return new DenoBlob([arrayBuffer], {
type: this.contentType,
});
}
// ref: https://fetch.spec.whatwg.org/#body-mixin
async formData(): Promise<FormData> {
const formData = new FormData();
const enc = new TextEncoder();
if (hasHeaderValueOf(this.contentType, "multipart/form-data")) {
const params = getHeaderValueParams(this.contentType);
if (!params.has("boundary")) {
// TypeError is required by spec
throw new TypeError("multipart/form-data must provide a boundary");
}
// ref: https://tools.ietf.org/html/rfc2046#section-5.1
const boundary = params.get("boundary")!;
const dashBoundary = `--${boundary}`;
const delimiter = `\r\n${dashBoundary}`;
const closeDelimiter = `${delimiter}--`;
const body = await this.text();
let bodyParts: string[];
const bodyEpilogueSplit = body.split(closeDelimiter);
if (bodyEpilogueSplit.length < 2) {
bodyParts = [];
} else {
// discard epilogue
const bodyEpilogueTrimmed = bodyEpilogueSplit[0];
// first boundary treated special due to optional prefixed \r\n
const firstBoundaryIndex = bodyEpilogueTrimmed.indexOf(dashBoundary);
if (firstBoundaryIndex < 0) {
throw new TypeError("Invalid boundary");
}
const bodyPreambleTrimmed = bodyEpilogueTrimmed
.slice(firstBoundaryIndex + dashBoundary.length)
.replace(/^[\s\r\n\t]+/, ""); // remove transport-padding CRLF
// trimStart might not be available
// Be careful! body-part allows trailing \r\n!
// (as long as it is not part of `delimiter`)
bodyParts = bodyPreambleTrimmed
.split(delimiter)
.map((s): string => s.replace(/^[\s\r\n\t]+/, ""));
// TODO: LWSP definition is actually trickier,
// but should be fine in our case since without headers
// we should just discard the part
}
for (const bodyPart of bodyParts) {
const headers = new Headers();
const headerOctetSeperatorIndex = bodyPart.indexOf("\r\n\r\n");
if (headerOctetSeperatorIndex < 0) {
continue; // Skip unknown part
}
const headerText = bodyPart.slice(0, headerOctetSeperatorIndex);
const octets = bodyPart.slice(headerOctetSeperatorIndex + 4);
// TODO: use textproto.readMIMEHeader from deno_std
const rawHeaders = headerText.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);
}
if (!headers.has("content-disposition")) {
continue; // Skip unknown part
}
// Content-Transfer-Encoding Deprecated
const contentDisposition = headers.get("content-disposition")!;
const partContentType = headers.get("content-type") || "text/plain";
// TODO: custom charset encoding (needs TextEncoder support)
// const contentTypeCharset =
// getHeaderValueParams(partContentType).get("charset") || "";
if (!hasHeaderValueOf(contentDisposition, "form-data")) {
continue; // Skip, might not be form-data
}
const dispositionParams = getHeaderValueParams(contentDisposition);
if (!dispositionParams.has("name")) {
continue; // Skip, unknown name
}
const dispositionName = dispositionParams.get("name")!;
if (dispositionParams.has("filename")) {
const filename = dispositionParams.get("filename")!;
const blob = new DenoBlob([enc.encode(octets)], {
type: partContentType,
});
// TODO: based on spec
// https://xhr.spec.whatwg.org/#dom-formdata-append
// https://xhr.spec.whatwg.org/#create-an-entry
// Currently it does not mention how I could pass content-type
// to the internally created file object...
formData.append(dispositionName, blob, filename);
} else {
formData.append(dispositionName, octets);
}
}
return formData;
} 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");
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async json(): Promise<any> {
const text = await this.text();
return JSON.parse(text);
}
async text(): Promise<string> {
const ab = await this.arrayBuffer();
const decoder = new TextDecoder("utf-8");
return decoder.decode(ab);
}
read(p: Uint8Array): Promise<number | null> {
this.#bodyUsed = true;
return read(this.#rid, p);
}
close(): Promise<void> {
close(this.#rid);
return Promise.resolve();
}
cancel(): Promise<void> {
return notImplemented();
}
getIterator(_options?: {
preventCancel?: boolean;
}): AsyncIterableIterator<Uint8Array> {
return notImplemented();
}
getReader(): ReadableStreamDefaultReader<Uint8Array> {
return notImplemented();
}
tee(): [ReadableStream, ReadableStream] {
return notImplemented();
}
[Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {
return io.iter(this);
}
get bodyUsed(): boolean {
return this.#bodyUsed;
}
pipeThrough<T>(
_: {
writable: WritableStream<Uint8Array>;
readable: ReadableStream<T>;
},
_options?: PipeOptions
): ReadableStream<T> {
return notImplemented();
}
pipeTo(
_dest: WritableStream<Uint8Array>,
_options?: PipeOptions
): Promise<void> {
return notImplemented();
}
}
export class Response implements domTypes.Response {
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;
readonly trailer: Promise<Headers>;
readonly body: Body | null;
constructor(
readonly url: string,
readonly status: number,
readonly statusText: string,
headersList: Array<[string, string]>,
rid: number,
redirected_: boolean,
readonly type_: null | ResponseType = "default",
body_: null | Body = null
) {
this.trailer = createResolvable();
this.headers = new Headers(headersList);
const contentType = this.headers.get("content-type") || "";
constructor(body: BodyInit | null = null, init?: domTypes.ResponseInit) {
init = init ?? {};
if (body_ == null) {
this.body = new Body(rid, contentType);
} else {
this.body = body_;
if (typeof init !== "object") {
throw new TypeError(`'init' is not an object`);
}
if (type_ == null) {
this.type = "default";
const extraInit = responseData.get(init) || {};
let { type = "default", url = "" } = extraInit;
let status = (Number(init.status) || 0) ?? 200;
let statusText = init.statusText ?? "";
let headers =
init.headers instanceof Headers
? init.headers
: new Headers(init.headers);
if (init.status && (status < 200 || status > 599)) {
throw new RangeError(
`The status provided (${init.status}) is outside the range [200, 599]`
);
}
// null body status
if (body && [/* 101, */ 204, 205, 304].includes(status)) {
throw new TypeError("Response with null body status cannot have body");
}
if (!type) {
type = "default";
} else {
this.type = type_;
if (type_ == "error") {
type = type;
if (type == "error") {
// spec: https://fetch.spec.whatwg.org/#concept-network-error
this.status = 0;
this.statusText = "";
this.headers = new Headers();
this.body = null;
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 this.headers) {
} 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())) {
this.headers.delete(h[0]);
headers.delete(h[0]);
}
}
} else if (type_ == "cors") {
} else if (type == "cors") {
/* CORS-safelisted Response-Header Names:
https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name */
const allowedHeaders = [
@ -334,7 +82,7 @@ export class Response implements domTypes.Response {
"Last-Modified",
"Pragma",
].map((c: string) => c.toLowerCase());
for (const h of this.headers) {
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'
@ -344,87 +92,39 @@ export class Response implements domTypes.Response {
TODO(serverhiccups): change how internal responses are handled
so we can do this properly. */
if (!allowedHeaders.includes(h[0].toLowerCase())) {
this.headers.delete(h[0]);
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") {
this.url = "";
this.status = 0;
this.statusText = "";
this.headers = new Headers();
this.body = null;
} else if (type == "opaque" || type == "opaqueredirect") {
url = "";
status = 0;
statusText = "";
headers = new Headers();
body = null;
}
}
this.redirected = redirected_;
}
const contentType = headers.get("content-type") || "";
#bodyViewable = (): boolean => {
if (
this.type == "error" ||
this.type == "opaque" ||
this.type == "opaqueredirect" ||
this.body == undefined
) {
return true;
}
return false;
};
super(body, contentType);
arrayBuffer(): Promise<ArrayBuffer> {
/* You have to do the null check here and not in the function because
* otherwise TS complains about this.body potentially being null */
if (this.#bodyViewable() || this.body == null) {
return Promise.reject(new Error("Response body is null"));
}
return this.body.arrayBuffer();
}
blob(): Promise<Blob> {
if (this.#bodyViewable() || this.body == null) {
return Promise.reject(new Error("Response body is null"));
}
return this.body.blob();
}
formData(): Promise<FormData> {
if (this.#bodyViewable() || this.body == null) {
return Promise.reject(new Error("Response body is null"));
}
return this.body.formData();
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
json(): Promise<any> {
if (this.#bodyViewable() || this.body == null) {
return Promise.reject(new Error("Response body is null"));
}
return this.body.json();
}
text(): Promise<string> {
if (this.#bodyViewable() || this.body == null) {
return Promise.reject(new Error("Response body is null"));
}
return this.body.text();
this.url = url;
this.statusText = statusText;
this.status = status;
this.headers = headers;
this.redirected = extraInit.redirected;
this.type = type;
}
get ok(): boolean {
return 200 <= this.status && this.status < 300;
}
get bodyUsed(): boolean {
if (this.body === null) return false;
return this.body.bodyUsed;
}
clone(): domTypes.Response {
public clone(): domTypes.Response {
if (this.bodyUsed) {
throw new TypeError(
"Failed to execute 'clone' on 'Response': Response body is already used"
);
throw TypeError(Body.BodyUsedError);
}
const iterators = this.headers.entries();
@ -433,16 +133,20 @@ export class Response implements domTypes.Response {
headersList.push(header);
}
return new Response(
this.url,
this.status,
this.statusText,
headersList,
-1,
this.redirected,
this.type,
this.body
);
let resBody = this._bodySource;
if (this._bodySource instanceof ReadableStreamImpl) {
const tees = this._bodySource.tee();
this._stream = this._bodySource = tees[0];
resBody = tees[1];
}
const cloned = new Response(resBody, {
status: this.status,
statusText: this.statusText,
headers: new Headers(headersList),
});
return cloned;
}
static redirect(url: URL | string, status: number): domTypes.Response {
@ -451,16 +155,11 @@ export class Response implements domTypes.Response {
"The redirection status must be one of 301, 302, 303, 307 and 308."
);
}
return new Response(
"",
return new Response(null, {
status,
"",
[["Location", typeof url === "string" ? url : url.toString()]],
-1,
false,
"default",
null
);
statusText: "",
headers: [["Location", typeof url === "string" ? url : url.toString()]],
});
}
}
@ -521,6 +220,8 @@ export async function fetch(
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";
@ -581,7 +282,7 @@ export async function fetch(
method = input.method;
headers = input.headers;
//@ts-ignore
//@ts-expect-error
if (input._bodySource) {
body = new DataView(await input.arrayBuffer());
}
@ -590,26 +291,65 @@ export async function fetch(
while (remRedirectCount) {
const fetchResponse = await sendFetchReq(url, method, headers, body);
const response = new Response(
const 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);
},
});
let responseInit: ResponseInit = {
status: fetchResponse.status,
statusText: fetchResponse.statusText,
headers: fetchResponse.headers,
};
responseData.set(responseInit, {
redirected,
rid: fetchResponse.bodyRid,
url,
fetchResponse.status,
fetchResponse.statusText,
fetchResponse.headers,
fetchResponse.bodyRid,
redirected
);
if ([301, 302, 303, 307, 308].includes(response.status)) {
});
const response = new Response(responseBody, responseInit);
if ([301, 302, 303, 307, 308].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);
// We're in a redirect status
switch ((init && init.redirect) || "follow") {
case "error":
/* I suspect that deno will probably crash if you try to use that
rid, which suggests to me that Response needs to be refactored */
return new Response("", 0, "", [], -1, false, "error", null);
responseInit = {};
responseData.set(responseInit, {
type: "error",
redirected: false,
url: "",
});
return new Response(null, responseInit);
case "manual":
return new Response("", 0, "", [], -1, false, "opaqueredirect", null);
responseInit = {};
responseData.set(responseInit, {
type: "opaqueredirect",
redirected: false,
url: "",
});
return new Response(null, responseInit);
case "follow":
default:
let redirectUrl = response.headers.get("Location");

View file

@ -39,7 +39,7 @@ export class Request extends body.Body implements domTypes.Request {
init = {};
}
let b: body.BodySource;
let b: BodyInit;
// prefer body from init
if (init.body) {

View file

@ -239,7 +239,7 @@ export function setTimeout(
...args: Args
): number {
checkBigInt(delay);
// @ts-ignore
// @ts-expect-error
checkThis(this);
return setTimer(cb, delay, args, false);
}
@ -250,7 +250,7 @@ export function setInterval(
...args: Args
): number {
checkBigInt(delay);
// @ts-ignore
// @ts-expect-error
checkThis(this);
return setTimer(cb, delay, args, true);
}

View file

@ -189,3 +189,22 @@ export function defineEnumerableProps(
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);
}

View file

@ -48,6 +48,13 @@ where
}
}
const SUPPORTED_MEDIA_TYPES: [MediaType; 4] = [
MediaType::JavaScript,
MediaType::TypeScript,
MediaType::JSX,
MediaType::TSX,
];
#[derive(Debug, Serialize)]
pub struct ModuleGraph(HashMap<String, ModuleGraphFile>);
@ -189,6 +196,7 @@ impl ModuleGraphLoader {
let (import_descs, ref_descs) = analyze_dependencies_and_references(
&specifier,
map_file_extension(&PathBuf::from(&specifier)),
&source_code,
self.analyze_dynamic_imports,
)?;
@ -384,9 +392,7 @@ impl ModuleGraphLoader {
let module_specifier = ModuleSpecifier::from(source_file.url.clone());
let source_code = String::from_utf8(source_file.source_code)?;
if source_file.media_type == MediaType::JavaScript
|| source_file.media_type == MediaType::TypeScript
{
if SUPPORTED_MEDIA_TYPES.contains(&source_file.media_type) {
if let Some(types_specifier) = source_file.types_header {
let type_header = ReferenceDescriptor {
specifier: types_specifier.to_string(),
@ -404,6 +410,7 @@ impl ModuleGraphLoader {
let (import_descs, ref_descs) = analyze_dependencies_and_references(
&module_specifier.to_string(),
source_file.media_type,
&source_code,
self.analyze_dynamic_imports,
)?;
@ -781,4 +788,23 @@ mod tests {
);
drop(http_server_guard);
}
#[tokio::test]
async fn source_graph_different_langs() {
let http_server_guard = crate::test_util::http_server();
// ModuleGraphLoader was mistakenly parsing this file as TSX
// https://github.com/denoland/deno/issues/5867
let module_specifier = ModuleSpecifier::resolve_url_or_path(
"http://localhost:4545/cli/tests/ts_with_generic.ts",
)
.unwrap();
build_graph(&module_specifier)
.await
.expect("Failed to build graph");
drop(http_server_guard);
}
}

View file

@ -302,6 +302,7 @@ fn op_connect(
transport_args: ArgsEnum::Unix(args),
} if transport == "unix" => {
let address_path = net_unix::Path::new(&args.path);
state.check_unstable("Deno.connect");
state.check_read(&address_path)?;
let op = async move {
let path = args.path;
@ -524,6 +525,9 @@ fn op_listen(
transport,
transport_args: ArgsEnum::Unix(args),
} if transport == "unix" || transport == "unixpacket" => {
if transport == "unix" {
state.check_unstable("Deno.listen");
}
if transport == "unixpacket" {
state.check_unstable("Deno.listenDatagram");
}

View file

@ -3,7 +3,6 @@ use crate::file_fetcher::SourceFileFetcher;
use crate::global_state::GlobalState;
use crate::global_timer::GlobalTimer;
use crate::import_map::ImportMap;
use crate::inspector::DenoInspector;
use crate::metrics::Metrics;
use crate::op_error::OpError;
use crate::ops::JsonOp;
@ -12,7 +11,6 @@ use crate::permissions::Permissions;
use crate::tsc::TargetLib;
use crate::web_worker::WebWorkerHandle;
use deno_core::Buf;
use deno_core::CoreIsolate;
use deno_core::ErrBox;
use deno_core::ModuleLoadId;
use deno_core::ModuleLoader;
@ -61,7 +59,6 @@ pub struct StateInner {
pub target_lib: TargetLib,
pub is_main: bool,
pub is_internal: bool,
pub inspector: Option<Box<DenoInspector>>,
}
impl State {
@ -420,7 +417,6 @@ impl State {
target_lib: TargetLib::Main,
is_main: true,
is_internal,
inspector: None,
}));
Ok(Self(state))
@ -457,7 +453,6 @@ impl State {
target_lib: TargetLib::Worker,
is_main: false,
is_internal: false,
inspector: None,
}));
Ok(Self(state))
@ -526,37 +521,6 @@ impl State {
}
}
pub fn maybe_init_inspector(&self, isolate: &mut CoreIsolate) {
let mut state = self.borrow_mut();
if state.is_internal {
return;
};
let inspector_host = {
let global_state = &state.global_state;
match global_state
.flags
.inspect
.or(global_state.flags.inspect_brk)
{
Some(host) => host,
None => return,
}
};
let inspector = DenoInspector::new(isolate, inspector_host);
state.inspector.replace(inspector);
}
#[inline]
pub fn should_inspector_break_on_first_statement(&self) -> bool {
let state = self.borrow();
state.inspector.is_some()
&& state.is_main
&& state.global_state.flags.inspect_brk.is_some()
}
#[cfg(test)]
pub fn mock(main_module: &str) -> State {
let module_specifier = ModuleSpecifier::resolve_url_or_path(main_module)

View file

@ -1,4 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::msg::MediaType;
use crate::swc_common;
use crate::swc_common::comments::CommentKind;
use crate::swc_common::comments::Comments;
@ -13,19 +14,42 @@ use crate::swc_common::SourceMap;
use crate::swc_common::Span;
use crate::swc_ecma_ast;
use crate::swc_ecma_parser::lexer::Lexer;
use crate::swc_ecma_parser::EsConfig;
use crate::swc_ecma_parser::JscTarget;
use crate::swc_ecma_parser::Parser;
use crate::swc_ecma_parser::Session;
use crate::swc_ecma_parser::SourceFileInput;
use crate::swc_ecma_parser::Syntax;
use crate::swc_ecma_parser::TsConfig;
use swc_ecma_visit::Node;
use swc_ecma_visit::Visit;
use std::error::Error;
use std::fmt;
use std::sync::Arc;
use std::sync::RwLock;
use swc_ecma_visit::Node;
use swc_ecma_visit::Visit;
fn get_default_es_config() -> EsConfig {
let mut config = EsConfig::default();
config.num_sep = true;
config.class_private_props = false;
config.class_private_methods = false;
config.class_props = false;
config.export_default_from = true;
config.export_namespace_from = true;
config.dynamic_import = true;
config.nullish_coalescing = true;
config.optional_chaining = true;
config.import_meta = true;
config.top_level_await = true;
config
}
fn get_default_ts_config() -> TsConfig {
let mut ts_config = TsConfig::default();
ts_config.dynamic_import = true;
ts_config.decorators = true;
ts_config
}
#[derive(Clone, Debug)]
pub struct SwcDiagnosticBuffer {
@ -126,6 +150,7 @@ impl AstParser {
pub fn parse_module<F, R>(
&self,
file_name: &str,
media_type: MediaType,
source_code: &str,
callback: F,
) -> R
@ -143,11 +168,21 @@ impl AstParser {
handler: &self.handler,
};
// TODO(bartlomieju): lexer should be configurable by the caller
let mut ts_config = TsConfig::default();
ts_config.dynamic_import = true;
ts_config.decorators = true;
let syntax = Syntax::Typescript(ts_config);
let syntax = match media_type {
MediaType::JavaScript => Syntax::Es(get_default_es_config()),
MediaType::JSX => {
let mut config = get_default_es_config();
config.jsx = true;
Syntax::Es(config)
}
MediaType::TypeScript => Syntax::Typescript(get_default_ts_config()),
MediaType::TSX => {
let mut config = get_default_ts_config();
config.tsx = true;
Syntax::Typescript(config)
}
_ => Syntax::Es(get_default_es_config()),
};
let lexer = Lexer::new(
session,
@ -432,6 +467,7 @@ pub struct TsReferenceDescriptor {
pub fn analyze_dependencies_and_references(
file_name: &str,
media_type: MediaType,
source_code: &str,
analyze_dynamic_imports: bool,
) -> Result<
@ -439,7 +475,7 @@ pub fn analyze_dependencies_and_references(
SwcDiagnosticBuffer,
> {
let parser = AstParser::new();
parser.parse_module(file_name, source_code, |parse_result| {
parser.parse_module(file_name, media_type, source_code, |parse_result| {
let module = parse_result?;
let mut collector = NewDependencyVisitor {
dependencies: vec![],
@ -546,8 +582,12 @@ console.log(fizz);
console.log(qat.qat);
"#;
let (imports, references) =
analyze_dependencies_and_references("some/file.ts", source, true)
let (imports, references) = analyze_dependencies_and_references(
"some/file.ts",
MediaType::TypeScript,
source,
true,
)
.expect("Failed to parse");
assert_eq!(

View file

@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error
Deno.core.evalContext(
"(async () => console.log(await import('./subdir/mod4.js')))()"
);

1
cli/tests/Component.tsx Normal file
View file

@ -0,0 +1 @@
import "./046_jsx_test.tsx";

View file

@ -1740,6 +1740,11 @@ itest!(disallow_http_from_https_ts {
exit_code: 1,
});
itest!(tsx_imports {
args: "run --reload tsx_imports.ts",
output: "tsx_imports.ts.out",
});
itest!(fix_js_import_js {
args: "run --quiet --reload fix_js_import_js.ts",
output: "fix_js_import_js.ts.out",
@ -2219,12 +2224,17 @@ fn test_permissions_net_listen_allow_localhost() {
assert!(!err.contains(util::PERMISSION_DENIED_PATTERN));
}
fn inspect_flag_with_unique_port(flag_prefix: &str) -> String {
use std::sync::atomic::{AtomicU16, Ordering};
static PORT: AtomicU16 = AtomicU16::new(9229);
let port = PORT.fetch_add(1, Ordering::Relaxed);
format!("{}=127.0.0.1:{}", flag_prefix, port)
}
fn extract_ws_url_from_stderr(
stderr: &mut std::process::ChildStderr,
stderr_lines: &mut impl std::iter::Iterator<Item = String>,
) -> url::Url {
let mut stderr = std::io::BufReader::new(stderr);
let mut stderr_first_line = String::from("");
let _ = stderr.read_line(&mut stderr_first_line).unwrap();
let stderr_first_line = stderr_lines.next().unwrap();
assert!(stderr_first_line.starts_with("Debugger listening on "));
let v: Vec<_> = stderr_first_line.match_indices("ws:").collect();
assert_eq!(v.len(), 1);
@ -2238,15 +2248,17 @@ async fn inspector_connect() {
let script = util::tests_path().join("inspector1.js");
let mut child = util::deno_cmd()
.arg("run")
// Warning: each inspector test should be on its own port to avoid
// conflicting with another inspector test.
.arg("--inspect=127.0.0.1:9228")
.arg(inspect_flag_with_unique_port("--inspect"))
.arg(script)
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap();
let ws_url = extract_ws_url_from_stderr(child.stderr.as_mut().unwrap());
println!("ws_url {}", ws_url);
let stderr = child.stderr.as_mut().unwrap();
let mut stderr_lines =
std::io::BufReader::new(stderr).lines().map(|r| r.unwrap());
let ws_url = extract_ws_url_from_stderr(&mut stderr_lines);
// We use tokio_tungstenite as a websocket client because warp (which is
// a dependency of Deno) uses it.
let (_socket, response) = tokio_tungstenite::connect_async(ws_url)
@ -2259,6 +2271,7 @@ async fn inspector_connect() {
enum TestStep {
StdOut(&'static str),
StdErr(&'static str),
WsRecv(&'static str),
WsSend(&'static str),
}
@ -2268,9 +2281,7 @@ async fn inspector_break_on_first_line() {
let script = util::tests_path().join("inspector2.js");
let mut child = util::deno_cmd()
.arg("run")
// Warning: each inspector test should be on its own port to avoid
// conflicting with another inspector test.
.arg("--inspect-brk=127.0.0.1:9229")
.arg(inspect_flag_with_unique_port("--inspect-brk"))
.arg(script)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
@ -2278,7 +2289,10 @@ async fn inspector_break_on_first_line() {
.unwrap();
let stderr = child.stderr.as_mut().unwrap();
let ws_url = extract_ws_url_from_stderr(stderr);
let mut stderr_lines =
std::io::BufReader::new(stderr).lines().map(|r| r.unwrap());
let ws_url = extract_ws_url_from_stderr(&mut stderr_lines);
let (socket, response) = tokio_tungstenite::connect_async(ws_url)
.await
.expect("Can't connect");
@ -2322,6 +2336,7 @@ async fn inspector_break_on_first_line() {
StdOut(s) => assert_eq!(&stdout_lines.next().unwrap(), s),
WsRecv(s) => assert!(socket_rx.next().await.unwrap().starts_with(s)),
WsSend(s) => socket_tx.send(s.into()).await.unwrap(),
_ => unreachable!(),
}
}
@ -2334,14 +2349,17 @@ async fn inspector_pause() {
let script = util::tests_path().join("inspector1.js");
let mut child = util::deno_cmd()
.arg("run")
// Warning: each inspector test should be on its own port to avoid
// conflicting with another inspector test.
.arg("--inspect=127.0.0.1:9230")
.arg(inspect_flag_with_unique_port("--inspect"))
.arg(script)
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap();
let ws_url = extract_ws_url_from_stderr(child.stderr.as_mut().unwrap());
let stderr = child.stderr.as_mut().unwrap();
let mut stderr_lines =
std::io::BufReader::new(stderr).lines().map(|r| r.unwrap());
let ws_url = extract_ws_url_from_stderr(&mut stderr_lines);
// We use tokio_tungstenite as a websocket client because warp (which is
// a dependency of Deno) uses it.
let (mut socket, _) = tokio_tungstenite::connect_async(ws_url)
@ -2388,19 +2406,25 @@ async fn inspector_pause() {
#[tokio::test]
async fn inspector_port_collision() {
let script = util::tests_path().join("inspector1.js");
let inspect_flag = inspect_flag_with_unique_port("--inspect");
let mut child1 = util::deno_cmd()
.arg("run")
.arg("--inspect=127.0.0.1:9231")
.arg(&inspect_flag)
.arg(script.clone())
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap();
let ws_url_1 = extract_ws_url_from_stderr(child1.stderr.as_mut().unwrap());
println!("ws_url {}", ws_url_1);
let stderr_1 = child1.stderr.as_mut().unwrap();
let mut stderr_lines_1 = std::io::BufReader::new(stderr_1)
.lines()
.map(|r| r.unwrap());
let _ = extract_ws_url_from_stderr(&mut stderr_lines_1);
let mut child2 = util::deno_cmd()
.arg("run")
.arg("--inspect=127.0.0.1:9231")
.arg(&inspect_flag)
.arg(script)
.stderr(std::process::Stdio::piped())
.spawn()
@ -2426,9 +2450,7 @@ async fn inspector_does_not_hang() {
let script = util::tests_path().join("inspector3.js");
let mut child = util::deno_cmd()
.arg("run")
// Warning: each inspector test should be on its own port to avoid
// conflicting with another inspector test.
.arg("--inspect-brk=127.0.0.1:9232")
.arg(inspect_flag_with_unique_port("--inspect-brk"))
.env("NO_COLOR", "1")
.arg(script)
.stdout(std::process::Stdio::piped())
@ -2437,7 +2459,10 @@ async fn inspector_does_not_hang() {
.unwrap();
let stderr = child.stderr.as_mut().unwrap();
let ws_url = extract_ws_url_from_stderr(stderr);
let mut stderr_lines =
std::io::BufReader::new(stderr).lines().map(|r| r.unwrap());
let ws_url = extract_ws_url_from_stderr(&mut stderr_lines);
let (socket, response) = tokio_tungstenite::connect_async(ws_url)
.await
.expect("Can't connect");
@ -2510,24 +2535,106 @@ async fn inspector_without_brk_runs_code() {
let script = util::tests_path().join("inspector4.js");
let mut child = util::deno_cmd()
.arg("run")
// Warning: each inspector test should be on its own port to avoid
// conflicting with another inspector test.
.arg("--inspect=127.0.0.1:9233")
.arg(inspect_flag_with_unique_port("--inspect"))
.arg(script)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap();
extract_ws_url_from_stderr(child.stderr.as_mut().unwrap());
let stderr = child.stderr.as_mut().unwrap();
let mut stderr_lines =
std::io::BufReader::new(stderr).lines().map(|r| r.unwrap());
let _ = extract_ws_url_from_stderr(&mut stderr_lines);
// Check that inspector actually runs code without waiting for inspector
// connection
let mut stdout = std::io::BufReader::new(child.stdout.as_mut().unwrap());
let mut stdout_first_line = String::from("");
let _ = stdout.read_line(&mut stdout_first_line).unwrap();
assert_eq!(stdout_first_line, "hello\n");
// connection.
let stdout = child.stdout.as_mut().unwrap();
let mut stdout_lines =
std::io::BufReader::new(stdout).lines().map(|r| r.unwrap());
let stdout_first_line = stdout_lines.next().unwrap();
assert_eq!(stdout_first_line, "hello");
child.kill().unwrap();
child.wait().unwrap();
}
#[tokio::test]
async fn inspector_runtime_evaluate_does_not_crash() {
let mut child = util::deno_cmd()
.arg("repl")
.arg(inspect_flag_with_unique_port("--inspect"))
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.unwrap();
let stderr = child.stderr.as_mut().unwrap();
let mut stderr_lines = std::io::BufReader::new(stderr)
.lines()
.map(|r| r.unwrap())
.filter(|s| s.as_str() != "Debugger session started.");
let ws_url = extract_ws_url_from_stderr(&mut stderr_lines);
let (socket, response) = tokio_tungstenite::connect_async(ws_url)
.await
.expect("Can't connect");
assert_eq!(response.status(), 101); // Switching protocols.
let (mut socket_tx, socket_rx) = socket.split();
let mut socket_rx =
socket_rx.map(|msg| msg.unwrap().to_string()).filter(|msg| {
let pass = !msg.starts_with(r#"{"method":"Debugger.scriptParsed","#);
futures::future::ready(pass)
});
let stdin = child.stdin.take().unwrap();
let stdout = child.stdout.as_mut().unwrap();
let mut stdout_lines = std::io::BufReader::new(stdout)
.lines()
.map(|r| r.unwrap())
.filter(|s| !s.starts_with("Deno "));
use TestStep::*;
let test_steps = vec![
WsSend(r#"{"id":1,"method":"Runtime.enable"}"#),
WsSend(r#"{"id":2,"method":"Debugger.enable"}"#),
WsRecv(
r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#,
),
WsRecv(r#"{"id":1,"result":{}}"#),
WsRecv(r#"{"id":2,"result":{"debuggerId":"#),
WsSend(r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#),
WsRecv(r#"{"id":3,"result":{}}"#),
StdOut("exit using ctrl+d or close()"),
WsSend(
r#"{"id":4,"method":"Runtime.compileScript","params":{"expression":"Deno.cwd()","sourceURL":"","persistScript":false,"executionContextId":1}}"#,
),
WsRecv(r#"{"id":4,"result":{}}"#),
WsSend(
r#"{"id":5,"method":"Runtime.evaluate","params":{"expression":"Deno.cwd()","objectGroup":"console","includeCommandLineAPI":true,"silent":false,"contextId":1,"returnByValue":true,"generatePreview":true,"userGesture":true,"awaitPromise":false,"replMode":true}}"#,
),
WsRecv(r#"{"id":5,"result":{"result":{"type":"string","value":""#),
WsSend(
r#"{"id":6,"method":"Runtime.evaluate","params":{"expression":"console.error('done');","objectGroup":"console","includeCommandLineAPI":true,"silent":false,"contextId":1,"returnByValue":true,"generatePreview":true,"userGesture":true,"awaitPromise":false,"replMode":true}}"#,
),
WsRecv(r#"{"id":6,"result":{"result":{"type":"undefined"}}}"#),
StdErr("done"),
];
for step in test_steps {
match step {
StdOut(s) => assert_eq!(&stdout_lines.next().unwrap(), s),
StdErr(s) => assert_eq!(&stderr_lines.next().unwrap(), s),
WsRecv(s) => assert!(socket_rx.next().await.unwrap().starts_with(s)),
WsSend(s) => socket_tx.send(s.into()).await.unwrap(),
}
}
std::mem::drop(stdin);
child.wait().unwrap();
}
#[test]

View file

@ -0,0 +1,3 @@
/* eslint-disable */
const foo = { delete<S>() {} };

1
cli/tests/tsx_imports.ts Normal file
View file

@ -0,0 +1 @@
import "./Component.tsx";

View file

@ -0,0 +1,2 @@
Compile [WILDCARD]tsx_imports.ts
{ factory: [Function: View], props: null, children: [] }

View file

@ -42,7 +42,7 @@ unitTest(
const body = buildBody(text);
// @ts-ignore
// @ts-expect-error
body.contentType = "multipart/form-data;boundary=boundary";
const formData = await body.formData();
@ -62,7 +62,7 @@ unitTest(
const body = buildBody(text);
// @ts-ignore
// @ts-expect-error
body.contentType = "application/x-www-form-urlencoded";
const formData = await body.formData();

View file

@ -22,7 +22,7 @@ const customInspect = Deno.customInspect;
const {
Console,
stringifyArgs,
// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
} = Deno[Deno.internal];
function stringify(...args: unknown[]): string {
@ -727,7 +727,6 @@ unitTest(function consoleTestCallToStringOnLabel(): void {
mockConsole((console) => {
for (const method of methods) {
let hasCalled = false;
// @ts-ignore
console[method]({
toString(): void {
hasCalled = true;

View file

@ -20,9 +20,9 @@ unitTest(
);
unitTest(function malformedJsonControlBuffer(): void {
// @ts-ignore
// @ts-expect-error
const opId = Deno.core.ops()["op_open"];
// @ts-ignore
// @ts-expect-error
const res = Deno.core.send(opId, new Uint8Array([1, 2, 3, 4, 5]));
const resText = new TextDecoder().decode(res);
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View file

@ -26,9 +26,9 @@ unitTest(async function sendAsyncStackTrace(): Promise<void> {
});
unitTest(function malformedMinimalControlBuffer(): void {
// @ts-ignore
// @ts-expect-error
const readOpId = Deno.core.ops()["op_read"];
// @ts-ignore
// @ts-expect-error
const res = Deno.core.send(readOpId, new Uint8Array([1, 2, 3, 4, 5]));
const header = res.slice(0, 12);
const buf32 = new Int32Array(

View file

@ -20,7 +20,7 @@ function setup() {
Base,
// This is using an internal API we don't want published as types, so having
// to cast to any to "trick" TypeScript
// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
DomIterable: Deno[Deno.internal].DomIterableMixin(Base, dataSymbol),
};
}

View file

@ -1,7 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { unitTest, assert } from "./test_util.ts";
// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
const { setPrepareStackTrace } = Deno[Deno.internal];
interface CallSite {

View file

@ -4,11 +4,8 @@ import { unitTest, assertEquals } from "./test_util.ts";
unitTest(function addEventListenerTest(): void {
const document = new EventTarget();
// @ts-ignore tests ignoring the type system for resilience
assertEquals(document.addEventListener("x", null, false), undefined);
// @ts-ignore
assertEquals(document.addEventListener("x", null, true), undefined);
// @ts-ignore
assertEquals(document.addEventListener("x", null), undefined);
});
@ -71,11 +68,8 @@ unitTest(function anEventTargetCanBeSubclassed(): void {
unitTest(function removingNullEventListenerShouldSucceed(): void {
const document = new EventTarget();
// @ts-ignore
assertEquals(document.removeEventListener("x", null, false), undefined);
// @ts-ignore
assertEquals(document.removeEventListener("x", null, true), undefined);
// @ts-ignore
assertEquals(document.removeEventListener("x", null), undefined);
});

View file

@ -93,7 +93,7 @@ unitTest({ perms: { net: true } }, async function fetchBodyUsed(): Promise<
assertEquals(response.bodyUsed, false);
assertThrows((): void => {
// Assigning to read-only property throws in the strict mode.
// @ts-ignore
// @ts-expect-error
response.bodyUsed = true;
});
await response.blob();
@ -118,6 +118,49 @@ unitTest({ perms: { net: true } }, async function fetchAsyncIterator(): Promise<
});
*/
unitTest({ perms: { net: true } }, async function fetchBodyReader(): Promise<
void
> {
const response = await fetch("http://localhost:4545/cli/tests/fixture.json");
const headers = response.headers;
assert(response.body !== null);
const reader = await response.body.getReader();
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
assert(value);
total += value.length;
}
assertEquals(total, Number(headers.get("Content-Length")));
});
unitTest(
{ perms: { net: true } },
async function fetchBodyReaderBigBody(): Promise<void> {
const data = "a".repeat(10 << 10); // 10mb
const response = await fetch(
"http://localhost:4545/cli/tests/echo_server",
{
method: "POST",
body: data,
}
);
assert(response.body !== null);
const reader = await response.body.getReader();
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
assert(value);
total += value.length;
}
assertEquals(total, data.length);
}
);
unitTest({ perms: { net: true } }, async function responseClone(): Promise<
void
> {
@ -258,6 +301,19 @@ unitTest(
}
);
unitTest(
{ perms: { net: true } },
async function fetchInitArrayBufferBody(): Promise<void> {
const data = "Hello World";
const response = await fetch("http://localhost:4545/echo_server", {
method: "POST",
body: new TextEncoder().encode(data).buffer,
});
const text = await response.text();
assertEquals(text, data);
}
);
unitTest(
{ perms: { net: true } },
async function fetchInitURLSearchParamsBody(): Promise<void> {
@ -367,8 +423,6 @@ function bufferServer(addr: string): Deno.Buffer {
unitTest(
{
// FIXME(bartlomieju)
ignore: true,
perms: { net: true },
},
async function fetchRequest(): Promise<void> {
@ -381,6 +435,7 @@ unitTest(
["Foo", "Bar"],
],
});
await response.arrayBuffer();
assertEquals(response.status, 404);
assertEquals(response.headers.get("Content-Length"), "2");
@ -389,6 +444,9 @@ unitTest(
"POST /blah HTTP/1.1\r\n",
"hello: World\r\n",
"foo: Bar\r\n",
"accept: */*\r\n",
`user-agent: Deno/${Deno.version.deno}\r\n`,
"accept-encoding: gzip, br\r\n",
`host: ${addr}\r\n\r\n`,
].join("");
assertEquals(actual, expected);
@ -397,8 +455,6 @@ unitTest(
unitTest(
{
// FIXME(bartlomieju)
ignore: true,
perms: { net: true },
},
async function fetchPostBodyString(): Promise<void> {
@ -413,6 +469,7 @@ unitTest(
],
body,
});
await response.arrayBuffer();
assertEquals(response.status, 404);
assertEquals(response.headers.get("Content-Length"), "2");
@ -421,6 +478,10 @@ unitTest(
"POST /blah HTTP/1.1\r\n",
"hello: World\r\n",
"foo: Bar\r\n",
"content-type: text/plain;charset=UTF-8\r\n",
"accept: */*\r\n",
`user-agent: Deno/${Deno.version.deno}\r\n`,
"accept-encoding: gzip, br\r\n",
`host: ${addr}\r\n`,
`content-length: ${body.length}\r\n\r\n`,
body,
@ -431,8 +492,6 @@ unitTest(
unitTest(
{
// FIXME(bartlomieju)
ignore: true,
perms: { net: true },
},
async function fetchPostBodyTypedArray(): Promise<void> {
@ -448,6 +507,7 @@ unitTest(
],
body,
});
await response.arrayBuffer();
assertEquals(response.status, 404);
assertEquals(response.headers.get("Content-Length"), "2");
@ -456,6 +516,9 @@ unitTest(
"POST /blah HTTP/1.1\r\n",
"hello: World\r\n",
"foo: Bar\r\n",
"accept: */*\r\n",
`user-agent: Deno/${Deno.version.deno}\r\n`,
"accept-encoding: gzip, br\r\n",
`host: ${addr}\r\n`,
`content-length: ${body.byteLength}\r\n\r\n`,
bodyStr,
@ -519,16 +582,109 @@ unitTest(function responseRedirect(): void {
assertEquals(redir.type, "default");
});
unitTest(function responseConstructionHeaderRemoval(): void {
const res = new Response(
"example.com",
200,
"OK",
[["Set-Cookie", "mysessionid"]],
-1,
false,
"basic",
null
unitTest({ perms: { net: true } }, async function fetchBodyReadTwice(): Promise<
void
> {
const response = await fetch("http://localhost:4545/cli/tests/fixture.json");
// Read body
const _json = await response.json();
assert(_json);
// All calls after the body was consumed, should fail
const methods = ["json", "text", "formData", "arrayBuffer"];
for (const method of methods) {
try {
// @ts-expect-error
await response[method]();
fail(
"Reading body multiple times should failed, the stream should've been locked."
);
assert(res.headers.get("Set-Cookie") != "mysessionid");
} catch {}
}
});
unitTest(
{ perms: { net: true } },
async function fetchBodyReaderAfterRead(): Promise<void> {
const response = await fetch(
"http://localhost:4545/cli/tests/fixture.json"
);
assert(response.body !== null);
const reader = await response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
assert(value);
}
try {
response.body.getReader();
fail("The stream should've been locked.");
} catch {}
}
);
unitTest(
{ perms: { net: true } },
async function fetchBodyReaderWithCancelAndNewReader(): Promise<void> {
const data = "a".repeat(1 << 10);
const response = await fetch(
"http://localhost:4545/cli/tests/echo_server",
{
method: "POST",
body: data,
}
);
assert(response.body !== null);
const firstReader = await response.body.getReader();
// Acquire reader without reading & release
await firstReader.releaseLock();
const reader = await response.body.getReader();
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
assert(value);
total += value.length;
}
assertEquals(total, data.length);
}
);
unitTest(
{ perms: { net: true } },
async function fetchBodyReaderWithReadCancelAndNewReader(): Promise<void> {
const data = "a".repeat(1 << 10);
const response = await fetch(
"http://localhost:4545/cli/tests/echo_server",
{
method: "POST",
body: data,
}
);
assert(response.body !== null);
const firstReader = await response.body.getReader();
// Do one single read with first reader
const { value: firstValue } = await firstReader.read();
assert(firstValue);
await firstReader.releaseLock();
// Continue read with second reader
const reader = await response.body.getReader();
let total = firstValue.length || 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
assert(value);
total += value.length;
}
assertEquals(total, data.length);
}
);

View file

@ -290,7 +290,7 @@ unitTest(
// writing null should throw an error
let err;
try {
// @ts-ignore
// @ts-expect-error
await file.write(null);
} catch (e) {
err = e;
@ -322,7 +322,7 @@ unitTest(
// reading file into null buffer should throw an error
let err;
try {
// @ts-ignore
// @ts-expect-error
await file.read(null);
} catch (e) {
err = e;

View file

@ -41,9 +41,9 @@ unitTest(function formDataParamsGetSuccess(): void {
formData.append("a", "true");
formData.append("b", "false");
formData.append("a", "null");
// @ts-ignore
// @ts-expect-error
formData.append("d", undefined);
// @ts-ignore
// @ts-expect-error
formData.append("e", null);
assertEquals(formData.get("a"), "true");
assertEquals(formData.get("b"), "false");
@ -70,10 +70,10 @@ unitTest(function formDataParamsSetSuccess(): void {
assertEquals(formData.getAll("b"), ["false"]);
formData.set("a", "false");
assertEquals(formData.getAll("a"), ["false"]);
// @ts-ignore
// @ts-expect-error
formData.set("d", undefined);
assertEquals(formData.get("d"), "undefined");
// @ts-ignore
// @ts-expect-error
formData.set("e", null);
assertEquals(formData.get("e"), "null");
});
@ -134,7 +134,7 @@ unitTest(function formDataParamsArgumentsCheck(): void {
let hasThrown = 0;
let errMsg = "";
try {
// @ts-ignore
// @ts-expect-error
formData[method]();
hasThrown = 1;
} catch (err) {
@ -158,7 +158,7 @@ unitTest(function formDataParamsArgumentsCheck(): void {
let errMsg = "";
try {
// @ts-ignore
// @ts-expect-error
formData[method]();
hasThrown = 1;
} catch (err) {
@ -178,7 +178,7 @@ unitTest(function formDataParamsArgumentsCheck(): void {
hasThrown = 0;
errMsg = "";
try {
// @ts-ignore
// @ts-expect-error
formData[method]("foo");
hasThrown = 1;
} catch (err) {

View file

@ -48,12 +48,12 @@ unitTest(function webAssemblyExists(): void {
unitTest(function DenoNamespaceImmutable(): void {
const denoCopy = window.Deno;
try {
// @ts-ignore
// @ts-expect-error
Deno = 1;
} catch {}
assert(denoCopy === Deno);
try {
// @ts-ignore
// @ts-expect-error
window.Deno = 1;
} catch {}
assert(denoCopy === Deno);
@ -64,7 +64,7 @@ unitTest(function DenoNamespaceImmutable(): void {
const { readFile } = Deno;
try {
// @ts-ignore
// @ts-expect-error
Deno.readFile = 1;
} catch {}
assert(readFile === Deno.readFile);
@ -73,19 +73,19 @@ unitTest(function DenoNamespaceImmutable(): void {
} catch {}
assert(readFile === Deno.readFile);
// @ts-ignore
// @ts-expect-error
const { print } = Deno.core;
try {
// @ts-ignore
// @ts-expect-error
Deno.core.print = 1;
} catch {}
// @ts-ignore
// @ts-expect-error
assert(print === Deno.core.print);
try {
// @ts-ignore
// @ts-expect-error
delete Deno.core.print;
} catch {}
// @ts-ignore
// @ts-expect-error
assert(print === Deno.core.print);
});

View file

@ -7,7 +7,7 @@ import {
} from "./test_util.ts";
const {
stringifyArgs,
// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
} = Deno[Deno.internal];
// Logic heavily copied from web-platform-tests, make
@ -18,7 +18,7 @@ unitTest(function newHeaderTest(): void {
new Headers(undefined);
new Headers({});
try {
// @ts-ignore
// @ts-expect-error
new Headers(null);
} catch (e) {
assertEquals(
@ -32,7 +32,7 @@ const headerDict: Record<string, string> = {
name1: "value1",
name2: "value2",
name3: "value3",
// @ts-ignore
// @ts-expect-error
name4: undefined,
"Content-Type": "value4",
};
@ -269,7 +269,7 @@ unitTest(function headerParamsArgumentsCheck(): void {
let hasThrown = 0;
let errMsg = "";
try {
// @ts-ignore
// @ts-expect-error
headers[method]();
hasThrown = 1;
} catch (err) {
@ -293,7 +293,7 @@ unitTest(function headerParamsArgumentsCheck(): void {
let errMsg = "";
try {
// @ts-ignore
// @ts-expect-error
headers[method]();
hasThrown = 1;
} catch (err) {
@ -313,7 +313,7 @@ unitTest(function headerParamsArgumentsCheck(): void {
hasThrown = 0;
errMsg = "";
try {
// @ts-ignore
// @ts-expect-error
headers[method]("foo");
hasThrown = 1;
} catch (err) {

View file

@ -4,7 +4,7 @@ import { unitTest, assert } from "./test_util.ts";
unitTest(function internalsExists(): void {
const {
stringifyArgs,
// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol
// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
} = Deno[Deno.internal];
assert(!!stringifyArgs);
});

View file

@ -10,7 +10,7 @@ unitTest(function fromInit(): void {
},
});
// @ts-ignore
// @ts-expect-error
assertEquals("ahoyhoy", req._bodySource);
assertEquals(req.url, "https://example.com");
assertEquals(req.headers.get("test-header"), "value");
@ -18,13 +18,13 @@ unitTest(function fromInit(): void {
unitTest(function fromRequest(): void {
const r = new Request("https://example.com");
// @ts-ignore
// @ts-expect-error
r._bodySource = "ahoyhoy";
r.headers.set("test-header", "value");
const req = new Request(r);
// @ts-ignore
// @ts-expect-error
assertEquals(req._bodySource, r._bodySource);
assertEquals(req.url, r.url);
assertEquals(req.headers.get("test-header"), r.headers.get("test-header"));
@ -44,6 +44,6 @@ unitTest(async function cloneRequestBodyStream(): Promise<void> {
assertEquals(b1, b2);
// @ts-ignore
// @ts-expect-error
assert(r1._bodySource !== r2._bodySource);
});

View file

@ -8,7 +8,7 @@ unitTest(function streamReadableHwmError() {
() => {
new ReadableStream<number>(
undefined,
// @ts-ignore
// @ts-expect-error
{ highWaterMark }
);
},
@ -20,7 +20,7 @@ unitTest(function streamReadableHwmError() {
assertThrows(() => {
new ReadableStream<number>(
undefined,
// @ts-ignore
// @ts-expect-error
{ highWaterMark: Symbol("hwk") }
);
}, TypeError);
@ -33,7 +33,7 @@ unitTest(function streamWriteableHwmError() {
() => {
new WritableStream(
undefined,
// @ts-ignore
// @ts-expect-error
new CountQueuingStrategy({ highWaterMark })
);
},
@ -45,7 +45,7 @@ unitTest(function streamWriteableHwmError() {
assertThrows(() => {
new WritableStream(
undefined,
// @ts-ignore
// @ts-expect-error
new CountQueuingStrategy({ highWaterMark: Symbol("hwmk") })
);
}, TypeError);
@ -59,7 +59,7 @@ unitTest(function streamTransformHwmError() {
new TransformStream(
undefined,
undefined,
// @ts-ignore
// @ts-expect-error
{ highWaterMark }
);
},
@ -72,7 +72,7 @@ unitTest(function streamTransformHwmError() {
new TransformStream(
undefined,
undefined,
// @ts-ignore
// @ts-expect-error
{ highWaterMark: Symbol("hwmk") }
);
}, TypeError);

View file

@ -11,7 +11,7 @@ import {
reportToConn,
} from "./test_util.ts";
// @ts-ignore
// @ts-expect-error
const internalObj = Deno[Deno.internal];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const reportToConsole = internalObj.reportToConsole as (message: any) => void;

View file

@ -177,7 +177,7 @@ unitTest(function urlSearchParamsAppendArgumentsCheck(): void {
const searchParams = new URLSearchParams();
let hasThrown = 0;
try {
// @ts-ignore
// @ts-expect-error
searchParams[method]();
hasThrown = 1;
} catch (err) {
@ -194,7 +194,7 @@ unitTest(function urlSearchParamsAppendArgumentsCheck(): void {
const searchParams = new URLSearchParams();
let hasThrown = 0;
try {
// @ts-ignore
// @ts-expect-error
searchParams[method]("foo");
hasThrown = 1;
} catch (err) {
@ -235,7 +235,7 @@ unitTest(function urlSearchParamsCustomSymbolIterator(): void {
unitTest(
function urlSearchParamsCustomSymbolIteratorWithNonStringParams(): void {
const params = {};
// @ts-ignore
// @ts-expect-error
params[Symbol.iterator] = function* (): IterableIterator<[number, number]> {
yield [1, 2];
};

View file

@ -12,7 +12,6 @@ use futures::channel::mpsc;
use futures::future::FutureExt;
use futures::stream::StreamExt;
use futures::task::AtomicWaker;
use std::cell::RefMut;
use std::env;
use std::future::Future;
use std::ops::Deref;
@ -88,6 +87,7 @@ fn create_channels() -> (WorkerChannelsInternal, WorkerHandle) {
pub struct Worker {
pub name: String,
pub isolate: Box<deno_core::EsIsolate>,
pub inspector: Option<Box<DenoInspector>>,
pub state: State,
pub waker: AtomicWaker,
pub(crate) internal_channels: WorkerChannelsInternal,
@ -99,18 +99,30 @@ impl Worker {
let loader = Rc::new(state.clone());
let mut isolate = deno_core::EsIsolate::new(loader, startup_data, false);
state.maybe_init_inspector(&mut isolate);
{
let global_state = state.borrow().global_state.clone();
isolate.set_js_error_create_fn(move |core_js_error| {
JSError::create(core_js_error, &global_state.ts_compiler)
});
}
let inspector = {
let state = state.borrow();
let global_state = &state.global_state;
global_state
.flags
.inspect
.or(global_state.flags.inspect_brk)
.filter(|_| !state.is_internal)
.map(|inspector_host| DenoInspector::new(&mut isolate, inspector_host))
};
let (internal_channels, external_channels) = create_channels();
Self {
name,
isolate,
inspector,
state,
waker: AtomicWaker::new(),
internal_channels,
@ -173,16 +185,14 @@ impl Worker {
self.external_channels.clone()
}
#[inline(always)]
fn inspector(&self) -> RefMut<Option<Box<DenoInspector>>> {
let state = self.state.borrow_mut();
RefMut::map(state, |s| &mut s.inspector)
}
fn wait_for_inspector_session(&self) {
if self.state.should_inspector_break_on_first_statement() {
fn wait_for_inspector_session(&mut self) {
let should_break_on_first_statement = self.inspector.is_some() && {
let state = self.state.borrow();
state.is_main && state.global_state.flags.inspect_brk.is_some()
};
if should_break_on_first_statement {
self
.inspector()
.inspector
.as_mut()
.unwrap()
.wait_for_session_and_break_on_next_statement()
@ -194,7 +204,7 @@ impl Drop for Worker {
fn drop(&mut self) {
// The Isolate object must outlive the Inspector object, but this is
// currently not enforced by the type system.
self.inspector().take();
self.inspector.take();
}
}
@ -205,7 +215,7 @@ impl Future for Worker {
let inner = self.get_mut();
// We always poll the inspector if it exists.
let _ = inner.inspector().as_mut().map(|i| i.poll_unpin(cx));
let _ = inner.inspector.as_mut().map(|i| i.poll_unpin(cx));
inner.waker.register(cx.waker());
inner.isolate.poll_unpin(cx)
}

View file

@ -314,3 +314,16 @@ export function foo(): string {
`https://deno.land/std/` is intended to be baseline functionality that all Deno
programs can rely on. We want to guarantee to users that this code does not
include potentially unreviewed third party code.
#### Document and maintain browser compatiblity.
If a module is browser compatible, include the following in the JSDoc at the top
of the module:
```ts
/** This module is browser compatible. */
```
Maintain browser compatibility for such a module by either not using the global
`Deno` namespace or feature-testing for it. Make sure any new dependencies are
also browser compatible.

View file

@ -13,7 +13,7 @@ if (status.state !== "granted") {
throw new Error("need write permission");
}
const log = await Deno.open("request.log", "a+");
const log = await Deno.open("request.log", { write: true, append: true });
// revoke some permissions
await Deno.permissions.revoke({ name: "read" });

View file

@ -1,7 +1,7 @@
## TCP echo server
This is an example of a simple server which accepts connections on port 8080,
and returns to the client anything it sends.
This is an example of a server which accepts connections on port 8080, and
returns to the client anything it sends.
```ts
const listener = Deno.listen({ port: 8080 });

View file

@ -3,7 +3,9 @@
In this chapter we'll discuss:
- Installing Deno
- Running a simple `Hello World` script
- Setting up your environment
- Running a `Hello World` script
- Writing our own script
- Understanding permissions
- Using Deno with TypeScript
- Using WebAssembly

View file

@ -1,7 +1,6 @@
## First steps
This page contains some simple examples to teach you about the fundamentals of
Deno.
This page contains some examples to teach you about the fundamentals of Deno.
This document assumes that you have some prior knowledge of JavaScript,
especially about `async`/`await`. If you have no prior knowledge of JavaScript,
@ -14,8 +13,8 @@ before attempting to start with Deno.
Deno is a runtime for JavaScript/TypeScript which tries to be web compatible and
use modern features wherever possible.
Browser compatibility means, a simple `Hello World` program in Deno is the same
as the one you can run in the browser:
Browser compatibility means a `Hello World` program in Deno is the same as the
one you can run in the browser:
```ts
console.log("Welcome to Deno 🦕");
@ -87,9 +86,9 @@ In this program each command-line argument is assumed to be a filename, the file
is opened, and printed to stdout.
```ts
for (let i = 0; i < Deno.args.length; i++) {
let filename = Deno.args[i];
let file = await Deno.open(filename);
const filenames = Deno.args;
for (const filename of filenames) {
const file = await Deno.open(filename);
await Deno.copy(file, Deno.stdout);
file.close();
}
@ -106,14 +105,16 @@ Try the program:
deno run --allow-read https://deno.land/std/examples/cat.ts /etc/passwd
```
### A simple TCP server
### TCP server
This is an example of a simple server which accepts connections on port 8080,
and returns to the client anything it sends.
This is an example of a server which accepts connections on port 8080, and
returns to the client anything it sends.
```ts
const listener = Deno.listen({ port: 8080 });
console.log("listening on 0.0.0.0:8080");
const hostname = "0.0.0.0";
const port = 8080;
const listener = Deno.listen({ hostname, port });
console.log(`Listening on ${hostname}:${port}`);
for await (const conn of listener) {
Deno.copy(conn, conn);
}

View file

@ -59,11 +59,22 @@ Use `deno help` to see help text documenting Deno's flags and usage. Use
### Updating
To update a previously installed version of Deno, you can run `deno upgrade`.
To update a previously installed version of Deno, you can run:
```shell
deno upgrade
```
This will fetch the latest release from
[github.com/denoland/deno/releases](https://github.com/denoland/deno/releases),
unzip it, and replace your current executable with it.
You can also use this utility to install a specific version of Deno:
```shell
deno upgrade --version 1.0.1
```
### Building from source
Information about how to build from source can be found in the `Contributing`

View file

@ -1,15 +1,50 @@
## Permissions
<!-- TODO(lucacasonato): what are permissions -->
Deno is secure by default. Therefore, unless you specifically enable it, a deno
module has no file, network, or environment access for example. Access to
security sensitive areas or functions requires the use of permissions to be
granted to a deno process on the command line.
<!-- TODO(lucacasonato): description of all permissions -->
For the following example, `mod.ts` has been granted read-only access to the
file system. It cannot write to it, or perform any other security sensitive
functions.
```shell
deno run --allow-read mod.ts
```
### Permissions list
The following permissions are available:
- **-A, --allow-all** Allow all permissions. This disables all security.
- **--allow-env** Allow environment access for things like getting and setting
of environment variables.
- **--allow-hrtime** Allow high resolution time measurement. High resolution
time can be used in timing attacks and fingerprinting.
- **--allow-net=\<allow-net\>** Allow network access. You can specify an
optional, comma separated list of domains to provide a whitelist of allowed
domains.
- **--allow-plugin** Allow loading plugins. Please note that --allow-plugin is
an unstable feature.
- **--allow-read=\<allow-read\>** Allow file system read access. You can specify
an optional, comma separated list of directories or files to provide a
whitelist of allowed file system access.
- **--allow-run** Allow running subprocesses. Be aware that subprocesses are not
run in a sandbox and therefore do not have the same security restrictions as
the deno process. Therefore, use with caution.
- **--allow-write=\<allow-write\>** Allow file system write access. You can
specify an optional, comma separated list of directories or files to provide a
whitelist of allowed file system access.
### Permissions whitelist
Deno also allows you to control the granularity of permissions with whitelists.
Deno also allows you to control the granularity of some permissions with
whitelists.
This example restricts file system access by whitelisting only the `/usr`
directory:
directory, however the execution fails as the process was attempting to access a
file in the `/etc` directory:
```shell
$ deno run --allow-read=/usr https://deno.land/std/examples/cat.ts /etc/passwd
@ -41,6 +76,9 @@ This is an example on how to whitelist hosts/urls:
$ deno run --allow-net=github.com,deno.land fetch.ts
```
If `fetch.ts` tries to establish network connections to any other domain, the
process will fail.
Allow net calls to any host/url:
```shell

View file

@ -8,8 +8,8 @@ IDE of choice.
There are several env vars that control how Deno behaves:
`DENO_DIR` defaults to `$HOME/.deno` but can be set to any path to control where
generated and cached source code is written and read to.
`DENO_DIR` defaults to `$HOME/.cache/deno` but can be set to any path to control
where generated and cached source code is written and read to.
`NO_COLOR` will turn off color output if set. See https://no-color.org/. User
code can test if `NO_COLOR` was set without having `--allow-env` by using the

View file

@ -2,12 +2,19 @@
<!-- TODO(lucacasonato): text on 'just import .ts' -->
### Using external type definitions
Deno supports both JavaScript and TypeScript as first class languages at
runtime. This means it requires fully qualified module names, including the
extension (or a server providing the correct media type). In addition, Deno has
no "magical" module resolution.
no "magical" module resolution. Instead, imported modules are specified as files
(including extensions) or fully qualified URL imports. Typescript modules can be
directly imported. E.g.
```
import { Response } from "https://deno.land/std@0.53.0/http/server.ts";
import { queue } from "./collections.ts";
```
### Using external type definitions
The out of the box TypeScript compiler though relies on both extension-less
modules and the Node.js module resolution logic to apply types to JavaScript
@ -98,7 +105,7 @@ way to support customization a configuration file such as `tsconfig.json` might
be provided to Deno on program execution.
You need to explicitly tell Deno where to look for this configuration by setting
the `-c` argument when executing your application.
the `-c` (or `--config`) argument when executing your application.
```shell
deno run -c tsconfig.json mod.ts

View file

@ -52,7 +52,7 @@ const [diagnostics, emitMap] = await Deno.compile(
);
```
In this case `emitMap` will contain a simple `console.log()` statement.
In this case `emitMap` will contain a `console.log()` statement.
### `Deno.bundle()`

View file

@ -35,6 +35,8 @@ You can also test asynchronous code by passing a test function that returns a
promise. For this you can use the `async` keyword when defining a function:
```ts
import { delay } from "https://deno.land/std/async/delay.ts";
Deno.test("async hello world", async () => {
const x = 1 + 2;

View file

@ -14,9 +14,9 @@ first line of code.
### Chrome Devtools
Let's try debugging simple program using Chrome Devtools; for this purpose we'll
use [file_server.ts](https://deno.land/std@v0.50.0/http/file_server.ts) from
`std`; a simple static file server.
Let's try debugging a program using Chrome Devtools; for this purpose we'll use
[file_server.ts](https://deno.land/std@v0.50.0/http/file_server.ts) from `std`;
a static file server.
Use `--inspect-brk` flag to break execution on the first line.
@ -83,7 +83,7 @@ Deno can be debugged using VSCode.
Official support in plugin is being worked on -
https://github.com/denoland/vscode_deno/issues/12
We can still attach debugger by manually providing simple `launch.json` config:
We can still attach debugger by manually providing a `launch.json` config:
```json
{
@ -108,10 +108,10 @@ This time let's try with local source file, create `server.ts`:
```ts
import { serve } from "https://deno.land/std@v0.50.0/http/server.ts";
const s = serve({ port: 8000 });
const server = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
for await (const req of server) {
req.respond({ body: "Hello World\n" });
}
```

41
std/encoding/base64.ts Normal file
View file

@ -0,0 +1,41 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/**
* Converts given data with base64 encoding
* @param data input to encode
*/
export function encode(data: string | ArrayBuffer): string {
if (typeof data === "string") {
return window.btoa(data);
} else {
const d = new Uint8Array(data);
let dataString = "";
for (let i = 0; i < d.length; ++i) {
dataString += String.fromCharCode(d[i]);
}
return window.btoa(dataString);
}
}
/**
* Converts given base64 encoded data back to original
* @param data input to decode
*/
export function decode(data: string): ArrayBuffer {
const binaryString = decodeString(data);
const binary = new Uint8Array(binaryString.length);
for (let i = 0; i < binary.length; ++i) {
binary[i] = binaryString.charCodeAt(i);
}
return binary.buffer;
}
/**
* Decodes data assuming the output is in string type
* @param data input to decode
*/
export function decodeString(data: string): string {
return window.atob(data);
}

View file

@ -0,0 +1,47 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
const { test } = Deno;
import { assertEquals } from "../testing/asserts.ts";
import { encode, decode, decodeString } from "./base64.ts";
const testsetString = [
["", ""],
["f", "Zg=="],
["fo", "Zm8="],
["foo", "Zm9v"],
["foob", "Zm9vYg=="],
["fooba", "Zm9vYmE="],
["foobar", "Zm9vYmFy"],
];
const testsetBinary = [
[new TextEncoder().encode("\x00"), "AA=="],
[new TextEncoder().encode("\x00\x00"), "AAA="],
[new TextEncoder().encode("\x00\x00\x00"), "AAAA"],
[new TextEncoder().encode("\x00\x00\x00\x00"), "AAAAAA=="],
];
test("[encoding/base64] testBase64EncodeString", () => {
for (const [input, output] of testsetString) {
assertEquals(encode(input), output);
}
});
test("[encoding/base64] testBase64DecodeString", () => {
for (const [input, output] of testsetString) {
assertEquals(decodeString(output), input);
}
});
test("[encoding/base64] testBase64EncodeBinary", () => {
for (const [input, output] of testsetBinary) {
assertEquals(encode(input), output);
}
});
test("[encoding/base64] testBase64DecodeBinary", () => {
for (const [input, output] of testsetBinary) {
const outputBinary = new Uint8Array(decode(output as string));
assertEquals(outputBinary, input as Uint8Array);
}
});

View file

@ -1,6 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/**
* A module to print ANSI terminal colors. Inspired by chalk, kleur, and colors
/** A module to print ANSI terminal colors. Inspired by chalk, kleur, and colors
* on npm.
*
* ```
@ -10,8 +9,10 @@
*
* This module supports `NO_COLOR` environmental variable disabling any coloring
* if `NO_COLOR` is set.
*/
const { noColor } = Deno;
*
* This module is browser compatible. */
const noColor = globalThis.Deno?.noColor ?? true;
interface Code {
open: string;

View file

@ -2,9 +2,9 @@
```typescript
import { serve } from "https://deno.land/std/http/server.ts";
const s = serve({ port: 8000 });
const server = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
for await (const req of server) {
req.respond({ body: "Hello World\n" });
}
```

View file

@ -247,8 +247,8 @@ export type HTTPOptions = Omit<Deno.ListenOptions, "transport">;
*
* import { serve } from "https://deno.land/std/http/server.ts";
* const body = "Hello World\n";
* const s = serve({ port: 8000 });
* for await (const req of s) {
* const server = serve({ port: 8000 });
* for await (const req of server) {
* req.respond({ body });
* }
*/

View file

@ -496,7 +496,6 @@ test({
async fn(): Promise<void> {
const serverRoutine = async (): Promise<void> => {
const server = serve(":8124");
// @ts-ignore
for await (const req of server) {
await assertThrowsAsync(async () => {
await req.respond({

View file

@ -125,7 +125,7 @@ export class FileHandler extends WriterHandler {
}
log(msg: string): void {
Deno.writeSync(this._file.rid, this.#encoder.encode(msg + "\n"));
Deno.writeAllSync(this._file, this.#encoder.encode(msg + "\n"));
}
destroy(): Promise<void> {

View file

@ -145,7 +145,7 @@ test("multipartMultipartWriter3", async function (): Promise<void> {
);
await assertThrowsAsync(
async (): Promise<void> => {
// @ts-ignore
// @ts-expect-error
await mw.writeFile("bar", "file", null);
},
Error,

View file

@ -10,13 +10,13 @@ const destFile = "./destination.txt";
test({
name: "[std/node/fs] copy file",
fn: async () => {
const srouceFile = Deno.makeTempFileSync();
const sourceFile = Deno.makeTempFileSync();
const err = await new Promise((resolve) => {
copyFile(srouceFile, destFile, (err?: Error | null) => resolve(err));
copyFile(sourceFile, destFile, (err?: Error | null) => resolve(err));
});
assert(!err);
assert(existsSync(destFile));
Deno.removeSync(srouceFile);
Deno.removeSync(sourceFile);
Deno.removeSync(destFile);
},
});
@ -24,10 +24,10 @@ test({
test({
name: "[std/node/fs] copy file sync",
fn: () => {
const srouceFile = Deno.makeTempFileSync();
copyFileSync(srouceFile, destFile);
const sourceFile = Deno.makeTempFileSync();
copyFileSync(sourceFile, destFile);
assert(existsSync(destFile));
Deno.removeSync(srouceFile);
Deno.removeSync(sourceFile);
Deno.removeSync(destFile);
},
});

View file

@ -5,5 +5,5 @@ Object.defineProperty(globalThis, Symbol.toStringTag, {
configurable: true,
});
// @ts-ignore
// @ts-expect-error
globalThis["global"] = globalThis;

View file

@ -263,9 +263,9 @@ class Module {
message = message + "\nRequire stack:\n- " + requireStack.join("\n- ");
}
const err = new Error(message);
// @ts-ignore
// @ts-expect-error
err.code = "MODULE_NOT_FOUND";
// @ts-ignore
// @ts-expect-error
err.requireStack = requireStack;
throw err;
}
@ -737,7 +737,7 @@ function tryPackage(
`Cannot find module '${filename}'. ` +
'Please verify that the package.json has a valid "main" entry'
);
// @ts-ignore
// @ts-expect-error
err.code = "MODULE_NOT_FOUND";
throw err;
}
@ -882,7 +882,7 @@ function applyExports(basePath: string, expansion: string): string {
`Package exports for '${basePath}' do not define ` +
`a '${mappingKey}' subpath`
);
// @ts-ignore
// @ts-expect-error
e.code = "MODULE_NOT_FOUND";
throw e;
}
@ -982,7 +982,7 @@ function resolveExportsTarget(
} else {
e = new Error(`No valid exports main found for '${basePath}'`);
}
// @ts-ignore
// @ts-expect-error
e.code = "MODULE_NOT_FOUND";
throw e;
}
@ -1007,7 +1007,7 @@ const CircularRequirePrototypeWarningProxy = new Proxy(
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get(target, prop): any {
// @ts-ignore
// @ts-expect-error
if (prop in target) return target[prop];
emitCircularRequireWarning(prop);
return undefined;
@ -1058,7 +1058,7 @@ type RequireWrapper = (
function wrapSafe(filename: string, content: string): RequireWrapper {
// TODO: fix this
const wrapper = Module.wrap(content);
// @ts-ignore
// @ts-expect-error
const [f, err] = Deno.core.evalContext(wrapper, filename);
if (err) {
throw err;

View file

@ -9,7 +9,7 @@ test({
fn() {
assertThrows(
() => {
// @ts-ignore
// @ts-expect-error
signal();
},
Error,

View file

@ -1,4 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/** This module is browser compatible. Do not rely on good formatting of values
* for AssertionError messages in browsers. */
import { red, green, white, gray, bold } from "../fmt/colors.ts";
import diff, { DiffType, DiffResult } from "./diff.ts";
@ -17,7 +20,7 @@ export class AssertionError extends Error {
}
function format(v: unknown): string {
let string = Deno.inspect(v);
let string = globalThis.Deno ? Deno.inspect(v) : String(v);
if (typeof v == "string") {
string = `"${string.replace(/(?=["\\])/g, "\\")}"`;
}
@ -254,7 +257,7 @@ export function assertStrContains(
): void {
if (!actual.includes(expected)) {
if (!msg) {
msg = `actual: "${actual}" expected to contains: "${expected}"`;
msg = `actual: "${actual}" expected to contain: "${expected}"`;
}
throw new AssertionError(msg);
}
@ -286,7 +289,7 @@ export function assertArrayContains(
return;
}
if (!msg) {
msg = `actual: "${actual}" expected to contains: "${expected}"`;
msg = `actual: "${actual}" expected to contain: "${expected}"`;
msg += "\n";
msg += `missing: ${missing}`;
}

View file

@ -169,7 +169,7 @@ test("testingAssertStringContainsThrow", function (): void {
} catch (e) {
assert(
e.message ===
`actual: "Denosaurus from Jurassic" expected to contains: "Raptor"`
`actual: "Denosaurus from Jurassic" expected to contain: "Raptor"`
);
assert(e instanceof AssertionError);
didThrow = true;

View file

@ -1,4 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/** This module is browser compatible. */
interface FarthestPoint {
y: number;
id: number;

View file

@ -1,7 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assert } from "../../testing/asserts.ts";
const { test } = Deno;
// @ts-ignore
import { NIL_UUID, isNil } from "../mod.ts";
test({

View file

@ -491,7 +491,7 @@ export async function handshake(
throw new Error("ws: invalid status line: " + statusLine);
}
// @ts-ignore
// @ts-expect-error
const { version, statusCode } = m.groups;
if (version !== "HTTP/1.1" || statusCode !== "101") {
throw new Error(