chore: use primordials in 40_testing.js (#21422)

This commit brings back usage of primordials in "40_testing.js" by
turning it back into an ES module and using new "lazy loading" functionality
of ES modules coming from "deno_core".

The same approach was applied to "40_jupyter.js".

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
Divy Srivastava 2023-12-08 13:03:25 +05:30 committed by GitHub
parent 2235a1a359
commit c5c5dea90d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 1561 additions and 1566 deletions

12
Cargo.lock generated
View file

@ -1065,9 +1065,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_core" name = "deno_core"
version = "0.236.0" version = "0.237.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ea0ab6f78d50bc3c9730f3a7faa3b9b32463b25f4af3dd0f02c6a18d995047e" checksum = "a2ea708c221abdb5734e3c4b72075379c3046eb0ac54afa0ecb5e58509cce72c"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -1493,9 +1493,9 @@ dependencies = [
[[package]] [[package]]
name = "deno_ops" name = "deno_ops"
version = "0.112.0" version = "0.113.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8050c4964e689fb05cac12df6c52727950b44ce48bdd6b5e4d3c0332f2e7aa76" checksum = "e5b9c0f6360795fb625774a8b5955c87c470c43159670cf5d2052df5ce9d84bc"
dependencies = [ dependencies = [
"proc-macro-rules", "proc-macro-rules",
"proc-macro2", "proc-macro2",
@ -4638,9 +4638,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_v8" name = "serde_v8"
version = "0.145.0" version = "0.146.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd782806b3088c7083a142be36ceb734ccfb1da6f82b5eb84a2bff2b4a68efe" checksum = "78309bd1ec4d14d165f271e203bdc45ad5bf45525da57bb70901f57942f6c0f7"
dependencies = [ dependencies = [
"bytes", "bytes",
"derive_more", "derive_more",

View file

@ -40,7 +40,7 @@ repository = "https://github.com/denoland/deno"
[workspace.dependencies] [workspace.dependencies]
deno_ast = { version = "0.31.6", features = ["transpiling"] } deno_ast = { version = "0.31.6", features = ["transpiling"] }
deno_core = { version = "0.236.0" } deno_core = { version = "0.237.0" }
deno_runtime = { version = "0.135.0", path = "./runtime" } deno_runtime = { version = "0.135.0", path = "./runtime" }
napi_sym = { version = "0.57.0", path = "./cli/napi/sym" } napi_sym = { version = "0.57.0", path = "./cli/napi/sym" }

View file

@ -36,38 +36,36 @@
* }, { raw: true }); * }, { raw: true });
* ``` * ```
*/ */
(() => { import { core, internals } from "ext:core/mod.js";
const internals = Deno[Deno.internal];
const core = internals.core;
const $display = Symbol.for("Jupyter.display"); const $display = Symbol.for("Jupyter.display");
/** Escape copied from https://deno.land/std@0.192.0/html/entities.ts */ /** Escape copied from https://deno.land/std@0.192.0/html/entities.ts */
const rawToEntityEntries = [ const rawToEntityEntries = [
["&", "&amp;"], ["&", "&amp;"],
["<", "&lt;"], ["<", "&lt;"],
[">", "&gt;"], [">", "&gt;"],
['"', "&quot;"], ['"', "&quot;"],
["'", "&#39;"], ["'", "&#39;"],
]; ];
const rawToEntity = new Map(rawToEntityEntries); const rawToEntity = new Map(rawToEntityEntries);
const rawRe = new RegExp(`[${[...rawToEntity.keys()].join("")}]`, "g"); const rawRe = new RegExp(`[${[...rawToEntity.keys()].join("")}]`, "g");
function escapeHTML(str) { function escapeHTML(str) {
return str.replaceAll( return str.replaceAll(
rawRe, rawRe,
(m) => rawToEntity.has(m) ? rawToEntity.get(m) : m, (m) => rawToEntity.has(m) ? rawToEntity.get(m) : m,
); );
} }
/** Duck typing our way to common visualization and tabular libraries */ /** Duck typing our way to common visualization and tabular libraries */
/** Vegalite */ /** Vegalite */
function isVegaLike(obj) { function isVegaLike(obj) {
return obj !== null && typeof obj === "object" && "toSpec" in obj; return obj !== null && typeof obj === "object" && "toSpec" in obj;
} }
function extractVega(obj) { function extractVega(obj) {
const spec = obj.toSpec(); const spec = obj.toSpec();
if (!("$schema" in spec)) { if (!("$schema" in spec)) {
return null; return null;
@ -86,9 +84,9 @@
return { return {
[mediaType]: spec, [mediaType]: spec,
}; };
} }
/** Polars */ /** Polars */
function isDataFrameLike(obj) { function isDataFrameLike(obj) {
const isObject = obj !== null && typeof obj === "object"; const isObject = obj !== null && typeof obj === "object";
if (!isObject) { if (!isObject) {
return false; return false;
@ -97,13 +95,13 @@
return df.schema !== void 0 && typeof df.schema === "object" && return df.schema !== void 0 && typeof df.schema === "object" &&
df.head !== void 0 && typeof df.head === "function" && df.head !== void 0 && typeof df.head === "function" &&
df.toRecords !== void 0 && typeof df.toRecords === "function"; df.toRecords !== void 0 && typeof df.toRecords === "function";
} }
/** /**
* Map Polars DataType to JSON Schema data types. * Map Polars DataType to JSON Schema data types.
* @param dataType - The Polars DataType. * @param dataType - The Polars DataType.
* @returns The corresponding JSON Schema data type. * @returns The corresponding JSON Schema data type.
*/ */
function mapPolarsTypeToJSONSchema(colType) { function mapPolarsTypeToJSONSchema(colType) {
const typeMapping = { const typeMapping = {
Null: "null", Null: "null",
Bool: "boolean", Bool: "boolean",
@ -129,9 +127,9 @@
// convert it to JSON // convert it to JSON
const dataType = colType.toJSON()["DataType"]; const dataType = colType.toJSON()["DataType"];
return typeMapping[dataType] || "string"; return typeMapping[dataType] || "string";
} }
function extractDataFrame(df) { function extractDataFrame(df) {
const fields = []; const fields = [];
const schema = { const schema = {
fields, fields,
@ -172,43 +170,43 @@
"application/vnd.dataresource+json": { data, schema }, "application/vnd.dataresource+json": { data, schema },
"text/html": htmlTable, "text/html": htmlTable,
}; };
} }
/** Canvas */ /** Canvas */
function isCanvasLike(obj) { function isCanvasLike(obj) {
return obj !== null && typeof obj === "object" && "toDataURL" in obj; return obj !== null && typeof obj === "object" && "toDataURL" in obj;
} }
/** Possible HTML and SVG Elements */ /** Possible HTML and SVG Elements */
function isSVGElementLike(obj) { function isSVGElementLike(obj) {
return obj !== null && typeof obj === "object" && "outerHTML" in obj && return obj !== null && typeof obj === "object" && "outerHTML" in obj &&
typeof obj.outerHTML === "string" && obj.outerHTML.startsWith("<svg"); typeof obj.outerHTML === "string" && obj.outerHTML.startsWith("<svg");
} }
function isHTMLElementLike(obj) { function isHTMLElementLike(obj) {
return obj !== null && typeof obj === "object" && "outerHTML" in obj && return obj !== null && typeof obj === "object" && "outerHTML" in obj &&
typeof obj.outerHTML === "string"; typeof obj.outerHTML === "string";
} }
/** Check to see if an object already contains a `Symbol.for("Jupyter.display") */ /** Check to see if an object already contains a `Symbol.for("Jupyter.display") */
function hasDisplaySymbol(obj) { function hasDisplaySymbol(obj) {
return obj !== null && typeof obj === "object" && $display in obj && return obj !== null && typeof obj === "object" && $display in obj &&
typeof obj[$display] === "function"; typeof obj[$display] === "function";
} }
function makeDisplayable(obj) { function makeDisplayable(obj) {
return { return {
[$display]: () => obj, [$display]: () => obj,
}; };
} }
/** /**
* Format an object for displaying in Deno * Format an object for displaying in Deno
* *
* @param obj - The object to be displayed * @param obj - The object to be displayed
* @returns MediaBundle * @returns MediaBundle
*/ */
async function format(obj) { async function format(obj) {
if (hasDisplaySymbol(obj)) { if (hasDisplaySymbol(obj)) {
return await obj[$display](); return await obj[$display]();
} }
@ -250,16 +248,16 @@
colors: !Deno.noColor, colors: !Deno.noColor,
}), }),
}; };
} }
/** /**
* This function creates a tagged template function for a given media type. * This function creates a tagged template function for a given media type.
* The tagged template function takes a template string and returns a displayable object. * The tagged template function takes a template string and returns a displayable object.
* *
* @param mediatype - The media type for the tagged template function. * @param mediatype - The media type for the tagged template function.
* @returns A function that takes a template string and returns a displayable object. * @returns A function that takes a template string and returns a displayable object.
*/ */
function createTaggedTemplateDisplayable(mediatype) { function createTaggedTemplateDisplayable(mediatype) {
return (strings, ...values) => { return (strings, ...values) => {
const payload = strings.reduce( const payload = strings.reduce(
(acc, string, i) => (acc, string, i) =>
@ -268,9 +266,9 @@
); );
return makeDisplayable({ [mediatype]: payload }); return makeDisplayable({ [mediatype]: payload });
}; };
} }
/** /**
* Show Markdown in Jupyter frontends with a tagged template function. * Show Markdown in Jupyter frontends with a tagged template function.
* *
* Takes a template string and returns a displayable object for Jupyter frontends. * Takes a template string and returns a displayable object for Jupyter frontends.
@ -289,9 +287,9 @@
* ` * `
* ``` * ```
*/ */
const md = createTaggedTemplateDisplayable("text/markdown"); const md = createTaggedTemplateDisplayable("text/markdown");
/** /**
* Show HTML in Jupyter frontends with a tagged template function. * Show HTML in Jupyter frontends with a tagged template function.
* *
* Takes a template string and returns a displayable object for Jupyter frontends. * Takes a template string and returns a displayable object for Jupyter frontends.
@ -302,8 +300,8 @@
* html`<h1>Hello, world!</h1>` * html`<h1>Hello, world!</h1>`
* ``` * ```
*/ */
const html = createTaggedTemplateDisplayable("text/html"); const html = createTaggedTemplateDisplayable("text/html");
/** /**
* SVG Tagged Template Function. * SVG Tagged Template Function.
* *
* Takes a template string and returns a displayable object for Jupyter frontends. * Takes a template string and returns a displayable object for Jupyter frontends.
@ -314,9 +312,9 @@
* <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /> * <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
* </svg>` * </svg>`
*/ */
const svg = createTaggedTemplateDisplayable("image/svg+xml"); const svg = createTaggedTemplateDisplayable("image/svg+xml");
function isMediaBundle(obj) { function isMediaBundle(obj) {
if (obj == null || typeof obj !== "object" || Array.isArray(obj)) { if (obj == null || typeof obj !== "object" || Array.isArray(obj)) {
return false; return false;
} }
@ -326,19 +324,19 @@
} }
} }
return true; return true;
} }
async function formatInner(obj, raw) { async function formatInner(obj, raw) {
if (raw && isMediaBundle(obj)) { if (raw && isMediaBundle(obj)) {
return obj; return obj;
} else { } else {
return await format(obj); return await format(obj);
} }
} }
internals.jupyter = { formatInner }; internals.jupyter = { formatInner };
function enableJupyter() { function enableJupyter() {
const { const {
op_jupyter_broadcast, op_jupyter_broadcast,
} = core.ensureFastOps(); } = core.ensureFastOps();
@ -425,7 +423,6 @@
svg, svg,
$display, $display,
}; };
} }
internals.enableJupyter = enableJupyter; internals.enableJupyter = enableJupyter;
})();

View file

@ -1,38 +1,55 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
// Do not use primordials because we do not want to depend on the __bootstrap
// namespace.
//
// deno-lint-ignore-file // deno-lint-ignore-file
(() => {
const internals = Deno[Deno.internal];
const core = internals.core;
const ops = core.ops;
const { import { core, internals, primordials } from "ext:core/mod.js";
setExitHandler, const ops = core.ops;
Console,
serializePermissions,
} = internals;
const opSanitizerDelayResolveQueue = []; import { setExitHandler } from "ext:runtime/30_os.js";
let hasSetOpSanitizerDelayMacrotask = false; import { Console } from "ext:deno_console/01_console.js";
import { serializePermissions } from "ext:runtime/10_permissions.js";
import { setTimeout } from "ext:deno_web/02_timers.js";
// Even if every resource is closed by the end of a test, there can be a delay const {
// until the pending ops have all finished. This function returns a promise ArrayPrototypeFilter,
// that resolves when it's (probably) fine to run the op sanitizer. ArrayPrototypeJoin,
// ArrayPrototypePush,
// This is implemented by adding a macrotask callback that runs after the ArrayPrototypeShift,
// all ready async ops resolve, and the timer macrotask. Using just a macrotask DateNow,
// callback without delaying is sufficient, because when the macrotask callback Error,
// runs after async op dispatch, we know that all async ops that can currently FunctionPrototype,
// return `Poll::Ready` have done so, and have been dispatched to JS. Map,
// MapPrototypeGet,
// Worker ops are an exception to this, because there is no way for the user to MapPrototypeHas,
// await shutdown of the worker from the thread calling `worker.terminate()`. MapPrototypeSet,
// Because of this, we give extra leeway for worker ops to complete, by waiting MathCeil,
// for a whole millisecond if there are pending worker ops. ObjectKeys,
function opSanitizerDelay(hasPendingWorkerOps) { ObjectPrototypeIsPrototypeOf,
Promise,
SafeArrayIterator,
Set,
StringPrototypeReplaceAll,
SymbolToStringTag,
TypeError,
} = primordials;
const opSanitizerDelayResolveQueue = [];
let hasSetOpSanitizerDelayMacrotask = false;
// Even if every resource is closed by the end of a test, there can be a delay
// until the pending ops have all finished. This function returns a promise
// that resolves when it's (probably) fine to run the op sanitizer.
//
// This is implemented by adding a macrotask callback that runs after the
// all ready async ops resolve, and the timer macrotask. Using just a macrotask
// callback without delaying is sufficient, because when the macrotask callback
// runs after async op dispatch, we know that all async ops that can currently
// return `Poll::Ready` have done so, and have been dispatched to JS.
//
// Worker ops are an exception to this, because there is no way for the user to
// await shutdown of the worker from the thread calling `worker.terminate()`.
// Because of this, we give extra leeway for worker ops to complete, by waiting
// for a whole millisecond if there are pending worker ops.
function opSanitizerDelay(hasPendingWorkerOps) {
if (!hasSetOpSanitizerDelayMacrotask) { if (!hasSetOpSanitizerDelayMacrotask) {
core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask); core.setMacrotaskCallback(handleOpSanitizerDelayMacrotask);
hasSetOpSanitizerDelayMacrotask = true; hasSetOpSanitizerDelayMacrotask = true;
@ -43,25 +60,25 @@
// timeout callback will mean that the resolver gets called in the same // timeout callback will mean that the resolver gets called in the same
// event loop tick as the timeout callback. // event loop tick as the timeout callback.
setTimeout(() => { setTimeout(() => {
opSanitizerDelayResolveQueue.push(resolve); ArrayPrototypePush(opSanitizerDelayResolveQueue, resolve);
}, hasPendingWorkerOps ? 1 : 0); }, hasPendingWorkerOps ? 1 : 0);
}); });
return p; return p;
} }
function handleOpSanitizerDelayMacrotask() { function handleOpSanitizerDelayMacrotask() {
const resolve = opSanitizerDelayResolveQueue.shift(); const resolve = ArrayPrototypeShift(opSanitizerDelayResolveQueue);
if (resolve) { if (resolve) {
resolve(); resolve();
return opSanitizerDelayResolveQueue.length === 0; return opSanitizerDelayResolveQueue.length === 0;
} }
return undefined; // we performed no work, so can skip microtasks checkpoint return undefined; // we performed no work, so can skip microtasks checkpoint
} }
// An async operation to $0 was started in this test, but never completed. This is often caused by not $1. // An async operation to $0 was started in this test, but never completed. This is often caused by not $1.
// An async operation to $0 was started in this test, but never completed. Async operations should not complete in a test if they were not started in that test. // An async operation to $0 was started in this test, but never completed. Async operations should not complete in a test if they were not started in that test.
// deno-fmt-ignore // deno-fmt-ignore
const OP_DETAILS = { const OP_DETAILS = {
"op_blob_read_part": ["read from a Blob or File", "awaiting the result of a Blob or File read"], "op_blob_read_part": ["read from a Blob or File", "awaiting the result of a Blob or File read"],
"op_broadcast_recv": ["receive a message from a BroadcastChannel", "closing the BroadcastChannel"], "op_broadcast_recv": ["receive a message from a BroadcastChannel", "closing the BroadcastChannel"],
"op_broadcast_send": ["send a message to a BroadcastChannel", "closing the BroadcastChannel"], "op_broadcast_send": ["send a message to a BroadcastChannel", "closing the BroadcastChannel"],
@ -135,22 +152,22 @@
"op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"], "op_ws_send_pong": ["send a message on a WebSocket", "closing a `WebSocket` or `WebSocketStream`"],
}; };
let opIdHostRecvMessage = -1; let opIdHostRecvMessage = -1;
let opIdHostRecvCtrl = -1; let opIdHostRecvCtrl = -1;
let opNames = null; let opNames = null;
function populateOpNames() { function populateOpNames() {
opNames = core.ops.op_op_names(); opNames = core.ops.op_op_names();
opIdHostRecvMessage = opNames.indexOf("op_host_recv_message"); opIdHostRecvMessage = opNames.indexOf("op_host_recv_message");
opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl"); opIdHostRecvCtrl = opNames.indexOf("op_host_recv_ctrl");
} }
// Wrap test function in additional assertion that makes sure // Wrap test function in additional assertion that makes sure
// the test case does not leak async "ops" - ie. number of async // the test case does not leak async "ops" - ie. number of async
// completed ops after the test is the same as number of dispatched // completed ops after the test is the same as number of dispatched
// ops. Note that "unref" ops are ignored since in nature that are // ops. Note that "unref" ops are ignored since in nature that are
// optional. // optional.
function assertOps(fn) { function assertOps(fn) {
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
return async function asyncOpSanitizer(desc) { return async function asyncOpSanitizer(desc) {
if (opNames === null) populateOpNames(); if (opNames === null) populateOpNames();
@ -219,17 +236,17 @@
const traces = []; const traces = [];
for (const [id, { opName: traceOpName, stack }] of postTraces) { for (const [id, { opName: traceOpName, stack }] of postTraces) {
if (traceOpName !== opName) continue; if (traceOpName !== opName) continue;
if (preTraces.has(id)) continue; if (MapPrototypeHas(preTraces, id)) continue;
traces.push(stack); ArrayPrototypePush(traces, stack);
} }
if (traces.length === 1) { if (traces.length === 1) {
message += " The operation was started here:\n"; message += " The operation was started here:\n";
message += traces[0]; message += traces[0];
} else if (traces.length > 1) { } else if (traces.length > 1) {
message += " The operations were started here:\n"; message += " The operations were started here:\n";
message += traces.join("\n\n"); message += ArrayPrototypeJoin(traces, "\n\n");
} }
details.push(message); ArrayPrototypePush(details, message);
} else if (diff < 0) { } else if (diff < 0) {
const [name, hint] = OP_DETAILS[opName] || [opName, null]; const [name, hint] = OP_DETAILS[opName] || [opName, null];
const count = -diff; const count = -diff;
@ -246,17 +263,17 @@
const traces = []; const traces = [];
for (const [id, { opName: traceOpName, stack }] of preTraces) { for (const [id, { opName: traceOpName, stack }] of preTraces) {
if (opName !== traceOpName) continue; if (opName !== traceOpName) continue;
if (postTraces.has(id)) continue; if (MapPrototypeHas(postTraces, id)) continue;
traces.push(stack); ArrayPrototypePush(traces, stack);
} }
if (traces.length === 1) { if (traces.length === 1) {
message += " The operation was started here:\n"; message += " The operation was started here:\n";
message += traces[0]; message += traces[0];
} else if (traces.length > 1) { } else if (traces.length > 1) {
message += " The operations were started here:\n"; message += " The operations were started here:\n";
message += traces.join("\n\n"); message += ArrayPrototypeJoin(traces, "\n\n");
} }
details.push(message); ArrayPrototypePush(details, message);
} else { } else {
throw new Error("unreachable"); throw new Error("unreachable");
} }
@ -266,9 +283,9 @@
failed: { leakedOps: [details, core.isOpCallTracingEnabled()] }, failed: { leakedOps: [details, core.isOpCallTracingEnabled()] },
}; };
}; };
} }
function prettyResourceNames(name) { function prettyResourceNames(name) {
switch (name) { switch (name) {
case "fsFile": case "fsFile":
return ["A file", "opened", "closed"]; return ["A file", "opened", "closed"];
@ -333,9 +350,9 @@
default: default:
return [`A "${name}" resource`, "created", "cleaned up"]; return [`A "${name}" resource`, "created", "cleaned up"];
} }
} }
function resourceCloseHint(name) { function resourceCloseHint(name) {
switch (name) { switch (name) {
case "fsFile": case "fsFile":
return "Close the file handle by calling `file.close()`."; return "Close the file handle by calling `file.close()`.";
@ -400,12 +417,12 @@
default: default:
return "Close the resource before the end of the test."; return "Close the resource before the end of the test.";
} }
} }
// Wrap test function in additional assertion that makes sure // Wrap test function in additional assertion that makes sure
// the test case does not "leak" resources - ie. resource table after // the test case does not "leak" resources - ie. resource table after
// the test has exactly the same contents as before the test. // the test has exactly the same contents as before the test.
function assertResources(fn) { function assertResources(fn) {
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
return async function resourceSanitizer(desc) { return async function resourceSanitizer(desc) {
const pre = core.resources(); const pre = core.resources();
@ -414,8 +431,8 @@
const post = core.resources(); const post = core.resources();
const allResources = new Set([ const allResources = new Set([
...Object.keys(pre), ...new SafeArrayIterator(ObjectKeys(pre)),
...Object.keys(post), ...new SafeArrayIterator(ObjectKeys(post)),
]); ]);
const details = []; const details = [];
@ -429,12 +446,12 @@
const hint = resourceCloseHint(postResource); const hint = resourceCloseHint(postResource);
const detail = const detail =
`${name} (rid ${resource}) was ${action1} during the test, but not ${action2} during the test. ${hint}`; `${name} (rid ${resource}) was ${action1} during the test, but not ${action2} during the test. ${hint}`;
details.push(detail); ArrayPrototypePush(details, detail);
} else { } else {
const [name, action1, action2] = prettyResourceNames(preResource); const [name, action1, action2] = prettyResourceNames(preResource);
const detail = const detail =
`${name} (rid ${resource}) was ${action1} before the test started, but was ${action2} during the test. Do not close resources in a test that were not created during that test.`; `${name} (rid ${resource}) was ${action1} before the test started, but was ${action2} during the test. Do not close resources in a test that were not created during that test.`;
details.push(detail); ArrayPrototypePush(details, detail);
} }
} }
if (details.length == 0) { if (details.length == 0) {
@ -442,11 +459,11 @@
} }
return { failed: { leakedResources: details } }; return { failed: { leakedResources: details } };
}; };
} }
// Wrap test function in additional assertion that makes sure // Wrap test function in additional assertion that makes sure
// that the test case does not accidentally exit prematurely. // that the test case does not accidentally exit prematurely.
function assertExit(fn, isTest) { function assertExit(fn, isTest) {
return async function exitSanitizer(...params) { return async function exitSanitizer(...params) {
setExitHandler((exitCode) => { setExitHandler((exitCode) => {
throw new Error( throw new Error(
@ -457,15 +474,15 @@
}); });
try { try {
const innerResult = await fn(...params); const innerResult = await fn(...new SafeArrayIterator(params));
if (innerResult) return innerResult; if (innerResult) return innerResult;
} finally { } finally {
setExitHandler(null); setExitHandler(null);
} }
}; };
} }
function wrapOuter(fn, desc) { function wrapOuter(fn, desc) {
return async function outerWrapped() { return async function outerWrapped() {
try { try {
if (desc.ignore) { if (desc.ignore) {
@ -475,30 +492,30 @@
} catch (error) { } catch (error) {
return { failed: { jsError: core.destructureError(error) } }; return { failed: { jsError: core.destructureError(error) } };
} finally { } finally {
const state = testStates.get(desc.id); const state = MapPrototypeGet(testStates, desc.id);
for (const childDesc of state.children) { for (const childDesc of state.children) {
stepReportResult(childDesc, { failed: "incomplete" }, 0); stepReportResult(childDesc, { failed: "incomplete" }, 0);
} }
state.completed = true; state.completed = true;
} }
}; };
} }
function wrapInner(fn) { function wrapInner(fn) {
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
return async function innerWrapped(desc) { return async function innerWrapped(desc) {
function getRunningStepDescs() { function getRunningStepDescs() {
const results = []; const results = [];
let childDesc = desc; let childDesc = desc;
while (childDesc.parent != null) { while (childDesc.parent != null) {
const state = testStates.get(childDesc.parent.id); const state = MapPrototypeGet(testStates, childDesc.parent.id);
for (const siblingDesc of state.children) { for (const siblingDesc of state.children) {
if (siblingDesc.id == childDesc.id) { if (siblingDesc.id == childDesc.id) {
continue; continue;
} }
const siblingState = testStates.get(siblingDesc.id); const siblingState = MapPrototypeGet(testStates, siblingDesc.id);
if (!siblingState.completed) { if (!siblingState.completed) {
results.push(siblingDesc); ArrayPrototypePush(results, siblingDesc);
} }
} }
childDesc = childDesc.parent; childDesc = childDesc.parent;
@ -506,7 +523,8 @@
return results; return results;
} }
const runningStepDescs = getRunningStepDescs(); const runningStepDescs = getRunningStepDescs();
const runningStepDescsWithSanitizers = runningStepDescs.filter( const runningStepDescsWithSanitizers = ArrayPrototypeFilter(
runningStepDescs,
(d) => usesSanitizer(d), (d) => usesSanitizer(d),
); );
@ -527,10 +545,10 @@
}, },
}; };
} }
await fn(testStates.get(desc.id).context); await fn(MapPrototypeGet(testStates, desc.id).context);
let failedSteps = 0; let failedSteps = 0;
for (const childDesc of testStates.get(desc.id).children) { for (const childDesc of MapPrototypeGet(testStates, desc.id).children) {
const state = testStates.get(childDesc.id); const state = MapPrototypeGet(testStates, childDesc.id);
if (!state.completed) { if (!state.completed) {
return { failed: "incompleteSteps" }; return { failed: "incompleteSteps" };
} }
@ -540,51 +558,51 @@
} }
return failedSteps == 0 ? null : { failed: { failedSteps } }; return failedSteps == 0 ? null : { failed: { failedSteps } };
}; };
} }
function pledgePermissions(permissions) { function pledgePermissions(permissions) {
return ops.op_pledge_test_permissions( return ops.op_pledge_test_permissions(
serializePermissions(permissions), serializePermissions(permissions),
); );
} }
function restorePermissions(token) { function restorePermissions(token) {
ops.op_restore_test_permissions(token); ops.op_restore_test_permissions(token);
} }
function withPermissions(fn, permissions) { function withPermissions(fn, permissions) {
return async function applyPermissions(...params) { return async function applyPermissions(...params) {
const token = pledgePermissions(permissions); const token = pledgePermissions(permissions);
try { try {
return await fn(...params); return await fn(...new SafeArrayIterator(params));
} finally { } finally {
restorePermissions(token); restorePermissions(token);
} }
}; };
} }
const ESCAPE_ASCII_CHARS = [ const ESCAPE_ASCII_CHARS = [
["\b", "\\b"], ["\b", "\\b"],
["\f", "\\f"], ["\f", "\\f"],
["\t", "\\t"], ["\t", "\\t"],
["\n", "\\n"], ["\n", "\\n"],
["\r", "\\r"], ["\r", "\\r"],
["\v", "\\v"], ["\v", "\\v"],
]; ];
/** /**
* @param {string} name * @param {string} name
* @returns {string} * @returns {string}
*/ */
function escapeName(name) { function escapeName(name) {
// Check if we need to escape a character // Check if we need to escape a character
for (let i = 0; i < name.length; i++) { for (let i = 0; i < name.length; i++) {
const ch = name.charCodeAt(i); const ch = name.charCodeAt(i);
if (ch <= 13 && ch >= 8) { if (ch <= 13 && ch >= 8) {
// Slow path: We do need to escape it // Slow path: We do need to escape it
for (const [escape, replaceWith] of ESCAPE_ASCII_CHARS) { for (const [escape, replaceWith] of ESCAPE_ASCII_CHARS) {
name = name.replaceAll(escape, replaceWith); name = StringPrototypeReplaceAll(name, escape, replaceWith);
} }
return name; return name;
} }
@ -592,9 +610,9 @@
// We didn't need to escape anything, return original string // We didn't need to escape anything, return original string
return name; return name;
} }
/** /**
* @typedef {{ * @typedef {{
* id: number, * id: number,
* name: string, * name: string,
@ -650,27 +668,27 @@
* }} BenchDescription * }} BenchDescription
*/ */
/** @type {Map<number, TestState | TestStepState>} */ /** @type {Map<number, TestState | TestStepState>} */
const testStates = new Map(); const testStates = new Map();
/** @type {number | null} */ /** @type {number | null} */
let currentBenchId = null; let currentBenchId = null;
// These local variables are used to track time measurements at // These local variables are used to track time measurements at
// `BenchContext::{start,end}` calls. They are global instead of using a state // `BenchContext::{start,end}` calls. They are global instead of using a state
// map to minimise the overhead of assigning them. // map to minimise the overhead of assigning them.
/** @type {number | null} */ /** @type {number | null} */
let currentBenchUserExplicitStart = null; let currentBenchUserExplicitStart = null;
/** @type {number | null} */ /** @type {number | null} */
let currentBenchUserExplicitEnd = null; let currentBenchUserExplicitEnd = null;
const registerTestIdRetBuf = new Uint32Array(1); const registerTestIdRetBuf = new Uint32Array(1);
const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer); const registerTestIdRetBufU8 = new Uint8Array(registerTestIdRetBuf.buffer);
function testInner( function testInner(
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
overrides = {}, overrides = {},
) { ) {
if (typeof ops.op_register_test != "function") { if (typeof ops.op_register_test != "function") {
return; return;
} }
@ -776,42 +794,42 @@
); );
testDesc.id = registerTestIdRetBuf[0]; testDesc.id = registerTestIdRetBuf[0];
testDesc.origin = origin; testDesc.origin = origin;
testStates.set(testDesc.id, { MapPrototypeSet(testStates, testDesc.id, {
context: createTestContext(testDesc), context: createTestContext(testDesc),
children: [], children: [],
completed: false, completed: false,
}); });
} }
// Main test function provided by Deno. // Main test function provided by Deno.
function test( function test(
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
) { ) {
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn); return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn);
} }
test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) { test.ignore = function (nameOrFnOrOptions, optionsOrFn, maybeFn) {
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true }); return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { ignore: true });
}; };
test.only = function ( test.only = function (
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
) { ) {
return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true }); return testInner(nameOrFnOrOptions, optionsOrFn, maybeFn, { only: true });
}; };
let registeredWarmupBench = false; let registeredWarmupBench = false;
// Main bench function provided by Deno. // Main bench function provided by Deno.
function bench( function bench(
nameOrFnOrOptions, nameOrFnOrOptions,
optionsOrFn, optionsOrFn,
maybeFn, maybeFn,
) { ) {
if (typeof ops.op_register_bench != "function") { if (typeof ops.op_register_bench != "function") {
return; return;
} }
@ -923,16 +941,16 @@
const { id, origin } = ops.op_register_bench(benchDesc); const { id, origin } = ops.op_register_bench(benchDesc);
benchDesc.id = id; benchDesc.id = id;
benchDesc.origin = origin; benchDesc.origin = origin;
} }
function compareMeasurements(a, b) { function compareMeasurements(a, b) {
if (a > b) return 1; if (a > b) return 1;
if (a < b) return -1; if (a < b) return -1;
return 0; return 0;
} }
function benchStats( function benchStats(
n, n,
highPrecision, highPrecision,
usedExplicitTimers, usedExplicitTimers,
@ -940,22 +958,22 @@
min, min,
max, max,
all, all,
) { ) {
return { return {
n, n,
min, min,
max, max,
p75: all[Math.ceil(n * (75 / 100)) - 1], p75: all[MathCeil(n * (75 / 100)) - 1],
p99: all[Math.ceil(n * (99 / 100)) - 1], p99: all[MathCeil(n * (99 / 100)) - 1],
p995: all[Math.ceil(n * (99.5 / 100)) - 1], p995: all[MathCeil(n * (99.5 / 100)) - 1],
p999: all[Math.ceil(n * (99.9 / 100)) - 1], p999: all[MathCeil(n * (99.9 / 100)) - 1],
avg: !highPrecision ? (avg / n) : Math.ceil(avg / n), avg: !highPrecision ? (avg / n) : MathCeil(avg / n),
highPrecision, highPrecision,
usedExplicitTimers, usedExplicitTimers,
}; };
} }
async function benchMeasure(timeBudget, fn, async, context) { async function benchMeasure(timeBudget, fn, async, context) {
let n = 0; let n = 0;
let avg = 0; let avg = 0;
let wavg = 0; let wavg = 0;
@ -1036,7 +1054,7 @@
n++; n++;
avg += measuredTime; avg += measuredTime;
budget -= totalTime; budget -= totalTime;
all.push(measuredTime); ArrayPrototypePush(all, measuredTime);
if (measuredTime < min) min = measuredTime; if (measuredTime < min) min = measuredTime;
if (measuredTime > max) max = measuredTime; if (measuredTime > max) max = measuredTime;
} }
@ -1059,7 +1077,7 @@
n++; n++;
avg += measuredTime; avg += measuredTime;
budget -= totalTime; budget -= totalTime;
all.push(measuredTime); ArrayPrototypePush(all, measuredTime);
if (measuredTime < min) min = measuredTime; if (measuredTime < min) min = measuredTime;
if (measuredTime > max) max = measuredTime; if (measuredTime > max) max = measuredTime;
} }
@ -1080,7 +1098,7 @@
n++; n++;
avg += iterationTime; avg += iterationTime;
all.push(iterationTime); ArrayPrototypePush(all, iterationTime);
if (iterationTime < min) min = iterationTime; if (iterationTime < min) min = iterationTime;
if (iterationTime > max) max = iterationTime; if (iterationTime > max) max = iterationTime;
budget -= iterationTime * lowPrecisionThresholdInNs; budget -= iterationTime * lowPrecisionThresholdInNs;
@ -1097,7 +1115,7 @@
n++; n++;
avg += iterationTime; avg += iterationTime;
all.push(iterationTime); ArrayPrototypePush(all, iterationTime);
if (iterationTime < min) min = iterationTime; if (iterationTime < min) min = iterationTime;
if (iterationTime > max) max = iterationTime; if (iterationTime > max) max = iterationTime;
budget -= iterationTime * lowPrecisionThresholdInNs; budget -= iterationTime * lowPrecisionThresholdInNs;
@ -1115,12 +1133,12 @@
max, max,
all, all,
); );
} }
/** @param desc {BenchDescription} */ /** @param desc {BenchDescription} */
function createBenchContext(desc) { function createBenchContext(desc) {
return { return {
[Symbol.toStringTag]: "BenchContext", [SymbolToStringTag]: "BenchContext",
name: desc.name, name: desc.name,
origin: desc.origin, origin: desc.origin,
start() { start() {
@ -1149,10 +1167,10 @@
currentBenchUserExplicitEnd = end; currentBenchUserExplicitEnd = end;
}, },
}; };
} }
/** Wrap a user benchmark function in one which returns a structured result. */ /** Wrap a user benchmark function in one which returns a structured result. */
function wrapBenchmark(desc) { function wrapBenchmark(desc) {
const fn = desc.fn; const fn = desc.fn;
return async function outerWrapped() { return async function outerWrapped() {
let token = null; let token = null;
@ -1197,25 +1215,25 @@
if (token !== null) restorePermissions(token); if (token !== null) restorePermissions(token);
} }
}; };
} }
function benchNow() { function benchNow() {
return ops.op_bench_now(); return ops.op_bench_now();
} }
function getFullName(desc) { function getFullName(desc) {
if ("parent" in desc) { if ("parent" in desc) {
return `${getFullName(desc.parent)} ... ${desc.name}`; return `${getFullName(desc.parent)} ... ${desc.name}`;
} }
return desc.name; return desc.name;
} }
function usesSanitizer(desc) { function usesSanitizer(desc) {
return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit; return desc.sanitizeResources || desc.sanitizeOps || desc.sanitizeExit;
} }
function stepReportResult(desc, result, elapsed) { function stepReportResult(desc, result, elapsed) {
const state = testStates.get(desc.id); const state = MapPrototypeGet(testStates, desc.id);
for (const childDesc of state.children) { for (const childDesc of state.children) {
stepReportResult(childDesc, { failed: "incomplete" }, 0); stepReportResult(childDesc, { failed: "incomplete" }, 0);
} }
@ -1226,16 +1244,16 @@
} else { } else {
ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed); ops.op_test_event_step_result_failed(desc.id, result.failed, elapsed);
} }
} }
/** @param desc {TestDescription | TestStepDescription} */ /** @param desc {TestDescription | TestStepDescription} */
function createTestContext(desc) { function createTestContext(desc) {
let parent; let parent;
let level; let level;
let rootId; let rootId;
let rootName; let rootName;
if ("parent" in desc) { if ("parent" in desc) {
parent = testStates.get(desc.parent.id).context; parent = MapPrototypeGet(testStates, desc.parent.id).context;
level = desc.level; level = desc.level;
rootId = desc.rootId; rootId = desc.rootId;
rootName = desc.rootName; rootName = desc.rootName;
@ -1246,7 +1264,7 @@
rootName = desc.name; rootName = desc.name;
} }
return { return {
[Symbol.toStringTag]: "TestContext", [SymbolToStringTag]: "TestContext",
/** /**
* The current test name. * The current test name.
*/ */
@ -1264,7 +1282,7 @@
* @param maybeFn {((t: TestContext) => void | Promise<void>) | undefined} * @param maybeFn {((t: TestContext) => void | Promise<void>) | undefined}
*/ */
async step(nameOrFnOrOptions, maybeFn) { async step(nameOrFnOrOptions, maybeFn) {
if (testStates.get(desc.id).completed) { if (MapPrototypeGet(testStates, desc.id).completed) {
throw new Error( throw new Error(
"Cannot run test step after parent scope has finished execution. " + "Cannot run test step after parent scope has finished execution. " +
"Ensure any `.step(...)` calls are executed before their parent scope completes execution.", "Ensure any `.step(...)` calls are executed before their parent scope completes execution.",
@ -1273,9 +1291,7 @@
let stepDesc; let stepDesc;
if (typeof nameOrFnOrOptions === "string") { if (typeof nameOrFnOrOptions === "string") {
if ( if (!(ObjectPrototypeIsPrototypeOf(FunctionPrototype, maybeFn))) {
!Object.prototype.isPrototypeOf.call(Function.prototype, maybeFn)
) {
throw new TypeError("Expected function for second argument."); throw new TypeError("Expected function for second argument.");
} }
stepDesc = { stepDesc = {
@ -1331,30 +1347,31 @@
failed: false, failed: false,
completed: false, completed: false,
}; };
testStates.set(stepDesc.id, state); MapPrototypeSet(testStates, stepDesc.id, state);
testStates.get(stepDesc.parent.id).children.push( ArrayPrototypePush(
MapPrototypeGet(testStates, stepDesc.parent.id).children,
stepDesc, stepDesc,
); );
ops.op_test_event_step_wait(stepDesc.id); ops.op_test_event_step_wait(stepDesc.id);
const earlier = Date.now(); const earlier = DateNow();
const result = await stepDesc.fn(stepDesc); const result = await stepDesc.fn(stepDesc);
const elapsed = Date.now() - earlier; const elapsed = DateNow() - earlier;
state.failed = !!result.failed; state.failed = !!result.failed;
stepReportResult(stepDesc, result, elapsed); stepReportResult(stepDesc, result, elapsed);
return result == "ok"; return result == "ok";
}, },
}; };
} }
/** /**
* Wrap a user test function in one which returns a structured result. * Wrap a user test function in one which returns a structured result.
* @template T {Function} * @template T {Function}
* @param testFn {T} * @param testFn {T}
* @param desc {TestDescription | TestStepDescription} * @param desc {TestDescription | TestStepDescription}
* @returns {T} * @returns {T}
*/ */
function wrapTest(desc) { function wrapTest(desc) {
let testFn = wrapInner(desc.fn); let testFn = wrapInner(desc.fn);
if (desc.sanitizeOps) { if (desc.sanitizeOps) {
testFn = assertOps(testFn); testFn = assertOps(testFn);
@ -1369,8 +1386,7 @@
testFn = withPermissions(testFn, desc.permissions); testFn = withPermissions(testFn, desc.permissions);
} }
return wrapOuter(testFn, desc); return wrapOuter(testFn, desc);
} }
globalThis.Deno.bench = bench; globalThis.Deno.bench = bench;
globalThis.Deno.test = test; globalThis.Deno.test = test;
})();

View file

@ -637,13 +637,13 @@ impl CliMainWorkerFactory {
); );
if self.shared.subcommand.needs_test() { if self.shared.subcommand.needs_test() {
worker.js_runtime.execute_script_static( worker.js_runtime.lazy_load_es_module_from_code(
"ext:cli/40_testing.js", "ext:cli/40_testing.js",
include_str!("js/40_testing.js"), deno_core::FastString::StaticAscii(include_str!("js/40_testing.js")),
)?; )?;
worker.js_runtime.execute_script_static( worker.js_runtime.lazy_load_es_module_from_code(
"ext:cli/40_jupyter.js", "ext:cli/40_jupyter.js",
include_str!("js/40_jupyter.js"), deno_core::FastString::StaticAscii(include_str!("js/40_jupyter.js")),
)?; )?;
} }

View file

@ -1,6 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { core, internals, primordials } from "ext:core/mod.js"; import { core, primordials } from "ext:core/mod.js";
const ops = core.ops; const ops = core.ops;
import { pathFromURL } from "ext:deno_web/00_infra.js"; import { pathFromURL } from "ext:deno_web/00_infra.js";
import { Event, EventTarget } from "ext:deno_web/02_event.js"; import { Event, EventTarget } from "ext:deno_web/02_event.js";
@ -290,6 +290,4 @@ function serializePermissions(permissions) {
return permissions; return permissions;
} }
internals.serializePermissions = serializePermissions;
export { Permissions, permissions, PermissionStatus, serializePermissions }; export { Permissions, permissions, PermissionStatus, serializePermissions };

View file

@ -1,6 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { core, internals, primordials } from "ext:core/mod.js"; import { core, primordials } from "ext:core/mod.js";
const ops = core.ops; const ops = core.ops;
import { Event, EventTarget } from "ext:deno_web/02_event.js"; import { Event, EventTarget } from "ext:deno_web/02_event.js";
const { const {
@ -105,8 +105,6 @@ function execPath() {
return ops.op_exec_path(); return ops.op_exec_path();
} }
internals.setExitHandler = setExitHandler;
export { export {
env, env,
execPath, execPath,

View file

@ -43,7 +43,6 @@ use deno_fs::FileSystem;
use deno_http::DefaultHttpPropertyExtractor; use deno_http::DefaultHttpPropertyExtractor;
use deno_io::Stdio; use deno_io::Stdio;
use deno_kv::dynamic::MultiBackendDbHandler; use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX;
use deno_tls::RootCertStoreProvider; use deno_tls::RootCertStoreProvider;
use deno_web::create_entangled_message_port; use deno_web::create_entangled_message_port;
use deno_web::BlobStore; use deno_web::BlobStore;
@ -523,11 +522,6 @@ impl WebWorker {
(None, None) (None, None)
}; };
// Clear extension modules from the module map, except preserve `node:*`
// modules as `node:` specifiers.
let preserve_snapshotted_modules =
Some(SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX);
let mut js_runtime = JsRuntime::new(RuntimeOptions { let mut js_runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(options.module_loader.clone()), module_loader: Some(options.module_loader.clone()),
startup_snapshot: options startup_snapshot: options
@ -539,7 +533,6 @@ impl WebWorker {
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(), compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
extensions, extensions,
inspector: options.maybe_inspector_server.is_some(), inspector: options.maybe_inspector_server.is_some(),
preserve_snapshotted_modules,
feature_checker: Some(options.feature_checker.clone()), feature_checker: Some(options.feature_checker.clone()),
op_metrics_factory_fn, op_metrics_factory_fn,
..Default::default() ..Default::default()

View file

@ -39,7 +39,6 @@ use deno_fs::FileSystem;
use deno_http::DefaultHttpPropertyExtractor; use deno_http::DefaultHttpPropertyExtractor;
use deno_io::Stdio; use deno_io::Stdio;
use deno_kv::dynamic::MultiBackendDbHandler; use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX;
use deno_tls::RootCertStoreProvider; use deno_tls::RootCertStoreProvider;
use deno_web::BlobStore; use deno_web::BlobStore;
use log::debug; use log::debug;
@ -420,11 +419,6 @@ impl MainWorker {
#[cfg(all(feature = "include_js_files_for_snapshotting", feature = "dont_create_runtime_snapshot", not(feature = "__runtime_js_sources")))] #[cfg(all(feature = "include_js_files_for_snapshotting", feature = "dont_create_runtime_snapshot", not(feature = "__runtime_js_sources")))]
options.startup_snapshot.as_ref().expect("Sources are not embedded, snapshotting was disabled and a user snapshot was not provided."); options.startup_snapshot.as_ref().expect("Sources are not embedded, snapshotting was disabled and a user snapshot was not provided.");
// Clear extension modules from the module map, except preserve `node:*`
// modules.
let preserve_snapshotted_modules =
Some(SUPPORTED_BUILTIN_NODE_MODULES_WITH_PREFIX);
let mut js_runtime = JsRuntime::new(RuntimeOptions { let mut js_runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(options.module_loader.clone()), module_loader: Some(options.module_loader.clone()),
startup_snapshot: options startup_snapshot: options
@ -437,7 +431,6 @@ impl MainWorker {
shared_array_buffer_store: options.shared_array_buffer_store.clone(), shared_array_buffer_store: options.shared_array_buffer_store.clone(),
compiled_wasm_module_store: options.compiled_wasm_module_store.clone(), compiled_wasm_module_store: options.compiled_wasm_module_store.clone(),
extensions, extensions,
preserve_snapshotted_modules,
inspector: options.maybe_inspector_server.is_some(), inspector: options.maybe_inspector_server.is_some(),
is_main: true, is_main: true,
feature_checker: Some(options.feature_checker.clone()), feature_checker: Some(options.feature_checker.clone()),