refactor: remove more compiler runtime code (#6841)

This commit is contained in:
Bartek Iwańczuk 2020-07-23 15:29:36 +02:00 committed by GitHub
parent e18e46a3b3
commit b449964d1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 227 additions and 4316 deletions

View file

@ -38,7 +38,7 @@ fn compiler_snapshot() {
deno_core::js_check(isolate.execute(
"<anon>",
r#"
if (!(bootstrap.tsCompilerRuntime)) {
if (!(bootstrapCompilerRuntime)) {
throw Error("bad");
}
console.log(`ts version: ${ts.version}`);

View file

@ -1,8 +1,20 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use super::dispatch_json::{JsonOp, Value};
use crate::op_error::OpError;
use crate::ops::json_op;
use crate::ops::JsonOpDispatcher;
use crate::state::State;
use deno_core::CoreIsolate;
use deno_core::CoreIsolateState;
use deno_core::ZeroCopyBuf;
use std::sync::Arc;
use std::sync::Mutex;
pub fn init(i: &mut CoreIsolate, _s: &State) {
pub fn init(
i: &mut CoreIsolate,
_s: &State,
response: Arc<Mutex<Option<String>>>,
) {
let custom_assets = std::collections::HashMap::new();
// TODO(ry) use None.
// TODO(bartlomieju): is this op even required?
@ -10,4 +22,42 @@ pub fn init(i: &mut CoreIsolate, _s: &State) {
"op_fetch_asset",
crate::op_fetch_asset::op_fetch_asset(custom_assets),
);
i.register_op(
"op_compiler_respond",
json_op(compiler_op(response, op_compiler_respond)),
);
}
pub fn compiler_op<D>(
response: Arc<Mutex<Option<String>>>,
dispatcher: D,
) -> impl JsonOpDispatcher
where
D: Fn(
Arc<Mutex<Option<String>>>,
Value,
&mut [ZeroCopyBuf],
) -> Result<JsonOp, OpError>,
{
move |_isolate_state: &mut CoreIsolateState,
args: Value,
zero_copy: &mut [ZeroCopyBuf]|
-> Result<JsonOp, OpError> {
dispatcher(response.clone(), args, zero_copy)
}
}
fn op_compiler_respond(
response: Arc<Mutex<Option<String>>>,
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<JsonOp, OpError> {
let mut r = response.lock().unwrap();
assert!(
r.is_none(),
"op_compiler_respond found unexpected existing compiler output"
);
*r = Some(args.to_string());
Ok(JsonOp::Sync(json!({})))
}

View file

@ -689,7 +689,7 @@ fn ts_reload() {
assert!(std::str::from_utf8(&output.stdout)
.unwrap()
.trim()
.contains("compiler::host.writeFile deno://002_hello.js"));
.contains("\"compiler::host.writeFile\" \"deno://002_hello.js\""));
}
#[test]

View file

@ -1,3 +1,3 @@
[WILDCARD]
DEBUG TS - compiler::host.getSourceFile http://127.0.0.1:4545/xTypeScriptTypes.d.ts
DEBUG TS - "compiler::host.getSourceFile" "http://127.0.0.1:4545/xTypeScriptTypes.d.ts"
[WILDCARD]

View file

@ -1,3 +1,3 @@
[WILDCARD]
DEBUG TS - compiler::host.getSourceFile file:[WILDCARD]cli/tests/subdir/type_reference.d.ts
DEBUG TS - "compiler::host.getSourceFile" "file:[WILDCARD]cli/tests/subdir/type_reference.d.ts"
[WILDCARD]

View file

@ -28,14 +28,11 @@ use crate::swc_ecma_visit::Visit;
use crate::swc_util::AstParser;
use crate::swc_util::SwcDiagnosticBuffer;
use crate::version;
use crate::web_worker::WebWorker;
use crate::worker::WorkerEvent;
use crate::worker::Worker;
use core::task::Context;
use deno_core::Buf;
use deno_core::ErrBox;
use deno_core::ModuleSpecifier;
use deno_core::StartupData;
use futures::future::Either;
use futures::future::Future;
use futures::future::FutureExt;
use log::debug;
@ -130,30 +127,47 @@ pub struct CompiledModule {
pub name: String,
}
pub struct CompilerWorker(WebWorker);
pub struct CompilerWorker {
worker: Worker,
response: Arc<Mutex<Option<String>>>,
}
impl CompilerWorker {
pub fn new(name: String, startup_data: StartupData, state: State) -> Self {
let state_ = state.clone();
let mut worker = WebWorker::new(name, startup_data, state_, false);
let mut worker = Worker::new(name, startup_data, state_);
let response = Arc::new(Mutex::new(None));
{
let isolate = &mut worker.isolate;
ops::compiler::init(isolate, &state);
ops::runtime::init(isolate, &state);
ops::errors::init(isolate, &state);
ops::timers::init(isolate, &state);
ops::compiler::init(isolate, &state, response.clone());
}
Self(worker)
Self { worker, response }
}
pub fn get_response(&mut self) -> String {
let mut maybe_response = self.response.lock().unwrap();
assert!(
maybe_response.is_some(),
"Unexpected missing response from TS compiler"
);
maybe_response.take().unwrap()
}
}
impl Deref for CompilerWorker {
type Target = WebWorker;
type Target = Worker;
fn deref(&self) -> &Self::Target {
&self.0
&self.worker
}
}
impl DerefMut for CompilerWorker {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
&mut self.worker
}
}
@ -162,7 +176,7 @@ impl Future for CompilerWorker {
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let inner = self.get_mut();
inner.0.poll_unpin(cx)
inner.worker.poll_unpin(cx)
}
}
@ -212,7 +226,9 @@ fn create_compiler_worker(
startup_data::compiler_isolate_init(),
worker_state,
);
worker.execute("bootstrap.tsCompilerRuntime()").unwrap();
worker
.execute("globalThis.bootstrapCompilerRuntime()")
.unwrap();
worker
}
@ -604,17 +620,15 @@ impl TsCompiler {
}),
};
let req_msg = j.to_string().into_boxed_str().into_boxed_bytes();
let req_msg = j.to_string();
// TODO(bartlomieju): lift this call up - TSC shouldn't print anything
info!("{} {}", colors::green("Check"), module_url.to_string());
let msg =
let json_str =
execute_in_same_thread(global_state, permissions, req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
let compile_response: CompileResponse = serde_json::from_str(json_str)?;
let compile_response: CompileResponse = serde_json::from_str(&json_str)?;
if !compile_response.diagnostics.items.is_empty() {
return Err(ErrBox::from(compile_response.diagnostics));
@ -713,13 +727,12 @@ impl TsCompiler {
}),
};
let req_msg = j.to_string().into_boxed_str().into_boxed_bytes();
let req_msg = j.to_string();
let msg =
let json_str =
execute_in_same_thread(global_state, permissions, req_msg).await?;
let json_str = std::str::from_utf8(&msg).unwrap();
let bundle_response: BundleResponse = serde_json::from_str(json_str)?;
let bundle_response: BundleResponse = serde_json::from_str(&json_str)?;
maybe_log_stats(bundle_response.stats);
@ -778,15 +791,14 @@ impl TsCompiler {
}),
};
let req_msg = j.to_string().into_boxed_str().into_boxed_bytes();
let req_msg = j.to_string();
let msg =
let json_str =
execute_in_same_thread(global_state.clone(), permissions, req_msg)
.await?;
let json_str = std::str::from_utf8(&msg).unwrap();
let transpile_response: TranspileResponse = serde_json::from_str(json_str)?;
let transpile_response: TranspileResponse =
serde_json::from_str(&json_str)?;
if !transpile_response.diagnostics.items.is_empty() {
return Err(ErrBox::from(transpile_response.diagnostics));
@ -1079,35 +1091,13 @@ impl TsCompiler {
async fn execute_in_same_thread(
global_state: GlobalState,
permissions: Permissions,
req: Buf,
) -> Result<Buf, ErrBox> {
req: String,
) -> Result<String, ErrBox> {
let mut worker = create_compiler_worker(global_state.clone(), permissions);
let handle = worker.thread_safe_handle();
handle.post_message(req)?;
let mut event_fut = handle.get_event().boxed_local();
loop {
let select_result = futures::future::select(event_fut, &mut worker).await;
match select_result {
Either::Left((event_result, _worker)) => {
let event = event_result
.expect("Compiler didn't respond")
.expect("Empty message");
let buf = match event {
WorkerEvent::Message(buf) => Ok(buf),
WorkerEvent::Error(error) => Err(error),
WorkerEvent::TerminalError(error) => Err(error),
}?;
return Ok(buf);
}
Either::Right((worker_result, event_fut_)) => {
event_fut = event_fut_;
worker_result?;
}
}
}
let script = format!("globalThis.tsCompilerOnMessage({{ data: {} }});", req);
worker.execute2("<compiler>", &script)?;
(&mut *worker).await?;
Ok(worker.get_response())
}
async fn create_runtime_module_graph(
@ -1200,18 +1190,15 @@ pub async fn runtime_compile(
"options": maybe_options,
"unstable": global_state.flags.unstable,
})
.to_string()
.into_boxed_str()
.into_boxed_bytes();
.to_string();
let compiler = global_state.ts_compiler.clone();
let msg = execute_in_same_thread(global_state, permissions, req_msg)
let json_str = execute_in_same_thread(global_state, permissions, req_msg)
.await
.map_err(js_error_to_op_error)?;
let json_str = std::str::from_utf8(&msg).unwrap();
let response: RuntimeCompileResponse = serde_json::from_str(json_str)?;
let response: RuntimeCompileResponse = serde_json::from_str(&json_str)?;
if response.diagnostics.is_empty() && sources.is_none() {
compiler.cache_emitted_files(response.emit_map)?;
@ -1220,7 +1207,7 @@ pub async fn runtime_compile(
// We're returning `Ok()` instead of `Err()` because it's not runtime
// error if there were diagnostics produced; we want to let user handle
// diagnostics in the runtime.
Ok(serde_json::from_str::<Value>(json_str).unwrap())
Ok(serde_json::from_str::<Value>(&json_str).unwrap())
}
/// This function is used by `Deno.bundle()` API.
@ -1250,19 +1237,16 @@ pub async fn runtime_bundle(
"options": maybe_options,
"unstable": global_state.flags.unstable,
})
.to_string()
.into_boxed_str()
.into_boxed_bytes();
.to_string();
let msg = execute_in_same_thread(global_state, permissions, req_msg)
let json_str = execute_in_same_thread(global_state, permissions, req_msg)
.await
.map_err(js_error_to_op_error)?;
let json_str = std::str::from_utf8(&msg).unwrap();
let _response: RuntimeBundleResponse = serde_json::from_str(json_str)?;
let _response: RuntimeBundleResponse = serde_json::from_str(&json_str)?;
// We're returning `Ok()` instead of `Err()` because it's not runtime
// error if there were diagnostics produced; we want to let user handle
// diagnostics in the runtime.
Ok(serde_json::from_str::<Value>(json_str).unwrap())
Ok(serde_json::from_str::<Value>(&json_str).unwrap())
}
/// This function is used by `Deno.transpileOnly()` API.
@ -1277,15 +1261,12 @@ pub async fn runtime_transpile(
"sources": sources,
"options": options,
})
.to_string()
.into_boxed_str()
.into_boxed_bytes();
.to_string();
let msg = execute_in_same_thread(global_state, permissions, req_msg)
let json_str = execute_in_same_thread(global_state, permissions, req_msg)
.await
.map_err(js_error_to_op_error)?;
let json_str = std::str::from_utf8(&msg).unwrap();
let v = serde_json::from_str::<serde_json::Value>(json_str)
let v = serde_json::from_str::<serde_json::Value>(&json_str)
.expect("Error decoding JSON string.");
Ok(v)
}
@ -1775,6 +1756,7 @@ mod tests {
.ts_compiler
.bundle(mock_state.clone(), module_name)
.await;
assert!(result.is_ok());
}

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -1,23 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const internalSymbol = Symbol("Deno.internal");
// The object where all the internal fields for testing will be living.
const internalObject = {};
// Register a field to internalObject for test access,
// through Deno[Deno.internal][name].
function exposeForTest(name, value) {
Object.defineProperty(internalObject, name, {
value,
enumerable: false,
});
}
window.__bootstrap.internals = {
internalSymbol,
internalObject,
exposeForTest,
};
})(this);

View file

@ -1,26 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const version = {
deno: "",
v8: "",
typescript: "",
};
function setVersions(
denoVersion,
v8Version,
tsVersion,
) {
version.deno = denoVersion;
version.v8 = v8Version;
version.typescript = tsVersion;
Object.freeze(version);
}
window.__bootstrap.version = {
version,
setVersions,
};
})(this);

View file

@ -1,202 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
function isTypedArray(x) {
return ArrayBuffer.isView(x) && !(x instanceof DataView);
}
function isInvalidDate(x) {
return isNaN(x.getTime());
}
function requiredArguments(
name,
length,
required,
) {
if (length < required) {
const errMsg = `${name} requires at least ${required} argument${
required === 1 ? "" : "s"
}, but only ${length} present`;
throw new TypeError(errMsg);
}
}
function immutableDefine(
o,
p,
value,
) {
Object.defineProperty(o, p, {
value,
configurable: false,
writable: false,
});
}
function hasOwnProperty(obj, v) {
if (obj == null) {
return false;
}
return Object.prototype.hasOwnProperty.call(obj, v);
}
/** Returns whether o is iterable. */
function isIterable(
o,
) {
// checks for null and undefined
if (o == null) {
return false;
}
return (
typeof (o)[Symbol.iterator] === "function"
);
}
const objectCloneMemo = new WeakMap();
function cloneArrayBuffer(
srcBuffer,
srcByteOffset,
srcLength,
_cloneConstructor,
) {
// this function fudges the return type but SharedArrayBuffer is disabled for a while anyway
return srcBuffer.slice(
srcByteOffset,
srcByteOffset + srcLength,
);
}
/** Clone a value in a similar way to structured cloning. It is similar to a
* StructureDeserialize(StructuredSerialize(...)). */
function cloneValue(value) {
switch (typeof value) {
case "number":
case "string":
case "boolean":
case "undefined":
case "bigint":
return value;
case "object": {
if (objectCloneMemo.has(value)) {
return objectCloneMemo.get(value);
}
if (value === null) {
return value;
}
if (value instanceof Date) {
return new Date(value.valueOf());
}
if (value instanceof RegExp) {
return new RegExp(value);
}
if (value instanceof SharedArrayBuffer) {
return value;
}
if (value instanceof ArrayBuffer) {
const cloned = cloneArrayBuffer(
value,
0,
value.byteLength,
ArrayBuffer,
);
objectCloneMemo.set(value, cloned);
return cloned;
}
if (ArrayBuffer.isView(value)) {
const clonedBuffer = cloneValue(value.buffer);
// Use DataViewConstructor type purely for type-checking, can be a
// DataView or TypedArray. They use the same constructor signature,
// only DataView has a length in bytes and TypedArrays use a length in
// terms of elements, so we adjust for that.
let length;
if (value instanceof DataView) {
length = value.byteLength;
} else {
length = value.length;
}
return new (value.constructor)(
clonedBuffer,
value.byteOffset,
length,
);
}
if (value instanceof Map) {
const clonedMap = new Map();
objectCloneMemo.set(value, clonedMap);
value.forEach((v, k) => clonedMap.set(k, cloneValue(v)));
return clonedMap;
}
if (value instanceof Set) {
const clonedSet = new Map();
objectCloneMemo.set(value, clonedSet);
value.forEach((v, k) => clonedSet.set(k, cloneValue(v)));
return clonedSet;
}
const clonedObj = {};
objectCloneMemo.set(value, clonedObj);
const sourceKeys = Object.getOwnPropertyNames(value);
for (const key of sourceKeys) {
clonedObj[key] = cloneValue(value[key]);
}
return clonedObj;
}
case "symbol":
case "function":
default:
throw new DOMException("Uncloneable value in stream", "DataCloneError");
}
}
/** A helper function which ensures accessors are enumerable, as they normally
* are not. */
function defineEnumerableProps(
Ctor,
props,
) {
for (const prop of props) {
Reflect.defineProperty(Ctor.prototype, prop, { enumerable: true });
}
}
function getHeaderValueParams(value) {
const params = new Map();
// Forced to do so for some Map constructor param mismatch
value
.split(";")
.slice(1)
.map((s) => s.trim().split("="))
.filter((arr) => arr.length > 1)
.map(([k, v]) => [k, v.replace(/^"([^"]*)"$/, "$1")])
.forEach(([k, v]) => params.set(k, v));
return params;
}
function hasHeaderValueOf(s, value) {
return new RegExp(`^${value}[\t\s]*;?`).test(s);
}
/** An internal function which provides a function name for some generated
* functions, so stack traces are a bit more readable.
*/
function setFunctionName(fn, value) {
Object.defineProperty(fn, "name", { value, configurable: true });
}
window.__bootstrap.webUtil = {
isTypedArray,
isInvalidDate,
requiredArguments,
immutableDefine,
hasOwnProperty,
isIterable,
cloneValue,
defineEnumerableProps,
getHeaderValueParams,
hasHeaderValueOf,
setFunctionName,
};
})(this);

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const { build } = window.__bootstrap.build;
const internals = window.__bootstrap.internals;
const core = Deno.core;
let logDebug = false;
let logSource = "JS";
@ -15,9 +14,8 @@
function log(...args) {
if (logDebug) {
// if we destructure `console` off `globalThis` too early, we don't bind to
// the right console, therefore we don't log anything out.
globalThis.console.log(`DEBUG ${logSource} -`, ...args);
const stringifiedArgs = args.map(JSON.stringify).join(" ");
core.print(`DEBUG ${logSource} - ${stringifiedArgs}\n`);
}
}
@ -50,93 +48,6 @@
throw new Error("not implemented");
}
function immutableDefine(
o,
p,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value,
) {
Object.defineProperty(o, p, {
value,
configurable: false,
writable: false,
});
}
function pathFromURLWin32(url) {
const hostname = url.hostname;
const pathname = decodeURIComponent(url.pathname.replace(/\//g, "\\"));
if (hostname !== "") {
//TODO(actual-size) Node adds a punycode decoding step, we should consider adding this
return `\\\\${hostname}${pathname}`;
}
const validPath = /^\\(?<driveLetter>[A-Za-z]):\\/;
const matches = validPath.exec(pathname);
if (!matches?.groups?.driveLetter) {
throw new TypeError("A URL with the file schema must be absolute.");
}
// we don't want a leading slash on an absolute path in Windows
return pathname.slice(1);
}
function pathFromURLPosix(url) {
if (url.hostname !== "") {
throw new TypeError(`Host must be empty.`);
}
return decodeURIComponent(url.pathname);
}
function pathFromURL(pathOrUrl) {
if (pathOrUrl instanceof URL) {
if (pathOrUrl.protocol != "file:") {
throw new TypeError("Must be a file URL.");
}
return build.os == "windows"
? pathFromURLWin32(pathOrUrl)
: pathFromURLPosix(pathOrUrl);
}
return pathOrUrl;
}
internals.exposeForTest("pathFromURL", pathFromURL);
function writable(value) {
return {
value,
writable: true,
enumerable: true,
configurable: true,
};
}
function nonEnumerable(value) {
return {
value,
writable: true,
configurable: true,
};
}
function readOnly(value) {
return {
value,
enumerable: true,
};
}
function getterOnly(getter) {
return {
get: getter,
enumerable: true,
};
}
window.__bootstrap.util = {
log,
setLogDebug,
@ -144,11 +55,5 @@
createResolvable,
assert,
AssertionError,
immutableDefine,
pathFromURL,
writable,
nonEnumerable,
readOnly,
getterOnly,
};
})(this);

View file

@ -1,638 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// The following code is based off of text-encoding at:
// https://github.com/inexorabletash/text-encoding
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
((window) => {
const core = Deno.core;
const CONTINUE = null;
const END_OF_STREAM = -1;
const FINISHED = -1;
function decoderError(fatal) {
if (fatal) {
throw new TypeError("Decoder error.");
}
return 0xfffd; // default code point
}
function inRange(a, min, max) {
return min <= a && a <= max;
}
function isASCIIByte(a) {
return inRange(a, 0x00, 0x7f);
}
function stringToCodePoints(input) {
const u = [];
for (const c of input) {
u.push(c.codePointAt(0));
}
return u;
}
class UTF8Encoder {
handler(codePoint) {
if (codePoint === END_OF_STREAM) {
return "finished";
}
if (inRange(codePoint, 0x00, 0x7f)) {
return [codePoint];
}
let count;
let offset;
if (inRange(codePoint, 0x0080, 0x07ff)) {
count = 1;
offset = 0xc0;
} else if (inRange(codePoint, 0x0800, 0xffff)) {
count = 2;
offset = 0xe0;
} else if (inRange(codePoint, 0x10000, 0x10ffff)) {
count = 3;
offset = 0xf0;
} else {
throw TypeError(
`Code point out of range: \\x${codePoint.toString(16)}`,
);
}
const bytes = [(codePoint >> (6 * count)) + offset];
while (count > 0) {
const temp = codePoint >> (6 * (count - 1));
bytes.push(0x80 | (temp & 0x3f));
count--;
}
return bytes;
}
}
class SingleByteDecoder {
#index = [];
#fatal = false;
constructor(
index,
{ ignoreBOM = false, fatal = false } = {},
) {
if (ignoreBOM) {
throw new TypeError("Ignoring the BOM is available only with utf-8.");
}
this.#fatal = fatal;
this.#index = index;
}
handler(_stream, byte) {
if (byte === END_OF_STREAM) {
return FINISHED;
}
if (isASCIIByte(byte)) {
return byte;
}
const codePoint = this.#index[byte - 0x80];
if (codePoint == null) {
return decoderError(this.#fatal);
}
return codePoint;
}
}
// The encodingMap is a hash of labels that are indexed by the conical
// encoding.
const encodingMap = {
"windows-1252": [
"ansi_x3.4-1968",
"ascii",
"cp1252",
"cp819",
"csisolatin1",
"ibm819",
"iso-8859-1",
"iso-ir-100",
"iso8859-1",
"iso88591",
"iso_8859-1",
"iso_8859-1:1987",
"l1",
"latin1",
"us-ascii",
"windows-1252",
"x-cp1252",
],
"utf-8": ["unicode-1-1-utf-8", "utf-8", "utf8"],
};
// We convert these into a Map where every label resolves to its canonical
// encoding type.
const encodings = new Map();
for (const key of Object.keys(encodingMap)) {
const labels = encodingMap[key];
for (const label of labels) {
encodings.set(label, key);
}
}
// A map of functions that return new instances of a decoder indexed by the
// encoding type.
const decoders = new Map();
// Single byte decoders are an array of code point lookups
const encodingIndexes = new Map();
// deno-fmt-ignore
encodingIndexes.set("windows-1252", [
8364,
129,
8218,
402,
8222,
8230,
8224,
8225,
710,
8240,
352,
8249,
338,
141,
381,
143,
144,
8216,
8217,
8220,
8221,
8226,
8211,
8212,
732,
8482,
353,
8250,
339,
157,
382,
376,
160,
161,
162,
163,
164,
165,
166,
167,
168,
169,
170,
171,
172,
173,
174,
175,
176,
177,
178,
179,
180,
181,
182,
183,
184,
185,
186,
187,
188,
189,
190,
191,
192,
193,
194,
195,
196,
197,
198,
199,
200,
201,
202,
203,
204,
205,
206,
207,
208,
209,
210,
211,
212,
213,
214,
215,
216,
217,
218,
219,
220,
221,
222,
223,
224,
225,
226,
227,
228,
229,
230,
231,
232,
233,
234,
235,
236,
237,
238,
239,
240,
241,
242,
243,
244,
245,
246,
247,
248,
249,
250,
251,
252,
253,
254,
255,
]);
for (const [key, index] of encodingIndexes) {
decoders.set(
key,
(options) => {
return new SingleByteDecoder(index, options);
},
);
}
function codePointsToString(codePoints) {
let s = "";
for (const cp of codePoints) {
s += String.fromCodePoint(cp);
}
return s;
}
class Stream {
#tokens = [];
constructor(tokens) {
this.#tokens = [...tokens];
this.#tokens.reverse();
}
endOfStream() {
return !this.#tokens.length;
}
read() {
return !this.#tokens.length ? END_OF_STREAM : this.#tokens.pop();
}
prepend(token) {
if (Array.isArray(token)) {
while (token.length) {
this.#tokens.push(token.pop());
}
} else {
this.#tokens.push(token);
}
}
push(token) {
if (Array.isArray(token)) {
while (token.length) {
this.#tokens.unshift(token.shift());
}
} else {
this.#tokens.unshift(token);
}
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isEitherArrayBuffer(x) {
return x instanceof SharedArrayBuffer || x instanceof ArrayBuffer;
}
class TextDecoder {
#encoding = "";
get encoding() {
return this.#encoding;
}
fatal = false;
ignoreBOM = false;
constructor(label = "utf-8", options = { fatal: false }) {
if (options.ignoreBOM) {
this.ignoreBOM = true;
}
if (options.fatal) {
this.fatal = true;
}
label = String(label).trim().toLowerCase();
const encoding = encodings.get(label);
if (!encoding) {
throw new RangeError(
`The encoding label provided ('${label}') is invalid.`,
);
}
if (!decoders.has(encoding) && encoding !== "utf-8") {
throw new TypeError(`Internal decoder ('${encoding}') not found.`);
}
this.#encoding = encoding;
}
decode(
input,
options = { stream: false },
) {
if (options.stream) {
throw new TypeError("Stream not supported.");
}
let bytes;
if (input instanceof Uint8Array) {
bytes = input;
} else if (isEitherArrayBuffer(input)) {
bytes = new Uint8Array(input);
} else if (
typeof input === "object" &&
"buffer" in input &&
isEitherArrayBuffer(input.buffer)
) {
bytes = new Uint8Array(
input.buffer,
input.byteOffset,
input.byteLength,
);
} else {
bytes = new Uint8Array(0);
}
// For simple utf-8 decoding "Deno.core.decode" can be used for performance
if (
this.#encoding === "utf-8" &&
this.fatal === false &&
this.ignoreBOM === false
) {
return core.decode(bytes);
}
// For performance reasons we utilise a highly optimised decoder instead of
// the general decoder.
if (this.#encoding === "utf-8") {
return decodeUtf8(bytes, this.fatal, this.ignoreBOM);
}
const decoder = decoders.get(this.#encoding)({
fatal: this.fatal,
ignoreBOM: this.ignoreBOM,
});
const inputStream = new Stream(bytes);
const output = [];
while (true) {
const result = decoder.handler(inputStream, inputStream.read());
if (result === FINISHED) {
break;
}
if (result !== CONTINUE) {
output.push(result);
}
}
if (output.length > 0 && output[0] === 0xfeff) {
output.shift();
}
return codePointsToString(output);
}
get [Symbol.toStringTag]() {
return "TextDecoder";
}
}
class TextEncoder {
encoding = "utf-8";
encode(input = "") {
// Deno.core.encode() provides very efficient utf-8 encoding
if (this.encoding === "utf-8") {
return core.encode(input);
}
const encoder = new UTF8Encoder();
const inputStream = new Stream(stringToCodePoints(input));
const output = [];
while (true) {
const result = encoder.handler(inputStream.read());
if (result === "finished") {
break;
}
output.push(...result);
}
return new Uint8Array(output);
}
encodeInto(input, dest) {
const encoder = new UTF8Encoder();
const inputStream = new Stream(stringToCodePoints(input));
let written = 0;
let read = 0;
while (true) {
const result = encoder.handler(inputStream.read());
if (result === "finished") {
break;
}
if (dest.length - written >= result.length) {
read++;
dest.set(result, written);
written += result.length;
if (result.length > 3) {
// increment read a second time if greater than U+FFFF
read++;
}
} else {
break;
}
}
return {
read,
written,
};
}
get [Symbol.toStringTag]() {
return "TextEncoder";
}
}
// This function is based on Bjoern Hoehrmann's DFA UTF-8 decoder.
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
//
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
function decodeUtf8(
input,
fatal,
ignoreBOM,
) {
let outString = "";
// Prepare a buffer so that we don't have to do a lot of string concats, which
// are very slow.
const outBufferLength = Math.min(1024, input.length);
const outBuffer = new Uint16Array(outBufferLength);
let outIndex = 0;
let state = 0;
let codepoint = 0;
let type;
let i =
ignoreBOM && input[0] === 0xef && input[1] === 0xbb && input[2] === 0xbf
? 3
: 0;
for (; i < input.length; ++i) {
// Encoding error handling
if (state === 12 || (state !== 0 && (input[i] & 0xc0) !== 0x80)) {
if (fatal) {
throw new TypeError(
`Decoder error. Invalid byte in sequence at position ${i} in data.`,
);
}
outBuffer[outIndex++] = 0xfffd; // Replacement character
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
state = 0;
}
// deno-fmt-ignore
type = [
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8
][input[i]];
codepoint = state !== 0
? (input[i] & 0x3f) | (codepoint << 6)
: (0xff >> type) & input[i];
// deno-fmt-ignore
state = [
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
12,36,12,12,12,12,12,12,12,12,12,12
][state + type];
if (state !== 0) continue;
// Add codepoint to buffer (as charcodes for utf-16), and flush buffer to
// string if needed.
if (codepoint > 0xffff) {
outBuffer[outIndex++] = 0xd7c0 + (codepoint >> 10);
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
outBuffer[outIndex++] = 0xdc00 | (codepoint & 0x3ff);
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
} else {
outBuffer[outIndex++] = codepoint;
if (outIndex === outBufferLength) {
outString += String.fromCharCode.apply(null, outBuffer);
outIndex = 0;
}
}
}
// Add a replacement character if we ended in the middle of a sequence or
// encountered an invalid code at the end.
if (state !== 0) {
if (fatal) throw new TypeError(`Decoder error. Unexpected end of data.`);
outBuffer[outIndex++] = 0xfffd; // Replacement character
}
// Final flush of buffer
outString += String.fromCharCode.apply(
null,
outBuffer.subarray(0, outIndex),
);
return outString;
}
window.TextEncoder = TextEncoder;
window.TextDecoder = TextDecoder;
})(this);

View file

@ -1,11 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const dispatchJson = window.__bootstrap.dispatchJson;
function opNow() {
return dispatchJson.sendSync("op_now");
}
window.__bootstrap.timers = { opNow };
})(this);

View file

@ -1,231 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
/* eslint-disable @typescript-eslint/no-explicit-any */
((window) => {
const { log } = window.__bootstrap.util;
const { sendSync, sendAsync } = window.__bootstrap.dispatchJson;
/*
import { blobURLMap } from "./web/url.ts";
*/
function createWorker(
specifier,
hasSourceCode,
sourceCode,
useDenoNamespace,
name,
) {
return sendSync("op_create_worker", {
specifier,
hasSourceCode,
sourceCode,
name,
useDenoNamespace,
});
}
function hostTerminateWorker(id) {
sendSync("op_host_terminate_worker", { id });
}
function hostPostMessage(id, data) {
sendSync("op_host_post_message", { id }, data);
}
function hostGetMessage(id) {
return sendAsync("op_host_get_message", { id });
}
const encoder = new TextEncoder();
const decoder = new TextDecoder();
class MessageEvent extends Event {
constructor(type, eventInitDict) {
super(type, {
bubbles: eventInitDict?.bubbles ?? false,
cancelable: eventInitDict?.cancelable ?? false,
composed: eventInitDict?.composed ?? false,
});
this.data = eventInitDict?.data ?? null;
this.origin = eventInitDict?.origin ?? "";
this.lastEventId = eventInitDict?.lastEventId ?? "";
}
}
function encodeMessage(data) {
const dataJson = JSON.stringify(data);
return encoder.encode(dataJson);
}
function decodeMessage(dataIntArray) {
const dataJson = decoder.decode(dataIntArray);
return JSON.parse(dataJson);
}
class Worker extends EventTarget {
#id = 0;
#name = "";
#terminated = false;
constructor(specifier, options) {
super();
const { type = "classic", name = "unknown" } = options ?? {};
if (type !== "module") {
throw new Error(
'Not yet implemented: only "module" type workers are supported',
);
}
this.#name = name;
const hasSourceCode = false;
const sourceCode = decoder.decode(new Uint8Array());
/* TODO(bartlomieju):
// Handle blob URL.
if (specifier.startsWith("blob:")) {
hasSourceCode = true;
const b = blobURLMap.get(specifier);
if (!b) {
throw new Error("No Blob associated with the given URL is found");
}
const blobBytes = blobBytesWeakMap.get(b!);
if (!blobBytes) {
throw new Error("Invalid Blob");
}
sourceCode = blobBytes!;
}
*/
const useDenoNamespace = options ? !!options.deno : false;
const { id } = createWorker(
specifier,
hasSourceCode,
sourceCode,
useDenoNamespace,
options?.name,
);
this.#id = id;
this.#poll();
}
#handleMessage = (msgData) => {
let data;
try {
data = decodeMessage(new Uint8Array(msgData));
} catch (e) {
const msgErrorEvent = new MessageEvent("messageerror", {
cancelable: false,
data,
});
if (this.onmessageerror) {
this.onmessageerror(msgErrorEvent);
}
return;
}
const msgEvent = new MessageEvent("message", {
cancelable: false,
data,
});
if (this.onmessage) {
this.onmessage(msgEvent);
}
this.dispatchEvent(msgEvent);
};
#handleError = (e) => {
const event = new ErrorEvent("error", {
cancelable: true,
message: e.message,
lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
colno: e.columnNumber ? e.columnNumber + 1 : undefined,
filename: e.fileName,
error: null,
});
let handled = false;
if (this.onerror) {
this.onerror(event);
}
this.dispatchEvent(event);
if (event.defaultPrevented) {
handled = true;
}
return handled;
};
#poll = async () => {
while (!this.#terminated) {
const event = await hostGetMessage(this.#id);
// If terminate was called then we ignore all messages
if (this.#terminated) {
return;
}
const type = event.type;
if (type === "terminalError") {
this.#terminated = true;
if (!this.#handleError(event.error)) {
throw Error(event.error.message);
}
continue;
}
if (type === "msg") {
this.#handleMessage(event.data);
continue;
}
if (type === "error") {
if (!this.#handleError(event.error)) {
throw Error(event.error.message);
}
continue;
}
if (type === "close") {
log(`Host got "close" message from worker: ${this.#name}`);
this.#terminated = true;
return;
}
throw new Error(`Unknown worker event: "${type}"`);
}
};
postMessage(message, transferOrOptions) {
if (transferOrOptions) {
throw new Error(
"Not yet implemented: `transfer` and `options` are not supported.",
);
}
if (this.#terminated) {
return;
}
hostPostMessage(this.#id, encodeMessage(message));
}
terminate() {
if (!this.#terminated) {
this.#terminated = true;
hostTerminateWorker(this.#id);
}
}
}
window.__bootstrap.worker = {
Worker,
MessageEvent,
};
})(this);

View file

@ -1,27 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Diagnostic provides an abstraction for advice/errors received from a
// compiler, which is strongly influenced by the format of TypeScript
// diagnostics.
((window) => {
const DiagnosticCategory = {
0: "Log",
1: "Debug",
2: "Info",
3: "Error",
4: "Warning",
5: "Suggestion",
Log: 0,
Debug: 1,
Info: 2,
Error: 3,
Warning: 4,
Suggestion: 5,
};
window.__bootstrap.diagnostics = {
DiagnosticCategory,
};
})(this);

View file

@ -3,22 +3,19 @@
((window) => {
// Some of the code here is adapted directly from V8 and licensed under a BSD
// style license available here: https://github.com/v8/v8/blob/24886f2d1c565287d33d71e4109a53bf0b54b75c/LICENSE.v8
const colors = window.__bootstrap.colors;
const assert = window.__bootstrap.util.assert;
const internals = window.__bootstrap.internals;
const dispatchJson = window.__bootstrap.dispatchJson;
function opFormatDiagnostics(items) {
return dispatchJson.sendSync("op_format_diagnostic", { items });
}
// https://github.com/chalk/ansi-regex/blob/2b56fb0c7a07108e5b54241e8faec160d393aedb/index.js
const ANSI_PATTERN = new RegExp(
[
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
].join("|"),
"g",
);
function opApplySourceMap(location) {
const res = dispatchJson.sendSync("op_apply_source_map", location);
return {
fileName: res.fileName,
lineNumber: res.lineNumber,
columnNumber: res.columnNumber,
};
function stripColor(string) {
return string.replace(ANSI_PATTERN, "");
}
function patchCallSite(callSite, location) {
@ -109,12 +106,9 @@
return result;
}
function getFileLocation(callSite, internal = false) {
const cyan = internal ? colors.gray : colors.cyan;
const yellow = internal ? colors.gray : colors.yellow;
const black = internal ? colors.gray : (s) => s;
function getFileLocation(callSite) {
if (callSite.isNative()) {
return cyan("native");
return "native";
}
let result = "";
@ -123,32 +117,29 @@
if (!fileName && callSite.isEval()) {
const evalOrigin = callSite.getEvalOrigin();
assert(evalOrigin != null);
result += cyan(`${evalOrigin}, `);
result += `${evalOrigin}, `;
}
if (fileName) {
result += cyan(fileName);
result += fileName;
} else {
result += cyan("<anonymous>");
result += "<anonymous>";
}
const lineNumber = callSite.getLineNumber();
if (lineNumber != null) {
result += `${black(":")}${yellow(lineNumber.toString())}`;
result += `:${lineNumber.toString()}`;
const columnNumber = callSite.getColumnNumber();
if (columnNumber != null) {
result += `${black(":")}${yellow(columnNumber.toString())}`;
result += `:${columnNumber.toString()}`;
}
}
return result;
}
function callSiteToString(callSite, internal = false) {
const cyan = internal ? colors.gray : colors.cyan;
const black = internal ? colors.gray : (s) => s;
function callSiteToString(callSite) {
let result = "";
const functionName = callSite.getFunctionName();
@ -159,35 +150,29 @@
const isMethodCall = !(isTopLevel || isConstructor);
if (isAsync) {
result += colors.gray("async ");
result += "async ";
}
if (isPromiseAll) {
result += colors.bold(
colors.italic(
black(`Promise.all (index ${callSite.getPromiseIndex()})`),
),
);
result += `Promise.all (index ${callSite.getPromiseIndex()})`;
return result;
}
if (isMethodCall) {
result += colors.bold(colors.italic(black(getMethodCall(callSite))));
result += getMethodCall(callSite);
} else if (isConstructor) {
result += colors.gray("new ");
result += "new ";
if (functionName) {
result += colors.bold(colors.italic(black(functionName)));
result += functionName;
} else {
result += cyan("<anonymous>");
result += "<anonymous>";
}
} else if (functionName) {
result += colors.bold(colors.italic(black(functionName)));
result += functionName;
} else {
result += getFileLocation(callSite, internal);
result += getFileLocation(callSite);
return result;
}
result += ` ${black("(")}${getFileLocation(callSite, internal)}${
black(")")
}`;
result += ` (${getFileLocation(callSite)})`;
return result;
}
@ -224,11 +209,11 @@
if (fileName && lineNumber != null && columnNumber != null) {
return patchCallSite(
callSite,
opApplySourceMap({
{
fileName,
lineNumber,
columnNumber,
}),
},
);
}
return callSite;
@ -240,15 +225,14 @@
});
for (const callSite of mappedCallSites) {
error.__callSiteEvals.push(Object.freeze(evaluateCallSite(callSite)));
const isInternal = callSite.getFileName()?.startsWith("$deno$") ?? false;
error.__formattedFrames.push(callSiteToString(callSite, isInternal));
error.__formattedFrames.push(callSiteToString(callSite));
}
Object.freeze(error.__callSiteEvals);
Object.freeze(error.__formattedFrames);
return (
`${error.name}: ${error.message}\n` +
error.__formattedFrames
.map((s) => ` at ${colors.stripColor(s)}`)
.map((s) => ` at ${stripColor(s)}`)
.join("\n")
);
}
@ -257,11 +241,7 @@
ErrorConstructor.prepareStackTrace = prepareStackTrace;
}
internals.exposeForTest("setPrepareStackTrace", setPrepareStackTrace);
window.__bootstrap.errorStack = {
setPrepareStackTrace,
opApplySourceMap,
opFormatDiagnostics,
};
})(this);

View file

@ -1,321 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
((window) => {
const { opNow } = window.__bootstrap.timers;
const { customInspect, inspect } = window.__bootstrap.console;
const { cloneValue } = window.__bootstrap.webUtil;
let performanceEntries = [];
function findMostRecent(
name,
type,
) {
return performanceEntries
.slice()
.reverse()
.find((entry) => entry.name === name && entry.entryType === type);
}
function convertMarkToTimestamp(mark) {
if (typeof mark === "string") {
const entry = findMostRecent(mark, "mark");
if (!entry) {
throw new SyntaxError(`Cannot find mark: "${mark}".`);
}
return entry.startTime;
}
if (mark < 0) {
throw new TypeError("Mark cannot be negative.");
}
return mark;
}
function filterByNameType(
name,
type,
) {
return performanceEntries.filter(
(entry) =>
(name ? entry.name === name : true) &&
(type ? entry.entryType === type : true),
);
}
function now() {
const res = opNow();
return res.seconds * 1e3 + res.subsecNanos / 1e6;
}
class PerformanceEntry {
#name = "";
#entryType = "";
#startTime = 0;
#duration = 0;
get name() {
return this.#name;
}
get entryType() {
return this.#entryType;
}
get startTime() {
return this.#startTime;
}
get duration() {
return this.#duration;
}
constructor(
name,
entryType,
startTime,
duration,
) {
this.#name = name;
this.#entryType = entryType;
this.#startTime = startTime;
this.#duration = duration;
}
toJSON() {
return {
name: this.#name,
entryType: this.#entryType,
startTime: this.#startTime,
duration: this.#duration,
};
}
[customInspect]() {
return `${this.constructor.name} { name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
}
}
class PerformanceMark extends PerformanceEntry {
#detail = null;
get detail() {
return this.#detail;
}
get entryType() {
return "mark";
}
constructor(
name,
{ detail = null, startTime = now() } = {},
) {
super(name, "mark", startTime, 0);
if (startTime < 0) {
throw new TypeError("startTime cannot be negative");
}
this.#detail = cloneValue(detail);
}
toJSON() {
return {
name: this.name,
entryType: this.entryType,
startTime: this.startTime,
duration: this.duration,
detail: this.detail,
};
}
[customInspect]() {
return this.detail
? `${this.constructor.name} {\n detail: ${
inspect(this.detail, { depth: 3 })
},\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
: `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
}
}
class PerformanceMeasure extends PerformanceEntry {
#detail = null;
get detail() {
return this.#detail;
}
get entryType() {
return "measure";
}
constructor(
name,
startTime,
duration,
detail = null,
) {
super(name, "measure", startTime, duration);
this.#detail = cloneValue(detail);
}
toJSON() {
return {
name: this.name,
entryType: this.entryType,
startTime: this.startTime,
duration: this.duration,
detail: this.detail,
};
}
[customInspect]() {
return this.detail
? `${this.constructor.name} {\n detail: ${
inspect(this.detail, { depth: 3 })
},\n name: "${this.name}",\n entryType: "${this.entryType}",\n startTime: ${this.startTime},\n duration: ${this.duration}\n}`
: `${this.constructor.name} { detail: ${this.detail}, name: "${this.name}", entryType: "${this.entryType}", startTime: ${this.startTime}, duration: ${this.duration} }`;
}
}
class Performance {
clearMarks(markName) {
if (markName == null) {
performanceEntries = performanceEntries.filter(
(entry) => entry.entryType !== "mark",
);
} else {
performanceEntries = performanceEntries.filter(
(entry) => !(entry.name === markName && entry.entryType === "mark"),
);
}
}
clearMeasures(measureName) {
if (measureName == null) {
performanceEntries = performanceEntries.filter(
(entry) => entry.entryType !== "measure",
);
} else {
performanceEntries = performanceEntries.filter(
(entry) =>
!(entry.name === measureName && entry.entryType === "measure"),
);
}
}
getEntries() {
return filterByNameType();
}
getEntriesByName(
name,
type,
) {
return filterByNameType(name, type);
}
getEntriesByType(type) {
return filterByNameType(undefined, type);
}
mark(
markName,
options = {},
) {
// 3.1.1.1 If the global object is a Window object and markName uses the
// same name as a read only attribute in the PerformanceTiming interface,
// throw a SyntaxError. - not implemented
const entry = new PerformanceMark(markName, options);
// 3.1.1.7 Queue entry - not implemented
performanceEntries.push(entry);
return entry;
}
measure(
measureName,
startOrMeasureOptions = {},
endMark,
) {
if (startOrMeasureOptions && typeof startOrMeasureOptions === "object") {
if (endMark) {
throw new TypeError("Options cannot be passed with endMark.");
}
if (
!("start" in startOrMeasureOptions) &&
!("end" in startOrMeasureOptions)
) {
throw new TypeError(
"A start or end mark must be supplied in options.",
);
}
if (
"start" in startOrMeasureOptions &&
"duration" in startOrMeasureOptions &&
"end" in startOrMeasureOptions
) {
throw new TypeError(
"Cannot specify start, end, and duration together in options.",
);
}
}
let endTime;
if (endMark) {
endTime = convertMarkToTimestamp(endMark);
} else if (
typeof startOrMeasureOptions === "object" &&
"end" in startOrMeasureOptions
) {
endTime = convertMarkToTimestamp(startOrMeasureOptions.end);
} else if (
typeof startOrMeasureOptions === "object" &&
"start" in startOrMeasureOptions &&
"duration" in startOrMeasureOptions
) {
const start = convertMarkToTimestamp(startOrMeasureOptions.start);
const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
endTime = start + duration;
} else {
endTime = now();
}
let startTime;
if (
typeof startOrMeasureOptions === "object" &&
"start" in startOrMeasureOptions
) {
startTime = convertMarkToTimestamp(startOrMeasureOptions.start);
} else if (
typeof startOrMeasureOptions === "object" &&
"end" in startOrMeasureOptions &&
"duration" in startOrMeasureOptions
) {
const end = convertMarkToTimestamp(startOrMeasureOptions.end);
const duration = convertMarkToTimestamp(startOrMeasureOptions.duration);
startTime = end - duration;
} else if (typeof startOrMeasureOptions === "string") {
startTime = convertMarkToTimestamp(startOrMeasureOptions);
} else {
startTime = 0;
}
const entry = new PerformanceMeasure(
measureName,
startTime,
endTime - startTime,
typeof startOrMeasureOptions === "object"
? startOrMeasureOptions.detail ?? null
: null,
);
performanceEntries.push(entry);
return entry;
}
now() {
return now();
}
}
window.__bootstrap.performance = {
PerformanceEntry,
PerformanceMark,
PerformanceMeasure,
Performance,
};
})(this);

View file

@ -1,13 +0,0 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// This module exports stable Deno APIs.
((window) => {
window.__bootstrap.denoNs = {
version: window.__bootstrap.version.version,
build: window.__bootstrap.build.build,
errors: window.__bootstrap.errors.errors,
customInspect: window.__bootstrap.console.customInspect,
inspect: window.__bootstrap.console.inspect,
};
})(this);

View file

@ -1,217 +0,0 @@
// Removes the `__proto__` for security reasons. This intentionally makes
// Deno non compliant with ECMA-262 Annex B.2.2.1
//
// eslint-disable-next-line @typescript-eslint/no-explicit-any
delete Object.prototype.__proto__;
((window) => {
const core = Deno.core;
const util = window.__bootstrap.util;
const eventTarget = window.__bootstrap.eventTarget;
const dispatchJson = window.__bootstrap.dispatchJson;
const build = window.__bootstrap.build;
const version = window.__bootstrap.version;
const errorStack = window.__bootstrap.errorStack;
const Console = window.__bootstrap.console.Console;
const worker = window.__bootstrap.worker;
const { internalSymbol, internalObject } = window.__bootstrap.internals;
const performance = window.__bootstrap.performance;
const crypto = window.__bootstrap.crypto;
const denoNs = window.__bootstrap.denoNs;
const encoder = new TextEncoder();
function workerClose() {
if (isClosing) {
return;
}
isClosing = true;
opCloseWorker();
}
// TODO(bartlomieju): remove these funtions
// Stuff for workers
const onmessage = () => {};
const onerror = () => {};
function postMessage(data) {
const dataJson = JSON.stringify(data);
const dataIntArray = encoder.encode(dataJson);
opPostMessage(dataIntArray);
}
let isClosing = false;
async function workerMessageRecvCallback(data) {
const msgEvent = new worker.MessageEvent("message", {
cancelable: false,
data,
});
try {
if (globalThis["onmessage"]) {
const result = globalThis.onmessage(msgEvent);
if (result && "then" in result) {
await result;
}
}
globalThis.dispatchEvent(msgEvent);
} catch (e) {
let handled = false;
const errorEvent = new ErrorEvent("error", {
cancelable: true,
message: e.message,
lineno: e.lineNumber ? e.lineNumber + 1 : undefined,
colno: e.columnNumber ? e.columnNumber + 1 : undefined,
filename: e.fileName,
error: null,
});
if (globalThis["onerror"]) {
const ret = globalThis.onerror(
e.message,
e.fileName,
e.lineNumber,
e.columnNumber,
e,
);
handled = ret === true;
}
globalThis.dispatchEvent(errorEvent);
if (errorEvent.defaultPrevented) {
handled = true;
}
if (!handled) {
throw e;
}
}
}
function opPostMessage(data) {
dispatchJson.sendSync("op_worker_post_message", {}, data);
}
function opCloseWorker() {
dispatchJson.sendSync("op_worker_close");
}
function opStart() {
return dispatchJson.sendSync("op_start");
}
// TODO(bartlomieju): temporary solution, must be fixed when moving
// dispatches to separate crates
function initOps() {
const opsMap = core.ops();
for (const [_name, opId] of Object.entries(opsMap)) {
core.setAsyncHandler(opId, dispatchJson.asyncMsgFromRust);
}
}
function runtimeStart(source) {
initOps();
// First we send an empty `Start` message to let the privileged side know we
// are ready. The response should be a `StartRes` message containing the CLI
// args and other info.
const s = opStart();
version.setVersions(s.denoVersion, s.v8Version, s.tsVersion);
build.setBuildInfo(s.target);
util.setLogDebug(s.debugFlag, source);
errorStack.setPrepareStackTrace(Error);
return s;
}
// Other properties shared between WindowScope and WorkerGlobalScope
const windowOrWorkerGlobalScopeProperties = {
console: util.writable(new Console(core.print)),
crypto: util.readOnly(crypto),
CustomEvent: util.nonEnumerable(CustomEvent),
ErrorEvent: util.nonEnumerable(ErrorEvent),
Event: util.nonEnumerable(Event),
EventTarget: util.nonEnumerable(EventTarget),
performance: util.writable(new performance.Performance()),
Performance: util.nonEnumerable(performance.Performance),
PerformanceEntry: util.nonEnumerable(performance.PerformanceEntry),
PerformanceMark: util.nonEnumerable(performance.PerformanceMark),
PerformanceMeasure: util.nonEnumerable(performance.PerformanceMeasure),
TextDecoder: util.nonEnumerable(TextDecoder),
TextEncoder: util.nonEnumerable(TextEncoder),
Worker: util.nonEnumerable(worker.Worker),
};
const eventTargetProperties = {
addEventListener: util.readOnly(
EventTarget.prototype.addEventListener,
),
dispatchEvent: util.readOnly(EventTarget.prototype.dispatchEvent),
removeEventListener: util.readOnly(
EventTarget.prototype.removeEventListener,
),
};
const workerRuntimeGlobalProperties = {
self: util.readOnly(globalThis),
onmessage: util.writable(onmessage),
onerror: util.writable(onerror),
// TODO: should be readonly?
close: util.nonEnumerable(workerClose),
postMessage: util.writable(postMessage),
workerMessageRecvCallback: util.nonEnumerable(workerMessageRecvCallback),
};
let hasBootstrapped = false;
function bootstrapWorkerRuntime(name, useDenoNamespace, internalName) {
if (hasBootstrapped) {
throw new Error("Worker runtime already bootstrapped");
}
// Remove bootstrapping methods from global scope
globalThis.__bootstrap = undefined;
globalThis.bootstrap = undefined;
util.log("bootstrapWorkerRuntime");
hasBootstrapped = true;
Object.defineProperties(globalThis, windowOrWorkerGlobalScopeProperties);
Object.defineProperties(globalThis, workerRuntimeGlobalProperties);
Object.defineProperties(globalThis, eventTargetProperties);
Object.defineProperties(globalThis, { name: util.readOnly(name) });
eventTarget.setEventTargetData(globalThis);
const { noColor, args } = runtimeStart(
internalName ?? name,
);
const finalDenoNs = {
core,
internal: internalSymbol,
[internalSymbol]: internalObject,
...denoNs,
};
if (useDenoNamespace) {
Object.defineProperties(finalDenoNs, {
noColor: util.readOnly(noColor),
args: util.readOnly(Object.freeze(args)),
});
// Setup `Deno` global - we're actually overriding already
// existing global `Deno` with `Deno` namespace from "./deno.ts".
util.immutableDefine(globalThis, "Deno", finalDenoNs);
Object.freeze(globalThis.Deno);
Object.freeze(globalThis.Deno.core);
Object.freeze(globalThis.Deno.core.sharedQueue);
} else {
delete globalThis.Deno;
util.assert(globalThis.Deno === undefined);
}
}
Object.defineProperties(globalThis, {
bootstrap: {
value: {
workerRuntime: bootstrapWorkerRuntime,
},
configurable: true,
writable: true,
},
});
})(this);

View file

@ -3,10 +3,13 @@
// This module is the entry point for "compiler" isolate, ie. the one
// that is created when Deno needs to compile TS/WASM to JS.
//
// It provides a single functions that should be called by Rust:
// - `bootstrapTsCompilerRuntime`
// It provides two functions that should be called by Rust:
// - `bootstrapCompilerRuntime`
// This functions must be called when creating isolate
// to properly setup runtime.
// - `tsCompilerOnMessage`
// This function must be called when sending a request
// to the compiler.
// Removes the `__proto__` for security reasons. This intentionally makes
// Deno non compliant with ECMA-262 Annex B.2.2.1
@ -16,9 +19,31 @@ delete Object.prototype.__proto__;
((window) => {
const core = Deno.core;
const { bold, cyan, yellow } = window.__bootstrap.colors;
const { assert, log, notImplemented } = window.__bootstrap.util;
const { DiagnosticCategory } = window.__bootstrap.diagnostics;
const dispatchJson = window.__bootstrap.dispatchJson;
const util = window.__bootstrap.util;
const errorStack = window.__bootstrap.errorStack;
function opNow() {
const res = dispatchJson.sendSync("op_now");
return res.seconds * 1e3 + res.subsecNanos / 1e6;
}
const DiagnosticCategory = {
0: "Log",
1: "Debug",
2: "Info",
3: "Error",
4: "Warning",
5: "Suggestion",
Log: 0,
Debug: 1,
Info: 2,
Error: 3,
Warning: 4,
Suggestion: 5,
};
const unstableDenoGlobalProperties = [
"umask",
@ -1136,7 +1161,7 @@ delete Object.prototype.__proto__;
function performanceStart() {
stats.length = 0;
// TODO(kitsonk) replace with performance.mark() when landed
statsStart = performance.now();
statsStart = opNow();
ts.performance.enable();
}
@ -1176,7 +1201,7 @@ delete Object.prototype.__proto__;
function performanceEnd() {
// TODO(kitsonk) replace with performance.measure() when landed
const duration = performance.now() - statsStart;
const duration = opNow() - statsStart;
stats.push({ key: "Compile time", value: duration });
return stats;
}
@ -1188,11 +1213,11 @@ delete Object.prototype.__proto__;
) {
const { ignoredOptions, diagnostics } = configResult;
if (ignoredOptions) {
console.warn(
yellow(`Unsupported compiler options in "${configPath}"\n`) +
cyan(` The following options were ignored:\n`) +
` ${ignoredOptions.map((value) => bold(value)).join(", ")}`,
);
const msg =
`Unsupported compiler options in "${configPath}"\n The following options were ignored:\n ${
ignoredOptions.map((value) => value).join(", ")
}\n`;
core.print(msg, true);
}
return diagnostics;
}
@ -1545,6 +1570,7 @@ delete Object.prototype.__proto__;
cwd,
sourceFileMap,
type,
performance,
}) {
if (performance) {
performanceStart();
@ -1804,64 +1830,83 @@ delete Object.prototype.__proto__;
return Promise.resolve(result);
}
async function tsCompilerOnMessage({
data: request,
}) {
function opCompilerRespond(msg) {
dispatchJson.sendSync("op_compiler_respond", msg);
}
async function tsCompilerOnMessage(msg) {
const request = msg.data;
switch (request.type) {
case CompilerRequestType.Compile: {
const result = compile(request);
globalThis.postMessage(result);
opCompilerRespond(result);
break;
}
case CompilerRequestType.Transpile: {
const result = transpile(request);
globalThis.postMessage(result);
opCompilerRespond(result);
break;
}
case CompilerRequestType.Bundle: {
const result = bundle(request);
globalThis.postMessage(result);
opCompilerRespond(result);
break;
}
case CompilerRequestType.RuntimeCompile: {
const result = runtimeCompile(request);
globalThis.postMessage(result);
opCompilerRespond(result);
break;
}
case CompilerRequestType.RuntimeBundle: {
const result = runtimeBundle(request);
globalThis.postMessage(result);
opCompilerRespond(result);
break;
}
case CompilerRequestType.RuntimeTranspile: {
const result = await runtimeTranspile(request);
globalThis.postMessage(result);
opCompilerRespond(result);
break;
}
default:
log(
throw new Error(
`!!! unhandled CompilerRequestType: ${request.type} (${
CompilerRequestType[request.type]
})`,
);
}
// Shutdown after single request
globalThis.close();
}
function bootstrapTsCompilerRuntime() {
globalThis.bootstrap.workerRuntime("TS", false);
globalThis.onmessage = tsCompilerOnMessage;
// TODO(bartlomieju): temporary solution, must be fixed when moving
// dispatches to separate crates
function initOps() {
const opsMap = core.ops();
for (const [_name, opId] of Object.entries(opsMap)) {
core.setAsyncHandler(opId, dispatchJson.asyncMsgFromRust);
}
}
Object.defineProperties(globalThis, {
bootstrap: {
value: {
...globalThis.bootstrap,
tsCompilerRuntime: bootstrapTsCompilerRuntime,
},
configurable: true,
writable: true,
},
});
function runtimeStart(source) {
initOps();
// First we send an empty `Start` message to let the privileged side know we
// are ready. The response should be a `StartRes` message containing the CLI
// args and other info.
const s = dispatchJson.sendSync("op_start");
util.setLogDebug(s.debugFlag, source);
errorStack.setPrepareStackTrace(Error);
return s;
}
let hasBootstrapped = false;
function bootstrapCompilerRuntime() {
if (hasBootstrapped) {
throw new Error("Worker runtime already bootstrapped");
}
hasBootstrapped = true;
globalThis.__bootstrap = undefined;
runtimeStart("TS");
}
globalThis.bootstrapCompilerRuntime = bootstrapCompilerRuntime;
globalThis.tsCompilerOnMessage = tsCompilerOnMessage;
})(this);