mirror of
https://github.com/denoland/deno.git
synced 2024-11-23 15:16:54 -05:00
Merge branch 'master' into v1.1
This commit is contained in:
commit
cf081f9b6e
79 changed files with 985 additions and 765 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -23,3 +23,9 @@ export {
|
|||
PermissionStatus,
|
||||
Permissions,
|
||||
} from "./permissions.ts";
|
||||
export {
|
||||
Diagnostic,
|
||||
DiagnosticCategory,
|
||||
DiagnosticItem,
|
||||
DiagnosticMessageChain,
|
||||
} from "./diagnostics.ts";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
11
cli/js/lib.deno.ns.d.ts
vendored
11
cli/js/lib.deno.ns.d.ts
vendored
|
@ -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" }
|
||||
* ```
|
||||
|
|
21
cli/js/lib.deno.shared_globals.d.ts
vendored
21
cli/js/lib.deno.shared_globals.d.ts
vendored
|
@ -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;
|
||||
};
|
||||
|
|
2
cli/js/lib.deno.unstable.d.ts
vendored
2
cli/js/lib.deno.unstable.d.ts
vendored
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 => {
|
||||
const parts: Uint8Array[] = [];
|
||||
const encoder = new TextEncoder();
|
||||
// recurse
|
||||
(function pump(): void {
|
||||
stream
|
||||
.read()
|
||||
.then(({ done, value }): void => {
|
||||
if (done) {
|
||||
return resolve(concatenate(...parts));
|
||||
}
|
||||
async function bufferFromStream(
|
||||
stream: ReadableStreamReader
|
||||
): Promise<ArrayBuffer> {
|
||||
const parts: Uint8Array[] = [];
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
if (typeof value === "string") {
|
||||
parts.push(encoder.encode(value));
|
||||
} else if (value instanceof ArrayBuffer) {
|
||||
parts.push(new Uint8Array(value));
|
||||
} else if (!value) {
|
||||
// noop for undefined
|
||||
} else {
|
||||
reject("unhandled type on stream read");
|
||||
}
|
||||
while (true) {
|
||||
const { done, value } = await stream.read();
|
||||
|
||||
return pump();
|
||||
})
|
||||
.catch((err): void => {
|
||||
reject(err);
|
||||
});
|
||||
})();
|
||||
});
|
||||
}
|
||||
if (done) break;
|
||||
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
throw new Error("unhandled type on stream read");
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
1
cli/js/web/dom_types.d.ts
vendored
1
cli/js/web/dom_types.d.ts
vendored
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
36
cli/state.rs
36
cli/state.rs
|
@ -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)
|
||||
|
|
|
@ -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,9 +582,13 @@ console.log(fizz);
|
|||
console.log(qat.qat);
|
||||
"#;
|
||||
|
||||
let (imports, references) =
|
||||
analyze_dependencies_and_references("some/file.ts", source, true)
|
||||
.expect("Failed to parse");
|
||||
let (imports, references) = analyze_dependencies_and_references(
|
||||
"some/file.ts",
|
||||
MediaType::TypeScript,
|
||||
source,
|
||||
true,
|
||||
)
|
||||
.expect("Failed to parse");
|
||||
|
||||
assert_eq!(
|
||||
imports,
|
||||
|
|
|
@ -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
1
cli/tests/Component.tsx
Normal file
|
@ -0,0 +1 @@
|
|||
import "./046_jsx_test.tsx";
|
|
@ -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]
|
||||
|
|
3
cli/tests/ts_with_generic.ts
Normal file
3
cli/tests/ts_with_generic.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
/* eslint-disable */
|
||||
|
||||
const foo = { delete<S>() {} };
|
1
cli/tests/tsx_imports.ts
Normal file
1
cli/tests/tsx_imports.ts
Normal file
|
@ -0,0 +1 @@
|
|||
import "./Component.tsx";
|
2
cli/tests/tsx_imports.ts.out
Normal file
2
cli/tests/tsx_imports.ts.out
Normal file
|
@ -0,0 +1,2 @@
|
|||
Compile [WILDCARD]tsx_imports.ts
|
||||
{ factory: [Function: View], props: null, children: [] }
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
@ -590,7 +590,7 @@ unitTest(function consoleTestStringifyIterable() {
|
|||
0, <120 empty items>
|
||||
]`
|
||||
);
|
||||
*/
|
||||
*/
|
||||
});
|
||||
|
||||
unitTest(async function consoleTestStringifyPromises(): Promise<void> {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
assert(res.headers.get("Set-Cookie") != "mysessionid");
|
||||
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."
|
||||
);
|
||||
} 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);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
|
@ -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 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)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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" });
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()`
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
41
std/encoding/base64.ts
Normal 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);
|
||||
}
|
47
std/encoding/base64_test.ts
Normal file
47
std/encoding/base64_test.ts
Normal 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);
|
||||
}
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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" });
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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 });
|
||||
* }
|
||||
*/
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -5,5 +5,5 @@ Object.defineProperty(globalThis, Symbol.toStringTag, {
|
|||
configurable: true,
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
globalThis["global"] = globalThis;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,7 +9,7 @@ test({
|
|||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
signal();
|
||||
},
|
||||
Error,
|
||||
|
|
|
@ -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}`;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue