From 651e3e9e6daf3243dd21b7f66ce9738abdc39a37 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Sat, 27 Apr 2024 17:11:57 -0400 Subject: [PATCH] fix(compile): certain jsr specifiers sometimes can't load (#23567) When returning a jsr specifier for resolve it seems like deno core does not work properly and hangs. Closes https://github.com/denoland/deno/issues/23551 Closes https://github.com/denoland/deno/issues/23139 --- cli/standalone/binary.rs | 4 +- cli/standalone/mod.rs | 7 ++ tests/specs/README.md | 1 + .../compile/jsr_with_deps/__test__.jsonc | 22 ++++++ tests/specs/compile/jsr_with_deps/main.out | 2 + tests/specs/compile/jsr_with_deps/main.ts | 8 ++ tests/specs/mod.rs | 25 ++++++- tests/specs/schema.json | 9 +++ .../@std/path/0.220.1/_common/assert_path.ts | 10 +++ .../@std/path/0.220.1/_common/constants.ts | 49 ++++++++++++ .../@std/path/0.220.1/_common/normalize.ts | 9 +++ .../path/0.220.1/_common/normalize_string.ts | 74 +++++++++++++++++++ .../registry/@std/path/0.220.1/posix/_util.ts | 10 +++ .../registry/@std/path/0.220.1/posix/join.ts | 25 +++++++ .../@std/path/0.220.1/posix/normalize.ts | 30 ++++++++ .../jsr/registry/@std/path/0.220.1_meta.json | 64 ++++++++++++++++ .../testdata/jsr/registry/@std/path/meta.json | 8 ++ .../jsr/registry/@std/url/0.220.1/join.ts | 28 +++++++ .../registry/@std/url/0.220.1/normalize.ts | 28 +++++++ .../jsr/registry/@std/url/0.220.1_meta.json | 10 +++ .../testdata/jsr/registry/@std/url/meta.json | 8 ++ tests/util/server/src/builders.rs | 2 + 22 files changed, 429 insertions(+), 4 deletions(-) create mode 100644 tests/specs/compile/jsr_with_deps/__test__.jsonc create mode 100644 tests/specs/compile/jsr_with_deps/main.out create mode 100644 tests/specs/compile/jsr_with_deps/main.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/_common/assert_path.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/_common/constants.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize_string.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/posix/_util.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/posix/join.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1/posix/normalize.ts create mode 100644 tests/testdata/jsr/registry/@std/path/0.220.1_meta.json create mode 100644 tests/testdata/jsr/registry/@std/path/meta.json create mode 100644 tests/testdata/jsr/registry/@std/url/0.220.1/join.ts create mode 100644 tests/testdata/jsr/registry/@std/url/0.220.1/normalize.ts create mode 100644 tests/testdata/jsr/registry/@std/url/0.220.1_meta.json create mode 100644 tests/testdata/jsr/registry/@std/url/meta.json diff --git a/cli/standalone/binary.rs b/cli/standalone/binary.rs index c96d838540107..4442f5a241bab 100644 --- a/cli/standalone/binary.rs +++ b/cli/standalone/binary.rs @@ -488,7 +488,9 @@ impl<'a> DenoCompileBinaryWriter<'a> { // Phase 2 of the 'min sized' deno compile RFC talks // about adding this as a flag. if let Some(path) = std::env::var_os("DENORT_BIN") { - return Ok(std::fs::read(path)?); + return std::fs::read(&path).with_context(|| { + format!("Could not find denort at '{}'", path.to_string_lossy()) + }); } let target = compile_flags.resolve_target(); diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 8ff822f5a32ee..3cfeb4f4ce58c 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -150,6 +150,13 @@ impl ModuleLoader for EmbeddedModuleLoader { Some(resolved) => resolved, None => deno_core::resolve_import(specifier, referrer.as_str())?, }; + + if specifier.scheme() == "jsr" { + if let Some(module) = self.shared.eszip.get_module(specifier.as_str()) { + return Ok(ModuleSpecifier::parse(&module.specifier).unwrap()); + } + } + self .shared .node_resolver diff --git a/tests/specs/README.md b/tests/specs/README.md index d9c620aa71a50..55880fe23d8fe 100644 --- a/tests/specs/README.md +++ b/tests/specs/README.md @@ -78,6 +78,7 @@ a "steps" array. - `output` - Path to use to assert the output. - `cleanDenoDir` (boolean) - Whether to empty the deno_dir before running the step. +- `if` (`"windows"`, `"linux"`, `"mac"`, `"unix"`) - Whether to run this step. - `exitCode` (number) - Expected exit code. ### Auto-complete diff --git a/tests/specs/compile/jsr_with_deps/__test__.jsonc b/tests/specs/compile/jsr_with_deps/__test__.jsonc new file mode 100644 index 0000000000000..be2bbd1e4fcc2 --- /dev/null +++ b/tests/specs/compile/jsr_with_deps/__test__.jsonc @@ -0,0 +1,22 @@ +{ + "tempDir": true, + "steps": [{ + "if": "unix", + "args": "compile --output main main.ts", + "output": "[WILDCARD]" + }, { + "if": "unix", + "commandName": "./main", + "args": [], + "output": "main.out" + }, { + "if": "windows", + "args": "compile --output main.exe main.ts", + "output": "[WILDCARD]" + }, { + "if": "windows", + "commandName": "./main.exe", + "args": [], + "output": "main.out" + }] +} diff --git a/tests/specs/compile/jsr_with_deps/main.out b/tests/specs/compile/jsr_with_deps/main.out new file mode 100644 index 0000000000000..6340327e03817 --- /dev/null +++ b/tests/specs/compile/jsr_with_deps/main.out @@ -0,0 +1,2 @@ +[Function: join] +http://[WILDLINE]/@std/url/0.220.1/join.ts diff --git a/tests/specs/compile/jsr_with_deps/main.ts b/tests/specs/compile/jsr_with_deps/main.ts new file mode 100644 index 0000000000000..44a7dc08c83df --- /dev/null +++ b/tests/specs/compile/jsr_with_deps/main.ts @@ -0,0 +1,8 @@ +// this was previously hanging in deno compile and wouldn't work +import { join } from "jsr:@std/url@0.220/join"; +import "jsr:@std/url@0.220/normalize"; + +console.log(join); + +// ensure import.meta.resolve works in compile for jsr specifiers +console.log(import.meta.resolve("jsr:@std/url@0.220/join")); diff --git a/tests/specs/mod.rs b/tests/specs/mod.rs index 2040eea6277f9..16a9e6f057eb3 100644 --- a/tests/specs/mod.rs +++ b/tests/specs/mod.rs @@ -73,6 +73,8 @@ struct StepMetaData { pub clean_deno_dir: bool, pub args: VecOrString, pub cwd: Option, + #[serde(rename = "if")] + pub if_cond: Option, pub command_name: Option, #[serde(default)] pub envs: HashMap, @@ -152,8 +154,11 @@ fn run_test(test: &CollectedTest, diagnostic_logger: Rc>>) { // todo(dsherret): add bases in the future as needed Some(base) => panic!("Unknown test base: {}", base), None => { - // by default add npm and jsr env vars - builder = builder.add_jsr_env_vars().add_npm_env_vars(); + // by default add all these + builder = builder + .add_jsr_env_vars() + .add_npm_env_vars() + .add_compile_env_vars(); } } @@ -167,7 +172,7 @@ fn run_test(test: &CollectedTest, diagnostic_logger: Rc>>) { cwd.copy_to_recursive_with_exclusions(temp_dir, &assertion_paths); } - for step in &metadata.steps { + for step in metadata.steps.iter().filter(|s| should_run_step(s)) { if step.clean_deno_dir { context.deno_dir().path().remove_dir_all(); } @@ -198,6 +203,20 @@ fn run_test(test: &CollectedTest, diagnostic_logger: Rc>>) { } } +fn should_run_step(step: &StepMetaData) -> bool { + if let Some(cond) = &step.if_cond { + match cond.as_str() { + "windows" => cfg!(windows), + "unix" => cfg!(unix), + "mac" => cfg!(target_os = "macos"), + "linux" => cfg!(target_os = "linux"), + value => panic!("Unknown if condition: {}", value), + } + } else { + true + } +} + fn resolve_test_and_assertion_files( dir: &PathRef, metadata: &MultiTestMetaData, diff --git a/tests/specs/schema.json b/tests/specs/schema.json index 8b21ab32cee50..b3a30f9363eab 100644 --- a/tests/specs/schema.json +++ b/tests/specs/schema.json @@ -36,6 +36,15 @@ "type": "string" } }, + "if": { + "type": "string", + "examples": [ + "mac", + "linux", + "windows", + "unix" + ] + }, "output": { "type": "string" }, diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/_common/assert_path.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/assert_path.ts new file mode 100644 index 0000000000000..7033edcd1a79b --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/assert_path.ts @@ -0,0 +1,10 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright the Browserify authors. MIT License. + +export function assertPath(path?: string) { + if (typeof path !== "string") { + throw new TypeError( + `Path must be a string. Received ${JSON.stringify(path)}`, + ); + } +} diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/_common/constants.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/constants.ts new file mode 100644 index 0000000000000..9bfd411b668de --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/constants.ts @@ -0,0 +1,49 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright the Browserify authors. MIT License. +// Ported from https://github.com/browserify/path-browserify/ +// This module is browser compatible. + +// Alphabet chars. +export const CHAR_UPPERCASE_A = 65; /* A */ +export const CHAR_LOWERCASE_A = 97; /* a */ +export const CHAR_UPPERCASE_Z = 90; /* Z */ +export const CHAR_LOWERCASE_Z = 122; /* z */ + +// Non-alphabetic chars. +export const CHAR_DOT = 46; /* . */ +export const CHAR_FORWARD_SLASH = 47; /* / */ +export const CHAR_BACKWARD_SLASH = 92; /* \ */ +export const CHAR_VERTICAL_LINE = 124; /* | */ +export const CHAR_COLON = 58; /* : */ +export const CHAR_QUESTION_MARK = 63; /* ? */ +export const CHAR_UNDERSCORE = 95; /* _ */ +export const CHAR_LINE_FEED = 10; /* \n */ +export const CHAR_CARRIAGE_RETURN = 13; /* \r */ +export const CHAR_TAB = 9; /* \t */ +export const CHAR_FORM_FEED = 12; /* \f */ +export const CHAR_EXCLAMATION_MARK = 33; /* ! */ +export const CHAR_HASH = 35; /* # */ +export const CHAR_SPACE = 32; /* */ +export const CHAR_NO_BREAK_SPACE = 160; /* \u00A0 */ +export const CHAR_ZERO_WIDTH_NOBREAK_SPACE = 65279; /* \uFEFF */ +export const CHAR_LEFT_SQUARE_BRACKET = 91; /* [ */ +export const CHAR_RIGHT_SQUARE_BRACKET = 93; /* ] */ +export const CHAR_LEFT_ANGLE_BRACKET = 60; /* < */ +export const CHAR_RIGHT_ANGLE_BRACKET = 62; /* > */ +export const CHAR_LEFT_CURLY_BRACKET = 123; /* { */ +export const CHAR_RIGHT_CURLY_BRACKET = 125; /* } */ +export const CHAR_HYPHEN_MINUS = 45; /* - */ +export const CHAR_PLUS = 43; /* + */ +export const CHAR_DOUBLE_QUOTE = 34; /* " */ +export const CHAR_SINGLE_QUOTE = 39; /* ' */ +export const CHAR_PERCENT = 37; /* % */ +export const CHAR_SEMICOLON = 59; /* ; */ +export const CHAR_CIRCUMFLEX_ACCENT = 94; /* ^ */ +export const CHAR_GRAVE_ACCENT = 96; /* ` */ +export const CHAR_AT = 64; /* @ */ +export const CHAR_AMPERSAND = 38; /* & */ +export const CHAR_EQUAL = 61; /* = */ + +// Digits +export const CHAR_0 = 48; /* 0 */ +export const CHAR_9 = 57; /* 9 */ diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize.ts new file mode 100644 index 0000000000000..3a1a1628453f5 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize.ts @@ -0,0 +1,9 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { assertPath } from "./assert_path.ts"; + +export function assertArg(path: string) { + assertPath(path); + if (path.length === 0) return "."; +} diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize_string.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize_string.ts new file mode 100644 index 0000000000000..d8f0e090a6ed2 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/_common/normalize_string.ts @@ -0,0 +1,74 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright the Browserify authors. MIT License. +// Ported from https://github.com/browserify/path-browserify/ +// This module is browser compatible. + +import { CHAR_DOT, CHAR_FORWARD_SLASH } from "./constants.ts"; + +// Resolves . and .. elements in a path with directory names +export function normalizeString( + path: string, + allowAboveRoot: boolean, + separator: string, + isPathSeparator: (code: number) => boolean, +): string { + let res = ""; + let lastSegmentLength = 0; + let lastSlash = -1; + let dots = 0; + let code: number | undefined; + for (let i = 0; i <= path.length; ++i) { + if (i < path.length) code = path.charCodeAt(i); + else if (isPathSeparator(code!)) break; + else code = CHAR_FORWARD_SLASH; + + if (isPathSeparator(code!)) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if ( + res.length < 2 || + lastSegmentLength !== 2 || + res.charCodeAt(res.length - 1) !== CHAR_DOT || + res.charCodeAt(res.length - 2) !== CHAR_DOT + ) { + if (res.length > 2) { + const lastSlashIndex = res.lastIndexOf(separator); + if (lastSlashIndex === -1) { + res = ""; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); + } + lastSlash = i; + dots = 0; + continue; + } else if (res.length === 2 || res.length === 1) { + res = ""; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) res += `${separator}..`; + else res = ".."; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) res += separator + path.slice(lastSlash + 1, i); + else res = path.slice(lastSlash + 1, i); + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === CHAR_DOT && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/posix/_util.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/posix/_util.ts new file mode 100644 index 0000000000000..b446155df5b3f --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/posix/_util.ts @@ -0,0 +1,10 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// Copyright the Browserify authors. MIT License. +// Ported from https://github.com/browserify/path-browserify/ +// This module is browser compatible. + +import { CHAR_FORWARD_SLASH } from "../_common/constants.ts"; + +export function isPosixPathSeparator(code: number): boolean { + return code === CHAR_FORWARD_SLASH; +} diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/posix/join.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/posix/join.ts new file mode 100644 index 0000000000000..625762ab97ace --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/posix/join.ts @@ -0,0 +1,25 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { assertPath } from "../_common/assert_path.ts"; +import { normalize } from "./normalize.ts"; + +/** + * Join all given a sequence of `paths`,then normalizes the resulting path. + * @param paths to be joined and normalized + */ +export function join(...paths: string[]): string { + if (paths.length === 0) return "."; + + let joined: string | undefined; + for (let i = 0; i < paths.length; ++i) { + const path = paths[i]!; + assertPath(path); + if (path.length > 0) { + if (!joined) joined = path; + else joined += `/${path}`; + } + } + if (!joined) return "."; + return normalize(joined); +} diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1/posix/normalize.ts b/tests/testdata/jsr/registry/@std/path/0.220.1/posix/normalize.ts new file mode 100644 index 0000000000000..8e88ad254b036 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1/posix/normalize.ts @@ -0,0 +1,30 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { assertArg } from "../_common/normalize.ts"; +import { normalizeString } from "../_common/normalize_string.ts"; +import { isPosixPathSeparator } from "./_util.ts"; + +/** + * Normalize the `path`, resolving `'..'` and `'.'` segments. + * Note that resolving these segments does not necessarily mean that all will be eliminated. + * A `'..'` at the top-level will be preserved, and an empty path is canonically `'.'`. + * @param path to be normalized + */ +export function normalize(path: string): string { + assertArg(path); + + const isAbsolute = isPosixPathSeparator(path.charCodeAt(0)); + const trailingSeparator = isPosixPathSeparator( + path.charCodeAt(path.length - 1), + ); + + // Normalize the path + path = normalizeString(path, !isAbsolute, "/", isPosixPathSeparator); + + if (path.length === 0 && !isAbsolute) path = "."; + if (path.length > 0 && trailingSeparator) path += "/"; + + if (isAbsolute) return `/${path}`; + return path; +} diff --git a/tests/testdata/jsr/registry/@std/path/0.220.1_meta.json b/tests/testdata/jsr/registry/@std/path/0.220.1_meta.json new file mode 100644 index 0000000000000..2a2f43f96d885 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/0.220.1_meta.json @@ -0,0 +1,64 @@ +{ + "exports": { + ".": "./mod.ts", + "./basename": "./basename.ts", + "./common": "./common.ts", + "./constants": "./constants.ts", + "./dirname": "./dirname.ts", + "./extname": "./extname.ts", + "./format": "./format.ts", + "./from_file_url": "./from_file_url.ts", + "./glob_to_regexp": "./glob_to_regexp.ts", + "./is_absolute": "./is_absolute.ts", + "./is_glob": "./is_glob.ts", + "./join": "./join.ts", + "./join_globs": "./join_globs.ts", + "./normalize": "./normalize.ts", + "./normalize_glob": "./normalize_glob.ts", + "./parse": "./parse.ts", + "./posix": "./posix/mod.ts", + "./posix/basename": "./posix/basename.ts", + "./posix/common": "./posix/common.ts", + "./posix/constants": "./posix/constants.ts", + "./posix/dirname": "./posix/dirname.ts", + "./posix/extname": "./posix/extname.ts", + "./posix/format": "./posix/format.ts", + "./posix/from_file_url": "./posix/from_file_url.ts", + "./posix/glob_to_regexp": "./posix/glob_to_regexp.ts", + "./posix/is_absolute": "./posix/is_absolute.ts", + "./posix/is_glob": "./posix/is_glob.ts", + "./posix/join": "./posix/join.ts", + "./posix/join_globs": "./posix/join_globs.ts", + "./posix/normalize": "./posix/normalize.ts", + "./posix/normalize_glob": "./posix/normalize_glob.ts", + "./posix/parse": "./posix/parse.ts", + "./posix/relative": "./posix/relative.ts", + "./posix/resolve": "./posix/resolve.ts", + "./posix/to_file_url": "./posix/to_file_url.ts", + "./posix/to_namespaced_path": "./posix/to_namespaced_path.ts", + "./relative": "./relative.ts", + "./resolve": "./resolve.ts", + "./to_file_url": "./to_file_url.ts", + "./to_namespaced_path": "./to_namespaced_path.ts", + "./windows": "./windows/mod.ts", + "./windows/basename": "./windows/basename.ts", + "./windows/common": "./windows/common.ts", + "./windows/constants": "./windows/constants.ts", + "./windows/dirname": "./windows/dirname.ts", + "./windows/extname": "./windows/extname.ts", + "./windows/format": "./windows/format.ts", + "./windows/from_file_url": "./windows/from_file_url.ts", + "./windows/glob_to_regexp": "./windows/glob_to_regexp.ts", + "./windows/is_absolute": "./windows/is_absolute.ts", + "./windows/is_glob": "./windows/is_glob.ts", + "./windows/join": "./windows/join.ts", + "./windows/join_globs": "./windows/join_globs.ts", + "./windows/normalize": "./windows/normalize.ts", + "./windows/normalize_glob": "./windows/normalize_glob.ts", + "./windows/parse": "./windows/parse.ts", + "./windows/relative": "./windows/relative.ts", + "./windows/resolve": "./windows/resolve.ts", + "./windows/to_file_url": "./windows/to_file_url.ts", + "./windows/to_namespaced_path": "./windows/to_namespaced_path.ts" + } +} diff --git a/tests/testdata/jsr/registry/@std/path/meta.json b/tests/testdata/jsr/registry/@std/path/meta.json new file mode 100644 index 0000000000000..89a4e07f91f02 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/path/meta.json @@ -0,0 +1,8 @@ +{ + "scope": "std", + "name": "path", + "latest": "0.220.1", + "versions": { + "0.220.1": {} + } +} diff --git a/tests/testdata/jsr/registry/@std/url/0.220.1/join.ts b/tests/testdata/jsr/registry/@std/url/0.220.1/join.ts new file mode 100644 index 0000000000000..158994ad3ace8 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/url/0.220.1/join.ts @@ -0,0 +1,28 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { join as posixJoin } from "jsr:/@std/path@^0.220.1/posix/join"; + +/** + * Join a base `URL` and a series of `paths`, then normalizes the resulting URL. + * + * @example + * ```ts + * import { join } from "@std/url/join"; + * + * console.log(join("https://deno.land/", "std", "path", "mod.ts").href); + * // Outputs: "https://deno.land/std/path/mod.ts" + * + * console.log(join("https://deno.land", "//std", "path/", "/mod.ts").href); + * // Outputs: "https://deno.land/path/mod.ts" + * ``` + * + * @param url the base URL to be joined with the paths and normalized + * @param paths array of path segments to be joined to the base URL + * @returns a complete URL string containing the base URL joined with the paths + */ +export function join(url: string | URL, ...paths: string[]): URL { + url = new URL(url); + url.pathname = posixJoin(url.pathname, ...paths); + return url; +} diff --git a/tests/testdata/jsr/registry/@std/url/0.220.1/normalize.ts b/tests/testdata/jsr/registry/@std/url/0.220.1/normalize.ts new file mode 100644 index 0000000000000..dc23057019d53 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/url/0.220.1/normalize.ts @@ -0,0 +1,28 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { normalize as posixNormalize } from "jsr:/@std/path@^0.220.1/posix/normalize"; + +/** + * Normalize the `URL`, resolving `'..'` and `'.'` segments and multiple + * `'/'`s into `'//'` after protocol and remaining into `'/'`. + * + * @example + * ```ts + * import { normalize } from "@std/url/normalize"; + * + * console.log(normalize("https:///deno.land///std//assert//.//mod.ts").href); + * // Outputs: "https://deno.land/std/path/mod.ts" + * + * console.log(normalize("https://deno.land/std/assert/../async/retry.ts").href); + * // Outputs: "https://deno.land/std/async/retry.ts" + * ``` + * + * @param url to be normalized + * @returns normalized URL + */ +export function normalize(url: string | URL): URL { + url = new URL(url); + url.pathname = posixNormalize(url.pathname); + return url; +} diff --git a/tests/testdata/jsr/registry/@std/url/0.220.1_meta.json b/tests/testdata/jsr/registry/@std/url/0.220.1_meta.json new file mode 100644 index 0000000000000..2a92cc6511cf8 --- /dev/null +++ b/tests/testdata/jsr/registry/@std/url/0.220.1_meta.json @@ -0,0 +1,10 @@ +{ + "exports": { + ".": "./mod.ts", + "./basename": "./basename.ts", + "./dirname": "./dirname.ts", + "./extname": "./extname.ts", + "./join": "./join.ts", + "./normalize": "./normalize.ts" + } +} diff --git a/tests/testdata/jsr/registry/@std/url/meta.json b/tests/testdata/jsr/registry/@std/url/meta.json new file mode 100644 index 0000000000000..3ae97c991db8b --- /dev/null +++ b/tests/testdata/jsr/registry/@std/url/meta.json @@ -0,0 +1,8 @@ +{ + "scope": "std", + "name": "url", + "latest": "0.220.1", + "versions": { + "0.220.1": {} + } +} diff --git a/tests/util/server/src/builders.rs b/tests/util/server/src/builders.rs index 9490c4c44b4a7..b41c684be3a10 100644 --- a/tests/util/server/src/builders.rs +++ b/tests/util/server/src/builders.rs @@ -740,6 +740,8 @@ impl TestCommandBuilder { }; if command_name == "deno" { deno_exe_path() + } else if command_name.starts_with("./") && self.cwd.is_some() { + self.cwd.as_ref().unwrap().join(command_name) } else { PathRef::new(PathBuf::from(command_name)) }