diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts index 457fa07dbc..b238bd6b31 100644 --- a/core/lib.deno_core.d.ts +++ b/core/lib.deno_core.d.ts @@ -184,5 +184,13 @@ declare namespace Deno { after_hook?: (promise: Promise) => void, resolve_hook?: (promise: Promise) => void, ): void; + + const build: { + target: string; + arch: string; + os: string; + vendor: string; + env: string | undefined; + }; } } diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js index a63a027e80..a1b1771221 100644 --- a/ext/ffi/00_ffi.js +++ b/ext/ffi/00_ffi.js @@ -2,7 +2,6 @@ const core = globalThis.Deno.core; const ops = core.ops; -const internals = globalThis.__bootstrap.internals; const primordials = globalThis.__bootstrap.primordials; const { ArrayPrototypeMap, @@ -28,6 +27,7 @@ const { SymbolFor, WeakMap, } = primordials; +import { pathFromURL } from "internal:deno_web/00_infra.js"; const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId"); @@ -542,9 +542,6 @@ class DynamicLibrary { } function dlopen(path, symbols) { - // TODO(@crowlKats): remove me - // URL support is progressively enhanced by util in `runtime/js`. - const pathFromURL = internals.pathFromURL ?? ((p) => p); return new DynamicLibrary(pathFromURL(path), symbols); } diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index b8e3ac5032..38a5a7eb2c 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -83,6 +83,7 @@ pub(crate) struct FfiState { pub fn init(unstable: bool) -> Extension { Extension::builder(env!("CARGO_PKG_NAME")) + .dependencies(vec!["deno_web"]) .esm(include_js_files!("00_ffi.js",)) .ops(vec![ op_ffi_load::decl::

(), diff --git a/ext/web/00_infra.js b/ext/web/00_infra.js index cff0f66d80..0c062f89c7 100644 --- a/ext/web/00_infra.js +++ b/ext/web/00_infra.js @@ -7,14 +7,17 @@ /// const core = globalThis.Deno.core; +const internals = globalThis.__bootstrap.internals; const ops = core.ops; const primordials = globalThis.__bootstrap.primordials; const { ArrayPrototypeJoin, ArrayPrototypeMap, + decodeURIComponent, Error, JSONStringify, NumberPrototypeToString, + ObjectPrototypeIsPrototypeOf, SafeArrayIterator, SafeRegExp, String, @@ -29,6 +32,7 @@ const { StringPrototypeToUpperCase, TypeError, } = primordials; +import { URLPrototype } from "internal:deno_url/00_url.js"; const ASCII_DIGIT = ["\u0030-\u0039"]; const ASCII_UPPER_ALPHA = ["\u0041-\u005A"]; @@ -362,6 +366,77 @@ function serializeJSValueToJSONString(value) { return result; } +const PATHNAME_WIN_RE = new SafeRegExp(/^\/*([A-Za-z]:)(\/|$)/); +const SLASH_WIN_RE = new SafeRegExp(/\//g); +const PERCENT_RE = new SafeRegExp(/%(?![0-9A-Fa-f]{2})/g); + +// Keep in sync with `fromFileUrl()` in `std/path/win32.ts`. +/** + * @param {URL} url + * @returns {string} + */ +function pathFromURLWin32(url) { + let p = StringPrototypeReplace( + url.pathname, + PATHNAME_WIN_RE, + "$1/", + ); + p = StringPrototypeReplace( + p, + SLASH_WIN_RE, + "\\", + ); + p = StringPrototypeReplace( + p, + PERCENT_RE, + "%25", + ); + let path = decodeURIComponent(p); + if (url.hostname != "") { + // Note: The `URL` implementation guarantees that the drive letter and + // hostname are mutually exclusive. Otherwise it would not have been valid + // to append the hostname and path like this. + path = `\\\\${url.hostname}${path}`; + } + return path; +} + +// Keep in sync with `fromFileUrl()` in `std/path/posix.ts`. +/** + * @param {URL} url + * @returns {string} + */ +function pathFromURLPosix(url) { + if (url.hostname !== "") { + throw new TypeError(`Host must be empty.`); + } + + return decodeURIComponent( + StringPrototypeReplace( + url.pathname, + PERCENT_RE, + "%25", + ), + ); +} + +function pathFromURL(pathOrUrl) { + if (ObjectPrototypeIsPrototypeOf(URLPrototype, pathOrUrl)) { + if (pathOrUrl.protocol != "file:") { + throw new TypeError("Must be a file URL."); + } + + return core.build.os == "windows" + ? pathFromURLWin32(pathOrUrl) + : pathFromURLPosix(pathOrUrl); + } + return pathOrUrl; +} + +// NOTE(bartlomieju): this is exposed on `internals` so we can test +// it in unit tests +internals.pathFromURL = pathFromURL; + export { ASCII_ALPHA, ASCII_ALPHANUMERIC, @@ -389,6 +464,7 @@ export { HTTP_WHITESPACE_PREFIX_RE, HTTP_WHITESPACE_SUFFIX_RE, httpTrim, + pathFromURL, regexMatcher, serializeJSValueToJSONString, }; diff --git a/runtime/js/06_util.js b/runtime/js/06_util.js index fc134d52d9..db4564e32d 100644 --- a/runtime/js/06_util.js +++ b/runtime/js/06_util.js @@ -1,18 +1,10 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -const core = globalThis.Deno.core; -const internals = globalThis.__bootstrap.internals; const primordials = globalThis.__bootstrap.primordials; const { - decodeURIComponent, - ObjectPrototypeIsPrototypeOf, Promise, SafeArrayIterator, - SafeRegExp, - StringPrototypeReplace, - TypeError, } = primordials; -import { URLPrototype } from "internal:deno_url/00_url.js"; let logDebug = false; let logSource = "JS"; @@ -46,64 +38,6 @@ function createResolvable() { return promise; } -// Keep in sync with `fromFileUrl()` in `std/path/win32.ts`. -function pathFromURLWin32(url) { - let p = StringPrototypeReplace( - url.pathname, - new SafeRegExp(/^\/*([A-Za-z]:)(\/|$)/), - "$1/", - ); - p = StringPrototypeReplace( - p, - /\//g, - "\\", - ); - p = StringPrototypeReplace( - p, - new SafeRegExp(/%(?![0-9A-Fa-f]{2})/g), - "%25", - ); - let path = decodeURIComponent(p); - if (url.hostname != "") { - // Note: The `URL` implementation guarantees that the drive letter and - // hostname are mutually exclusive. Otherwise it would not have been valid - // to append the hostname and path like this. - path = `\\\\${url.hostname}${path}`; - } - return path; -} - -// Keep in sync with `fromFileUrl()` in `std/path/posix.ts`. -function pathFromURLPosix(url) { - if (url.hostname !== "") { - throw new TypeError(`Host must be empty.`); - } - - return decodeURIComponent( - StringPrototypeReplace( - url.pathname, - new SafeRegExp(/%(?![0-9A-Fa-f]{2})/g), - "%25", - ), - ); -} - -function pathFromURL(pathOrUrl) { - if (ObjectPrototypeIsPrototypeOf(URLPrototype, pathOrUrl)) { - if (pathOrUrl.protocol != "file:") { - throw new TypeError("Must be a file URL."); - } - - return core.build.os == "windows" - ? pathFromURLWin32(pathOrUrl) - : pathFromURLPosix(pathOrUrl); - } - return pathOrUrl; -} - -// TODO(bartlomieju): remove -internals.pathFromURL = pathFromURL; - function writable(value) { return { value, @@ -145,7 +79,6 @@ export { getterOnly, log, nonEnumerable, - pathFromURL, readOnly, setLogDebug, writable, diff --git a/runtime/js/10_permissions.js b/runtime/js/10_permissions.js index acdbae8e7a..13ea9828b4 100644 --- a/runtime/js/10_permissions.js +++ b/runtime/js/10_permissions.js @@ -2,8 +2,8 @@ const core = globalThis.Deno.core; const ops = core.ops; +import { pathFromURL } from "internal:deno_web/00_infra.js"; import { Event, EventTarget } from "internal:deno_web/02_event.js"; -import { pathFromURL } from "internal:runtime/06_util.js"; const primordials = globalThis.__bootstrap.primordials; const { ArrayIsArray, diff --git a/runtime/js/30_fs.js b/runtime/js/30_fs.js index fc0bbdca51..19e7f372b8 100644 --- a/runtime/js/30_fs.js +++ b/runtime/js/30_fs.js @@ -24,7 +24,7 @@ import { ReadableStreamPrototype, writableStreamForRid, } from "internal:deno_web/06_streams.js"; -import { pathFromURL } from "internal:runtime/06_util.js"; +import { pathFromURL } from "internal:deno_web/00_infra.js"; function chmodSync(path, mode) { ops.op_chmod_sync(pathFromURL(path), mode); diff --git a/runtime/js/40_process.js b/runtime/js/40_process.js index 9599b7b746..28bb2870cd 100644 --- a/runtime/js/40_process.js +++ b/runtime/js/40_process.js @@ -18,8 +18,7 @@ const { } = primordials; import { FsFile } from "internal:runtime/30_fs.js"; import { readAll } from "internal:deno_io/12_io.js"; -import { pathFromURL } from "internal:runtime/06_util.js"; -import { assert } from "internal:deno_web/00_infra.js"; +import { assert, pathFromURL } from "internal:deno_web/00_infra.js"; import * as abortSignal from "internal:deno_web/03_abort_signal.js"; import { readableStreamCollectIntoUint8Array,