From 60fd17304f96fd903f4ef1597a94a5aff197c035 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 8 Feb 2024 14:38:44 +0530 Subject: [PATCH 01/63] fix: version bump workflow (#4288) --- .github/workflows/version_bump.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/version_bump.yml b/.github/workflows/version_bump.yml index 1b8ce518d61a..afcfe5ac2c70 100644 --- a/.github/workflows/version_bump.yml +++ b/.github/workflows/version_bump.yml @@ -1,5 +1,8 @@ name: version_bump +permissions: + contents: write + on: workflow_dispatch: inputs: From dc6f3c9f15358119bebd686aed546c7cf5720957 Mon Sep 17 00:00:00 2001 From: denobot <33910674+denobot@users.noreply.github.com> Date: Thu, 8 Feb 2024 04:23:08 -0500 Subject: [PATCH 02/63] 0.215.0 (#4289) Co-authored-by: Divy Srivastava --- Releases.md | 15 +++++++++++++++ version.ts | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Releases.md b/Releases.md index fce118bbd383..29db45a05dc4 100644 --- a/Releases.md +++ b/Releases.md @@ -1,3 +1,18 @@ +### 0.215.0 / 2024.02.08 + +- BREAKING(log): remove `WARNING` log level (#4258) +- BREAKING(path): remove `glob.ts` files (#4259) +- BREAKING(path): remove `separator.ts` files (#4260) +- BREAKING(semver): remove `Comparator` functions (#4278) +- BREAKING(semver): remove `rangeFormat()` (#4265) +- BREAKING(semver): remove `sort()` (#4264) +- deprecation(semver): deprecate `ltr()` and `gtr()` (#4228) +- deprecation(semver): deprecate `reverseSort()` (#4280) +- feat(expect): add `expect.addEqualityTesters` api. (#4255) +- fix: version bump workflow (#4288) +- refactor(dotenv): prepare for `noUncheckedIndexedAccess` (#4261) +- refatcor(toml): prepare for `noUncheckedIndexedAccess` (#4274) + ### 0.214.0 / 2024.02.01 - BREAKING(io): remove `types.d.ts` (#4237) diff --git a/version.ts b/version.ts index 38b626affe50..79a17fb2775a 100644 --- a/version.ts +++ b/version.ts @@ -5,4 +5,4 @@ * the cli's API is stable. In the future when std becomes stable, likely we * will match versions with cli as we have in the past. */ -export const VERSION = "0.214.0"; +export const VERSION = "0.215.0"; From 6e2838f3a98501c33fc6e5634aa501bde7a9eabe Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 8 Feb 2024 15:08:27 +0530 Subject: [PATCH 03/63] fix: ci workflow (#4290) --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06bda5806b8a..cfcdec95a33e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ name: ci +permissions: + contents: write + on: push: branches: [main] From dd95b2c7dc28a2696e5d87d4bdf613b35a938ce5 Mon Sep 17 00:00:00 2001 From: Gabriele Belluardo Date: Thu, 8 Feb 2024 23:00:55 +0100 Subject: [PATCH 04/63] refactor(expect): format test names (#4287) * refactor(expect): format test names * Update expect/_assert_not_equals_test.ts --------- Co-authored-by: Yoshiya Hinosawa --- expect/_assert_not_equals_test.ts | 2 +- expect/_diff_test.ts | 32 ++++++++++---------- expect/_equal_test.ts | 6 ++-- expect/_to_be_instance_of_test.ts | 2 +- expect/_to_be_less_than_or_equal_test.ts | 2 +- expect/_to_equal_test.ts | 24 +++++++-------- expect/_to_have_been_nth_called_with_test.ts | 2 +- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/expect/_assert_not_equals_test.ts b/expect/_assert_not_equals_test.ts index e130993c102e..99fb5ff75bf0 100644 --- a/expect/_assert_not_equals_test.ts +++ b/expect/_assert_not_equals_test.ts @@ -6,7 +6,7 @@ import { assert, AssertionError } from "../assert/mod.ts"; import { assertEquals } from "./_assert_equals.ts"; import { assertNotEquals } from "./_assert_not_equals.ts"; -Deno.test("NotEquals", function () { +Deno.test("assertNotEquals() passes when values are not equals", function () { const a = { foo: "bar" }; const b = { bar: "foo" }; assertNotEquals(a, b); diff --git a/expect/_diff_test.ts b/expect/_diff_test.ts index 786de7918fb4..d62ad43290c6 100644 --- a/expect/_diff_test.ts +++ b/expect/_diff_test.ts @@ -6,14 +6,14 @@ import { diff, diffstr, DiffType } from "./_diff.ts"; import { assertEquals } from "./_assert_equals.ts"; Deno.test({ - name: "empty", + name: "diff() with empty values", fn() { assertEquals(diff([], []), []); }, }); Deno.test({ - name: '"a" vs "b"', + name: 'diff() "a" vs "b"', fn() { assertEquals(diff(["a"], ["b"]), [ { type: DiffType.removed, value: "a" }, @@ -23,28 +23,28 @@ Deno.test({ }); Deno.test({ - name: '"a" vs "a"', + name: 'diff() "a" vs "a"', fn() { assertEquals(diff(["a"], ["a"]), [{ type: DiffType.common, value: "a" }]); }, }); Deno.test({ - name: '"a" vs ""', + name: 'diff() "a" vs ""', fn() { assertEquals(diff(["a"], []), [{ type: DiffType.removed, value: "a" }]); }, }); Deno.test({ - name: '"" vs "a"', + name: 'diff() "" vs "a"', fn() { assertEquals(diff([], ["a"]), [{ type: DiffType.added, value: "a" }]); }, }); Deno.test({ - name: '"a" vs "a, b"', + name: 'diff() "a" vs "a, b"', fn() { assertEquals(diff(["a"], ["a", "b"]), [ { type: DiffType.common, value: "a" }, @@ -54,7 +54,7 @@ Deno.test({ }); Deno.test({ - name: '"strength" vs "string"', + name: 'diff() "strength" vs "string"', fn() { assertEquals(diff(Array.from("strength"), Array.from("string")), [ { type: DiffType.common, value: "s" }, @@ -71,7 +71,7 @@ Deno.test({ }); Deno.test({ - name: '"strength" vs ""', + name: 'diff() "strength" vs ""', fn() { assertEquals(diff(Array.from("strength"), Array.from("")), [ { type: DiffType.removed, value: "s" }, @@ -87,7 +87,7 @@ Deno.test({ }); Deno.test({ - name: '"" vs "strength"', + name: 'diff() "" vs "strength"', fn() { assertEquals(diff(Array.from(""), Array.from("strength")), [ { type: DiffType.added, value: "s" }, @@ -103,7 +103,7 @@ Deno.test({ }); Deno.test({ - name: '"abc", "c" vs "abc", "bcd", "c"', + name: 'diff() "abc", "c" vs "abc", "bcd", "c"', fn() { assertEquals(diff(["abc", "c"], ["abc", "bcd", "c"]), [ { type: DiffType.common, value: "abc" }, @@ -114,7 +114,7 @@ Deno.test({ }); Deno.test({ - name: '"a b c d" vs "a b x d e" (diffstr)', + name: 'diff() "a b c d" vs "a b x d e" (diffstr)', fn() { const diffResult = diffstr( [..."abcd"].join("\n"), @@ -167,7 +167,7 @@ Deno.test({ }); Deno.test({ - name: `"3.14" vs "2.71" (diffstr)`, + name: `diff() "3.14" vs "2.71" (diffstr)`, fn() { const diffResult = diffstr("3.14", "2.71"); assertEquals(diffResult, [ @@ -220,7 +220,7 @@ Deno.test({ }); Deno.test({ - name: `single line "a b" vs "c d" (diffstr)`, + name: `diff() single line "a b" vs "c d" (diffstr)`, fn() { const diffResult = diffstr("a b", "c d"); assertEquals(diffResult, [ @@ -249,7 +249,7 @@ Deno.test({ }); Deno.test({ - name: `single line, different word length "a bc" vs "cd e" (diffstr)`, + name: `diff() single line, different word length "a bc" vs "cd e" (diffstr)`, fn() { const diffResult = diffstr("a bc", "cd e"); assertEquals(diffResult, [ @@ -278,7 +278,7 @@ Deno.test({ }); Deno.test({ - name: `"\\b\\f\\r\\t\\v\\n" vs "\\r\\n" (diffstr)`, + name: `diff() "\\b\\f\\r\\t\\v\\n" vs "\\r\\n" (diffstr)`, fn() { const diffResult = diffstr("\b\f\r\t\v\n", "\r\n"); assertEquals(diffResult, [ @@ -319,7 +319,7 @@ Deno.test({ }); Deno.test({ - name: "multiline diff with more removed lines", + name: "diff() multiline with more removed lines", fn() { const diffResult = diffstr("a\na", "e"); assertEquals(diffResult, [ diff --git a/expect/_equal_test.ts b/expect/_equal_test.ts index d9efc3df131a..ae40285d291d 100644 --- a/expect/_equal_test.ts +++ b/expect/_equal_test.ts @@ -5,7 +5,7 @@ import { assert, assertFalse, assertThrows } from "../assert/mod.ts"; import { equal } from "./_equal.ts"; -Deno.test("EqualDifferentZero", () => { +Deno.test("equal() matches with different zero", () => { assert(equal(0, -0)); assert(equal(0, +0)); assert(equal(+0, -0)); @@ -17,7 +17,7 @@ Deno.test("EqualDifferentZero", () => { assert(equal({ msg: "hello", array: [0] }, { msg: "hello", array: [-0] })); }); -Deno.test("Equal", function () { +Deno.test("equal() matches when values are equal", function () { assert(equal("world", "world")); assert(!equal("hello", "world")); assertFalse(equal("hello", "world")); @@ -235,7 +235,7 @@ Deno.test("Equal", function () { ); }); -Deno.test("EqualCircular", () => { +Deno.test("equal() matches when values have circular references", () => { const objA: { prop?: unknown } = {}; objA.prop = objA; const objB: { prop?: unknown } = {}; diff --git a/expect/_to_be_instance_of_test.ts b/expect/_to_be_instance_of_test.ts index 29eda559ce9a..102e8eadec5d 100644 --- a/expect/_to_be_instance_of_test.ts +++ b/expect/_to_be_instance_of_test.ts @@ -3,7 +3,7 @@ import { expect } from "./expect.ts"; import { AssertionError, assertThrows } from "../assert/mod.ts"; -Deno.test("expect().toBeInstanceOf", () => { +Deno.test("expect().toBeInstanceOf()", () => { expect(new Error()).toBeInstanceOf(Error); expect(new Error()).toBeInstanceOf(Object); diff --git a/expect/_to_be_less_than_or_equal_test.ts b/expect/_to_be_less_than_or_equal_test.ts index ae5aa605d027..e531bdb61f58 100644 --- a/expect/_to_be_less_than_or_equal_test.ts +++ b/expect/_to_be_less_than_or_equal_test.ts @@ -3,7 +3,7 @@ import { expect } from "./expect.ts"; import { AssertionError, assertThrows } from "../assert/mod.ts"; -Deno.test("expect().toBeLessThanOrEqual", () => { +Deno.test("expect().toBeLessThanOrEqual()", () => { expect(10).toBeLessThanOrEqual(10); expect(9).toBeLessThanOrEqual(10); diff --git a/expect/_to_equal_test.ts b/expect/_to_equal_test.ts index 18ef2de15d5d..d5b493bbf1ba 100644 --- a/expect/_to_equal_test.ts +++ b/expect/_to_equal_test.ts @@ -29,7 +29,7 @@ const removed: (s: string) => string = (s: string): string => red(bold(stripAnsiCode(s))); Deno.test({ - name: "pass case", + name: "expect().toEqual() matches when values are equal", fn() { expect({ a: 10 }).toEqual({ a: 10 }); expect(true).toEqual(true); @@ -41,7 +41,7 @@ Deno.test({ }); Deno.test({ - name: "failed with number", + name: "expect().toEqual() throws when numbers are not equal", fn() { assertThrows( () => expect(1).toEqual(2), @@ -58,7 +58,7 @@ Deno.test({ }); Deno.test({ - name: "failed with number vs string", + name: "expect().toEqual() throws when compare number with string", fn() { assertThrows( () => expect(1).toEqual("1"), @@ -74,7 +74,7 @@ Deno.test({ }); Deno.test({ - name: "failed with array", + name: "expect().toEqual() throws when array are not equal", fn() { assertThrows( () => expect([1, "2", 3]).toEqual(["1", "2", 3]), @@ -91,7 +91,7 @@ Deno.test({ }); Deno.test({ - name: "failed with object", + name: "expect().toEqual() throws when objects are no equal", fn() { assertThrows( () => expect({ a: 1, b: "2", c: 3 }).toEqual({ a: 1, b: 2, c: [3] }), @@ -111,7 +111,7 @@ Deno.test({ }); Deno.test({ - name: "failed with date", + name: "expect().toEqual() throws when date are not equal", fn() { assertThrows( () => @@ -143,7 +143,7 @@ Deno.test({ }); Deno.test({ - name: "failed with custom msg", + name: "expect().toEqual() throws with a custom message", fn() { assertThrows( () => expect(1, "CUSTOM MESSAGE").toEqual(2), @@ -160,7 +160,7 @@ Deno.test({ }); Deno.test( - "expect().toEqual compares objects structurally if one object's constructor is undefined and the other is Object", + "expect().toEqual() compares objects structurally if one object's constructor is undefined and the other is Object", () => { const a = Object.create(null); a.prop = "test"; @@ -173,7 +173,7 @@ Deno.test( }, ); -Deno.test("expect().toEqual diff for differently ordered objects", () => { +Deno.test("expect().toEqual() diff for differently ordered objects", () => { assertThrows( () => { expect({ @@ -199,7 +199,7 @@ Deno.test("expect().toEqual diff for differently ordered objects", () => { ); }); -Deno.test("expect().toEqual same Set with object keys", () => { +Deno.test("expect().toEqual() same Set with object keys", () => { const data = [ { id: "_1p7ZED73OF98VbT1SzSkjn", @@ -225,7 +225,7 @@ Deno.test("expect().toEqual() does not throw when a key with undfined value exis }); // https://github.com/denoland/deno_std/issues/4244 -Deno.test("align to jest test cases", () => { +Deno.test("expect().toEqual() align to jest test cases", () => { function create() { class Person { constructor(public readonly name = "deno") {} @@ -263,7 +263,7 @@ Deno.test("align to jest test cases", () => { }, AssertionError); }); -Deno.test("toEqual case for Error Object", () => { +Deno.test("expect().toEqual() matches when Error Objects are equal", () => { function getError() { return new Error("missing param: name"); } diff --git a/expect/_to_have_been_nth_called_with_test.ts b/expect/_to_have_been_nth_called_with_test.ts index 0d7773fcb00e..ed847224bce8 100644 --- a/expect/_to_have_been_nth_called_with_test.ts +++ b/expect/_to_have_been_nth_called_with_test.ts @@ -4,7 +4,7 @@ import { expect } from "./expect.ts"; import { fn } from "./fn.ts"; import { AssertionError, assertThrows } from "../assert/mod.ts"; -Deno.test("expect().", () => { +Deno.test("expect().toHaveBeenNthCalledWith()", () => { const mockFn = fn(); mockFn(1, 2, 3); From 841c8449d898c361bb426bd203b4620884f29e89 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Fri, 9 Feb 2024 21:17:15 +1100 Subject: [PATCH 05/63] chore: fix publish of `std/crypto` to JSR (#4291) fix: publish of `std/crypto` to JSR --- _tools/convert_to_workspace.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/_tools/convert_to_workspace.ts b/_tools/convert_to_workspace.ts index bca2ed7bce1a..b57e30231a1c 100644 --- a/_tools/convert_to_workspace.ts +++ b/_tools/convert_to_workspace.ts @@ -228,6 +228,11 @@ for (const pkg of packages) { version: VERSION, exports, }; + /** @see {@link https://github.com/denoland/deno/issues/22317} */ + if (pkg === "crypto") { + // @ts-ignore Trust me + denoJson.exclude = ["_wasm/target"]; + } await Deno.writeTextFile( join(pkg, "deno.json"), JSON.stringify(denoJson, null, 2) + "\n", From 57fc775b3129fe55ab2ed96810cb54f5bf7b604b Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Fri, 9 Feb 2024 21:22:20 +1100 Subject: [PATCH 06/63] BREAKING(semver): remove `outside()` (#4293) --- semver/mod.ts | 1 - semver/outside.ts | 33 --------------------------------- semver/outside_test.ts | 36 ------------------------------------ 3 files changed, 70 deletions(-) delete mode 100644 semver/outside.ts delete mode 100644 semver/outside_test.ts diff --git a/semver/mod.ts b/semver/mod.ts index aaa5111af1ac..75873040a2da 100644 --- a/semver/mod.ts +++ b/semver/mod.ts @@ -288,7 +288,6 @@ export * from "./ltr.ts"; export * from "./max_satisfying.ts"; export * from "./min_satisfying.ts"; export * from "./neq.ts"; -export * from "./outside.ts"; export * from "./parse_range.ts"; export * from "./parse.ts"; export * from "./range_intersects.ts"; diff --git a/semver/outside.ts b/semver/outside.ts deleted file mode 100644 index ae079bf12e50..000000000000 --- a/semver/outside.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { greaterThan } from "./greater_than.ts"; -import { lessThan } from "./less_than.ts"; -import type { Range, SemVer, SemVerRange } from "./types.ts"; -import { rangeMax } from "./range_max.ts"; -import { rangeMin } from "./range_min.ts"; - -/** - * Returns true if the version is outside the bounds of the range in either the - * high or low direction. The hilo argument must be either the string '>' or - * '<'. (This is the function called by {@linkcode gtr} and {@linkcode ltr}.) - * @param version The version to compare to the range - * @param range The range of possible versions - * @param hilo The operator for the comparison or both if undefined. - * @returns True if the version is outside of the range based on the operator - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode gtr}, {@linkcode ltr} or {@linkcode testRange} instead. - */ -export function outside( - version: SemVer, - range: SemVerRange | Range, - hilo?: ">" | "<", -): boolean { - switch (hilo) { - case ">": - return greaterThan(version, rangeMax(range)); - case "<": - return lessThan(version, rangeMin(range)); - default: - return lessThan(version, rangeMin(range)) || - greaterThan(version, rangeMax(range)); - } -} diff --git a/semver/outside_test.ts b/semver/outside_test.ts deleted file mode 100644 index 85feb7a21090..000000000000 --- a/semver/outside_test.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright Isaac Z. Schlueter and Contributors. All rights reserved. ISC license. -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../assert/mod.ts"; -import { outside } from "./outside.ts"; -import { parse } from "./parse.ts"; -import { parseRange } from "./parse_range.ts"; - -Deno.test({ - name: "outside", - fn: async (t) => { - const steps: [string, string, boolean][] = [ - ["1.2.3", "1.0.0 - 1.2.2", true], - ["1.2.3", "1.0.0 - 1.2.3", false], - ["0.0.0", "1.0.0 - 1.2.2", true], - ["1.0.0", "1.0.0 - 1.2.3", false], - /** - * This test case is included because it aligns with `npm:semver` - * behavior. However, this behavior appears to be a bug. - * - * @see {@link https://github.com/denoland/deno_std/issues/3948#issuecomment-1876875415} - */ - ["2.5.0", ">= 1.0.0 < 2.0.0 || >=3.0.0 < 4.0.0", true], - ]; - for (const [version, range, expected] of steps) { - await t.step({ - name: `${range} ${expected ? "∋" : "∌"} ${version}`, - fn: () => { - const v = parse(version); - const r = parseRange(range); - const actual = outside(v, r); - assertEquals(actual, expected); - }, - }); - } - }, -}); From 2b5149ebdaec74f76d4d69639f76599129391ac6 Mon Sep 17 00:00:00 2001 From: David Luis <95457148+babiabeo@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:35:14 +0700 Subject: [PATCH 07/63] feat(datetime): `format()` options (#4285) Co-authored-by: Asher Gomez --- datetime/format.ts | 26 +++++++++++++++++++++----- datetime/format_test.ts | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/datetime/format.ts b/datetime/format.ts index 09cc68d4c15b..f4e8b40d30e4 100644 --- a/datetime/format.ts +++ b/datetime/format.ts @@ -18,13 +18,29 @@ import { DateTimeFormatter } from "./_common.ts"; * format(new Date(2019, 0, 20, 16, 34), "HH:mm MM-dd-yyyy"); // output : "16:34 01-20-2019" * format(new Date(2019, 0, 20, 16, 34, 23, 123), "MM-dd-yyyy HH:mm:ss.SSS"); // output : "01-20-2019 16:34:23.123" * format(new Date(2019, 0, 20), "'today:' yyyy-MM-dd"); // output : "today: 2019-01-20" + * format(new Date("2019-01-20T16:34:23:123-05:00"), "yyyy-MM-dd HH:mm:ss", { utc: true }); + * // output : "2019-01-20 21:34:23" * ``` * - * @param date Date - * @param formatString Format string - * @return formatted date string + * @param date The date to be formatted. + * @param formatString The date time string format. + * @param options The options to customize the formatting of the date. + * @return The formatted date string. */ -export function format(date: Date, formatString: string): string { +export function format( + date: Date, + formatString: string, + options: FormatOptions = {}, +): string { const formatter = new DateTimeFormatter(formatString); - return formatter.format(date); + return formatter.format( + date, + options.utc ? { timeZone: "UTC" } : undefined, + ); +} + +/** Options for {@linkcode format}. */ +export interface FormatOptions { + /** Whether returns the formatted date in UTC instead of local time. */ + utc?: boolean; } diff --git a/datetime/format_test.ts b/datetime/format_test.ts index 0023ca89e1f1..b4acdb3a55d9 100644 --- a/datetime/format_test.ts +++ b/datetime/format_test.ts @@ -102,5 +102,23 @@ Deno.test({ "1", format(new Date("2019-01-01T13:00:00.000"), "h"), ); + + assertEquals( + "2019-01-01 04:00:00.000", + format( + new Date("2019-01-01T13:00:00.000+09:00"), + "yyyy-MM-dd HH:mm:ss.SSS", + { utc: true }, + ), + ); + + assertEquals( + "2019-01-01 18:00:00.000", + format( + new Date("2019-01-01T13:00:00.000-05:00"), + "yyyy-MM-dd HH:mm:ss.SSS", + { utc: true }, + ), + ); }, }); From 6da4e4e840406aa7f32c5ef760acc5176aa49875 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Fri, 9 Feb 2024 21:55:23 +1100 Subject: [PATCH 08/63] BREAKING(path): remove `path/windows/separator.ts` (#4292) --- path/windows/mod.ts | 1 - path/windows/separator.ts | 11 ----------- 2 files changed, 12 deletions(-) delete mode 100644 path/windows/separator.ts diff --git a/path/windows/mod.ts b/path/windows/mod.ts index 6649e91d0ed0..6ac88e637069 100644 --- a/path/windows/mod.ts +++ b/path/windows/mod.ts @@ -36,7 +36,6 @@ export * from "./resolve.ts"; export * from "./to_file_url.ts"; export * from "./to_namespaced_path.ts"; export * from "./common.ts"; -export * from "./separator.ts"; export * from "../_interface.ts"; export * from "./glob_to_regexp.ts"; export * from "./is_glob.ts"; diff --git a/path/windows/separator.ts b/path/windows/separator.ts deleted file mode 100644 index f37808a879a8..000000000000 --- a/path/windows/separator.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -// This module is browser compatible. - -/** - * @deprecated (will be removed in 0.216.0) Use {@linkcode SEPARATOR} from {@link https://deno.land/std/path/windows/constants.ts} instead. - */ -export const SEP = "\\"; -/** - * @deprecated (will be removed in 0.216.0) Use {@linkcode SEPARATOR_PATTERN} from {@link https://deno.land/std/path/windows/constants.ts} instead. - */ -export const SEP_PATTERN = /[\\/]+/; From b9f3a74c8bf67cd027384899bc49cb268faa585b Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Sat, 10 Feb 2024 10:26:42 +1100 Subject: [PATCH 09/63] BREAKING(semver): remove `eq()`, `gt()`, `gte()`, `lt()`, `lte()` and `neq()` (#4294) --- _tools/check_deprecation.ts | 12 ++++++++++-- semver/eq.ts | 12 ------------ semver/gt.ts | 13 ------------- semver/gte.ts | 13 ------------- semver/lt.ts | 13 ------------- semver/lte.ts | 13 ------------- semver/mod.ts | 14 ++++---------- semver/neq.ts | 13 ------------- 8 files changed, 14 insertions(+), 89 deletions(-) delete mode 100644 semver/eq.ts delete mode 100644 semver/gt.ts delete mode 100644 semver/gte.ts delete mode 100644 semver/lt.ts delete mode 100644 semver/lte.ts delete mode 100644 semver/neq.ts diff --git a/_tools/check_deprecation.ts b/_tools/check_deprecation.ts index d11c16234c61..b6a58c0683cc 100644 --- a/_tools/check_deprecation.ts +++ b/_tools/check_deprecation.ts @@ -83,7 +83,10 @@ for await ( if (afterVersion) { if ( - semver.lt(semver.parse(afterVersion), semver.parse(VERSION)) + semver.lessThan( + semver.parse(afterVersion), + semver.parse(VERSION), + ) ) { console.warn( colors.yellow("Warn"), @@ -109,7 +112,12 @@ for await ( continue; } - if (!semver.gt(semver.parse(inVersion), semver.parse(VERSION))) { + if ( + !semver.greaterThan( + semver.parse(inVersion), + semver.parse(VERSION), + ) + ) { console.error( colors.red("Error"), `${ diff --git a/semver/eq.ts b/semver/eq.ts deleted file mode 100644 index 87879e0e2624..000000000000 --- a/semver/eq.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { equals } from "./equals.ts"; -import { SemVer } from "./types.ts"; - -/** - * Returns `true` if they're logically equivalent, even if they're not the exact same version object. - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode equals} instead. - */ -export function eq(s0: SemVer, s1: SemVer): boolean { - return equals(s0, s1); -} diff --git a/semver/gt.ts b/semver/gt.ts deleted file mode 100644 index 7dbb2c26325b..000000000000 --- a/semver/gt.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -import { greaterThan } from "./greater_than.ts"; -import { SemVer } from "./types.ts"; - -/** - * Greater than comparison - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode greaterThan} instead. - */ -export function gt(s0: SemVer, s1: SemVer): boolean { - return greaterThan(s0, s1); -} diff --git a/semver/gte.ts b/semver/gte.ts deleted file mode 100644 index 55e3dde883be..000000000000 --- a/semver/gte.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -import { greaterOrEqual } from "./greater_or_equal.ts"; -import { SemVer } from "./types.ts"; - -/** - * Greater than or equal to comparison - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode greaterOrEqual} instead. - */ -export function gte(s0: SemVer, s1: SemVer): boolean { - return greaterOrEqual(s0, s1); -} diff --git a/semver/lt.ts b/semver/lt.ts deleted file mode 100644 index 97db4d3c527d..000000000000 --- a/semver/lt.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -import { lessThan } from "./less_than.ts"; -import { SemVer } from "./types.ts"; - -/** - * Less than comparison - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode lessThan} instead. - */ -export function lt(s0: SemVer, s1: SemVer): boolean { - return lessThan(s0, s1); -} diff --git a/semver/lte.ts b/semver/lte.ts deleted file mode 100644 index a43590e7110e..000000000000 --- a/semver/lte.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -import { lessOrEqual } from "./less_or_equal.ts"; -import { SemVer } from "./types.ts"; - -/** - * Less than or equal to comparison - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode lessOrEqual} instead. - */ -export function lte(s0: SemVer, s1: SemVer): boolean { - return lessOrEqual(s0, s1); -} diff --git a/semver/mod.ts b/semver/mod.ts index 75873040a2da..4a029ccda171 100644 --- a/semver/mod.ts +++ b/semver/mod.ts @@ -252,8 +252,8 @@ * import { * parse, * parseRange, - * gt, - * lt, + * greaterThan, + * lessThan, * format * } from "https://deno.land/std@$STD_VERSION/semver/mod.ts"; * @@ -262,8 +262,8 @@ * * const s0 = parse("1.2.3"); * const s1 = parse("9.8.7"); - * gt(s0, s1); // false - * lt(s0, s1); // true + * greaterThan(s0, s1); // false + * lessThan(s0, s1); // true * * format(semver) // "1.2.3" * ``` @@ -273,21 +273,15 @@ export * from "./compare.ts"; export * from "./constants.ts"; export * from "./difference.ts"; -export * from "./eq.ts"; export * from "./format.ts"; -export * from "./gt.ts"; -export * from "./gte.ts"; export * from "./gtr.ts"; export * from "./test_range.ts"; export * from "./increment.ts"; export * from "./is_semver_range.ts"; export * from "./is_semver.ts"; -export * from "./lt.ts"; -export * from "./lte.ts"; export * from "./ltr.ts"; export * from "./max_satisfying.ts"; export * from "./min_satisfying.ts"; -export * from "./neq.ts"; export * from "./parse_range.ts"; export * from "./parse.ts"; export * from "./range_intersects.ts"; diff --git a/semver/neq.ts b/semver/neq.ts deleted file mode 100644 index d15aa6732d66..000000000000 --- a/semver/neq.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -import { notEquals } from "./not_equals.ts"; -import { SemVer } from "./types.ts"; - -/** - * Not equal comparison - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode notEquals} instead. - */ -export function neq(s0: SemVer, s1: SemVer): boolean { - return notEquals(s0, s1); -} From 083a2b12ba45381c78dbabfcf06d48e2da27f16b Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Sat, 10 Feb 2024 10:30:39 +1100 Subject: [PATCH 10/63] BREAKING(semver): remove `SemVerRange` and `isSemVerRange()` (#4295) --- semver/_comparator_intersects_test.ts | 63 ------------------- semver/format_range.ts | 8 +-- semver/format_range_test.ts | 68 --------------------- semver/gtr.ts | 4 +- semver/is_semver_range.ts | 26 -------- semver/is_semver_range_test.ts | 24 -------- semver/ltr.ts | 4 +- semver/max_satisfying.ts | 4 +- semver/min_satisfying.ts | 4 +- semver/mod.ts | 1 - semver/parse_range.ts | 8 +-- semver/range_intersects.ts | 16 +++-- semver/range_intersects_test.ts | 87 --------------------------- semver/range_max.ts | 6 +- semver/range_min.ts | 6 +- semver/range_min_test.ts | 76 ----------------------- semver/test_range.ts | 6 +- semver/try_parse_range.ts | 8 +-- semver/types.ts | 12 ---- 19 files changed, 35 insertions(+), 396 deletions(-) delete mode 100644 semver/is_semver_range.ts delete mode 100644 semver/is_semver_range_test.ts diff --git a/semver/_comparator_intersects_test.ts b/semver/_comparator_intersects_test.ts index e49c6cdefc45..7bd461751ebe 100644 --- a/semver/_comparator_intersects_test.ts +++ b/semver/_comparator_intersects_test.ts @@ -5,69 +5,6 @@ import { parseComparator } from "./_parse_comparator.ts"; import { comparatorIntersects } from "./_comparator_intersects.ts"; import { rangeIntersects } from "./range_intersects.ts"; -Deno.test("comparatorIntersects() handles deprecated SemVerRange.ranges property", async (t) => { - const versions: [string, string, boolean][] = [ - // One is a Version - ["1.3.0", ">=1.3.0", true], - ["1.3.0", ">1.3.0", false], - [">=1.3.0", "1.3.0", true], - [">1.3.0", "1.3.0", false], - - // Same direction increasing - [">1.3.0", ">1.2.0", true], - [">1.2.0", ">1.3.0", true], - [">=1.2.0", ">1.3.0", true], - [">1.2.0", ">=1.3.0", true], - - // Same direction decreasing - ["<1.3.0", "<1.2.0", true], - ["<1.2.0", "<1.3.0", true], - ["<=1.2.0", "<1.3.0", true], - ["<1.2.0", "<=1.3.0", true], - - // Different directions, same semver and inclusive operator - [">=1.3.0", "<=1.3.0", true], - [">=v1.3.0", "<=1.3.0", true], - [">=1.3.0", ">=1.3.0", true], - ["<=1.3.0", "<=1.3.0", true], - ["<=1.3.0", "<=v1.3.0", true], - [">1.3.0", "<=1.3.0", false], - [">=1.3.0", "<1.3.0", false], - - // Opposite matching directions - [">1.0.0", "<2.0.0", true], - [">=1.0.0", "<2.0.0", true], - [">=1.0.0", "<=2.0.0", true], - [">1.0.0", "<=2.0.0", true], - ["<=2.0.0", ">1.0.0", true], - ["<=1.0.0", ">=2.0.0", false], - ]; - for (const v of versions) { - const comparator1 = parseComparator(v[0]); - const comparator2 = parseComparator(v[1]); - const expect = v[2]; - await t.step({ - name: `${v[0]} ${expect ? "∩" : "∁"} ${v[1]}`, - fn: () => { - const actual1 = comparatorIntersects(comparator1, comparator2); - const actual2 = comparatorIntersects(comparator2, comparator1); - const actual3 = rangeIntersects( - { ranges: [[comparator1]] }, - { ranges: [[comparator2]] }, - ); - const actual4 = rangeIntersects( - { ranges: [[comparator2]] }, - { ranges: [[comparator1]] }, - ); - assertEquals(actual1, expect); - assertEquals(actual2, expect); - assertEquals(actual3, expect); - assertEquals(actual4, expect); - }, - }); - } -}); - Deno.test("comparatorIntersects()", async (t) => { const versions: [string, string, boolean][] = [ // One is a Version diff --git a/semver/format_range.ts b/semver/format_range.ts index d8cfed6207cb..837c3e3b4c97 100644 --- a/semver/format_range.ts +++ b/semver/format_range.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVerRange } from "./types.ts"; +import type { Range } from "./types.ts"; import { comparatorFormat } from "./_comparator_format.ts"; /** @@ -8,9 +8,7 @@ import { comparatorFormat } from "./_comparator_format.ts"; * @param range The range to format * @returns A string representation of the range */ -export function formatRange(range: SemVerRange | Range): string { - return (Array.isArray(range) ? range : range.ranges).map((c) => - c.map((c) => comparatorFormat(c)).join(" ") - ) +export function formatRange(range: Range): string { + return range.map((c) => c.map((c) => comparatorFormat(c)).join(" ")) .join("||"); } diff --git a/semver/format_range_test.ts b/semver/format_range_test.ts index 786810a3452a..f6757e8f9d3a 100644 --- a/semver/format_range_test.ts +++ b/semver/format_range_test.ts @@ -71,71 +71,3 @@ Deno.test({ } }, }); - -Deno.test({ - name: "formatRange() handles deprecated SemVerRange.ranges property", - fn: async (t) => { - const versions: [string, string][] = [ - ["1.0.0 - 2.0.0", ">=1.0.0 <=2.0.0"], - ["1.0.0", "1.0.0"], - [">=*", "*"], - ["", "*"], - ["*", "*"], - [">=1.0.0", ">=1.0.0"], - [">1.0.0", ">1.0.0"], - ["<=2.0.0", "<=2.0.0"], - ["1", ">=1.0.0 <2.0.0"], - ["<=2.0.0", "<=2.0.0"], - ["<=2.0.0", "<=2.0.0"], - ["<2.0.0", "<2.0.0"], - ["<2.0.0", "<2.0.0"], - [">=0.1.97", ">=0.1.97"], - [">=0.1.97", ">=0.1.97"], - ["0.1.20 || 1.2.4", "0.1.20||1.2.4"], - [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"], - [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"], - [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"], - ["||", "*||*"], - ["2.x.x", ">=2.0.0 <3.0.0"], - ["1.2.x", ">=1.2.0 <1.3.0"], - ["1.2.x || 2.x", ">=1.2.0 <1.3.0||>=2.0.0 <3.0.0"], - ["1.2.x || 2.x", ">=1.2.0 <1.3.0||>=2.0.0 <3.0.0"], - ["x", "*"], - ["2.*.*", ">=2.0.0 <3.0.0"], - ["1.2.*", ">=1.2.0 <1.3.0"], - ["1.2.* || 2.*", ">=1.2.0 <1.3.0||>=2.0.0 <3.0.0"], - ["2", ">=2.0.0 <3.0.0"], - ["2.3", ">=2.3.0 <2.4.0"], - ["~2.4", ">=2.4.0 <2.5.0"], - ["~2.4", ">=2.4.0 <2.5.0"], - ["~>3.2.1", ">=3.2.1 <3.3.0"], - ["~1", ">=1.0.0 <2.0.0"], - ["~>1", ">=1.0.0 <2.0.0"], - ["~1.0", ">=1.0.0 <1.1.0"], - ["^0", ">=0.0.0 <1.0.0"], - ["^0.1", ">=0.1.0 <0.2.0"], - ["^1.0", ">=1.0.0 <2.0.0"], - ["^1.2", ">=1.2.0 <2.0.0"], - ["^0.0.1", ">=0.0.1 <0.0.2"], - ["^0.0.1-beta", ">=0.0.1-beta <0.0.2"], - ["^0.1.2", ">=0.1.2 <0.2.0"], - ["^1.2.3", ">=1.2.3 <2.0.0"], - ["^1.2.3-beta.4", ">=1.2.3-beta.4 <2.0.0"], - ["<1", "<1.0.0"], - [">=1", ">=1.0.0"], - ["<1.2", "<1.2.0"], - ["1", ">=1.0.0 <2.0.0"], - ]; - - for (const [r, expected] of versions) { - await t.step({ - name: `${r} -> ${expected}`, - fn: () => { - const range = parseRange(r); - const actual = formatRange({ ranges: range.ranges }); - assertEquals(actual, expected); - }, - }); - } - }, -}); diff --git a/semver/gtr.ts b/semver/gtr.ts index f4ec3f3ecadd..9342ee8ac989 100644 --- a/semver/gtr.ts +++ b/semver/gtr.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { rangeMax } from "./range_max.ts"; import { greaterThan } from "./greater_than.ts"; @@ -11,7 +11,7 @@ import { greaterThan } from "./greater_than.ts"; */ export function gtr( version: SemVer, - range: SemVerRange | Range, + range: Range, ): boolean { return greaterThan(version, rangeMax(range)); } diff --git a/semver/is_semver_range.ts b/semver/is_semver_range.ts deleted file mode 100644 index 8573e74cc6e9..000000000000 --- a/semver/is_semver_range.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { SemVerRange } from "./types.ts"; -import { isComparator } from "./_is_comparator.ts"; - -/** - * Does a deep check on the object to determine if its a valid range. - * - * Objects with extra fields are still considered valid if they have at - * least the correct fields. - * - * Adds a type assertion if true. - * @param value The value to check if its a valid SemVerRange - * @returns True if its a valid SemVerRange otherwise false. - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode isRange} instead. - */ -export function isSemVerRange(value: unknown): value is SemVerRange { - if (value === null || value === undefined) return false; - if (Array.isArray(value)) return false; - if (typeof value !== "object") return false; - const { ranges } = value as SemVerRange; - return ( - Array.isArray(ranges) && - ranges.every((r) => Array.isArray(r) && r.every((c) => isComparator(c))) - ); -} diff --git a/semver/is_semver_range_test.ts b/semver/is_semver_range_test.ts deleted file mode 100644 index 3fc005bf648c..000000000000 --- a/semver/is_semver_range_test.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assert } from "../assert/mod.ts"; -import { ALL } from "./constants.ts"; -import { isSemVerRange } from "./is_semver_range.ts"; - -Deno.test({ - name: "valid_range", - fn: async (t) => { - let i = 0; - const ranges: unknown[] = [ - { - ranges: [ - [ALL], - ], - }, - ]; - for (const r of ranges) { - await t.step(`valid_range_${(i++).toString().padStart(2, "0")}`, () => { - const actual = isSemVerRange(r); - assert(actual); - }); - } - }, -}); diff --git a/semver/ltr.ts b/semver/ltr.ts index b076c9ccfcf2..ef3fdf7ffae3 100644 --- a/semver/ltr.ts +++ b/semver/ltr.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { lessThan } from "./less_than.ts"; import { rangeMin } from "./range_min.ts"; @@ -11,7 +11,7 @@ import { rangeMin } from "./range_min.ts"; */ export function ltr( version: SemVer, - range: SemVerRange | Range, + range: Range, ): boolean { return lessThan(version, rangeMin(range)); } diff --git a/semver/max_satisfying.ts b/semver/max_satisfying.ts index ecbc2f8e60f4..bd7b4aa03e27 100644 --- a/semver/max_satisfying.ts +++ b/semver/max_satisfying.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { testRange } from "./test_range.ts"; import { greaterThan } from "./greater_than.ts"; @@ -12,7 +12,7 @@ import { greaterThan } from "./greater_than.ts"; */ export function maxSatisfying( versions: SemVer[], - range: SemVerRange | Range, + range: Range, ): SemVer | undefined { let max; for (const version of versions) { diff --git a/semver/min_satisfying.ts b/semver/min_satisfying.ts index acfe66f879f9..3b74391cb11b 100644 --- a/semver/min_satisfying.ts +++ b/semver/min_satisfying.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { testRange } from "./test_range.ts"; import { lessThan } from "./less_than.ts"; @@ -12,7 +12,7 @@ import { lessThan } from "./less_than.ts"; */ export function minSatisfying( versions: SemVer[], - range: SemVerRange | Range, + range: Range, ): SemVer | undefined { let min; for (const version of versions) { diff --git a/semver/mod.ts b/semver/mod.ts index 4a029ccda171..196b28bf1dc7 100644 --- a/semver/mod.ts +++ b/semver/mod.ts @@ -277,7 +277,6 @@ export * from "./format.ts"; export * from "./gtr.ts"; export * from "./test_range.ts"; export * from "./increment.ts"; -export * from "./is_semver_range.ts"; export * from "./is_semver.ts"; export * from "./ltr.ts"; export * from "./max_satisfying.ts"; diff --git a/semver/parse_range.ts b/semver/parse_range.ts index 55baa406b603..c491c95d991f 100644 --- a/semver/parse_range.ts +++ b/semver/parse_range.ts @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { ALL } from "./constants.ts"; -import type { Comparator, Range, SemVerRange } from "./types.ts"; +import type { Comparator, Range } from "./types.ts"; import { OPERATOR_XRANGE_REGEXP, XRANGE } from "./_shared.ts"; import { parseComparator } from "./_parse_comparator.ts"; import { parseBuild, parsePrerelease } from "./_shared.ts"; @@ -273,14 +273,14 @@ function parseRangeString(string: string) { } /** - * Parses a range string into a SemVerRange object or throws a TypeError. + * Parses a range string into a Range object or throws a TypeError. * @param range The range set string * @returns A valid semantic range */ -export function parseRange(range: string): SemVerRange & Range { +export function parseRange(range: string): Range { const ranges = range .split(/\s*\|\|\s*/) .map((range) => parseHyphenRange(range).flatMap(parseRangeString)); Object.defineProperty(ranges, "ranges", { value: ranges }); - return ranges as SemVerRange & Range; + return ranges as Range; } diff --git a/semver/range_intersects.ts b/semver/range_intersects.ts index 7085922a40ee..9dc802c40f70 100644 --- a/semver/range_intersects.ts +++ b/semver/range_intersects.ts @@ -1,13 +1,11 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { comparatorIntersects } from "./_comparator_intersects.ts"; -import type { Comparator, Range, SemVerRange } from "./types.ts"; +import type { Comparator, Range } from "./types.ts"; -function rangesSatisfiable(ranges: (SemVerRange | Range)[]): boolean { +function rangesSatisfiable(ranges: Range[]): boolean { return ranges.every((r) => { // For each OR at least one AND must be satisfiable - return (Array.isArray(r) ? r : r.ranges).some((comparators) => - comparatorsSatisfiable(comparators) - ); + return r.some((comparators) => comparatorsSatisfiable(comparators)); }); } @@ -31,12 +29,12 @@ function comparatorsSatisfiable(comparators: Comparator[]): boolean { * @returns returns true if any */ export function rangeIntersects( - r0: SemVerRange | Range, - r1: SemVerRange | Range, + r0: Range, + r1: Range, ): boolean { return rangesSatisfiable([r0, r1]) && - (Array.isArray(r0) ? r0 : r0.ranges).some((r00) => { - return (Array.isArray(r1) ? r1 : r1.ranges).some((r11) => { + r0.some((r00) => { + return r1.some((r11) => { return r00.every((c0) => { return r11.every((c1) => comparatorIntersects(c0, c1)); }); diff --git a/semver/range_intersects_test.ts b/semver/range_intersects_test.ts index a8afb928844f..dd24b55459bf 100644 --- a/semver/range_intersects_test.ts +++ b/semver/range_intersects_test.ts @@ -86,90 +86,3 @@ Deno.test({ } }, }); - -Deno.test({ - name: "rangesIntersects() handles deprecated SemVerRange.ranges property", - fn: async (t) => { - const versions: [string, string, boolean][] = [ - ["1.3.0 || <1.0.0 >2.0.0", "1.3.0 || <1.0.0 >2.0.0", true], - [">0.0.0", "<1.0.0 >2.0.0", false], - ["<1.0.0 >2.0.0", ">1.4.0 <1.6.0", false], - ["<1.0.0 >2.0.0", ">1.4.0 <1.6.0 || 2.0.0", false], - [">1.0.0 <=2.0.0", "2.0.0", true], - ["<1.0.0 >=2.0.0", "2.1.0", false], - ["<1.0.0 >=2.0.0", ">1.4.0 <1.6.0 || 2.0.0", false], - ["1.5.x", "<1.5.0 || >=1.6.0", false], - ["<1.5.0 || >=1.6.0", "1.5.x", false], - [ - "<1.6.16 || >=1.7.0 <1.7.11 || >=1.8.0 <1.8.2", - ">=1.6.16 <1.7.0 || >=1.7.11 <1.8.0 || >=1.8.2", - false, - ], - [ - "<=1.6.16 || >=1.7.0 <1.7.11 || >=1.8.0 <1.8.2", - ">=1.6.16 <1.7.0 || >=1.7.11 <1.8.0 || >=1.8.2", - true, - ], - [">=1.0.0", "<=1.0.0", true], - [">1.0.0 <1.0.0", "<=0.0.0", false], - ["*", "0.0.1", true], - ["*", ">=1.0.0", true], - ["*", ">1.0.0", true], - ["*", "~1.0.0", true], - ["*", "<1.6.0", true], - ["*", "<=1.6.0", true], - ["1.*", "0.0.1", false], - ["1.*", "2.0.0", false], - ["1.*", "1.0.0", true], - ["1.*", "<2.0.0", true], - ["1.*", ">1.0.0", true], - ["1.*", "<=1.0.0", true], - ["1.*", "^1.0.0", true], - ["1.0.*", "0.0.1", false], - ["1.0.*", "<0.0.1", false], - ["1.0.*", ">0.0.1", true], - ["*", "1.3.0 || <1.0.0 >2.0.0", true], - ["1.3.0 || <1.0.0 >2.0.0", "*", true], - ["1.*", "1.3.0 || <1.0.0 >2.0.0", true], - ["x", "0.0.1", true], - ["x", ">=1.0.0", true], - ["x", ">1.0.0", true], - ["x", "~1.0.0", true], - ["x", "<1.6.0", true], - ["x", "<=1.6.0", true], - ["1.x", "0.0.1", false], - ["1.x", "2.0.0", false], - ["1.x", "1.0.0", true], - ["1.x", "<2.0.0", true], - ["1.x", ">1.0.0", true], - ["1.x", "<=1.0.0", true], - ["1.x", "^1.0.0", true], - ["1.0.x", "0.0.1", false], - ["1.0.x", "<0.0.1", false], - ["1.0.x", ">0.0.1", true], - ["x", "1.3.0 || <1.0.0 >2.0.0", true], - ["1.3.0 || <1.0.0 >2.0.0", "x", true], - ["1.x", "1.3.0 || <1.0.0 >2.0.0", true], - ["*", "*", true], - ["x", "", true], - ]; - - for (const [r1, r2, expected] of versions) { - await t.step({ - name: `${r1} ∩ ${r2}`, - fn: () => { - const range1 = parseRange(r1); - const range2 = parseRange(r2); - const actual1 = rangeIntersects({ ranges: range1.ranges }, { - ranges: range2.ranges, - }); - const actual2 = rangeIntersects({ ranges: range2.ranges }, { - ranges: range1.ranges, - }); - assertEquals(actual1, expected); - assertEquals(actual2, expected); - }, - }); - } - }, -}); diff --git a/semver/range_max.ts b/semver/range_max.ts index 58c402ae469e..40677a796e73 100644 --- a/semver/range_max.ts +++ b/semver/range_max.ts @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { INVALID } from "./constants.ts"; -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { testRange } from "./test_range.ts"; import { comparatorMax } from "./_comparator_max.ts"; import { greaterThan } from "./greater_than.ts"; @@ -10,9 +10,9 @@ import { greaterThan } from "./greater_than.ts"; * @param range The range to calculate the max for * @returns A valid SemVer or INVALID */ -export function rangeMax(range: SemVerRange | Range): SemVer { +export function rangeMax(range: Range): SemVer { let max; - for (const comparators of (Array.isArray(range) ? range : range.ranges)) { + for (const comparators of range) { for (const comparator of comparators) { const candidate = comparatorMax( comparator.semver ?? comparator, diff --git a/semver/range_min.ts b/semver/range_min.ts index 3d47262853d9..653b78fd3b69 100644 --- a/semver/range_min.ts +++ b/semver/range_min.ts @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { INVALID } from "./constants.ts"; -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { testRange } from "./test_range.ts"; import { comparatorMin } from "./_comparator_min.ts"; import { lessThan } from "./less_than.ts"; @@ -10,9 +10,9 @@ import { lessThan } from "./less_than.ts"; * @param range The range to calculate the min for * @returns A valid SemVer or INVALID */ -export function rangeMin(range: SemVerRange | Range): SemVer { +export function rangeMin(range: Range): SemVer { let min; - for (const comparators of (Array.isArray(range) ? range : range.ranges)) { + for (const comparators of range) { for (const comparator of comparators) { const candidate = comparatorMin( comparator.semver ?? comparator, diff --git a/semver/range_min_test.ts b/semver/range_min_test.ts index e6deead93add..c71c257dc9a3 100644 --- a/semver/range_min_test.ts +++ b/semver/range_min_test.ts @@ -84,79 +84,3 @@ Deno.test({ } }, }); - -Deno.test({ - name: "rangeMin() handles deprecated SemVerRange.ranges property", - fn: async (t) => { - const versions: [string, string | SemVer][] = [ - // Stars - ["*", "0.0.0"], - ["* || >=2", "0.0.0"], - [">=2 || *", "0.0.0"], - [">2 || *", "0.0.0"], - - // equal - ["1.0.0", "1.0.0"], - ["1.0", "1.0.0"], - ["1.0.x", "1.0.0"], - ["1.0.*", "1.0.0"], - ["1", "1.0.0"], - ["1.x.x", "1.0.0"], - ["1.x.x", "1.0.0"], - ["1.*.x", "1.0.0"], - ["1.x.*", "1.0.0"], - ["1.x", "1.0.0"], - ["1.*", "1.0.0"], - ["=1.0.0", "1.0.0"], - - // Tilde - ["~1.1.1", "1.1.1"], - ["~1.1.1-beta", "1.1.1-beta"], - ["~1.1.1 || >=2", "1.1.1"], - - // Caret - ["^1.1.1", "1.1.1"], - ["^1.1.1-beta", "1.1.1-beta"], - ["^1.1.1 || >=2", "1.1.1"], - - // '-' operator - ["1.1.1 - 1.8.0", "1.1.1"], - ["1.1 - 1.8.0", "1.1.0"], - - // Less / less or equal - ["<2", "0.0.0"], - ["<0.0.0-beta", INVALID], - ["<0.0.1-beta", "0.0.0"], - ["<2 || >4", "0.0.0"], - [">4 || <2", "0.0.0"], - ["<=2 || >=4", "0.0.0"], - [">=4 || <=2", "0.0.0"], - ["<0.0.0-beta >0.0.0-alpha", INVALID], - [">0.0.0-alpha <0.0.0-beta", INVALID], - - // Greater than or equal - [">=1.1.1 <2 || >=2.2.2 <2", "1.1.1"], - [">=2.2.2 <2 || >=1.1.1 <2", "1.1.1"], - - // Greater than but not equal - [">1.0.0", "1.0.1"], - [">1.0.0-0", "1.0.0-1"], - [">1.0.0-beta", "1.0.0-beta.0"], - [">2 || >1.0.0", "1.0.1"], - [">2 || >1.0.0-0", "1.0.0-1"], - [">2 || >1.0.0-beta", "1.0.0-beta.0"], - - // Impossible range - [">4 <3", INVALID], - ]; - - for (const [a, b] of versions) { - await t.step(a, () => { - const range = parseRange(a); - const version = typeof b === "string" ? parse(b) : b; - const min = rangeMin({ ranges: range.ranges }); - assert(equals(min, version), `${format(min)} != ${format(version)}`); - }); - } - }, -}); diff --git a/semver/test_range.ts b/semver/test_range.ts index 3c876ca68f20..3188d435dd95 100644 --- a/semver/test_range.ts +++ b/semver/test_range.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVer, SemVerRange } from "./types.ts"; +import type { Range, SemVer } from "./types.ts"; import { greaterOrEqual } from "./greater_or_equal.ts"; import { lessOrEqual } from "./less_or_equal.ts"; import { comparatorMin } from "./_comparator_min.ts"; @@ -13,9 +13,9 @@ import { comparatorMax } from "./_comparator_max.ts"; */ export function testRange( version: SemVer, - range: SemVerRange | Range, + range: Range, ): boolean { - for (const r of (Array.isArray(range) ? range : range.ranges)) { + for (const r of range) { if ( r.every((c) => greaterOrEqual(version, comparatorMin(c.semver ?? c, c.operator)) && diff --git a/semver/try_parse_range.ts b/semver/try_parse_range.ts index d1c9e33629f9..010580629e3d 100644 --- a/semver/try_parse_range.ts +++ b/semver/try_parse_range.ts @@ -1,16 +1,16 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { Range, SemVerRange } from "./types.ts"; +import { Range } from "./types.ts"; import { parseRange } from "./parse_range.ts"; /** - * A tries to parse a valid SemVerRange string or returns undefined + * A tries to parse a valid Range string or returns undefined * @param range The range string - * @returns A SemVerRange object if valid otherwise `undefined` + * @returns A Range object if valid otherwise `undefined` */ export function tryParseRange( range: string, -): SemVerRange & Range | undefined { +): Range | undefined { try { // Return '*' instead of '' so that truthiness works. // This will throw if it's invalid anyway diff --git a/semver/types.ts b/semver/types.ts index b1a1c10f4431..7db09669a03d 100644 --- a/semver/types.ts +++ b/semver/types.ts @@ -50,15 +50,3 @@ export interface SemVer { * inner array represents AND comparisons. */ export type Range = Comparator[][]; - -/** - * A type representing a semantic version range. The ranges consist of - * a nested array, which represents a set of OR comparisons while the - * inner array represents AND comparisons. - * - * @deprecated (will be removed in 0.216.0) Use {@linkcode Range} instead. - */ -export interface SemVerRange { - // The outer array is OR while each inner array is AND - ranges: Comparator[][]; -} From 8c022c4f6488accaca1f0ccea93d982ba0c503dc Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Mon, 12 Feb 2024 00:15:51 +0100 Subject: [PATCH 11/63] refactor(cli): cleanup `parse_args.ts` (#4189) * initial commit * fix typo * rename negated capturing group * update nested functions * update * simplify setNested * update * add parseBooleanValue * update * remove unknown value type * rename fns * update * Update parse_args.ts Co-authored-by: Asher Gomez * Update cli/parse_args.ts Co-authored-by: Asher Gomez * update * revert to letters.entries() --------- Co-authored-by: Asher Gomez --- cli/parse_args.ts | 465 +++++++++++++++++++++------------------------- 1 file changed, 211 insertions(+), 254 deletions(-) diff --git a/cli/parse_args.ts b/cli/parse_args.ts index 094678906389..f34daef64da8 100644 --- a/cli/parse_args.ts +++ b/cli/parse_args.ts @@ -16,7 +16,7 @@ * * @module */ -import { assertExists } from "../assert/assert_exists.ts"; +import { assert } from "../assert/assert.ts"; /** Combines recursively all intersection types and returns a new single type. */ type Id = TRecord extends Record @@ -329,52 +329,75 @@ export interface ParseOptions< unknown?: (arg: string, key?: string, value?: unknown) => unknown; } -interface Flags { - bools: Record; - strings: Record; - collect: Record; - negatable: Record; - unknownFn: (arg: string, key?: string, value?: unknown) => unknown; - allBools: boolean; -} - interface NestedMapping { [key: string]: NestedMapping | unknown; } -const { hasOwn } = Object; - -function get( - obj: Record, - key: string, -): TValue | undefined { - if (hasOwn(obj, key)) { - return obj[key]; - } -} - -function getForce(obj: Record, key: string): TValue { - const v = get(obj, key); - assertExists(v); - return v; -} - function isNumber(x: unknown): boolean { if (typeof x === "number") return true; if (/^0x[0-9a-f]+$/i.test(String(x))) return true; return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(String(x)); } -function hasKey(obj: NestedMapping, keys: string[]): boolean { - let o = obj; +function setNested( + object: NestedMapping, + keys: string[], + value: unknown, + collect = false, +) { keys.slice(0, -1).forEach((key) => { - o = (get(o, key) ?? {}) as NestedMapping; + object[key] ??= {}; + object = object[key] as NestedMapping; }); - const key = keys.at(-1); - return key !== undefined && hasOwn(o, key); + const key = keys[keys.length - 1]; + + if (collect) { + const v = object[key]; + if (Array.isArray(v)) { + v.push(value); + return; + } + + value = v ? [v, value] : [value]; + } + + object[key] = value; +} + +function hasNested(object: NestedMapping, keys: string[]): boolean { + keys = [...keys]; + const lastKey = keys.pop(); + if (!lastKey) return false; + for (const key of keys) { + if (!object[key]) return false; + object = object[key] as NestedMapping; + } + return Object.hasOwn(object, lastKey); +} + +function aliasIsBoolean( + aliasMap: Map>, + booleanSet: Set, + key: string, +): boolean { + const set = aliasMap.get(key); + if (set === undefined) return false; + for (const alias of set) if (booleanSet.has(alias)) return true; + return false; +} + +function isBooleanString(value: string) { + return value === "true" || value === "false"; +} + +function parseBooleanString(value: unknown) { + return value !== "false"; } +const FLAG_REGEXP = + /^(?:-(?:(?-)(?no-)?)?)(?.+?)(?:=(?.+?))?$/s; + /** * Take a set of command line arguments, optionally with a set of options, and * return an object representing the flags found in the passed arguments. @@ -439,7 +462,7 @@ export function parseArgs< string = [], collect = [], negatable = [], - unknown = (i: string): unknown => i, + unknown: unknownFn = (i: string): unknown => i, }: ParseOptions< TBooleans, TStrings, @@ -450,219 +473,153 @@ export function parseArgs< TDoubleDash > = {}, ): Args { - const aliases: Record = {}; - const flags: Flags = { - bools: {}, - strings: {}, - unknownFn: unknown, - allBools: false, - collect: {}, - negatable: {}, - }; - - if (alias !== undefined) { + const aliasMap: Map> = new Map(); + const booleanSet = new Set(); + const stringSet = new Set(); + const collectSet = new Set(); + const negatableSet = new Set(); + + let allBools = false; + + if (alias) { for (const key in alias) { - const val = getForce(alias, key); - if (typeof val === "string") { - aliases[key] = [val]; - } else { - aliases[key] = val as Array; - } - const aliasesForKey = getForce(aliases, key); - for (const alias of aliasesForKey) { - aliases[alias] = [key].concat(aliasesForKey.filter((y) => alias !== y)); - } + const val = (alias as Record)[key]; + assert(val !== undefined); + const aliases = Array.isArray(val) ? val : [val]; + aliasMap.set(key, new Set(aliases)); + const set = new Set([key, ...aliases]); + aliases.forEach((alias) => aliasMap.set(alias, set)); } } - if (boolean !== undefined) { + if (boolean) { if (typeof boolean === "boolean") { - flags.allBools = !!boolean; + allBools = boolean; } else { - const booleanArgs: ReadonlyArray = typeof boolean === "string" - ? [boolean] - : boolean; - + const booleanArgs = Array.isArray(boolean) ? boolean : [boolean]; for (const key of booleanArgs.filter(Boolean)) { - flags.bools[key] = true; - const alias = get(aliases, key); - if (alias) { - for (const al of alias) { - flags.bools[al] = true; - } - } + booleanSet.add(key); + aliasMap.get(key)?.forEach((al) => { + booleanSet.add(al); + }); } } } - if (string !== undefined) { - const stringArgs: ReadonlyArray = typeof string === "string" - ? [string] - : string; - + if (string) { + const stringArgs = Array.isArray(string) ? string : [string]; for (const key of stringArgs.filter(Boolean)) { - flags.strings[key] = true; - const alias = get(aliases, key); - if (alias) { - for (const al of alias) { - flags.strings[al] = true; - } - } + stringSet.add(key); + aliasMap.get(key)?.forEach((al) => stringSet.add(al)); } } - if (collect !== undefined) { - const collectArgs: ReadonlyArray = typeof collect === "string" - ? [collect] - : collect; - + if (collect) { + const collectArgs = Array.isArray(collect) ? collect : [collect]; for (const key of collectArgs.filter(Boolean)) { - flags.collect[key] = true; - const alias = get(aliases, key); - if (alias) { - for (const al of alias) { - flags.collect[al] = true; - } - } + collectSet.add(key); + aliasMap.get(key)?.forEach((al) => collectSet.add(al)); } } - if (negatable !== undefined) { - const negatableArgs: ReadonlyArray = typeof negatable === "string" - ? [negatable] - : negatable; - + if (negatable) { + const negatableArgs = Array.isArray(negatable) ? negatable : [negatable]; for (const key of negatableArgs.filter(Boolean)) { - flags.negatable[key] = true; - const alias = get(aliases, key); - if (alias) { - for (const al of alias) { - flags.negatable[al] = true; - } - } + negatableSet.add(key); + aliasMap.get(key)?.forEach((alias) => negatableSet.add(alias)); } } const argv: Args = { _: [] }; - function argDefined(key: string, arg: string): boolean { - return ( - (flags.allBools && /^--[^=]+$/.test(arg)) || - get(flags.bools, key) || - !!get(flags.strings, key) || - !!get(aliases, key) - ); - } - - function setKey( - obj: NestedMapping, - name: string, - value: unknown, - collect = true, - ) { - let o = obj; - const keys = name.split("."); - keys.slice(0, -1).forEach(function (key) { - if (get(o, key) === undefined) { - o[key] = {}; - } - o = get(o, key) as NestedMapping; - }); - - const key = keys.at(-1)!; - const collectable = collect && !!get(flags.collect, name); - - if (!collectable) { - o[key] = value; - } else if (get(o, key) === undefined) { - o[key] = [value]; - } else if (Array.isArray(get(o, key))) { - (o[key] as unknown[]).push(value); - } else { - o[key] = [get(o, key), value]; - } - } - - function setArg( + function setArgument( key: string, - val: unknown, - arg: string | undefined = undefined, - collect?: boolean, + value: string | number | boolean, + arg: string, + collect: boolean, ) { - if (arg && flags.unknownFn && !argDefined(key, arg)) { - if (flags.unknownFn(arg, key, val) === false) return; + if ( + !booleanSet.has(key) && + !stringSet.has(key) && + !aliasMap.has(key) && + !(allBools && /^--[^=]+$/.test(arg)) && + unknownFn?.(arg, key, value) === false + ) { + return; } - - const value = !get(flags.strings, key) && isNumber(val) ? Number(val) : val; - setKey(argv, key, value, collect); - - const alias = get(aliases, key); - if (alias) { - for (const x of alias) { - setKey(argv, x, value, collect); - } + if (typeof value === "string" && !stringSet.has(key)) { + value = isNumber(value) ? Number(value) : value; } - } - function aliasIsBoolean(key: string): boolean { - return getForce(aliases, key).some( - (x) => typeof get(flags.bools, x) === "boolean", + const collectable = collect && collectSet.has(key); + setNested(argv, key.split("."), value, collectable); + aliasMap.get(key)?.forEach((key) => + setNested(argv, key.split("."), value, collectable) ); } let notFlags: string[] = []; // all args after "--" are not parsed - if (args.includes("--")) { - notFlags = args.slice(args.indexOf("--") + 1); - args = args.slice(0, args.indexOf("--")); + const index = args.indexOf("--"); + if (index !== -1) { + notFlags = args.slice(index + 1); + args = args.slice(0, index); } for (let i = 0; i < args.length; i++) { const arg = args[i]; - assertExists(arg); - - if (/^--.+=/.test(arg)) { - const m = arg.match(/^--([^=]+)=(.*)$/s); - assertExists(m); - const [, key, value] = m; - assertExists(key); - - if (flags.bools[key]) { - const booleanValue = value !== "false"; - setArg(key, booleanValue, arg); - } else { - setArg(key, value, arg); - } - } else if ( - /^--no-.+/.test(arg) && get(flags.negatable, arg.replace(/^--no-/, "")) - ) { - const m = arg.match(/^--no-(.+)/); - assertExists(m); - assertExists(m[1]); - setArg(m[1], false, arg, false); - } else if (/^--.+/.test(arg)) { - const m = arg.match(/^--(.+)/); - assertExists(m); - assertExists(m[1]); - const [, key] = m; - const next = args[i + 1]; - if ( - next !== undefined && - !/^-/.test(next) && - !get(flags.bools, key) && - !flags.allBools && - (get(aliases, key) ? !aliasIsBoolean(key) : true) - ) { - setArg(key, next, arg); - i++; - } else if (next !== undefined && (next === "true" || next === "false")) { - setArg(key, next === "true", arg); - i++; - } else { - setArg(key, get(flags.strings, key) ? "" : true, arg); + + const groups = arg.match(FLAG_REGEXP)?.groups; + + if (groups) { + const { doubleDash, negated } = groups; + let key = groups.key; + let value: string | number | boolean = groups.value; + + if (doubleDash) { + if (value) { + if (booleanSet.has(key)) value = parseBooleanString(value); + setArgument(key, value, arg, true); + continue; + } + + if (negated) { + if (negatableSet.has(key)) { + setArgument(key, false, arg, false); + continue; + } + key = `no-${key}`; + } + + const next = args[i + 1]; + + if ( + !booleanSet.has(key) && + !allBools && + next && + !/^-/.test(next) && + (aliasMap.get(key) + ? !aliasIsBoolean(aliasMap, booleanSet, key) + : true) + ) { + value = next; + i++; + setArgument(key, value, arg, true); + continue; + } + + if (isBooleanString(next)) { + value = parseBooleanString(next); + i++; + setArgument(key, value, arg, true); + continue; + } + + value = stringSet.has(key) ? "" : true; + setArgument(key, value, arg, true); + continue; } - } else if (/^-[^-]+/.test(arg)) { const letters = arg.slice(1, -1).split(""); let broken = false; @@ -670,12 +627,12 @@ export function parseArgs< const next = arg.slice(j + 2); if (next === "-") { - setArg(letter, next, arg); + setArgument(letter, next, arg, true); continue; } - if (/[A-Za-z]/.test(letter) && next.includes("=")) { - setArg(letter, next.split(/=(.+)/)[1], arg); + if (/[A-Za-z]/.test(letter) && /=/.test(next)) { + setArgument(letter, next.split(/=(.+)/)[1], arg, true); broken = true; break; } @@ -684,82 +641,82 @@ export function parseArgs< /[A-Za-z]/.test(letter) && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next) ) { - setArg(letter, next, arg); + setArgument(letter, next, arg, true); broken = true; break; } - if (letters[j + 1]?.match(/\W/)) { - setArg(letter, arg.slice(j + 2), arg); + if (letters[j + 1] && letters[j + 1].match(/\W/)) { + setArgument(letter, arg.slice(j + 2), arg, true); broken = true; break; - } else { - setArg(letter, get(flags.strings, letter) ? "" : true, arg); } + setArgument( + letter, + stringSet.has(letter) ? "" : true, + arg, + true, + ); } - const key = arg.at(-1)!; + key = arg.slice(-1); if (!broken && key !== "-") { const nextArg = args[i + 1]; if ( nextArg && !/^(-|--)[^-]/.test(nextArg) && - !get(flags.bools, key) && - (get(aliases, key) ? !aliasIsBoolean(key) : true) + !booleanSet.has(key) && + (aliasMap.get(key) + ? !aliasIsBoolean(aliasMap, booleanSet, key) + : true) ) { - setArg(key, nextArg, arg); + setArgument(key, nextArg, arg, true); i++; - } else if (nextArg && (nextArg === "true" || nextArg === "false")) { - setArg(key, nextArg === "true", arg); + } else if (nextArg && isBooleanString(nextArg)) { + const value = parseBooleanString(nextArg); + setArgument(key, value, arg, true); i++; } else { - setArg(key, get(flags.strings, key) ? "" : true, arg); + setArgument(key, stringSet.has(key) ? "" : true, arg, true); } } - } else { - if (!flags.unknownFn || flags.unknownFn(arg) !== false) { - argv._.push(flags.strings["_"] ?? !isNumber(arg) ? arg : Number(arg)); - } - if (stopEarly) { - argv._.push(...args.slice(i + 1)); - break; - } + continue; } - } - for (const [key, value] of Object.entries(defaults)) { - if (!hasKey(argv, key.split("."))) { - setKey(argv, key, value, false); + if (unknownFn?.(arg) !== false) { + argv._.push( + stringSet.has("_") || !isNumber(arg) ? arg : Number(arg), + ); + } - const alias = aliases[key]; - if (alias !== undefined) { - for (const x of alias) { - setKey(argv, x, value, false); - } - } + if (stopEarly) { + argv._.push(...args.slice(i + 1)); + break; } } - for (const key of Object.keys(flags.bools)) { - if (!hasKey(argv, key.split("."))) { - const value = get(flags.collect, key) ? [] : false; - setKey( - argv, - key, - value, - false, + for (const [key, value] of Object.entries(defaults)) { + const keys = key.split("."); + if (!hasNested(argv, keys)) { + setNested(argv, keys, value); + aliasMap.get(key)?.forEach((key) => + setNested(argv, key.split("."), value) ); } } - for (const key of Object.keys(flags.strings)) { - if (!hasKey(argv, key.split(".")) && get(flags.collect, key)) { - setKey( - argv, - key, - [], - false, - ); + for (const key of booleanSet.keys()) { + const keys = key.split("."); + if (!hasNested(argv, keys)) { + const value = collectSet.has(key) ? [] : false; + setNested(argv, keys, value); + } + } + + for (const key of stringSet.keys()) { + const keys = key.split("."); + if (!hasNested(argv, keys) && collectSet.has(key)) { + setNested(argv, keys, []); } } From 94d9e5b6fd8acaeb5c32274703c3a41f18e5a348 Mon Sep 17 00:00:00 2001 From: scarf Date: Mon, 12 Feb 2024 10:15:58 +0900 Subject: [PATCH 12/63] docs(fmt/colors): warn that `dim` is incompatible accross terminals (#4303) --- fmt/colors.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fmt/colors.ts b/fmt/colors.ts index ac253732a935..8e5048b470c1 100644 --- a/fmt/colors.ts +++ b/fmt/colors.ts @@ -134,6 +134,9 @@ export function bold(str: string): string { /** * The text emits only a small amount of light. * @param str text to dim + * + * Warning: Not all terminal emulators support `dim`. + * For compatibility across all terminals, use {@linkcode gray} or {@linkcode brightBlack} instead. */ export function dim(str: string): string { return run(str, code([2], 22)); From 34921103e4d56c11094b3883a933e4bee46b7422 Mon Sep 17 00:00:00 2001 From: Gabriele Belluardo Date: Mon, 12 Feb 2024 04:12:28 +0100 Subject: [PATCH 13/63] refactor(html): prepare for `noUncheckedIndexedAccess` (#4297) --- html/entities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/entities.ts b/html/entities.ts index 38838d9b3226..c3b20e2d8efd 100644 --- a/html/entities.ts +++ b/html/entities.ts @@ -93,7 +93,7 @@ export function unescape( } return str - .replaceAll(entityRe, (m) => entityList[m]) + .replaceAll(entityRe, (m) => entityList[m]!) .replaceAll(RX_DEC_ENTITY, (_, dec) => codePointStrToChar(dec, 10)) .replaceAll(RX_HEX_ENTITY, (_, hex) => codePointStrToChar(hex, 16)); } From aa856b9218a9261ad95d40c5a8c1bfe9b347426d Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Mon, 12 Feb 2024 17:23:52 +1100 Subject: [PATCH 14/63] docs: update stability table (#4305) --- README.md | 79 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 57f0a6980c5c..3cec7df2fd8d 100644 --- a/README.md +++ b/README.md @@ -68,42 +68,49 @@ Check out the documentation [here](https://deno.land/std?doc). ## Stability -| Sub-module | Status | -| ------------ | ---------- | -| archive | Unstable | -| assert | Stable | -| async | Stable | -| bytes | Stable | -| collections | Stable | -| console | Unstable | -| csv | Stable | -| datetime | Unstable | -| dotenv | Unstable | -| encoding | Unstable | -| flags | Unstable | -| fmt | Stable | -| front_matter | Unstable | -| fs | Stable | -| html | Unstable | -| http | Unstable | -| io | Deprecated | -| json | Stable | -| jsonc | Stable | -| log | Unstable | -| media_types | Stable | -| msgpack | Unstable | -| path | Unstable | -| permissions | Deprecated | -| regexp | Unstable | -| semver | Unstable | -| streams | Unstable | -| testing | Stable | -| toml | Stable | -| ulid | Unstable | -| url | Unstable | -| uuid | Stable | -| webgpu | Unstable | -| yaml | Stable | +| Sub-module | Status | +| --------------- | ---------- | +| archive | Unstable | +| assert | Stable | +| async | Stable | +| bytes | Stable | +| cli | Unstable | +| collections | Stable | +| console | Unstable | +| crypto | Stable | +| csv | Stable | +| data_structures | Unstable | +| datetime | Unstable | +| dotenv | Unstable | +| encoding | Unstable | +| expect | Unstable | +| flags | Unstable | +| fmt | Stable | +| front_matter | Unstable | +| fs | Stable | +| html | Unstable | +| http | Unstable | +| ini | Unstable | +| io | Deprecated | +| json | Stable | +| jsonc | Stable | +| log | Unstable | +| media_types | Stable | +| msgpack | Unstable | +| net | Unstable | +| path | Unstable | +| permissions | Deprecated | +| regexp | Unstable | +| semver | Unstable | +| streams | Unstable | +| testing | Stable | +| text | Unstable | +| toml | Stable | +| ulid | Unstable | +| url | Unstable | +| uuid | Stable | +| webgpu | Unstable | +| yaml | Stable | > For background and discussions regarding the stability of the following > sub-modules, see [#3489](https://github.com/denoland/deno_std/issues/3489). From 775058040a75a1530a90f7a2aaae1ecd65d9a506 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Mon, 12 Feb 2024 11:57:56 +0100 Subject: [PATCH 15/63] fix(semver): return new object instance in `comparatorMin()` and `comparatorMax()` (#4314) --- semver/_comparator_max.ts | 8 +++++++- semver/_comparator_min.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/semver/_comparator_max.ts b/semver/_comparator_max.ts index 5e9608e4c486..046bf2dc0f0a 100644 --- a/semver/_comparator_max.ts +++ b/semver/_comparator_max.ts @@ -24,7 +24,13 @@ export function comparatorMax(semver: SemVer, operator: Operator): SemVer { case "==": case "===": case "<=": - return semver; + return { + major: semver.major, + minor: semver.minor, + patch: semver.patch, + prerelease: semver.prerelease, + build: semver.build, + }; case "<": { const patch = semver.patch - 1; const minor = patch >= 0 ? semver.minor : semver.minor - 1; diff --git a/semver/_comparator_min.ts b/semver/_comparator_min.ts index eaa47ee88665..238cd0f9c51f 100644 --- a/semver/_comparator_min.ts +++ b/semver/_comparator_min.ts @@ -31,6 +31,12 @@ export function comparatorMin(semver: SemVer, operator: Operator): SemVer { case "=": case "==": case "===": - return semver; + return { + major: semver.major, + minor: semver.minor, + patch: semver.patch, + prerelease: semver.prerelease, + build: semver.build, + }; } } From 7f5693a5f3b402499a848ef0d3633017ffeb9dcc Mon Sep 17 00:00:00 2001 From: David Luis <95457148+babiabeo@users.noreply.github.com> Date: Tue, 13 Feb 2024 03:32:41 +0700 Subject: [PATCH 16/63] docs(regexp): complete documentation (#4319) --- regexp/escape.ts | 1 + regexp/mod.ts | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/regexp/escape.ts b/regexp/escape.ts index e592bbb339c7..48d6db7b709f 100644 --- a/regexp/escape.ts +++ b/regexp/escape.ts @@ -1,4 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. // // For future forward-compatibility with regexp `v` flag, reservedCharMap is // // autogenerated from the ClassSetReservedDoublePunctuator, diff --git a/regexp/mod.ts b/regexp/mod.ts index 4eaa567a26e2..cab2ada81b5b 100644 --- a/regexp/mod.ts +++ b/regexp/mod.ts @@ -2,8 +2,9 @@ // This module is browser compatible. /** - * Functions for tasks related to regular expression (regexps), such as - * escaping text for interpolation into a regexp + * Functions for tasks related to + * {@link https://en.wikipedia.org/wiki/Regular_expression | regular expression} (regexp), + * such as escaping text for interpolation into a regexp. * * @module */ From 283888de59f9bb6e795714b5a5229b061521be21 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Mon, 12 Feb 2024 21:49:22 +0100 Subject: [PATCH 17/63] refactor(semver): simplify args for `comparatorMin()` and `comparatorMax()` (#4316) initial commit --- semver/_comparator_intersects.ts | 8 ++++---- semver/_comparator_max.ts | 11 +++++------ semver/_comparator_min.ts | 14 ++++++-------- semver/range_max.ts | 5 +---- semver/range_min.ts | 5 +---- semver/test_range.ts | 4 ++-- 6 files changed, 19 insertions(+), 28 deletions(-) diff --git a/semver/_comparator_intersects.ts b/semver/_comparator_intersects.ts index 73eb241948a0..f5df665dd656 100644 --- a/semver/_comparator_intersects.ts +++ b/semver/_comparator_intersects.ts @@ -14,10 +14,10 @@ export function comparatorIntersects( c0: Comparator, c1: Comparator, ): boolean { - const l0 = comparatorMin(c0.semver ?? c0, c0.operator); - const l1 = comparatorMax(c0.semver ?? c0, c0.operator); - const r0 = comparatorMin(c1.semver ?? c1, c1.operator); - const r1 = comparatorMax(c1.semver ?? c1, c1.operator); + const l0 = comparatorMin(c0); + const l1 = comparatorMax(c0); + const r0 = comparatorMin(c1); + const r1 = comparatorMax(c1); // We calculate the min and max ranges of both comparators. // The minimum min is 0.0.0, the maximum max is ANY. diff --git a/semver/_comparator_max.ts b/semver/_comparator_max.ts index 046bf2dc0f0a..f5d06b265911 100644 --- a/semver/_comparator_max.ts +++ b/semver/_comparator_max.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Operator, SemVer } from "./types.ts"; +import type { Comparator, SemVer } from "./types.ts"; import { ANY, INVALID, MAX } from "./constants.ts"; /** @@ -9,11 +9,10 @@ import { ANY, INVALID, MAX } from "./constants.ts"; * an out of range semver will be returned. * @returns the version, the MAX version or the next smallest patch version */ -export function comparatorMax(semver: SemVer, operator: Operator): SemVer { - if (semver === ANY) { - return MAX; - } - switch (operator) { +export function comparatorMax(comparator: Comparator): SemVer { + const semver = comparator.semver ?? comparator; + if (semver === ANY) return MAX; + switch (comparator.operator) { case "!=": case "!==": case ">": diff --git a/semver/_comparator_min.ts b/semver/_comparator_min.ts index 238cd0f9c51f..cd683842d2ee 100644 --- a/semver/_comparator_min.ts +++ b/semver/_comparator_min.ts @@ -1,21 +1,19 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Operator, SemVer } from "./types.ts"; +import type { Comparator, SemVer } from "./types.ts"; import { ANY, MAX, MIN } from "./constants.ts"; import { greaterThan } from "./greater_than.ts"; import { increment } from "./increment.ts"; /** * The minimum semantic version that could match this comparator - * @param semver The semantic version of the comparator + * @param comparator The semantic version of the comparator * @param operator The operator of the comparator * @returns The minimum valid semantic version */ -export function comparatorMin(semver: SemVer, operator: Operator): SemVer { - if (semver === ANY) { - return MIN; - } - - switch (operator) { +export function comparatorMin(comparator: Comparator): SemVer { + const semver = comparator.semver ?? comparator; + if (semver === ANY) return MIN; + switch (comparator.operator) { case ">": return semver.prerelease && semver.prerelease.length > 0 ? increment(semver, "pre") diff --git a/semver/range_max.ts b/semver/range_max.ts index 40677a796e73..bf68572f681a 100644 --- a/semver/range_max.ts +++ b/semver/range_max.ts @@ -14,10 +14,7 @@ export function rangeMax(range: Range): SemVer { let max; for (const comparators of range) { for (const comparator of comparators) { - const candidate = comparatorMax( - comparator.semver ?? comparator, - comparator.operator, - ); + const candidate = comparatorMax(comparator); if (!testRange(candidate, range)) continue; max = (max && greaterThan(max, candidate)) ? max : candidate; } diff --git a/semver/range_min.ts b/semver/range_min.ts index 653b78fd3b69..ed04fa9098c8 100644 --- a/semver/range_min.ts +++ b/semver/range_min.ts @@ -14,10 +14,7 @@ export function rangeMin(range: Range): SemVer { let min; for (const comparators of range) { for (const comparator of comparators) { - const candidate = comparatorMin( - comparator.semver ?? comparator, - comparator.operator, - ); + const candidate = comparatorMin(comparator); if (!testRange(candidate, range)) continue; min = (min && lessThan(min, candidate)) ? min : candidate; } diff --git a/semver/test_range.ts b/semver/test_range.ts index 3188d435dd95..047e94991097 100644 --- a/semver/test_range.ts +++ b/semver/test_range.ts @@ -18,8 +18,8 @@ export function testRange( for (const r of range) { if ( r.every((c) => - greaterOrEqual(version, comparatorMin(c.semver ?? c, c.operator)) && - lessOrEqual(version, comparatorMax(c.semver ?? c, c.operator)) + greaterOrEqual(version, comparatorMin(c)) && + lessOrEqual(version, comparatorMax(c)) ) ) { return true; From 36d4ec5012b8563406b693408a469501b11b6b1c Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Tue, 13 Feb 2024 08:06:00 +0100 Subject: [PATCH 18/63] chore(semver): add tests for `rangeMax()` (#4315) --- semver/range_max_test.ts | 279 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 semver/range_max_test.ts diff --git a/semver/range_max_test.ts b/semver/range_max_test.ts new file mode 100644 index 000000000000..e5b9a5f5eb25 --- /dev/null +++ b/semver/range_max_test.ts @@ -0,0 +1,279 @@ +// Copyright Isaac Z. Schlueter and Contributors. All rights reserved. ISC license. +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +import { parseRange } from "./parse_range.ts"; +import { rangeMax } from "./range_max.ts"; +import { INVALID } from "./constants.ts"; +import type { SemVer } from "./types.ts"; +import { assertEquals } from "../assert/assert_equals.ts"; + +Deno.test({ + name: "rangeMax()", + fn: async (t) => { + const versions: [string, SemVer][] = [ + ["=1.0.0", { major: 1, minor: 0, patch: 0, prerelease: [], build: [] }], + ["1.0.0", { major: 1, minor: 0, patch: 0, prerelease: [], build: [] }], + ["1.0", { + major: 1, + minor: 0, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["1", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["1.0.x", { + major: 1, + minor: 0, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["1.x.x", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["1.x", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["1.0.*", { + major: 1, + minor: 0, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["1.*.*", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["1.*", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["*", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["1.*.x", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["1.x.*", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["~1.1.1", { + major: 1, + minor: 1, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["~1.1.1-beta", { + major: 1, + minor: 1, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["^1.1.1", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + ["^1.1.1-beta", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["1.1.1 - 1.8.0", { + major: 1, + minor: 8, + patch: 0, + prerelease: [], + build: [], + }], + ["1.1 - 1.8.0", { + major: 1, + minor: 8, + patch: 0, + prerelease: [], + build: [], + }], + ["1.1.1 - 1.8", { + major: 1, + minor: 8, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["<1.0.0", { + build: [], + major: 0, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + }], + ["<1.0.0-0", { + build: [], + major: 0, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + }], + ["<1.0.0-beta", { + build: [], + major: 0, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + }], + + [">1.0.0", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + [">1.0.0-0", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + [">1.0.0-beta", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["<0.0.0-beta", INVALID], + [">0.0.0-beta", { + build: [], + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + }], + ["<0.0.1-beta", { + major: 0, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }], + [">0.0.1-beta", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["<2 || >4", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + [">=4 || <=2", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + [">=1.1.1 <2 || >=2.2.2 <2", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + [">=2.2.2 <2 || >=1.1.1 <2", { + major: 1, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + [">2 || >1.0.0", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + [">2 || >1.0.0-0", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + [">2 || >1.0.0-beta", { + major: Number.POSITIVE_INFINITY, + minor: Number.POSITIVE_INFINITY, + patch: Number.POSITIVE_INFINITY, + prerelease: [], + build: [], + }], + + ["<0.0.0-beta >0.0.0-alpha", INVALID], + [">0.0.0-alpha <0.0.0-beta", INVALID], + [">4 <3", INVALID], + ]; + + for (const [version, expected] of versions) { + await t.step(version, () => { + const actual = rangeMax(parseRange(version)); + assertEquals(actual, expected); + }); + } + }, +}); From 53c474ed4b427880552255c867970baa47a276fe Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Tue, 13 Feb 2024 16:10:19 +0900 Subject: [PATCH 19/63] docs(semver): remove obsolete docs (#4324) --- semver/mod.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/semver/mod.ts b/semver/mod.ts index 196b28bf1dc7..cbb928886f63 100644 --- a/semver/mod.ts +++ b/semver/mod.ts @@ -91,11 +91,6 @@ * aware of the risk. However, it is still not appropriate to assume that they have * opted into taking a similar risk on the _next_ set of prerelease versions. * - * Note that this behavior can be suppressed (treating all prerelease versions as - * if they were normal versions, for the purpose of range matching) by setting the - * `includePrerelease` flag on the options object to any [functions](#functions) - * that do range matching. - * * #### Prerelease Identifiers * * The method `.increment` takes an additional `identifier` string argument that From 6de2aefdbf50c0083dd26f0d20cd1bd9875093dd Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Wed, 14 Feb 2024 13:04:52 +0900 Subject: [PATCH 20/63] docs(semver): fix arg names in jsdoc (#4328) --- semver/compare.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semver/compare.ts b/semver/compare.ts index 57ad69569ea0..ed7bca0c504b 100644 --- a/semver/compare.ts +++ b/semver/compare.ts @@ -9,7 +9,7 @@ import { /** * Compare two semantic version objects. * - * Returns `0` if `v1 === v2`, or `1` if `v1` is greater, or `-1` if `v2` is + * Returns `0` if `s0 === s1`, or `1` if `s0` is greater, or `-1` if `s1` is * greater. * * Sorts in ascending order if passed to `Array.sort()`, From 8706b2c7b5790f383b3b41e1fb5d44941b143913 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Wed, 14 Feb 2024 13:34:18 +0900 Subject: [PATCH 21/63] docs: update module stability (#4329) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3cec7df2fd8d..192dc5ac6cd2 100644 --- a/README.md +++ b/README.md @@ -82,27 +82,27 @@ Check out the documentation [here](https://deno.land/std?doc). | data_structures | Unstable | | datetime | Unstable | | dotenv | Unstable | -| encoding | Unstable | +| encoding | Stable | | expect | Unstable | | flags | Unstable | | fmt | Stable | -| front_matter | Unstable | +| front_matter | Stable | | fs | Stable | | html | Unstable | | http | Unstable | | ini | Unstable | -| io | Deprecated | +| io | Unstable | | json | Stable | | jsonc | Stable | | log | Unstable | | media_types | Stable | | msgpack | Unstable | | net | Unstable | -| path | Unstable | +| path | Stable | | permissions | Deprecated | | regexp | Unstable | | semver | Unstable | -| streams | Unstable | +| streams | Stable | | testing | Stable | | text | Unstable | | toml | Stable | From 5e3b3f54a3413d6a584d36c4f527db155877c8f5 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Wed, 14 Feb 2024 14:37:50 +0900 Subject: [PATCH 22/63] chore: update dependency checker tool (#4331) --- .../check_circular_submodule_dependencies.ts | 107 +++++++++++------- 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/_tools/check_circular_submodule_dependencies.ts b/_tools/check_circular_submodule_dependencies.ts index f61bcf8c8e4f..07501c65a4ea 100644 --- a/_tools/check_circular_submodule_dependencies.ts +++ b/_tools/check_circular_submodule_dependencies.ts @@ -4,10 +4,19 @@ import { createGraph, ModuleGraphJson, ModuleJson } from "deno_graph"; /** * Checks for circular dependencies in the std submodules. * - * When run with `--graph` it will output a graphviz graph in dot language. + * Usage: deno run -A _tools/check_circular_submodule_dependencies.ts + * + * `--graph` option outputs graphviz diagram. You can convert the output to + * a visual graph using tools like https://dreampuf.github.io/GraphvizOnline/ + * + * $ deno run -A _tools/check_circular_submodule_dependencies.ts --graph + * + * `--table` option outputs a table of submodules and their status. + * + * $ deno run -A _tools/check_circular_submodule_dependencies.ts --table */ -type DepState = "ready" | "not ready" | "needs clean up" | "deprecated"; +type DepState = "Stable" | "Unstable" | "Deprecated"; type Dep = { name: string; set: Set; @@ -38,6 +47,7 @@ async function check( } } deps.delete(submod); + deps.delete("version.ts"); return { name: submod, set: deps, state }; } @@ -71,18 +81,19 @@ function getSubmoduleDepsFromSpecifier( return deps; } -deps["archive"] = await check("archive", "not ready"); -deps["assert"] = await check("assert", "ready"); -deps["async"] = await check("async", "ready"); -deps["bytes"] = await check("bytes", "ready"); -deps["collections"] = await check("collections", "ready"); -deps["console"] = await check("console", "not ready"); -deps["crypto"] = await check("crypto", "needs clean up"); -deps["csv"] = await check("csv", "ready"); -deps["data_structures"] = await check("data_structures", "not ready"); -deps["datetime"] = await check("datetime", "deprecated"); -deps["dotenv"] = await check("dotenv", "not ready"); -deps["encoding"] = await check("encoding", "needs clean up", [ +deps["archive"] = await check("archive", "Unstable"); +deps["assert"] = await check("assert", "Stable"); +deps["async"] = await check("async", "Stable"); +deps["bytes"] = await check("bytes", "Stable"); +deps["cli"] = await check("cli", "Unstable"); +deps["collections"] = await check("collections", "Stable"); +deps["console"] = await check("console", "Unstable"); +deps["crypto"] = await check("crypto", "Stable"); +deps["csv"] = await check("csv", "Stable"); +deps["data_structures"] = await check("data_structures", "Unstable"); +deps["datetime"] = await check("datetime", "Unstable"); +deps["dotenv"] = await check("dotenv", "Unstable"); +deps["encoding"] = await check("encoding", "Stable", [ "ascii85.ts", "base32.ts", "base58.ts", @@ -92,41 +103,45 @@ deps["encoding"] = await check("encoding", "needs clean up", [ "hex.ts", "varint.ts", ]); -deps["flags"] = await check("flags", "not ready"); -deps["fmt"] = await check("fmt", "ready", [ +deps["expect"] = await check("expect", "Unstable"); +deps["flags"] = await check("flags", "Unstable"); +deps["fmt"] = await check("fmt", "Stable", [ "bytes.ts", "colors.ts", "duration.ts", "printf.ts", ]); -deps["front_matter"] = await check("front_matter", "needs clean up"); -deps["fs"] = await check("fs", "ready"); -deps["html"] = await check("html", "not ready"); -deps["http"] = await check("http", "needs clean up"); -deps["io"] = await check("io", "deprecated"); -deps["json"] = await check("json", "ready"); -deps["jsonc"] = await check("jsonc", "ready"); -deps["log"] = await check("log", "not ready"); -deps["media_types"] = await check("media_types", "ready"); -deps["msgpack"] = await check("msgpack", "not ready"); -deps["path"] = await check("path", "needs clean up"); -deps["permissions"] = await check("permissions", "deprecated"); -deps["regexp"] = await check("regexp", "not ready"); -deps["semver"] = await check("semver", "not ready"); -deps["streams"] = await check("streams", "needs clean up"); -deps["testing"] = await check("testing", "ready", [ +deps["front_matter"] = await check("front_matter", "Stable"); +deps["fs"] = await check("fs", "Stable"); +deps["html"] = await check("html", "Unstable"); +deps["http"] = await check("http", "Unstable"); +deps["ini"] = await check("ini", "Unstable"); +deps["io"] = await check("io", "Unstable"); +deps["json"] = await check("json", "Stable"); +deps["jsonc"] = await check("jsonc", "Stable"); +deps["log"] = await check("log", "Unstable"); +deps["media_types"] = await check("media_types", "Stable"); +deps["msgpack"] = await check("msgpack", "Unstable"); +deps["net"] = await check("net", "Unstable"); +deps["path"] = await check("path", "Stable"); +deps["permissions"] = await check("permissions", "Deprecated"); +deps["regexp"] = await check("regexp", "Unstable"); +deps["semver"] = await check("semver", "Unstable"); +deps["streams"] = await check("streams", "Stable"); +deps["testing"] = await check("testing", "Stable", [ "bdd.ts", "mock.ts", "snapshot.ts", "time.ts", "types.ts", ]); -deps["toml"] = await check("toml", "ready"); -deps["ulid"] = await check("ulid", "not ready"); -deps["url"] = await check("url", "not ready"); -deps["uuid"] = await check("uuid", "ready"); -deps["webgpu"] = await check("webgpu", "not ready"); -deps["yaml"] = await check("yaml", "ready"); +deps["text"] = await check("text", "Unstable"); +deps["toml"] = await check("toml", "Stable"); +deps["ulid"] = await check("ulid", "Unstable"); +deps["url"] = await check("url", "Unstable"); +deps["uuid"] = await check("uuid", "Stable"); +deps["webgpu"] = await check("webgpu", "Unstable"); +deps["yaml"] = await check("yaml", "Stable"); /** Checks circular deps between sub modules */ function checkCircularDeps( @@ -158,14 +173,12 @@ function formatLabel(mod: string) { /** Returns node style (in DOT language) for each state */ function stateToNodeStyle(state: DepState) { switch (state) { - case "ready": + case "Stable": return "[shape=doublecircle fixedsize=1 height=1.1]"; - case "not ready": + case "Unstable": return "[shape=box style=filled, fillcolor=pink]"; - case "needs clean up": - return "[shape=circle fixedsize=1 height=1.1 style=filled, fillcolor=yellow]"; - case "deprecated": - return "[shape=septagon style=filled, fillcolor=gray]"; + case "Deprecated": + return "[shape=box style=filled, fillcolor=gray]"; } } @@ -179,6 +192,12 @@ if (Deno.args.includes("--graph")) { } } console.log("}"); +} else if (Deno.args.includes("--table")) { + console.log("| Sub-module | Status |"); + console.log("| --------------- | ---------- |"); + for (const [mod, info] of Object.entries(deps)) { + console.log(`| ${mod.padEnd(15)} | ${info.state.padEnd(10)} |`); + } } else { console.log(`${Object.keys(deps).length} submodules checked.`); for (const mod of Object.keys(deps)) { From 55c33e1e8a3f51747d7d02213cd7c5913bfba5a4 Mon Sep 17 00:00:00 2001 From: denobot <33910674+denobot@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:01:02 +0900 Subject: [PATCH 23/63] 0.216.0 (#4333) Co-authored-by: Divy Srivastava --- Releases.md | 11 +++++++++++ version.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Releases.md b/Releases.md index 29db45a05dc4..c364fb6bc922 100644 --- a/Releases.md +++ b/Releases.md @@ -1,3 +1,14 @@ +### 0.216.0 / 2024.02.15 + +- BREAKING(path): remove `path/windows/separator.ts` (#4292) +- BREAKING(semver): remove `SemVerRange` and `isSemVerRange()` (#4295) +- BREAKING(semver): remove `eq()`, `gt()`, `gte()`, `lt()`, `lte()` and `neq()` + (#4294) +- BREAKING(semver): remove `outside()` (#4293) +- feat(datetime): `format()` options (#4285) +- fix(semver): return new object instance in `comparatorMin()` and + `comparatorMax()` (#4314) + ### 0.215.0 / 2024.02.08 - BREAKING(log): remove `WARNING` log level (#4258) diff --git a/version.ts b/version.ts index 79a17fb2775a..feb6d6ce48f2 100644 --- a/version.ts +++ b/version.ts @@ -5,4 +5,4 @@ * the cli's API is stable. In the future when std becomes stable, likely we * will match versions with cli as we have in the past. */ -export const VERSION = "0.215.0"; +export const VERSION = "0.216.0"; From 73ff70d870cfa87f16b94971456b07b13670b318 Mon Sep 17 00:00:00 2001 From: Gabriele Belluardo Date: Thu, 15 Feb 2024 22:07:19 +0100 Subject: [PATCH 24/63] refactor(http): prepare for `noUncheckedIndexedAccess` (#4298) * refactor(http): prepare for `noUncheckedIndexedAccess` * fix with requested changes * rm: quote counting --- http/_negotiation/encoding.ts | 8 ++-- http/_negotiation/language.ts | 12 ++++-- http/_negotiation/media_type.ts | 67 +++++++-------------------------- http/cookie.ts | 7 +++- http/file_server.ts | 2 +- http/server_test.ts | 10 ++--- http/user_agent.ts | 4 +- 7 files changed, 39 insertions(+), 71 deletions(-) diff --git a/http/_negotiation/encoding.ts b/http/_negotiation/encoding.ts index 878ad52c5764..4b9a25638532 100644 --- a/http/_negotiation/encoding.ts +++ b/http/_negotiation/encoding.ts @@ -52,7 +52,7 @@ function parseEncoding( const params = match[2].split(";"); for (const param of params) { const p = param.trim().split("="); - if (p[0] === "q") { + if (p[0] === "q" && p[1]) { q = parseFloat(p[1]); break; } @@ -91,8 +91,8 @@ function parseAcceptEncoding(accept: string): EncodingSpecificity[] { let hasIdentity = false; let minQuality = 1; - for (let i = 0; i < accepts.length; i++) { - const encoding = parseEncoding(accepts[i].trim(), i); + for (const [i, accept] of accepts.entries()) { + const encoding = parseEncoding(accept.trim(), i); if (encoding) { parsedAccepts.push(encoding); @@ -158,5 +158,5 @@ export function preferredEncodings( return priorities .filter(isQuality) .sort(compareSpecs) - .map((priority) => provided[priorities.indexOf(priority)]); + .map((priority) => provided[priorities.indexOf(priority)]!); } diff --git a/http/_negotiation/language.ts b/http/_negotiation/language.ts index 57cd56adfc63..a453e2a25426 100644 --- a/http/_negotiation/language.ts +++ b/http/_negotiation/language.ts @@ -49,6 +49,10 @@ function parseLanguage( } const [, prefix, suffix] = match; + if (!prefix) { + return undefined; + } + const full = suffix ? `${prefix}-${suffix}` : prefix; let q = 1; @@ -56,7 +60,7 @@ function parseLanguage( const params = match[3].split(";"); for (const param of params) { const [key, value] = param.trim().split("="); - if (key === "q") { + if (key === "q" && value) { q = parseFloat(value); break; } @@ -70,8 +74,8 @@ function parseAcceptLanguage(accept: string): LanguageSpecificity[] { const accepts = accept.split(","); const result: LanguageSpecificity[] = []; - for (let i = 0; i < accepts.length; i++) { - const language = parseLanguage(accepts[i].trim(), i); + for (const [i, accept] of accepts.entries()) { + const language = parseLanguage(accept.trim(), i); if (language) { result.push(language); } @@ -140,5 +144,5 @@ export function preferredLanguages( return priorities .filter(isQuality) .sort(compareSpecs) - .map((priority) => provided[priorities.indexOf(priority)]); + .map((priority) => provided[priorities.indexOf(priority)]!); } diff --git a/http/_negotiation/media_type.ts b/http/_negotiation/media_type.ts index 636d3a0c5c0d..2c26028cebf6 100644 --- a/http/_negotiation/media_type.ts +++ b/http/_negotiation/media_type.ts @@ -39,55 +39,9 @@ interface MediaTypeSpecificity extends Specificity { const simpleMediaTypeRegExp = /^\s*([^\s\/;]+)\/([^;\s]+)\s*(?:;(.*))?$/; -function quoteCount(str: string): number { - let count = 0; - let index = 0; - - while ((index = str.indexOf(`"`, index)) !== -1) { - count++; - index++; - } - - return count; -} - -function splitMediaTypes(accept: string): string[] { - const accepts = accept.split(","); - - let j = 0; - for (let i = 1; i < accepts.length; i++) { - if (quoteCount(accepts[j]) % 2 === 0) { - accepts[++j] = accepts[i]; - } else { - accepts[j] += `,${accepts[i]}`; - } - } - - accepts.length = j + 1; - - return accepts; -} - -function splitParameters(str: string): string[] { - const parameters = str.split(";"); - - let j = 0; - for (let i = 1; i < parameters.length; i++) { - if (quoteCount(parameters[j]) % 2 === 0) { - parameters[++j] = parameters[i]; - } else { - parameters[j] += `;${parameters[i]}`; - } - } - - parameters.length = j + 1; - - return parameters.map((p) => p.trim()); -} - function splitKeyValuePair(str: string): [string, string | undefined] { const [key, value] = str.split("="); - return [key.toLowerCase(), value]; + return [key!.toLowerCase(), value]; } function parseMediaType( @@ -100,12 +54,17 @@ function parseMediaType( return; } - const params: { [param: string]: string | undefined } = Object.create(null); - let q = 1; const [, type, subtype, parameters] = match; + if (!type || !subtype) { + return; + } + const params: { [param: string]: string | undefined } = Object.create(null); + let q = 1; if (parameters) { - const kvps = splitParameters(parameters).map(splitKeyValuePair); + const kvps = parameters.split(";").map((p) => p.trim()).map( + splitKeyValuePair, + ); for (const [key, val] of kvps) { const value = val && val[0] === `"` && val[val.length - 1] === `"` @@ -125,11 +84,11 @@ function parseMediaType( } function parseAccept(accept: string): MediaTypeSpecificity[] { - const accepts = splitMediaTypes(accept); + const accepts = accept.split(",").map((p) => p.trim()); const mediaTypes: MediaTypeSpecificity[] = []; - for (let i = 0; i < accepts.length; i++) { - const mediaType = parseMediaType(accepts[i].trim(), i); + for (const [index, accept] of accepts.entries()) { + const mediaType = parseMediaType(accept.trim(), index); if (mediaType) { mediaTypes.push(mediaType); @@ -233,5 +192,5 @@ export function preferredMediaTypes( return priorities .filter(isQuality) .sort(compareSpecs) - .map((priority) => provided[priorities.indexOf(priority)]); + .map((priority) => provided[priorities.indexOf(priority)]!); } diff --git a/http/cookie.ts b/http/cookie.ts index 0345dad8843a..3019a626b5af 100644 --- a/http/cookie.ts +++ b/http/cookie.ts @@ -293,8 +293,13 @@ function parseSetCookie(value: string): Cookie | null { .split(";") .map((attr) => { const [key, ...values] = attr.trim().split("="); - return [key, values.join("=")]; + return [key!, values.join("=")] as const; }); + + if (!attrs[0]) { + return null; + } + const cookie: Cookie = { name: attrs[0][0], value: attrs[0][1], diff --git a/http/file_server.ts b/http/file_server.ts index e6d5f479a01f..214cc74bcc6d 100644 --- a/http/file_server.ts +++ b/http/file_server.ts @@ -636,7 +636,7 @@ export async function serveDir( if (opts.headers && !isRedirectResponse) { for (const header of opts.headers) { const headerSplit = header.split(":"); - const name = headerSplit[0]; + const name = headerSplit[0]!; const value = headerSplit.slice(1).join(":"); response.headers.append(name, value); } diff --git a/http/server_test.ts b/http/server_test.ts index 845da4ee9369..5b6013e05568 100644 --- a/http/server_test.ts +++ b/http/server_test.ts @@ -155,7 +155,7 @@ Deno.test( try { assertEquals(server.addrs.length, 3); - assertEquals(server.addrs[0].transport, "tcp"); + assertEquals(server.addrs[0]!.transport, "tcp"); assertEquals( (server.addrs[0] as Deno.NetAddr).hostname, listenerOneOptions.hostname, @@ -164,7 +164,7 @@ Deno.test( (server.addrs[0] as Deno.NetAddr).port, listenerOneOptions.port, ); - assertEquals(server.addrs[1].transport, "tcp"); + assertEquals(server.addrs[1]!.transport, "tcp"); assertEquals( (server.addrs[1] as Deno.NetAddr).hostname, listenerTwoOptions.hostname, @@ -173,7 +173,7 @@ Deno.test( (server.addrs[1] as Deno.NetAddr).port, listenerTwoOptions.port, ); - assertEquals(server.addrs[2].transport, "tcp"); + assertEquals(server.addrs[2]!.transport, "tcp"); assertEquals((server.addrs[2] as Deno.NetAddr).hostname, addrHostname); assertEquals((server.addrs[2] as Deno.NetAddr).port, addrPort); } finally { @@ -973,14 +973,14 @@ Deno.test( // the expected backoff delay. for (let i = 0; i < rejectionCount; i++) { assertEquals( - listener.acceptCallIntervals[i] >= expectedBackoffDelays[i], + listener.acceptCallIntervals[i]! >= expectedBackoffDelays[i]!, true, ); } // Assert that the backoff delay has been reset following successfully // accepting a connection, i.e. it doesn't remain at 1000ms. - assertEquals(listener.acceptCallIntervals[rejectionCount] < 1000, true); + assertEquals(listener.acceptCallIntervals[rejectionCount]! < 1000, true); }, ); diff --git a/http/user_agent.ts b/http/user_agent.ts index 56764d3155f3..46b913ae0167 100644 --- a/http/user_agent.ts +++ b/http/user_agent.ts @@ -189,11 +189,11 @@ function mapper( if (!matchers[j]) { break; } - matches = matchers[j++].exec(ua); + matches = matchers[j++]!.exec(ua); if (matches) { for (const processor of processors) { - const match = matches[++k]; + const match = matches[++k]!; if (Array.isArray(processor)) { if (processor.length === 2) { const [prop, value] = processor; From f78de1334c0a172a11be5bb5eb68677f897fbb08 Mon Sep 17 00:00:00 2001 From: Gabriele Belluardo Date: Thu, 15 Feb 2024 22:09:51 +0100 Subject: [PATCH 25/63] refactor(ini): prepare for `noUncheckedIndexedAccess` (#4335) * refactor(ini): prepare for `noUncheckedIndexedAccess` * fix for stringify test --- ini/ini_map.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ini/ini_map.ts b/ini/ini_map.ts index 04e3dcd9d066..bfce3f3abe16 100644 --- a/ini/ini_map.ts +++ b/ini/ini_map.ts @@ -58,9 +58,7 @@ export class IniMap { #comments: Comments = { clear: (): void => { this.#lines = this.#lines.filter((line) => line.type !== "comment"); - const { length } = this.#lines; - for (let i = 0; i < length; i += 1) { - const line = this.#lines[i]; + for (const [i, line] of this.#lines.entries()) { if (line.type === "section") { line.end = line.end - line.num + i + 1; } @@ -346,13 +344,13 @@ export class IniMap { this.#appendOrDeleteLine(lineValue, LineOp.Add); } else { // For global values, find the line preceding the first section - let i = 0; - for (; i < this.#lines.length; i += 1) { - if (this.#lines[i].type === "section") { + lineValue.num = this.#lines.length + 1; + for (const [i, line] of this.#lines.entries()) { + if (line.type === "section") { + lineValue.num = i + 1; break; } } - lineValue.num = i + 1; // Append the line value at the end of all global values this.#appendOrDeleteLine(lineValue, LineOp.Add); } @@ -364,12 +362,10 @@ export class IniMap { } else { this.#lines.splice(input.num - 1, 1); } - const { length } = this.#lines; // If the input is a comment, find the next section if any to update. let updateSection = input.type === "comment"; - let i = op === LineOp.Add ? input.num : input.num - 1; - for (; i < length; i += 1) { - const line = this.#lines[i]; + const start = op === LineOp.Add ? input.num : input.num - 1; + for (const line of this.#lines.slice(start)) { line.num += op; if (line.type === "section") { line.end += op; @@ -397,7 +393,7 @@ export class IniMap { let line = ""; for (let i = 0; i < length; i += 1) { - const char = text[i]; + const char = text[i]!; if (lineBreak.includes(char)) { yield line; From b83c20ff69874e6ad3e77eba2dc79e71583ab7e1 Mon Sep 17 00:00:00 2001 From: jersou Date: Thu, 15 Feb 2024 22:54:02 +0100 Subject: [PATCH 26/63] doc: fix `std/path/posix` link (#4337) --- path/mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/path/mod.ts b/path/mod.ts index 3551e6d073df..e352365df277 100644 --- a/path/mod.ts +++ b/path/mod.ts @@ -40,7 +40,7 @@ import * as _posix from "./posix/mod.ts"; /** @deprecated (will be removed after 1.0.0) Import from {@link https://deno.land/std/path/windows/mod.ts} instead. */ export const win32: typeof _windows = _windows; -/** @deprecated (will be removed after 1.0.0) Import from {@link https://deno.land/std/posix/mod.ts} instead. */ +/** @deprecated (will be removed after 1.0.0) Import from {@link https://deno.land/std/path/posix/mod.ts} instead. */ export const posix: typeof _posix = _posix; export * from "./basename.ts"; From 44998e539d7a108a1907c8e3c901f10d7930e2ff Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 16 Feb 2024 12:11:03 +0900 Subject: [PATCH 27/63] chore(semver): align removal version of reverseSort to others (#4334) --- semver/reverse_sort.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semver/reverse_sort.ts b/semver/reverse_sort.ts index b0f6c59ea4f4..d8ea1e40690d 100644 --- a/semver/reverse_sort.ts +++ b/semver/reverse_sort.ts @@ -4,7 +4,7 @@ import { compare } from "./compare.ts"; /** * Sorts a list of semantic versions in descending order. - * @deprecated (will be removed in 0.217.0) Use `versions.sort((a, b) => compare(b, a))` instead. + * @deprecated (will be removed after 0.217.0) Use `versions.sort((a, b) => compare(b, a))` instead. */ export function reverseSort( versions: SemVer[], From 192a912d9c298421ee3111f44e78d44e2c93445f Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 16 Feb 2024 13:20:20 +0900 Subject: [PATCH 28/63] chore(semver): align removal version (#4338) Co-authored-by: Asher Gomez --- semver/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semver/types.ts b/semver/types.ts index 7db09669a03d..8285ea5d86cc 100644 --- a/semver/types.ts +++ b/semver/types.ts @@ -28,7 +28,7 @@ export type Operator = typeof OPERATORS[number]; export interface Comparator extends SemVer { operator: Operator; /** - * @deprecated (will be removed in 0.216.0) {@linkcode Comparator} extends {@linkcode SemVer}. Use `major`, `minor`, `patch`, `prerelease`, and `build` properties instead. + * @deprecated (will be removed after 0.217.0) {@linkcode Comparator} extends {@linkcode SemVer}. Use `major`, `minor`, `patch`, `prerelease`, and `build` properties instead. */ semver?: SemVer; } From c6ed026ec407d5858c3ca1a3361e64f7c11b3fd8 Mon Sep 17 00:00:00 2001 From: Kyle June Date: Thu, 15 Feb 2024 23:26:33 -0500 Subject: [PATCH 29/63] feat(testing): explicit resource management for `spy()` and `stub()` (#4306) * feat(testing): Explicit resource management for `spy()` and `stub()` * Undo explicitly making FakeTime Disposable * Update test cases to use explicit resource management --------- Co-authored-by: Yoshiya Hinosawa Co-authored-by: Asher Gomez --- http/file_server_test.ts | 3 +- testing/bdd_test.ts | 24 +++---- testing/mock.ts | 117 ++++++++++++++++++++++++++++-- testing/mock_test.ts | 150 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+), 22 deletions(-) diff --git a/http/file_server_test.ts b/http/file_server_test.ts index d42b0edcec6f..81cffda38a99 100644 --- a/http/file_server_test.ts +++ b/http/file_server_test.ts @@ -227,7 +227,7 @@ Deno.test("serveDir() returns a response even if fileinfo is inaccessible", asyn // even if the fileInfo for a particular file cannot be obtained. // Assuming that fileInfo of `test_file.txt` cannot be accessible - const denoStatStub = stub(Deno, "stat", (path): Promise => { + using denoStatStub = stub(Deno, "stat", (path): Promise => { if (path.toString().includes("test_file.txt")) { return Promise.reject(new Error("__stubed_error__")); } @@ -236,7 +236,6 @@ Deno.test("serveDir() returns a response even if fileinfo is inaccessible", asyn const req = new Request("http://localhost/"); const res = await serveDir(req, serveDirOptions); const page = await res.text(); - denoStatStub.restore(); assertEquals(res.status, 200); assertStringIncludes(page, "/test_file.txt"); diff --git a/testing/bdd_test.ts b/testing/bdd_test.ts index c3a27530bec5..72cd08261bb2 100644 --- a/testing/bdd_test.ts +++ b/testing/bdd_test.ts @@ -118,7 +118,7 @@ Deno.test("global", async (t) => { } await t.step("global hooks", async () => { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [spy(), spy()] as const; const { beforeAllFn, afterAllFn, beforeEachFn, afterEachFn } = hookFns(); @@ -148,7 +148,6 @@ Deno.test("global", async (t) => { assertSpyCalls(context.spies.step, 2); } finally { TestSuiteInternal.reset(); - test.restore(); } let fn = fns[0]; @@ -182,7 +181,7 @@ Deno.test("global", async (t) => { expectedOptions: Omit, cb: (fn: Spy) => void, ) { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fn = spy(); try { cb(fn); @@ -212,7 +211,6 @@ Deno.test("global", async (t) => { }); } finally { TestSuiteInternal.reset(); - test.restore(); } } @@ -685,7 +683,7 @@ Deno.test("global", async (t) => { expectedOptions: Omit, cb: (fns: readonly [Spy, Spy]) => void, ) { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [spy(), spy()] as const; try { cb(fns); @@ -727,7 +725,6 @@ Deno.test("global", async (t) => { assertSpyCalls(fn, 1); } finally { TestSuiteInternal.reset(); - test.restore(); } } @@ -1329,7 +1326,7 @@ Deno.test("global", async (t) => { async function assertOnly( cb: (fns: readonly [Spy, Spy, Spy]) => void, ) { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [spy(), spy(), spy()] as const; try { cb(fns); @@ -1369,7 +1366,6 @@ Deno.test("global", async (t) => { assertSpyCalls(fn, 0); } finally { TestSuiteInternal.reset(); - test.restore(); } } @@ -1427,7 +1423,7 @@ Deno.test("global", async (t) => { async function assertOnly( cb: (fns: readonly [Spy, Spy, Spy]) => void, ) { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [spy(), spy(), spy()] as const; try { cb(fns); @@ -1466,7 +1462,6 @@ Deno.test("global", async (t) => { assertSpyCalls(fn, 0); } finally { TestSuiteInternal.reset(); - test.restore(); } } @@ -1535,7 +1530,7 @@ Deno.test("global", async (t) => { }, ) => void, ) { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [spy(), spy()] as const; const { beforeAllFn, afterAllFn, beforeEachFn, afterEachFn } = hookFns(); @@ -1559,7 +1554,6 @@ Deno.test("global", async (t) => { assertSpyCalls(context.spies.step, 2); } finally { TestSuiteInternal.reset(); - test.restore(); } let fn = fns[0]; @@ -1632,7 +1626,7 @@ Deno.test("global", async (t) => { await t.step( "nested", async () => { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [spy(), spy()] as const; const { beforeAllFn, afterAllFn, beforeEachFn, afterEachFn } = hookFns(); @@ -1671,7 +1665,6 @@ Deno.test("global", async (t) => { assertSpyCalls(context.steps[0]!.spies.step, 2); } finally { TestSuiteInternal.reset(); - test.restore(); } let fn = fns[0]; @@ -1707,7 +1700,7 @@ Deno.test("global", async (t) => { await t.step( "nested with hooks", async () => { - const test = stub(Deno, "test"); + using test = stub(Deno, "test"); const fns = [ spy(function (this: NestedContext) { this.x = 2; @@ -1789,7 +1782,6 @@ Deno.test("global", async (t) => { assertSpyCalls(context.steps[0]!.spies.step, 2); } finally { TestSuiteInternal.reset(); - test.restore(); } let fn = fns[0]; diff --git a/testing/mock.ts b/testing/mock.ts index 06c6ba56140a..dd54052c87ab 100644 --- a/testing/mock.ts +++ b/testing/mock.ts @@ -114,6 +114,45 @@ * function was not modified in any way like the `_internals` object was in the * second example. * + * Method spys are disposable, meaning that you can have them automatically restore + * themselves with the `using` keyword. Using this approach is cleaner because you + * do not need to wrap your assertions in a try statement to ensure you restore the + * methods before the tests finish. + * + * ```ts + * import { + * assertSpyCall, + * assertSpyCalls, + * spy, + * } from "https://deno.land/std@$STD_VERSION/testing/mock.ts"; + * import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts"; + * + * function multiply(a: number, b: number): number { + * return a * b; + * } + * + * function square(value: number): number { + * return _internals.multiply(value, value); + * } + * + * const _internals = { multiply }; + * + * Deno.test("square calls multiply and returns results", () => { + * using multiplySpy = spy(_internals, "multiply"); + * + * assertEquals(square(5), 25); + * + * // asserts that multiplySpy was called at least once and details about the first call. + * assertSpyCall(multiplySpy, 0, { + * args: [5, 5], + * returned: 25, + * }); + * + * // asserts that multiplySpy was only called once. + * assertSpyCalls(multiplySpy, 1); + * }); + * ``` + * * ## Stubbing * * Say we have two functions, `randomMultiple` and `randomInt`, if we want to @@ -187,6 +226,52 @@ * }); * ``` * + * Like method spys, stubs are disposable, meaning that you can have them automatically + * restore themselves with the `using` keyword. Using this approach is cleaner because + * you do not need to wrap your assertions in a try statement to ensure you restore the + * methods before the tests finish. + * + * ```ts + * import { + * assertSpyCall, + * assertSpyCalls, + * returnsNext, + * stub, + * } from "https://deno.land/std@$STD_VERSION/testing/mock.ts"; + * import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts"; + * + * function randomInt(lowerBound: number, upperBound: number): number { + * return lowerBound + Math.floor(Math.random() * (upperBound - lowerBound)); + * } + * + * function randomMultiple(value: number): number { + * return value * _internals.randomInt(-10, 10); + * } + * + * const _internals = { randomInt }; + * + * Deno.test("randomMultiple uses randomInt to generate random multiples between -10 and 10 times the value", () => { + * using randomIntStub = stub(_internals, "randomInt", returnsNext([-3, 3])); + * + * assertEquals(randomMultiple(5), -15); + * assertEquals(randomMultiple(5), 15); + * + * // asserts that randomIntStub was called at least once and details about the first call. + * assertSpyCall(randomIntStub, 0, { + * args: [-10, 10], + * returned: -3, + * }); + * // asserts that randomIntStub was called at least twice and details about the second call. + * assertSpyCall(randomIntStub, 1, { + * args: [-10, 10], + * returned: 3, + * }); + * + * // asserts that randomIntStub was only called twice. + * assertSpyCalls(randomIntStub, 2); + * }); + * ``` + * * ## Faking time * * Say we have a function that has time based behavior that we would like to test. @@ -288,6 +373,16 @@ export interface Spy< restore(): void; } +/** An instance method wrapper that records all calls made to it. */ +export interface MethodSpy< + // deno-lint-ignore no-explicit-any + Self = any, + // deno-lint-ignore no-explicit-any + Args extends unknown[] = any[], + // deno-lint-ignore no-explicit-any + Return = any, +> extends Spy, Disposable {} + /** Wraps a function with a Spy. */ function functionSpy< Self, @@ -437,7 +532,7 @@ function methodSpy< Self, Args extends unknown[], Return, ->(self: Self, property: keyof Self): Spy { +>(self: Self, property: keyof Self): MethodSpy { if (typeof self[property] !== "function") { throw new MockError("property is not an instance method"); } @@ -468,7 +563,7 @@ function methodSpy< } calls.push(call); return call.returned; - } as Spy; + } as MethodSpy; Object.defineProperties(spy, { original: { enumerable: true, @@ -497,6 +592,11 @@ function methodSpy< unregisterMock(spy); }, }, + [Symbol.dispose]: { + value: () => { + spy.restore(); + }, + }, }); Object.defineProperty(self, property, { @@ -612,7 +712,11 @@ export function spy< >( self: Self, property: Prop, -): Spy, GetReturnFromProp>; +): MethodSpy< + Self, + GetParametersFromProp, + GetReturnFromProp +>; export function spy< Self, Args extends unknown[], @@ -647,7 +751,7 @@ export interface Stub< Args extends unknown[] = any[], // deno-lint-ignore no-explicit-any Return = any, -> extends Spy { +> extends MethodSpy { /** The function that is used instead of the original. */ fake: (this: Self, ...args: Args) => Return; } @@ -745,6 +849,11 @@ export function stub< unregisterMock(stub); }, }, + [Symbol.dispose]: { + value: () => { + stub.restore(); + }, + }, }); Object.defineProperty(self, property, { diff --git a/testing/mock_test.ts b/testing/mock_test.ts index 636c19410464..1de41775947f 100644 --- a/testing/mock_test.ts +++ b/testing/mock_test.ts @@ -13,6 +13,7 @@ import { assertSpyCallArgs, assertSpyCallAsync, assertSpyCalls, + MethodSpy, MockError, mockSession, mockSessionAsync, @@ -24,6 +25,7 @@ import { returnsThis, Spy, spy, + Stub, stub, } from "./mock.ts"; import { Point, PointWithExtra, stringifyPoint } from "./_test_utils.ts"; @@ -345,6 +347,109 @@ Deno.test("spy instance method property descriptor", () => { assertEquals(action.restored, true); }); +Deno.test("spy explicit resource management", () => { + const point = new Point(2, 3); + let funcRef: MethodSpy | null = null; + { + using func = spy(point, "action"); + funcRef = func; + assertSpyCalls(func, 0); + + assertEquals(func.call(point), undefined); + assertSpyCall(func, 0, { + self: point, + args: [], + returned: undefined, + }); + assertSpyCalls(func, 1); + + assertEquals(point.action(), undefined); + assertSpyCall(func, 1, { self: point, args: [] }); + assertSpyCalls(func, 2); + + assertEquals(func.call(point, "x"), "x"); + assertSpyCall(func, 2, { + self: point, + args: ["x"], + returned: "x", + }); + assertSpyCalls(func, 3); + + assertEquals(point.action("x"), "x"); + assertSpyCall(func, 3, { + self: point, + args: ["x"], + returned: "x", + }); + assertSpyCalls(func, 4); + + assertEquals(func.call(point, { x: 3 }), { x: 3 }); + assertSpyCall(func, 4, { + self: point, + args: [{ x: 3 }], + returned: { x: 3 }, + }); + assertSpyCalls(func, 5); + + assertEquals(point.action({ x: 3 }), { x: 3 }); + assertSpyCall(func, 5, { + self: point, + args: [{ x: 3 }], + returned: { x: 3 }, + }); + assertSpyCalls(func, 6); + + assertEquals(func.call(point, 3, 5, 7), 3); + assertSpyCall(func, 6, { + self: point, + args: [3, 5, 7], + returned: 3, + }); + assertSpyCalls(func, 7); + + assertEquals(point.action(3, 5, 7), 3); + assertSpyCall(func, 7, { + self: point, + args: [3, 5, 7], + returned: 3, + }); + assertSpyCalls(func, 8); + + assertEquals(func.call(point, Point, stringifyPoint, point), Point); + assertSpyCall(func, 8, { + self: point, + args: [Point, stringifyPoint, point], + returned: Point, + }); + assertSpyCalls(func, 9); + + assertEquals(point.action(Point, stringifyPoint, point), Point); + assertSpyCall(func, 9, { + self: point, + args: [Point, stringifyPoint, point], + returned: Point, + }); + assertSpyCalls(func, 10); + + assertNotEquals(func, Point.prototype.action); + assertEquals(point.action, func); + + assertEquals(func.restored, false); + } + if (funcRef) { + assertEquals(funcRef.restored, true); + assertEquals(point.action, Point.prototype.action); + assertThrows( + () => { + if (funcRef) funcRef.restore(); + }, + MockError, + "instance method already restored", + ); + assertEquals(funcRef.restored, true); + } +}); + Deno.test("spy constructor", () => { const PointSpy = spy(Point); assertSpyCalls(PointSpy, 0); @@ -480,6 +585,51 @@ Deno.test("stub function", () => { assertEquals(func.restored, true); }); +Deno.test("stub explicit resource management", () => { + const point = new Point(2, 3); + const returns = [1, "b", 2, "d"]; + let funcRef: Stub | null = null; + { + using func = stub(point, "action", () => returns.shift()); + funcRef = func; + + assertSpyCalls(func, 0); + + assertEquals(func.call(point), 1); + assertSpyCall(func, 0, { + self: point, + args: [], + returned: 1, + }); + assertSpyCalls(func, 1); + + assertEquals(point.action(), "b"); + assertSpyCall(func, 1, { + self: point, + args: [], + returned: "b", + }); + assertSpyCalls(func, 2); + + assertEquals(func.original, Point.prototype.action); + assertEquals(point.action, func); + + assertEquals(func.restored, false); + } + if (funcRef) { + assertEquals(funcRef.restored, true); + assertEquals(point.action, Point.prototype.action); + assertThrows( + () => { + if (funcRef) funcRef.restore(); + }, + MockError, + "instance method already restored", + ); + assertEquals(funcRef.restored, true); + } +}); + Deno.test("stub non existent function", () => { const point = new Point(2, 3); const castPoint = point as PointWithExtra; From f6c4447524fbbd4a3c64c61eea4146ec62f21536 Mon Sep 17 00:00:00 2001 From: mersey <73640929+javihernant@users.noreply.github.com> Date: Fri, 16 Feb 2024 11:34:29 +0100 Subject: [PATCH 30/63] chore(semver): rename range_test.ts (#4339) --- semver/{range_test.ts => test_range_test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename semver/{range_test.ts => test_range_test.ts} (100%) diff --git a/semver/range_test.ts b/semver/test_range_test.ts similarity index 100% rename from semver/range_test.ts rename to semver/test_range_test.ts From 453cc363706146bef5bbe730873346571c7ff658 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 16 Feb 2024 19:48:20 +0900 Subject: [PATCH 31/63] fix(semver): fix `prerelease` handlings in range utils (#4323) --- semver/_comparator_intersects.ts | 80 ++++++++++++++-------------- semver/_shared.ts | 10 ++++ semver/range_intersects_test.ts | 8 +++ semver/range_min_test.ts | 4 +- semver/test_range.ts | 89 ++++++++++++++++++++++++++------ semver/test_range_test.ts | 34 +++++------- 6 files changed, 145 insertions(+), 80 deletions(-) diff --git a/semver/_comparator_intersects.ts b/semver/_comparator_intersects.ts index f5df665dd656..72cbba2766a6 100644 --- a/semver/_comparator_intersects.ts +++ b/semver/_comparator_intersects.ts @@ -1,9 +1,9 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import type { Comparator } from "./types.ts"; -import { greaterOrEqual } from "./greater_or_equal.ts"; -import { lessOrEqual } from "./less_or_equal.ts"; -import { comparatorMin } from "./_comparator_min.ts"; -import { comparatorMax } from "./_comparator_max.ts"; +import { compare } from "./compare.ts"; +import { testRange } from "./test_range.ts"; +import { isWildcardComparator } from "./_shared.ts"; + /** * Returns true if the range of possible versions intersects with the other comparators set of possible versions * @param c0 The left side comparator @@ -14,41 +14,41 @@ export function comparatorIntersects( c0: Comparator, c1: Comparator, ): boolean { - const l0 = comparatorMin(c0); - const l1 = comparatorMax(c0); - const r0 = comparatorMin(c1); - const r1 = comparatorMax(c1); + const op0 = c0.operator; + const op1 = c1.operator; + + if (op0 === "" || op0 === undefined) { + // if c0 is empty comparator, then returns true + if (isWildcardComparator(c0)) { + return true; + } + return testRange(c0, [[c1]]); + } else if (op1 === "" || op1 === undefined) { + if (isWildcardComparator(c1)) { + return true; + } + return testRange(c1, [[c0]]); + } + + const cmp = compare(c0, c1); + + const sameDirectionIncreasing = (op0 === ">=" || op0 === ">") && + (op1 === ">=" || op1 === ">"); + const sameDirectionDecreasing = (op0 === "<=" || op0 === "<") && + (op1 === "<=" || op1 === "<"); + const sameSemVer = cmp === 0; + const differentDirectionsInclusive = (op0 === ">=" || op0 === "<=") && + (op1 === ">=" || op1 === "<="); + const oppositeDirectionsLessThan = cmp === -1 && + (op0 === ">=" || op0 === ">") && + (op1 === "<=" || op1 === "<"); + const oppositeDirectionsGreaterThan = cmp === 1 && + (op0 === "<=" || op0 === "<") && + (op1 === ">=" || op1 === ">"); - // We calculate the min and max ranges of both comparators. - // The minimum min is 0.0.0, the maximum max is ANY. - // - // Comparators with equality operators have the same min and max. - // - // We then check to see if the min's of either range falls within the span of the other range. - // - // A couple of intersection examples: - // ``` - // l0 ---- l1 - // r0 ---- r1 - // ``` - // ``` - // l0 ---- l1 - // r0 ---- r1 - // ``` - // ``` - // l0 ------ l1 - // r0--r1 - // ``` - // ``` - // l0 - l1 - // r0 - r1 - // ``` - // - // non-intersection example - // ``` - // l0 -- l1 - // r0 -- r1 - // ``` - return (greaterOrEqual(l0, r0) && lessOrEqual(l0, r1)) || - (greaterOrEqual(r0, l0) && lessOrEqual(r0, l1)); + return sameDirectionIncreasing || + sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || + oppositeDirectionsGreaterThan; } diff --git a/semver/_shared.ts b/semver/_shared.ts index 2543ca23b98d..f31f5366e9d5 100644 --- a/semver/_shared.ts +++ b/semver/_shared.ts @@ -1,5 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +import { type Comparator } from "./types.ts"; + export function compareNumber( a: number, b: number, @@ -188,3 +190,11 @@ export function parseNumber(input: string, errorMessage: string) { if (!isValidNumber(number)) throw new TypeError(errorMessage); return number; } + +export function isWildcardComparator(c: Comparator): boolean { + return ( + Number.isNaN(c.major) && Number.isNaN(c.minor) && Number.isNaN(c.patch) && + (c.prerelease === undefined || c.prerelease.length === 0) && + (c.build === undefined || c.build.length === 0) + ); +} diff --git a/semver/range_intersects_test.ts b/semver/range_intersects_test.ts index dd24b55459bf..65b2fb6a59ba 100644 --- a/semver/range_intersects_test.ts +++ b/semver/range_intersects_test.ts @@ -29,6 +29,14 @@ Deno.test({ ], [">=1.0.0", "<=1.0.0", true], [">1.0.0 <1.0.0", "<=0.0.0", false], + // Pre-release ranges + ["<1.0.0", ">1.0.0-5", true], + [">1.0.0", "<1.0.0-5", false], + [">1.0.0-2", "<=1.0.0-5", true], + [">=1.0.0-2", "<1.0.0-5", true], + ["<7.0.0-beta.20", ">7.0.0-beta.0", true], + ["<7.0.0-beta.beta", ">7.0.0-beta.alpha", true], + // Wildcards ["*", "0.0.1", true], ["*", ">=1.0.0", true], ["*", ">1.0.0", true], diff --git a/semver/range_min_test.ts b/semver/range_min_test.ts index c71c257dc9a3..2d57862fc82c 100644 --- a/semver/range_min_test.ts +++ b/semver/range_min_test.ts @@ -55,8 +55,8 @@ Deno.test({ [">4 || <2", "0.0.0"], ["<=2 || >=4", "0.0.0"], [">=4 || <=2", "0.0.0"], - ["<0.0.0-beta >0.0.0-alpha", INVALID], - [">0.0.0-alpha <0.0.0-beta", INVALID], + ["<0.0.0-beta >=0.0.0-alpha", "0.0.0-alpha"], + [">=0.0.0-alpha <0.0.0-beta", "0.0.0-alpha"], // Greater than or equal [">=1.1.1 <2 || >=2.2.2 <2", "1.1.1"], diff --git a/semver/test_range.ts b/semver/test_range.ts index 047e94991097..92094b828406 100644 --- a/semver/test_range.ts +++ b/semver/test_range.ts @@ -1,9 +1,76 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import type { Range, SemVer } from "./types.ts"; -import { greaterOrEqual } from "./greater_or_equal.ts"; -import { lessOrEqual } from "./less_or_equal.ts"; -import { comparatorMin } from "./_comparator_min.ts"; -import { comparatorMax } from "./_comparator_max.ts"; +import type { Comparator, Range, SemVer } from "./types.ts"; +import { compare } from "./compare.ts"; +import { isWildcardComparator } from "./_shared.ts"; + +function testComparator(version: SemVer, comparator: Comparator): boolean { + if (isWildcardComparator(comparator)) { + return true; + } + const cmp = compare(version, comparator.semver ?? comparator); + switch (comparator.operator) { + case "": + case "=": + case "==": + case "===": + case undefined: { + return cmp === 0; + } + case "!=": + case "!==": { + return cmp !== 0; + } + case ">": { + return cmp > 0; + } + case "<": { + return cmp < 0; + } + case ">=": { + return cmp >= 0; + } + case "<=": { + return cmp <= 0; + } + } +} + +function testComparatorSet( + version: SemVer, + set: Comparator[], +): boolean { + for (const comparator of set) { + if (!testComparator(version, comparator)) { + return false; + } + } + if (version.prerelease && version.prerelease.length > 0) { + // Find the comparator that is allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (const comparator of set) { + if (isWildcardComparator(comparator)) { + continue; + } + const { prerelease } = comparator.semver ?? comparator; + if (prerelease && prerelease.length > 0) { + const major = comparator.semver?.major ?? comparator.major; + const minor = comparator.semver?.minor ?? comparator.minor; + const patch = comparator.semver?.patch ?? comparator.patch; + if ( + version.major === major && version.minor === minor && + version.patch === patch + ) { + return true; + } + } + } + return false; + } + return true; +} /** * Test to see if the version satisfies the range. @@ -15,15 +82,5 @@ export function testRange( version: SemVer, range: Range, ): boolean { - for (const r of range) { - if ( - r.every((c) => - greaterOrEqual(version, comparatorMin(c)) && - lessOrEqual(version, comparatorMax(c)) - ) - ) { - return true; - } - } - return false; + return range.some((set) => testComparatorSet(version, set)); } diff --git a/semver/test_range_test.ts b/semver/test_range_test.ts index eb13f708b498..0f2afc97f374 100644 --- a/semver/test_range_test.ts +++ b/semver/test_range_test.ts @@ -5,7 +5,7 @@ import { parse } from "./parse.ts"; import { parseRange } from "./parse_range.ts"; import { testRange } from "./test_range.ts"; -Deno.test("range", async (t) => { +Deno.test("testRange() returns true when the version is in the range", async (t) => { const versions: [string, string][] = [ ["1.0.0 - 2.0.0", "1.2.3"], ["^1.2.3+build", "1.2.3"], @@ -13,7 +13,6 @@ Deno.test("range", async (t) => { ["1.2.3-pre+asdf - 2.4.3-pre+asdf", "1.2.3"], ["1.2.3-pre+asdf - 2.4.3-pre+asdf", "1.2.3-pre.2"], ["1.2.3-pre+asdf - 2.4.3-pre+asdf", "2.4.3-alpha"], - ["1.2.3+asdf - 2.4.3+asdf", "2.4.3-alpha"], ["1.2.3+asdf - 2.4.3+asdf", "2.4.3"], ["1.0.0", "1.0.0"], [">=*", "0.2.4"], @@ -71,7 +70,6 @@ Deno.test("range", async (t) => { ["1.2.3 >=1.2.1", "1.2.3"], [">=1.2.3 >=1.2.1", "1.2.3"], [">=1.2.1 >=1.2.3", "1.2.3"], - ["<=1.2.3", "1.2.3-beta"], [">=1.2", "1.2.8"], ["^1.2.3", "1.8.1"], ["^0.1.2", "0.1.2"], @@ -102,7 +100,7 @@ Deno.test("range", async (t) => { }); Deno.test({ - name: "negativeRange", + name: "testRange() returns false when the version is not in the range", fn: async (t) => { const versions: [string, string][] = [ ["1.0.0 - 2.0.0", "2.2.3"], @@ -110,6 +108,7 @@ Deno.test({ ["^1.2.3+build", "2.0.0"], ["^1.2.3+build", "1.2.0"], ["1.2.3-pre+asdf - 2.4.3-pre+asdf", "2.4.3"], + ["1.2.3+asdf - 2.4.3+asdf", "2.4.3-alpha"], ["^1.2.3", "1.2.3-pre"], ["^1.2", "1.2.0-pre"], [">1.2", "1.3.0-beta"], @@ -169,6 +168,14 @@ Deno.test({ ["^1.2.3", "1.2.2"], ["^1.2", "1.1.9"], + // unsatisfiable patterns with prereleases + ["*", "1.0.0-rc1"], + ["^1.0.0-0", "1.0.1-rc1"], + ["^1.0.0-rc2", "1.0.1-rc1"], + ["^1.0.0", "1.0.1-rc1"], + ["^1.0.0", "1.1.0-rc1"], + ["<=1.2.3", "1.2.3-beta"], + // invalid ranges never satisfied! ["blerg", "1.2.3"], ["^1.2.3", "2.0.0-pre"], @@ -185,28 +192,11 @@ Deno.test({ }, }); -Deno.test("unlockedPrereleaseRange", function () { - const versions: [string, string][] = [ - ["*", "1.0.0-rc1"], - ["^1.0.0-0", "1.0.1-rc1"], - ["^1.0.0-rc2", "1.0.1-rc1"], - ["^1.0.0", "1.0.1-rc1"], - ["^1.0.0", "1.1.0-rc1"], - ]; - - for (const [r, v] of versions) { - const range = parseRange(r); - const s = parse(v); - const found = testRange(s, range); - assert(found, `${r} not satisfied by ${v}`); - } -}); - Deno.test("negativeUnlockedPrereleaseRange", function () { const versions: [string, string][] = [ ["^1.0.0", "1.0.0-rc1"], ["^1.2.3-rc2", "2.0.0"], - ["^1.0.0", "2.0.0-rc1"], // todo: review, this is inverted from original test case + ["^1.0.0", "2.0.0-rc1"], ]; for (const [r, v] of versions) { From f3cce1b01791951c17da68a296d36cae496be7ae Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Sat, 17 Feb 2024 14:33:19 +1100 Subject: [PATCH 32/63] fix(http): `version` from `deno.json` import (#4342) --- _tools/convert_to_workspace.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/_tools/convert_to_workspace.ts b/_tools/convert_to_workspace.ts index b57e30231a1c..35527bac550d 100644 --- a/_tools/convert_to_workspace.ts +++ b/_tools/convert_to_workspace.ts @@ -43,21 +43,24 @@ await Deno.writeTextFile("README.md", readme); let fileServer = await Deno.readTextFile("http/file_server.ts"); fileServer = fileServer.replace( `import { VERSION } from "../version.ts";`, - `import { version } from "./deno.json" with { type: "json" };`, + `import denoConfig from "./deno.json" with { type: "json" };`, ); -fileServer = fileServer.replaceAll("${VERSION}", "${version}"); +fileServer = fileServer.replaceAll("${VERSION}", "${denoConfig.version}"); fileServer = fileServer.replace( "https://deno.land/std/http/file_server.ts", - "jsr:@std/http@${version}/file_server", + "jsr:@std/http@${denoConfig.version}/file_server", ); await Deno.writeTextFile("http/file_server.ts", fileServer); let fileServerTest = await Deno.readTextFile("http/file_server_test.ts"); fileServerTest = fileServerTest.replace( `import { VERSION } from "../version.ts";`, - `import { version } from "./deno.json" with { type: "json" };`, + `import denoConfig from "./deno.json" with { type: "json" };`, +); +fileServerTest = fileServerTest.replaceAll( + "${VERSION}", + "${denoConfig.version}", ); -fileServerTest = fileServerTest.replaceAll("${VERSION}", "${version}"); await Deno.writeTextFile("http/file_server_test.ts", fileServerTest); const packages = await discoverPackages(); From 4e0db3fb3b81cff55dfaf785b38cab0361484819 Mon Sep 17 00:00:00 2001 From: Nicholas Berlette Date: Sat, 17 Feb 2024 20:32:35 -0800 Subject: [PATCH 33/63] docs(media_types): fix erroneous docs in extensions_by_type.ts (#4347) --- media_types/extensions_by_type.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/media_types/extensions_by_type.ts b/media_types/extensions_by_type.ts index fb0452206102..6e8e11bf3e75 100644 --- a/media_types/extensions_by_type.ts +++ b/media_types/extensions_by_type.ts @@ -8,8 +8,6 @@ export { extensions }; /** * Returns the extensions known to be associated with the media type `type`. - * The returned extensions will each begin with a leading dot, as in `.html`. - * * When `type` has no associated extensions, the function returns `undefined`. * * Extensions are returned without a leading `.`. From 24abc640f7e48cc469e0880e6087d19695fc25c1 Mon Sep 17 00:00:00 2001 From: mersey <73640929+javihernant@users.noreply.github.com> Date: Sun, 18 Feb 2024 07:15:41 +0100 Subject: [PATCH 34/63] fix(semver): fix parse_range for `>x.y` pattern (#4350) Co-authored-by: Yoshiya Hinosawa --- semver/parse_range.ts | 8 +++----- semver/test_range_test.ts | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/semver/parse_range.ts b/semver/parse_range.ts index c491c95d991f..94cfb09c4836 100644 --- a/semver/parse_range.ts +++ b/semver/parse_range.ts @@ -187,14 +187,12 @@ function handleGreaterThanOperator(groups: RegExpGroups): Comparator[] { const patch = +groups.patch; if (majorIsWildcard) return [{ operator: "<", major: 0, minor: 0, patch: 0 }]; + if (minorIsWildcard) { - if (patchIsWildcard) { - return [{ operator: ">=", major: major + 1, minor: 0, patch: 0 }]; - } - return [{ operator: ">", major: major + 1, minor: 0, patch: 0 }]; + return [{ operator: ">=", major: major + 1, minor: 0, patch: 0 }]; } if (patchIsWildcard) { - return [{ operator: ">", major: major + 1, minor: 0, patch: 0 }]; + return [{ operator: ">=", major, minor: minor + 1, patch: 0 }]; } const prerelease = parsePrerelease(groups.prerelease ?? ""); const build = parseBuild(groups.build ?? ""); diff --git a/semver/test_range_test.ts b/semver/test_range_test.ts index 0f2afc97f374..1ddc5ffae3a5 100644 --- a/semver/test_range_test.ts +++ b/semver/test_range_test.ts @@ -71,6 +71,7 @@ Deno.test("testRange() returns true when the version is in the range", async (t) [">=1.2.3 >=1.2.1", "1.2.3"], [">=1.2.1 >=1.2.3", "1.2.3"], [">=1.2", "1.2.8"], + [">1.2", "1.3.0"], ["^1.2.3", "1.8.1"], ["^0.1.2", "0.1.2"], ["^0.1", "0.1.2"], From dd89077f99991e6e647fc4b730f166e70fe55c2e Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Sun, 18 Feb 2024 07:43:09 +0100 Subject: [PATCH 35/63] deprecation(semver): deprecate `==`, `===`, `!==`, and `""` operators (#4271) Co-authored-by: Yoshiya Hinosawa --- semver/_comparator_format.ts | 4 +++- semver/_comparator_max.ts | 3 ++- semver/_comparator_min.ts | 1 + semver/_constants.ts | 3 +++ semver/_is_comparator.ts | 3 ++- semver/_parse_comparator.ts | 9 ++------- semver/parse_range.ts | 2 +- semver/types.ts | 3 ++- 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/semver/_comparator_format.ts b/semver/_comparator_format.ts index a74d344db232..ae3e2f459516 100644 --- a/semver/_comparator_format.ts +++ b/semver/_comparator_format.ts @@ -10,5 +10,7 @@ import { format } from "./format.ts"; */ export function comparatorFormat(comparator: Comparator): string { const { semver, operator } = comparator; - return `${operator}${format(semver ?? comparator)}`; + return `${operator === undefined ? "" : operator}${ + format(semver ?? comparator) + }`; } diff --git a/semver/_comparator_max.ts b/semver/_comparator_max.ts index f5d06b265911..f18a1ad272bf 100644 --- a/semver/_comparator_max.ts +++ b/semver/_comparator_max.ts @@ -19,9 +19,10 @@ export function comparatorMax(comparator: Comparator): SemVer { case ">=": return MAX; case "": - case "=": case "==": case "===": + case undefined: + case "=": case "<=": return { major: semver.major, diff --git a/semver/_comparator_min.ts b/semver/_comparator_min.ts index cd683842d2ee..fb206442454d 100644 --- a/semver/_comparator_min.ts +++ b/semver/_comparator_min.ts @@ -25,6 +25,7 @@ export function comparatorMin(comparator: Comparator): SemVer { // The min(<0.0.0) is MAX return greaterThan(semver, MIN) ? MIN : MAX; case ">=": + case undefined: case "": case "=": case "==": diff --git a/semver/_constants.ts b/semver/_constants.ts index c45da36249cf..0bdfad061246 100644 --- a/semver/_constants.ts +++ b/semver/_constants.ts @@ -1,5 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +/** + * @deprecated (will be removed in 0.219.0) `"=="`, `"==="`, `"!=="` and `""` operators are deprecated. Use `"="`, `"!="` or `undefined` instead. + */ export const OPERATORS = [ "", "=", diff --git a/semver/_is_comparator.ts b/semver/_is_comparator.ts index e3a1a03a64d6..a4c3c7417b83 100644 --- a/semver/_is_comparator.ts +++ b/semver/_is_comparator.ts @@ -22,7 +22,8 @@ export function isComparator(value: unknown): value is Comparator { if (value === NONE || value === ALL) return true; const { operator, semver } = value as Comparator; return ( - OPERATORS.includes(operator) && + (operator === undefined || + OPERATORS.includes(operator)) && isSemVer(semver) ); } diff --git a/semver/_parse_comparator.ts b/semver/_parse_comparator.ts index b49396290b26..b174657547fb 100644 --- a/semver/_parse_comparator.ts +++ b/semver/_parse_comparator.ts @@ -28,12 +28,7 @@ export function parseComparator(comparator: string): Comparator { if (!groups) return NONE; - const { - operator = "", - - prerelease, - buildmetadata, - } = groups as REGEXP_GROUPS; + const { operator, prerelease, buildmetadata } = groups as REGEXP_GROUPS; const semver = groups.major ? { @@ -45,5 +40,5 @@ export function parseComparator(comparator: string): Comparator { } : ANY; - return { operator, ...semver, semver }; + return { operator: operator || undefined, ...semver, semver }; } diff --git a/semver/parse_range.ts b/semver/parse_range.ts index 94cfb09c4836..94c88d5c0c0b 100644 --- a/semver/parse_range.ts +++ b/semver/parse_range.ts @@ -241,7 +241,7 @@ function handleEqualOperator(groups: RegExpGroups): Comparator[] { } const prerelease = parsePrerelease(groups.prerelease ?? ""); const build = parseBuild(groups.build ?? ""); - return [{ operator: "", major, minor, patch, prerelease, build }]; + return [{ operator: undefined, major, minor, patch, prerelease, build }]; } function parseRangeString(string: string) { diff --git a/semver/types.ts b/semver/types.ts index 8285ea5d86cc..8e0f1e9bdfd4 100644 --- a/semver/types.ts +++ b/semver/types.ts @@ -18,6 +18,7 @@ export type ReleaseType = /** * SemVer comparison operators. + * @deprecated (will be removed in 0.219.0) `"=="`, `"==="`, `"!=="` and `""` operators are deprecated. Use `"="`, `"!="` or `undefined` instead. */ export type Operator = typeof OPERATORS[number]; @@ -26,7 +27,7 @@ export type Operator = typeof OPERATORS[number]; * @example >=0.0.0 */ export interface Comparator extends SemVer { - operator: Operator; + operator?: Operator; /** * @deprecated (will be removed after 0.217.0) {@linkcode Comparator} extends {@linkcode SemVer}. Use `major`, `minor`, `patch`, `prerelease`, and `build` properties instead. */ From 253e329d1dc0d112221b8888229b67494f3afa02 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Mon, 19 Feb 2024 16:34:51 +1100 Subject: [PATCH 36/63] feat(io): un-deprecate `readerFromStreamReader()` (#4343) * feat(io): un-deprecate `readerFromStreamReader()` * adjust removal version --- io/mod.ts | 1 + io/reader_from_stream_reader.ts | 42 +++++++++++++ io/reader_from_stream_reader_test.ts | 94 ++++++++++++++++++++++++++++ streams/reader_from_stream_reader.ts | 22 +------ 4 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 io/reader_from_stream_reader.ts create mode 100644 io/reader_from_stream_reader_test.ts diff --git a/io/mod.ts b/io/mod.ts index c172819dfae3..393a7856f16a 100644 --- a/io/mod.ts +++ b/io/mod.ts @@ -24,6 +24,7 @@ export * from "./read_long.ts"; export * from "./read_range.ts"; export * from "./read_short.ts"; export * from "./read_string_delim.ts"; +export * from "./reader_from_stream_reader.ts"; export * from "./slice_long_to_bytes.ts"; export * from "./string_reader.ts"; export * from "./string_writer.ts"; diff --git a/io/reader_from_stream_reader.ts b/io/reader_from_stream_reader.ts new file mode 100644 index 000000000000..4817650bae00 --- /dev/null +++ b/io/reader_from_stream_reader.ts @@ -0,0 +1,42 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { Buffer } from "./buffer.ts"; +import { writeAll } from "./write_all.ts"; +import type { Reader } from "./types.ts"; + +/** + * Create a {@linkcode Reader} from a {@linkcode ReadableStreamDefaultReader}. + * + * @example + * ```ts + * import { copy } from "https://deno.land/std@$STD_VERSION/io/copy.ts"; + * import { readerFromStreamReader } from "https://deno.land/std@$STD_VERSION/io/reader_from_stream_reader.ts"; + * + * const res = await fetch("https://deno.land"); + * using file = await Deno.open("./deno.land.html", { create: true, write: true }); + * + * const reader = readerFromStreamReader(res.body!.getReader()); + * await copy(reader, file); + * ``` + */ +export function readerFromStreamReader( + streamReader: ReadableStreamDefaultReader, +): Reader { + const buffer = new Buffer(); + + return { + async read(p: Uint8Array): Promise { + if (buffer.empty()) { + const res = await streamReader.read(); + if (res.done) { + return null; // EOF + } + + await writeAll(buffer, res.value); + } + + return buffer.read(p); + }, + }; +} diff --git a/io/reader_from_stream_reader_test.ts b/io/reader_from_stream_reader_test.ts new file mode 100644 index 000000000000..ceead382e1ad --- /dev/null +++ b/io/reader_from_stream_reader_test.ts @@ -0,0 +1,94 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { assert, assertEquals } from "../assert/mod.ts"; +import { copy } from "./copy.ts"; +import { readerFromStreamReader } from "./reader_from_stream_reader.ts"; +import { Buffer } from "./buffer.ts"; + +function repeat(c: string, bytes: number): Uint8Array { + assertEquals(c.length, 1); + const ui8 = new Uint8Array(bytes); + ui8.fill(c.charCodeAt(0)); + return ui8; +} + +Deno.test("[streams] readerFromStreamReader()", async function () { + const chunks: string[] = ["hello", "deno", "land"]; + const expected = chunks.slice(); + const readChunks: Uint8Array[] = []; + const readableStream = ReadableStream.from(chunks) + .pipeThrough(new TextEncoderStream()); + + const decoder = new TextDecoder(); + const reader = readerFromStreamReader(readableStream.getReader()); + + let i = 0; + + while (true) { + const b = new Uint8Array(1024); + const n = await reader.read(b); + + if (n === null) break; + + readChunks.push(b.subarray(0, n)); + assert(i < expected.length); + + i++; + } + + assertEquals( + expected, + readChunks.map((chunk) => decoder.decode(chunk)), + ); +}); + +Deno.test("[streams] readerFromStreamReader() big chunks", async function () { + const bufSize = 1024; + const chunkSize = 3 * bufSize; + const writer = new Buffer(); + + // A readable stream can enqueue chunks bigger than Copy bufSize + // Reader returned by toReader should enqueue exceeding bytes + const chunks: string[] = [ + "a".repeat(chunkSize), + "b".repeat(chunkSize), + "c".repeat(chunkSize), + ]; + const expected = chunks.slice(); + const readableStream = ReadableStream.from(chunks) + .pipeThrough(new TextEncoderStream()); + + const reader = readerFromStreamReader(readableStream.getReader()); + const n = await copy(reader, writer, { bufSize }); + + const expectedWritten = chunkSize * expected.length; + assertEquals(n, chunkSize * expected.length); + assertEquals(writer.length, expectedWritten); +}); + +Deno.test("[streams] readerFromStreamReader() irregular chunks", async function () { + const bufSize = 1024; + const chunkSize = 3 * bufSize; + const writer = new Buffer(); + + // A readable stream can enqueue chunks bigger than Copy bufSize + // Reader returned by toReader should enqueue exceeding bytes + const chunks: Uint8Array[] = [ + repeat("a", chunkSize), + repeat("b", chunkSize + 253), + repeat("c", chunkSize + 8), + ]; + const expected = new Uint8Array( + chunks + .slice() + .map((chunk) => [...chunk]) + .flat(), + ); + const readableStream = ReadableStream.from(chunks); + + const reader = readerFromStreamReader(readableStream.getReader()); + + const n = await copy(reader, writer, { bufSize }); + assertEquals(n, expected.length); + assertEquals(expected, writer.bytes()); +}); diff --git a/streams/reader_from_stream_reader.ts b/streams/reader_from_stream_reader.ts index 54142cb6e9fc..28571361b5cb 100644 --- a/streams/reader_from_stream_reader.ts +++ b/streams/reader_from_stream_reader.ts @@ -1,8 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. -import { Buffer } from "../io/buffer.ts"; -import { writeAll } from "../io/write_all.ts"; +import { readerFromStreamReader as _readerFromStreamReader } from "../io/reader_from_stream_reader.ts"; import type { Reader } from "../io/types.ts"; /** @@ -20,25 +19,10 @@ import type { Reader } from "../io/types.ts"; * await copy(reader, file); * ``` * - * @deprecated (will be removed after 1.0.0) Use {@linkcode ReadableStreamDefaultReader} directly. + * @deprecated (will be removed in 1.0.0) Import from {@link https://deno.land/std/io/reader_from_stream_reader.ts} instead. */ export function readerFromStreamReader( streamReader: ReadableStreamDefaultReader, ): Reader { - const buffer = new Buffer(); - - return { - async read(p: Uint8Array): Promise { - if (buffer.empty()) { - const res = await streamReader.read(); - if (res.done) { - return null; // EOF - } - - await writeAll(buffer, res.value); - } - - return buffer.read(p); - }, - }; + return _readerFromStreamReader(streamReader); } From 505285141892231f07b7c7cef814d9b9a16e377a Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Mon, 19 Feb 2024 14:49:58 +0900 Subject: [PATCH 37/63] fix(media_types): load extensions when directly importing `extensionsByTypes()` (#4351) --- media_types/extensions_by_type.ts | 1 + media_types/extensions_by_type_test.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/media_types/extensions_by_type.ts b/media_types/extensions_by_type.ts index 6e8e11bf3e75..9ea141b8a536 100644 --- a/media_types/extensions_by_type.ts +++ b/media_types/extensions_by_type.ts @@ -3,6 +3,7 @@ import { parseMediaType } from "./parse_media_type.ts"; import { extensions } from "./_util.ts"; +import "./_db.ts"; export { extensions }; diff --git a/media_types/extensions_by_type_test.ts b/media_types/extensions_by_type_test.ts index c9acbe829c7a..1b1185c865e8 100644 --- a/media_types/extensions_by_type_test.ts +++ b/media_types/extensions_by_type_test.ts @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { assertEquals } from "../assert/mod.ts"; -import { extensionsByType } from "./mod.ts"; +import { extensionsByType } from "./extensions_by_type.ts"; Deno.test({ name: "media_types - extensionsByType()", From 8205edc184f6320ac620b7a1189ec436cd3c9f00 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Mon, 19 Feb 2024 14:50:30 +0900 Subject: [PATCH 38/63] test(semver): add test for fix #4350 (#4352) --- semver/test_range_test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/semver/test_range_test.ts b/semver/test_range_test.ts index 1ddc5ffae3a5..ed99681adcc2 100644 --- a/semver/test_range_test.ts +++ b/semver/test_range_test.ts @@ -72,6 +72,7 @@ Deno.test("testRange() returns true when the version is in the range", async (t) [">=1.2.1 >=1.2.3", "1.2.3"], [">=1.2", "1.2.8"], [">1.2", "1.3.0"], + [">1.x.0", "2.0.0"], ["^1.2.3", "1.8.1"], ["^0.1.2", "0.1.2"], ["^0.1", "0.1.2"], From a828744083e2c0d7bca7e1b764f352ac1b7f7922 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Mon, 19 Feb 2024 21:24:22 +1100 Subject: [PATCH 39/63] feat(io): `iterateReader[Sync]()` (#4247) --- io/iterate_reader.ts | 104 +++++++++++++++++++++++++++++++++++ io/iterate_reader_test.ts | 111 ++++++++++++++++++++++++++++++++++++++ io/mod.ts | 1 + io/types.ts | 10 ++-- streams/iterate_reader.ts | 35 ++++-------- 5 files changed, 232 insertions(+), 29 deletions(-) create mode 100644 io/iterate_reader.ts create mode 100644 io/iterate_reader_test.ts diff --git a/io/iterate_reader.ts b/io/iterate_reader.ts new file mode 100644 index 000000000000..d9d370127405 --- /dev/null +++ b/io/iterate_reader.ts @@ -0,0 +1,104 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +// This module is browser compatible. + +import { DEFAULT_BUFFER_SIZE } from "./_constants.ts"; +import type { Reader, ReaderSync } from "./types.ts"; + +export type { Reader, ReaderSync }; + +/** + * Turns a {@linkcode Reader} into an async iterator. + * + * @example + * ```ts + * import { iterateReader } from "https://deno.land/std@$STD_VERSION/io/iterate_reader.ts"; + * + * using file = await Deno.open("/etc/passwd"); + * for await (const chunk of iterateReader(file)) { + * console.log(chunk); + * } + * ``` + * + * Second argument can be used to tune size of a buffer. + * Default size of the buffer is 32kB. + * + * @example + * ```ts + * import { iterateReader } from "https://deno.land/std@$STD_VERSION/io/iterate_reader.ts"; + * + * using file = await Deno.open("/etc/passwd"); + * const iter = iterateReader(file, { + * bufSize: 1024 * 1024 + * }); + * for await (const chunk of iter) { + * console.log(chunk); + * } + * ``` + */ +export async function* iterateReader( + reader: Reader, + options?: { + bufSize?: number; + }, +): AsyncIterableIterator { + const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; + const b = new Uint8Array(bufSize); + while (true) { + const result = await reader.read(b); + if (result === null) { + break; + } + + yield b.slice(0, result); + } +} + +/** + * Turns a {@linkcode ReaderSync} into an iterator. + * + * ```ts + * import { iterateReaderSync } from "https://deno.land/std@$STD_VERSION/io/iterate_reader.ts"; + * + * using file = Deno.openSync("/etc/passwd"); + * for (const chunk of iterateReaderSync(file)) { + * console.log(chunk); + * } + * ``` + * + * Second argument can be used to tune size of a buffer. + * Default size of the buffer is 32kB. + * + * ```ts + * import { iterateReaderSync } from "https://deno.land/std@$STD_VERSION/io/iterate_reader.ts"; + + * using file = await Deno.open("/etc/passwd"); + * const iter = iterateReaderSync(file, { + * bufSize: 1024 * 1024 + * }); + * for (const chunk of iter) { + * console.log(chunk); + * } + * ``` + * + * Iterator uses an internal buffer of fixed size for efficiency; it returns + * a view on that buffer on each iteration. It is therefore caller's + * responsibility to copy contents of the buffer if needed; otherwise the + * next iteration will overwrite contents of previously returned chunk. + */ +export function* iterateReaderSync( + reader: ReaderSync, + options?: { + bufSize?: number; + }, +): IterableIterator { + const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; + const b = new Uint8Array(bufSize); + while (true) { + const result = reader.readSync(b); + if (result === null) { + break; + } + + yield b.slice(0, result); + } +} diff --git a/io/iterate_reader_test.ts b/io/iterate_reader_test.ts new file mode 100644 index 000000000000..b2adea11051b --- /dev/null +++ b/io/iterate_reader_test.ts @@ -0,0 +1,111 @@ +import { assertEquals } from "../assert/assert_equals.ts"; +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { iterateReader, iterateReaderSync } from "./iterate_reader.ts"; +import { readerFromIterable } from "../streams/reader_from_iterable.ts"; +import { delay } from "../async/delay.ts"; +import type { Reader, ReaderSync } from "./types.ts"; + +Deno.test("iterateReader()", async () => { + // ref: https://github.com/denoland/deno/issues/2330 + const encoder = new TextEncoder(); + + class TestReader implements Reader { + #offset = 0; + #buf: Uint8Array; + + constructor(s: string) { + this.#buf = new Uint8Array(encoder.encode(s)); + } + + read(p: Uint8Array): Promise { + const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset); + p.set(this.#buf.slice(this.#offset, this.#offset + n)); + this.#offset += n; + + if (n === 0) { + return Promise.resolve(null); + } + + return Promise.resolve(n); + } + } + + const reader = new TestReader("hello world!"); + + let totalSize = 0; + await Array.fromAsync( + iterateReader(reader), + (buf) => totalSize += buf.byteLength, + ); + + assertEquals(totalSize, 12); +}); + +Deno.test("iterateReader() works with slow consumer", async () => { + const a = new Uint8Array([97]); + const b = new Uint8Array([98]); + const iter = iterateReader(readerFromIterable([a, b])); + const promises = []; + for await (const bytes of iter) { + promises.push(delay(10).then(() => bytes)); + } + assertEquals([a, b], await Promise.all(promises)); +}); + +Deno.test("iterateReaderSync()", () => { + // ref: https://github.com/denoland/deno/issues/2330 + const encoder = new TextEncoder(); + + class TestReader implements ReaderSync { + #offset = 0; + #buf: Uint8Array; + + constructor(s: string) { + this.#buf = new Uint8Array(encoder.encode(s)); + } + + readSync(p: Uint8Array): number | null { + const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset); + p.set(this.#buf.slice(this.#offset, this.#offset + n)); + this.#offset += n; + + if (n === 0) { + return null; + } + + return n; + } + } + + const reader = new TestReader("hello world!"); + + let totalSize = 0; + for (const buf of iterateReaderSync(reader)) { + totalSize += buf.byteLength; + } + + assertEquals(totalSize, 12); +}); + +Deno.test("iterateReaderSync() works with slow consumer", async () => { + const a = new Uint8Array([97]); + const b = new Uint8Array([98]); + const data = [a, b]; + const readerSync = { + readSync(u8: Uint8Array) { + const bytes = data.shift(); + if (bytes) { + u8.set(bytes); + return bytes.length; + } + return null; + }, + }; + const iter = iterateReaderSync(readerSync); + const promises = []; + for (const bytes of iter) { + promises.push(delay(10).then(() => bytes)); + } + assertEquals([a, b], await Promise.all(promises)); +}); diff --git a/io/mod.ts b/io/mod.ts index 393a7856f16a..56750e0df945 100644 --- a/io/mod.ts +++ b/io/mod.ts @@ -14,6 +14,7 @@ export * from "./buf_writer.ts"; export * from "./buffer.ts"; export * from "./copy.ts"; export * from "./copy_n.ts"; +export * from "./iterate_reader.ts"; export * from "./limited_reader.ts"; export * from "./multi_reader.ts"; export * from "./read_all.ts"; diff --git a/io/types.ts b/io/types.ts index 5bf45f057bf5..5e0fac6eae93 100644 --- a/io/types.ts +++ b/io/types.ts @@ -24,8 +24,9 @@ export interface Reader { * * Implementations should not retain a reference to `p`. * - * Use iterateReader() from https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts to turn a Reader into an - * AsyncIterator. + * Use + * {@linkcode https://deno.land/std@$STD_VERSION/io/to_iterator.ts?s=toIterator} + * to turn a {@linkcode Reader} into an {@linkcode AsyncIterableIterator}. */ read(p: Uint8Array): Promise; } @@ -52,8 +53,9 @@ export interface ReaderSync { * * Implementations should not retain a reference to `p`. * - * Use iterateReaderSync() from https://deno.land/std@$STD_VERSION/streams/iterate_reader.ts to turn a ReaderSync - * into an Iterator. + * Use + * {@linkcode https://deno.land/std@$STD_VERSION/io/to_iterator.ts?s=toIteratorSync} + * to turn a {@linkcode ReaderSync} into an {@linkcode IterableIterator}. */ readSync(p: Uint8Array): number | null; } diff --git a/streams/iterate_reader.ts b/streams/iterate_reader.ts index 131f95fdbd84..2057ce0dbdf3 100644 --- a/streams/iterate_reader.ts +++ b/streams/iterate_reader.ts @@ -1,7 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. -import { DEFAULT_BUFFER_SIZE } from "./_common.ts"; +import { + iterateReader as _iterateReader, + iterateReaderSync as _iterateReaderSync, +} from "../io/iterate_reader.ts"; import type { Reader, ReaderSync } from "../io/types.ts"; export type { Reader, ReaderSync }; @@ -35,24 +38,15 @@ export type { Reader, ReaderSync }; * } * ``` * - * @deprecated (will be removed after 1.0.0) Use {@linkcode ReadableStreamDefaultReader} instead. + * @deprecated (will be removed in 1.0.0) Import from {@link https://deno.land/std/io/iterate_reader.ts} instead. */ -export async function* iterateReader( +export function iterateReader( r: Reader, options?: { bufSize?: number; }, ): AsyncIterableIterator { - const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; - const b = new Uint8Array(bufSize); - while (true) { - const result = await r.read(b); - if (result === null) { - break; - } - - yield b.slice(0, result); - } + return _iterateReader(r, options); } /** @@ -87,22 +81,13 @@ export async function* iterateReader( * responsibility to copy contents of the buffer if needed; otherwise the * next iteration will overwrite contents of previously returned chunk. * - * @deprecated (will be removed after 1.0.0) Use {@linkcode ReadableStream} instead. + * @deprecated (will be removed in 1.0.0) Import from {@link https://deno.land/std/io/iterate_reader.ts} instead. */ -export function* iterateReaderSync( +export function iterateReaderSync( r: ReaderSync, options?: { bufSize?: number; }, ): IterableIterator { - const bufSize = options?.bufSize ?? DEFAULT_BUFFER_SIZE; - const b = new Uint8Array(bufSize); - while (true) { - const result = r.readSync(b); - if (result === null) { - break; - } - - yield b.slice(0, result); - } + return _iterateReaderSync(r, options); } From ece94b601901cf55411408d4652b37f44d504c7e Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Tue, 20 Feb 2024 20:00:58 +1100 Subject: [PATCH 40/63] chore(internal): remove `warnOnDeprecatedApi()` and `internal` folder (#4359) --- _tools/check_mod_exports.ts | 1 - deno.json | 2 +- internal/mod.ts | 9 --- internal/warn_on_deprecated_api.ts | 92 ------------------------- internal/warn_on_deprecated_api_test.ts | 47 ------------- 5 files changed, 1 insertion(+), 150 deletions(-) delete mode 100644 internal/mod.ts delete mode 100644 internal/warn_on_deprecated_api.ts delete mode 100644 internal/warn_on_deprecated_api_test.ts diff --git a/_tools/check_mod_exports.ts b/_tools/check_mod_exports.ts index 1b2888b3c64c..6e4f05153782 100644 --- a/_tools/check_mod_exports.ts +++ b/_tools/check_mod_exports.ts @@ -8,7 +8,6 @@ import ts from "npm:typescript"; const ROOT = new URL("../", import.meta.url); const FAIL_FAST = Deno.args.includes("--fail-fast"); const EXCLUDED_PATHS = [ - "internal/warn_on_deprecated_api.ts", "dotenv/load.ts", "path/glob.ts", "front_matter/yaml.ts", diff --git a/deno.json b/deno.json index ad745fd8a681..6dce2b1ab506 100644 --- a/deno.json +++ b/deno.json @@ -12,7 +12,7 @@ "automation/": "https://raw.githubusercontent.com/denoland/automation/0.10.0/" }, "tasks": { - "test": "DENO_NO_DEPRECATION_WARNINGS=1 deno test --unstable-http --unstable-webgpu --doc --allow-all --parallel --coverage --trace-ops", + "test": "deno test --unstable-http --unstable-webgpu --doc --allow-all --parallel --coverage --trace-ops", "test:browser": "git grep --name-only \"This module is browser compatible.\" | grep -v deno.json | grep -v .github/workflows | grep -v _tools | xargs deno check --config browser-compat.tsconfig.json", "fmt:licence-headers": "deno run --allow-read --allow-write ./_tools/check_licence.ts", "lint:deprecations": "deno run --allow-read --allow-net --allow-env=HOME ./_tools/check_deprecation.ts", diff --git a/internal/mod.ts b/internal/mod.ts deleted file mode 100644 index 33d4eddc3c78..000000000000 --- a/internal/mod.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -/** - * Internal utilities for the public API of the Deno Standard Library. - * - * Note: for internal use only. - * - * @module - */ diff --git a/internal/warn_on_deprecated_api.ts b/internal/warn_on_deprecated_api.ts deleted file mode 100644 index b9a27ae33a3d..000000000000 --- a/internal/warn_on_deprecated_api.ts +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -// This module is browser compatible. - -// deno-lint-ignore no-explicit-any -const { Deno } = globalThis as any; - -const ALREADY_WARNED_DEPRECATED = new Set(); -const ENV_VAR_KEY = "DENO_NO_DEPRECATION_WARNINGS"; -const shouldDisableDeprecatedApiWarning = - Deno?.permissions.querySync?.({ name: "env", variable: ENV_VAR_KEY }) - .state === "granted" && Deno?.env.has(ENV_VAR_KEY); - -interface WarnDeprecatedApiConfig { - /** The name of the deprecated API. */ - apiName: string; - /** The stack trace of the deprecated API. */ - stack: string; - /** The version in which the API will be removed. */ - removalVersion: string; - /** An optional message to print. */ - suggestion?: string; -} - -/** - * Prints a warning message to the console for the given deprecated API. - * - * These warnings can be disabled by setting `DENO_NO_DEPRECATION_WARNINGS=1` - * in the current process. - * - * Mostly copied from - * {@link https://github.com/denoland/deno/blob/c62615bfe5a070c2517f3af3208d4308c72eb054/runtime/js/99_main.js#L101}. - */ -export function warnOnDeprecatedApi(config: WarnDeprecatedApiConfig) { - if (shouldDisableDeprecatedApiWarning) return; - - const key = config.apiName + config.stack; - if (ALREADY_WARNED_DEPRECATED.has(key)) return; - - // If we haven't warned yet, let's do some processing of the stack trace - // to make it more useful. - const stackLines = config.stack.split("\n"); - stackLines.shift(); - - let isFromRemoteDependency = false; - const firstStackLine = stackLines[0]; - if (firstStackLine && !firstStackLine.includes("file:")) { - isFromRemoteDependency = true; - } - - ALREADY_WARNED_DEPRECATED.add(key); - console.log( - "%cWarning", - "color: yellow; font-weight: bold;", - ); - console.log( - `%c\u251c Use of deprecated "${config.apiName}" API.`, - "color: yellow;", - ); - console.log("%c\u2502", "color: yellow;"); - console.log( - `%c\u251c This API will be removed in version ${config.removalVersion} of the Deno Standard Library.`, - "color: yellow;", - ); - console.log("%c\u2502", "color: yellow;"); - console.log( - `%c\u251c Suggestion: ${config.suggestion}`, - "color: yellow;", - ); - if (isFromRemoteDependency) { - console.log("%c\u2502", "color: yellow;"); - console.log( - `%c\u251c Suggestion: It appears this API is used by a remote dependency.`, - "color: yellow;", - ); - console.log( - "%c\u2502 Try upgrading to the latest version of that dependency.", - "color: yellow;", - ); - } - - console.log("%c\u2502", "color: yellow;"); - console.log("%c\u2514 Stack trace:", "color: yellow;"); - for (let i = 0; i < stackLines.length; i++) { - console.log( - `%c ${i == stackLines.length - 1 ? "\u2514" : "\u251c"}\u2500 ${ - stackLines[i].trim() - }`, - "color: yellow;", - ); - } - console.log(); -} diff --git a/internal/warn_on_deprecated_api_test.ts b/internal/warn_on_deprecated_api_test.ts deleted file mode 100644 index 3d13ba5f8b68..000000000000 --- a/internal/warn_on_deprecated_api_test.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { assertEquals } from "../assert/assert_equals.ts"; -import { warnOnDeprecatedApi } from "./warn_on_deprecated_api.ts"; - -Deno.test("warnDeprecatedApi()", async () => { - const command = new Deno.Command(Deno.execPath(), { - args: ["run", "--quiet", "--no-lock", import.meta.url], - stderr: "inherit", - }); - const { success, stdout } = await command.output(); - const output = new TextDecoder().decode(stdout); - - assertEquals(success, true); - assertEquals( - output, - `Warning -├ Use of deprecated "fn()" API. -│ -├ This API will be removed in version 1.0.0 of the Deno Standard Library. -│ -├ Suggestion: Do something else instead. -│ -└ Stack trace: - ├─ at fn (${import.meta.url}:37:12) - └─ at ${import.meta.url}:45:31 - -Hello, world! -Hello, world! -END -`, - ); -}); - -function fn() { - warnOnDeprecatedApi({ - apiName: "fn()", - stack: new Error().stack!, - removalVersion: "1.0.0", - suggestion: "Do something else instead.", - }); - console.log("Hello, world!"); -} - -if (import.meta.main) { - for (let i = 0; i < 2; i++) fn(); - console.log("END"); -} From fe84d285f726f922608331c4081e65423eaea9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Hern=C3=A1ndez?= <73640929+javihernant@users.noreply.github.com> Date: Tue, 20 Feb 2024 21:57:21 +0100 Subject: [PATCH 41/63] refactor(semver): prepare for `noUncheckedIndexedAccess` (#4354) ref #4040 --- semver/_parse_comparator.ts | 10 ++++++++-- semver/parse.ts | 6 +++--- semver/parse_range.ts | 6 +++--- semver/range_intersects.ts | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/semver/_parse_comparator.ts b/semver/_parse_comparator.ts index b174657547fb..c2361e90634c 100644 --- a/semver/_parse_comparator.ts +++ b/semver/_parse_comparator.ts @@ -33,8 +33,14 @@ export function parseComparator(comparator: string): Comparator { const semver = groups.major ? { major: parseNumber(groups.major, "Invalid major version"), - minor: parseNumber(groups.minor, "Invalid minor version"), - patch: parseNumber(groups.patch, "Invalid patch version"), + minor: parseNumber( + groups.minor!, + "Invalid minor version", + ), + patch: parseNumber( + groups.patch!, + "Invalid patch version", + ), prerelease: prerelease ? parsePrerelease(prerelease) : [], build: buildmetadata ? parseBuild(buildmetadata) : [], } diff --git a/semver/parse.ts b/semver/parse.ts index 470ce0690191..73d74ac1a837 100644 --- a/semver/parse.ts +++ b/semver/parse.ts @@ -27,9 +27,9 @@ export function parse(version: string): SemVer { const groups = version.match(FULL_REGEXP)?.groups; if (!groups) throw new TypeError(`Invalid Version: ${version}`); - const major = parseNumber(groups.major, "Invalid major version"); - const minor = parseNumber(groups.minor, "Invalid minor version"); - const patch = parseNumber(groups.patch, "Invalid patch version"); + const major = parseNumber(groups.major!, "Invalid major version"); + const minor = parseNumber(groups.minor!, "Invalid minor version"); + const patch = parseNumber(groups.patch!, "Invalid patch version"); const prerelease = groups.prerelease ? parsePrerelease(groups.prerelease) diff --git a/semver/parse_range.ts b/semver/parse_range.ts index 94c88d5c0c0b..c429d1a02760 100644 --- a/semver/parse_range.ts +++ b/semver/parse_range.ts @@ -5,7 +5,7 @@ import { OPERATOR_XRANGE_REGEXP, XRANGE } from "./_shared.ts"; import { parseComparator } from "./_parse_comparator.ts"; import { parseBuild, parsePrerelease } from "./_shared.ts"; -function isWildcard(id: string): boolean { +function isWildcard(id?: string): boolean { return !id || id.toLowerCase() === "x" || id === "*"; } @@ -50,9 +50,9 @@ function parseHyphenRange(range: string) { if (isWildcard(rightGroups.major)) { to = ""; } else if (isWildcard(rightGroups.minor)) { - to = `<${+rightGroups.major + 1}.0.0`; + to = `<${+rightGroups.major! + 1}.0.0`; } else if (isWildcard(rightGroups.patch)) { - to = `<${rightGroups.major}.${+rightGroups.minor + 1}.0`; + to = `<${rightGroups.major}.${+rightGroups.minor! + 1}.0`; } else if (rightGroups.prerelease) { to = `<=${rightGroups.major}.${rightGroups.minor}.${rightGroups.patch}-${rightGroups.prerelease}`; diff --git a/semver/range_intersects.ts b/semver/range_intersects.ts index 9dc802c40f70..471ef54d42b3 100644 --- a/semver/range_intersects.ts +++ b/semver/range_intersects.ts @@ -12,7 +12,7 @@ function rangesSatisfiable(ranges: Range[]): boolean { function comparatorsSatisfiable(comparators: Comparator[]): boolean { // Comparators are satisfiable if they all intersect with each other for (let i = 0; i < comparators.length - 1; i++) { - const c0 = comparators[i]; + const c0 = comparators[i]!; for (const c1 of comparators.slice(i + 1)) { if (!comparatorIntersects(c0, c1)) { return false; From 88cbc0f7b3a84bc8ade81f76e25812fbe3369138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Hern=C3=A1ndez?= <73640929+javihernant@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:01:07 +0100 Subject: [PATCH 42/63] refactor(path): prepare for `noUncheckedIndexedAccess` (#4356) refactor(path): prepare for noUncheckedIndexedAccess (#4040) --- path/_common/assert_path.ts | 2 +- path/_common/glob_to_reg_exp.ts | 12 +++++++----- path/posix/join.ts | 2 +- path/posix/resolve.ts | 2 +- path/windows/join.ts | 2 +- path/windows/resolve.ts | 2 +- path/windows/to_file_url.ts | 3 +-- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/path/_common/assert_path.ts b/path/_common/assert_path.ts index abd021fd472a..7033edcd1a79 100644 --- a/path/_common/assert_path.ts +++ b/path/_common/assert_path.ts @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright the Browserify authors. MIT License. -export function assertPath(path: string) { +export function assertPath(path?: string) { if (typeof path !== "string") { throw new TypeError( `Path must be a string. Received ${JSON.stringify(path)}`, diff --git a/path/_common/glob_to_reg_exp.ts b/path/_common/glob_to_reg_exp.ts index 0a3dfbb4f7d5..26e8c82a054f 100644 --- a/path/_common/glob_to_reg_exp.ts +++ b/path/_common/glob_to_reg_exp.ts @@ -65,7 +65,7 @@ export function _globToRegExp( // Remove trailing separators. let newLength = glob.length; - for (; newLength > 1 && c.seps.includes(glob[newLength - 1]); newLength--); + for (; newLength > 1 && c.seps.includes(glob[newLength - 1]!); newLength--); glob = glob.slice(0, newLength); let regExpString = ""; @@ -80,11 +80,11 @@ export function _globToRegExp( let i = j; // Terminates with `i` at the non-inclusive end of the current segment. - for (; i < glob.length && !c.seps.includes(glob[i]); i++) { + for (; i < glob.length && !c.seps.includes(glob[i]!); i++) { if (inEscape) { inEscape = false; const escapeChars = inRange ? rangeEscapeChars : regExpEscapeChars; - segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; + segment += escapeChars.includes(glob[i]!) ? `\\${glob[i]}` : glob[i]; continue; } @@ -247,7 +247,9 @@ export function _globToRegExp( continue; } - segment += regExpEscapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; + segment += regExpEscapeChars.includes(glob[i]!) + ? `\\${glob[i]}` + : glob[i]; } // Check for unclosed groups or a dangling backslash. @@ -267,7 +269,7 @@ export function _globToRegExp( } // Terminates with `i` at the start of the next segment. - while (c.seps.includes(glob[i])) i++; + while (c.seps.includes(glob[i]!)) i++; // Check that the next value of `j` is indeed higher than the current value. if (!(i > j)) { diff --git a/path/posix/join.ts b/path/posix/join.ts index 0f7b152f6044..ad4bbae55d8e 100644 --- a/path/posix/join.ts +++ b/path/posix/join.ts @@ -13,7 +13,7 @@ export function join(...paths: string[]): string { let joined: string | undefined; for (let i = 0, len = paths.length; i < len; ++i) { - const path = paths[i]; + const path = paths[i]!; assertPath(path); if (path.length > 0) { if (!joined) joined = path; diff --git a/path/posix/resolve.ts b/path/posix/resolve.ts index 50022c0531ff..196a08a568ba 100644 --- a/path/posix/resolve.ts +++ b/path/posix/resolve.ts @@ -16,7 +16,7 @@ export function resolve(...pathSegments: string[]): string { for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) { let path: string; - if (i >= 0) path = pathSegments[i]; + if (i >= 0) path = pathSegments[i]!; else { // deno-lint-ignore no-explicit-any const { Deno } = globalThis as any; diff --git a/path/windows/join.ts b/path/windows/join.ts index 59f6777c5018..b17493dee81a 100644 --- a/path/windows/join.ts +++ b/path/windows/join.ts @@ -16,7 +16,7 @@ export function join(...paths: string[]): string { let joined: string | undefined; let firstPart: string | null = null; for (let i = 0; i < paths.length; ++i) { - const path = paths[i]; + const path = paths[i]!; assertPath(path); if (path.length > 0) { if (joined === undefined) joined = firstPart = path; diff --git a/path/windows/resolve.ts b/path/windows/resolve.ts index 1732ff6cb293..c34f1e8c668f 100644 --- a/path/windows/resolve.ts +++ b/path/windows/resolve.ts @@ -20,7 +20,7 @@ export function resolve(...pathSegments: string[]): string { // deno-lint-ignore no-explicit-any const { Deno } = globalThis as any; if (i >= 0) { - path = pathSegments[i]; + path = pathSegments[i]!; } else if (!resolvedDevice) { if (typeof Deno?.cwd !== "function") { throw new TypeError("Resolved a drive-letter-less path without a CWD."); diff --git a/path/windows/to_file_url.ts b/path/windows/to_file_url.ts index a3d52c5857cf..426646cba4c9 100644 --- a/path/windows/to_file_url.ts +++ b/path/windows/to_file_url.ts @@ -20,12 +20,11 @@ export function toFileUrl(path: string): URL { if (!isAbsolute(path)) { throw new TypeError("Must be an absolute path."); } - const [, hostname, pathname] = path.match( /^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/, )!; const url = new URL("file:///"); - url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25")); + url.pathname = encodeWhitespace(pathname!.replace(/%/g, "%25")); if (hostname !== undefined && hostname !== "localhost") { url.hostname = hostname; if (!url.hostname) { From 0e9f8694a21b13cf803a7b08fd0716bb990b7bb0 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Wed, 21 Feb 2024 15:51:30 +1100 Subject: [PATCH 43/63] chore(_tools): remove unneeded `--unstable` flag (#4360) --- .github/workflows/workspace_publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workspace_publish.yml b/.github/workflows/workspace_publish.yml index 4162dea0be2d..38e25e797d63 100644 --- a/.github/workflows/workspace_publish.yml +++ b/.github/workflows/workspace_publish.yml @@ -34,7 +34,7 @@ jobs: run: deno fmt - name: Type check - run: deno test --unstable --no-run --doc + run: deno test --no-run --doc - name: Publish (dry run) if: startsWith(github.ref, 'refs/tags/') == false From 6e97b91f5b15fdcdc7e1fecf3c96652c73978195 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Wed, 21 Feb 2024 17:19:05 +1100 Subject: [PATCH 44/63] chore(media_types): move `extensions` utility (#4358) --- media_types/_db.ts | 61 ++++++++++++++++--------------- media_types/_util.ts | 3 -- media_types/extensions_by_type.ts | 3 +- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/media_types/_db.ts b/media_types/_db.ts index efa658440394..45d4c653784e 100644 --- a/media_types/_db.ts +++ b/media_types/_db.ts @@ -1,46 +1,47 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import db from "./vendor/mime-db.v1.52.0.ts"; -import { type DBEntry, extensions } from "./_util.ts"; +import { type DBEntry } from "./_util.ts"; export type KeyOfDb = keyof typeof db; /** A map of the media type for a given extension */ export const types = new Map(); +/** A map of extensions for a given media type. */ +const extensions: Map = new Map(); + /** Internal function to populate the maps based on the Mime DB. */ -(function populateMaps() { - const preference = ["nginx", "apache", undefined, "iana"]; +const preference = ["nginx", "apache", undefined, "iana"]; - for (const type of Object.keys(db) as KeyOfDb[]) { - const mime = db[type] as DBEntry; - const exts = mime.extensions; +for (const type of Object.keys(db) as KeyOfDb[]) { + const mime = db[type] as DBEntry; + const exts = mime.extensions; - if (!exts || !exts.length) { - continue; - } + if (!exts || !exts.length) { + continue; + } - // @ts-ignore work around denoland/dnt#148 - extensions.set(type, exts); - - for (const ext of exts) { - const current = types.get(ext); - if (current) { - const from = preference.indexOf((db[current] as DBEntry).source); - const to = preference.indexOf(mime.source); - - if ( - current !== "application/octet-stream" && - (from > to || - // @ts-ignore work around denoland/dnt#148 - (from === to && current.startsWith("application/"))) - ) { - continue; - } + // @ts-ignore work around denoland/dnt#148 + extensions.set(type, exts); + + for (const ext of exts) { + const current = types.get(ext); + if (current) { + const from = preference.indexOf((db[current] as DBEntry).source); + const to = preference.indexOf(mime.source); + + if ( + current !== "application/octet-stream" && + (from > to || + // @ts-ignore work around denoland/dnt#148 + (from === to && current.startsWith("application/"))) + ) { + continue; } - - types.set(ext, type); } + + types.set(ext, type); } -})(); +} -export { db }; +export { db, extensions }; diff --git a/media_types/_util.ts b/media_types/_util.ts index b365a135f8a9..50d3282991bd 100644 --- a/media_types/_util.ts +++ b/media_types/_util.ts @@ -13,9 +13,6 @@ export interface DBEntry { extensions?: string[]; } -/** A map of extensions for a given media type. */ -export const extensions: Map = new Map(); - export function consumeToken(v: string): [token: string, rest: string] { const notPos = indexOf(v, isNotTokenChar); if (notPos === -1) { diff --git a/media_types/extensions_by_type.ts b/media_types/extensions_by_type.ts index 9ea141b8a536..5937017ccfda 100644 --- a/media_types/extensions_by_type.ts +++ b/media_types/extensions_by_type.ts @@ -2,8 +2,7 @@ // This module is browser compatible. import { parseMediaType } from "./parse_media_type.ts"; -import { extensions } from "./_util.ts"; -import "./_db.ts"; +import { extensions } from "./_db.ts"; export { extensions }; From ac82d732a3ae799b3a3113cdcf78890b6cc37dfa Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Wed, 21 Feb 2024 13:43:55 +0100 Subject: [PATCH 45/63] build: update _ to - in workspace converter script (#4357) --- _tools/convert_to_workspace.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/_tools/convert_to_workspace.ts b/_tools/convert_to_workspace.ts index 35527bac550d..ba9a3f97a4ad 100644 --- a/_tools/convert_to_workspace.ts +++ b/_tools/convert_to_workspace.ts @@ -192,7 +192,7 @@ for await (const entry of walk(cwd)) { replacedImports.push([specifier, newSpecifier]); } else { const newSpecifier = "@std/" + - target.replace(/(\.d)?\.ts$/, "").replace(/\/mod$/, ""); + fixPackagePath(target).replace(/(\.d)?\.ts$/, "").replace(/\/mod$/, ""); replacedImports.push([specifier, newSpecifier]); } } @@ -203,7 +203,7 @@ for await (const entry of walk(cwd)) { "", ); const newSpecifier = "@std/" + - target.replace(/(\.d)?\.ts$/, "").replace(/\/mod$/, ""); + fixPackagePath(target).replace(/(\.d)?\.ts$/, "").replace(/\/mod$/, ""); replacedImports.push([specifier, newSpecifier]); } @@ -227,7 +227,7 @@ for (const pkg of packages) { exports = Object.fromEntries(exportsList); } const denoJson = { - name: `@std/${pkg}`, + name: `@std/${fixPackageName(pkg)}`, version: VERSION, exports, }; @@ -242,12 +242,24 @@ for (const pkg of packages) { ); } +function fixPackageName(pkg: string) { + return pkg.replaceAll("_", "-"); +} + +function fixPackagePath(path: string) { + const packageName = /^[^/]+/.exec(path); + if (packageName) { + return path.replace(packageName[0], fixPackageName(packageName[0])); + } + return path; +} + // Generate `deno.json` file. const denoJson = JSON.parse(await Deno.readTextFile("deno.json")); denoJson.workspaces = orderedPackages.map((pkg) => `./${pkg}`); for (const pkg of packages) { - denoJson.imports[`@std/${pkg}`] = `jsr:@std/${pkg}@^${VERSION}`; - denoJson.imports[`@std/${pkg}/`] = `jsr:/@std/${pkg}@^${VERSION}/`; + const fixedPkg = fixPackageName(pkg); + denoJson.imports[`@std/${fixedPkg}`] = `jsr:@std/${fixedPkg}@^${VERSION}`; } await Deno.writeTextFile( "deno.json", From 104d02ad8eb32048969b8233062fca002f0b22c4 Mon Sep 17 00:00:00 2001 From: denobot <33910674+denobot@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:57:01 +0900 Subject: [PATCH 46/63] 0.217.0 (#4369) Co-authored-by: bartlomieju --- Releases.md | 13 +++++++++++++ version.ts | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Releases.md b/Releases.md index c364fb6bc922..dbfb079fe690 100644 --- a/Releases.md +++ b/Releases.md @@ -1,3 +1,16 @@ +### 0.217.0 / 2024.02.22 + +- deprecation(semver): deprecate `==`, `===`, `!==`, and `""` operators (#4271) +- doc: fix `std/path/posix` link (#4337) +- feat(io): `iterateReader[Sync]()` (#4247) +- feat(io): un-deprecate `readerFromStreamReader()` (#4343) +- feat(testing): explicit resource management for `spy()` and `stub()` (#4306) +- fix(http): `version` from `deno.json` import (#4342) +- fix(media_types): load extensions when directly importing + `extensionsByTypes()` (#4351) +- fix(semver): fix `prerelease` handlings in range utils (#4323) +- fix(semver): fix parse_range for `>x.y` pattern (#4350) + ### 0.216.0 / 2024.02.15 - BREAKING(path): remove `path/windows/separator.ts` (#4292) diff --git a/version.ts b/version.ts index feb6d6ce48f2..16745663debd 100644 --- a/version.ts +++ b/version.ts @@ -5,4 +5,4 @@ * the cli's API is stable. In the future when std becomes stable, likely we * will match versions with cli as we have in the past. */ -export const VERSION = "0.216.0"; +export const VERSION = "0.217.0"; From 22c0dfc6aab46b05970d38186afe7a5a424f234b Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Thu, 22 Feb 2024 15:39:35 +1100 Subject: [PATCH 47/63] chore(crypto): move test scripts to own files (#4367) --- crypto/crypto_test.ts | 65 ++------------------------ crypto/testdata/digest_large_inputs.ts | 28 +++++++++++ crypto/testdata/digest_many_calls.ts | 26 +++++++++++ 3 files changed, 58 insertions(+), 61 deletions(-) create mode 100644 crypto/testdata/digest_large_inputs.ts create mode 100644 crypto/testdata/digest_many_calls.ts diff --git a/crypto/crypto_test.ts b/crypto/crypto_test.ts index fadc95d5ec84..2df53b7cb5ef 100644 --- a/crypto/crypto_test.ts +++ b/crypto/crypto_test.ts @@ -2,12 +2,9 @@ import { assert, assertEquals, assertInstanceOf, fail } from "../assert/mod.ts"; import { crypto as stdCrypto } from "./mod.ts"; import { repeat } from "../bytes/repeat.ts"; -import { dirname, fromFileUrl } from "../path/mod.ts"; import { DigestAlgorithm, digestAlgorithms } from "./_wasm/mod.ts"; import { encodeHex } from "../encoding/hex.ts"; -const moduleDir = dirname(fromFileUrl(import.meta.url)); - const webCrypto = globalThis.crypto; Deno.test( @@ -167,35 +164,9 @@ Deno.test("digest() handles length option", async () => { }); Deno.test("digest() keeps memory usage reasonable with large inputs", async () => { - const code = ` - import { crypto as stdCrypto } from "./mod.ts"; - import { instantiateWithInstance } from "./_wasm/lib/deno_std_wasm_crypto.generated.mjs"; - import { encodeHex } from "../encoding/hex.ts"; - - const { memory } = instantiateWithInstance().instance.exports; - - const heapBytesInitial = memory.buffer.byteLength; - - const smallData = new Uint8Array(64); - const smallDigest = encodeHex(stdCrypto.subtle.digestSync("BLAKE3", smallData.buffer)); - const heapBytesAfterSmall = memory.buffer.byteLength; - - const largeData = new Uint8Array(64_000_000); - const largeDigest = encodeHex(stdCrypto.subtle.digestSync("BLAKE3", largeData.buffer)); - const heapBytesAfterLarge = memory.buffer.byteLength; - - console.log(JSON.stringify({ - heapBytesInitial, - smallDigest, - heapBytesAfterSmall, - largeDigest, - heapBytesAfterLarge, - })); - `; - const command = new Deno.Command(Deno.execPath(), { - args: ["eval", "--no-lock", code], - cwd: moduleDir, + args: ["run", "--no-lock", "crypto/testdata/digest_large_inputs.ts"], + stderr: "inherit", }); const { success, stdout } = await command.output(); @@ -249,37 +220,9 @@ Deno.test("digest() keeps memory usage reasonable with large inputs", async () = }); Deno.test("digest() keeps memory usage reasonable with many calls", async () => { - const code = ` - import { crypto as stdCrypto } from "./mod.ts"; - import { instantiateWithInstance } from "./_wasm/lib/deno_std_wasm_crypto.generated.mjs"; - import { encodeHex } from "../encoding/hex.ts"; - - const { memory } = instantiateWithInstance().instance.exports; - - const heapBytesInitial = memory.buffer.byteLength; - - let state = new ArrayBuffer(0); - - for (let i = 0; i < 1_000_000; i++) { - state = stdCrypto.subtle.digestSync({ - name: "BLAKE3" - }, state); - } - - const heapBytesFinal = memory.buffer.byteLength; - - const stateFinal = encodeHex(state); - - console.log(JSON.stringify({ - heapBytesInitial, - heapBytesFinal, - stateFinal, - })); - `; - const command = new Deno.Command(Deno.execPath(), { - args: ["eval", "--no-lock", code], - cwd: moduleDir, + args: ["run", "--no-lock", "crypto/testdata/digest_many_calls.ts"], + stderr: "inherit", }); const { stdout, success } = await command.output(); const output = new TextDecoder().decode(stdout); diff --git a/crypto/testdata/digest_large_inputs.ts b/crypto/testdata/digest_large_inputs.ts new file mode 100644 index 000000000000..321c46eeb6a0 --- /dev/null +++ b/crypto/testdata/digest_large_inputs.ts @@ -0,0 +1,28 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +import { crypto as stdCrypto } from "../crypto.ts"; +import { instantiateWithInstance } from "../_wasm/lib/deno_std_wasm_crypto.generated.mjs"; +import { encodeHex } from "../../encoding/hex.ts"; + +const { memory } = instantiateWithInstance().instance.exports; + +const heapBytesInitial = memory.buffer.byteLength; + +const smallData = new Uint8Array(64); +const smallDigest = encodeHex( + stdCrypto.subtle.digestSync("BLAKE3", smallData.buffer), +); +const heapBytesAfterSmall = memory.buffer.byteLength; + +const largeData = new Uint8Array(64_000_000); +const largeDigest = encodeHex( + stdCrypto.subtle.digestSync("BLAKE3", largeData.buffer), +); +const heapBytesAfterLarge = memory.buffer.byteLength; + +console.log(JSON.stringify({ + heapBytesInitial, + smallDigest, + heapBytesAfterSmall, + largeDigest, + heapBytesAfterLarge, +})); diff --git a/crypto/testdata/digest_many_calls.ts b/crypto/testdata/digest_many_calls.ts new file mode 100644 index 000000000000..ba07f761b696 --- /dev/null +++ b/crypto/testdata/digest_many_calls.ts @@ -0,0 +1,26 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +import { crypto as stdCrypto } from "../crypto.ts"; +import { instantiateWithInstance } from "../_wasm/lib/deno_std_wasm_crypto.generated.mjs"; +import { encodeHex } from "../../encoding/hex.ts"; + +const { memory } = instantiateWithInstance().instance.exports; + +const heapBytesInitial = memory.buffer.byteLength; + +let state = new ArrayBuffer(0); + +for (let i = 0; i < 1_000_000; i++) { + state = stdCrypto.subtle.digestSync({ + name: "BLAKE3", + }, state); +} + +const heapBytesFinal = memory.buffer.byteLength; + +const stateFinal = encodeHex(state); + +console.log(JSON.stringify({ + heapBytesInitial, + heapBytesFinal, + stateFinal, +})); From 241c6b26e9a605168deb9eed31d0f7e6c06be4ce Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Thu, 22 Feb 2024 15:40:55 +1100 Subject: [PATCH 48/63] chore(http): fix spawned tests after migration script (#4368) --- http/file_server_test.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/http/file_server_test.ts b/http/file_server_test.ts index 81cffda38a99..1932733d3ebb 100644 --- a/http/file_server_test.ts +++ b/http/file_server_test.ts @@ -344,10 +344,11 @@ Deno.test("serveDir() script prints help", async () => { "--no-check", "--quiet", "--no-lock", - "file_server.ts", + "--config", + "deno.json", + "http/file_server.ts", "--help", ], - cwd: moduleDir, }); const { stdout } = await command.output(); const output = new TextDecoder().decode(stdout); @@ -361,10 +362,11 @@ Deno.test("serveDir() script prints version", async () => { "--no-check", "--quiet", "--no-lock", - "file_server.ts", + "--config", + "deno.json", + "http/file_server.ts", "--version", ], - cwd: moduleDir, }); const { stdout } = await command.output(); const output = new TextDecoder().decode(stdout); @@ -390,7 +392,9 @@ Deno.test("serveDir() script fails with partial TLS args", async () => { "--allow-read", "--allow-net", "--no-lock", - "file_server.ts", + "--config", + "deno.json", + "http/file_server.ts", ".", "--host", "localhost", @@ -399,7 +403,6 @@ Deno.test("serveDir() script fails with partial TLS args", async () => { "-p", `4578`, ], - cwd: moduleDir, stderr: "null", }); const { stdout, success } = await command.output(); From fc86bd91fa8bbe2aef115dc60ed4c1778e7fb7dc Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Thu, 22 Feb 2024 16:11:40 +0900 Subject: [PATCH 49/63] chore: use 'release' event for triggering jsr publish (#4370) --- .github/workflows/workspace_publish.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/workspace_publish.yml b/.github/workflows/workspace_publish.yml index 38e25e797d63..7a2dd1a1812e 100644 --- a/.github/workflows/workspace_publish.yml +++ b/.github/workflows/workspace_publish.yml @@ -2,9 +2,9 @@ name: workspace publish on: push: - branches: [main, workspace_publish] - tags: - - '[0-9]+.[0-9]+.[0-9]+' + branches: [main] + release: + types: [published] env: DENO_UNSTABLE_WORKSPACES: true @@ -37,9 +37,9 @@ jobs: run: deno test --no-run --doc - name: Publish (dry run) - if: startsWith(github.ref, 'refs/tags/') == false + if: github.event_name == 'push' run: deno publish --dry-run - name: Publish (real) - if: startsWith(github.ref, 'refs/tags/') + if: github.event_name == 'release' run: deno publish From 3e42606ddd7c641bc441115fcf46dc172f74a7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Hern=C3=A1ndez?= <73640929+javihernant@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:36:36 +0100 Subject: [PATCH 50/63] test(semver): add test for parse_range (#4345) --- semver/parse_range_test.ts | 681 +++++++++++++++++++++++++++++++++++++ 1 file changed, 681 insertions(+) create mode 100644 semver/parse_range_test.ts diff --git a/semver/parse_range_test.ts b/semver/parse_range_test.ts new file mode 100644 index 000000000000..9cb116633995 --- /dev/null +++ b/semver/parse_range_test.ts @@ -0,0 +1,681 @@ +// Copyright Isaac Z. Schlueter and Contributors. All rights reserved. ISC license. +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +import { assertEquals } from "../assert/mod.ts"; +import { parseRange } from "./parse_range.ts"; +import type { Range } from "./types.ts"; + +Deno.test("parseRange() parse ranges of different kinds", () => { + const ranges: [string, Range][] = [ + ["1.0.0 - 2.0.0", [ + [ + { + operator: ">=", + major: 1, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + { + operator: "<=", + major: 2, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + ["1.2.3+asdf - 2.4.3+asdf", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + { + operator: "<=", + major: 2, + minor: 4, + patch: 3, + prerelease: [], + build: [], + }, + ], + ]], + ["^1.2.3+build", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["1.2.3-pre+asdf - 2.4.3-pre+asdf", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: ["pre"], + build: [], + }, + { + operator: "<=", + major: 2, + minor: 4, + patch: 3, + prerelease: ["pre"], + build: [], + }, + ], + ]], + ["^1.2", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + [">1.2", [[{ operator: ">=", major: 1, minor: 3, patch: 0 }]]], + ["<=1.2.3", [ + [ + { + operator: "<=", + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + ], + ]], + ["<1.2.3", [ + [ + { + operator: "<", + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + ], + ]], + ["=1.2.3", [ + [ + { + operator: undefined, + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + ], + ]], + ["=0.7.x", [ + [ + { operator: ">=", major: 0, minor: 7, patch: 0 }, + { operator: "<", major: 0, minor: 8, patch: 0 }, + ], + ]], + [">=0.7.x", [[{ operator: ">=", major: 0, minor: 7, patch: 0 }]]], + ["1.0.0", [ + [ + { + operator: undefined, + major: 1, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + [">=1.0.0", [ + [ + { + operator: ">=", + major: 1, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + [">1.0.0", [ + [ + { + operator: ">", + major: 1, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + ["<=2.0.0", [ + [ + { + operator: "<=", + major: 2, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + ["<2.0.0", [ + [ + { + operator: "<", + major: 2, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + [">=0.1.97", [ + [ + { + operator: ">=", + major: 0, + minor: 1, + patch: 97, + prerelease: [], + build: [], + }, + ], + ]], + ["0.1.20 || 1.2.4", [ + [ + { + operator: undefined, + major: 0, + minor: 1, + patch: 20, + prerelease: [], + build: [], + }, + ], + [ + { + operator: undefined, + major: 1, + minor: 2, + patch: 4, + prerelease: [], + build: [], + }, + ], + ]], + [">=0.2.3 || <0.0.1", [ + [ + { + operator: ">=", + major: 0, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + ], + [ + { + operator: "<", + major: 0, + minor: 0, + patch: 1, + prerelease: [], + build: [], + }, + ], + ]], + ["2.x.x", [ + [ + { operator: ">=", major: 2, minor: 0, patch: 0 }, + { operator: "<", major: 3, minor: 0, patch: 0 }, + ], + ]], + ["1.2.x", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ["1.2.x || 2.x", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + [ + { operator: ">=", major: 2, minor: 0, patch: 0 }, + { operator: "<", major: 3, minor: 0, patch: 0 }, + ], + ]], + ["2.*.*", [ + [ + { operator: ">=", major: 2, minor: 0, patch: 0 }, + { operator: "<", major: 3, minor: 0, patch: 0 }, + ], + ]], + ["1.2.*", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ["1.2.* || 2.*", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + [ + { operator: ">=", major: 2, minor: 0, patch: 0 }, + { operator: "<", major: 3, minor: 0, patch: 0 }, + ], + ]], + ["2", [ + [ + { operator: ">=", major: 2, minor: 0, patch: 0 }, + { operator: "<", major: 3, minor: 0, patch: 0 }, + ], + ]], + ["2.3", [ + [ + { operator: ">=", major: 2, minor: 3, patch: 0 }, + { operator: "<", major: 2, minor: 4, patch: 0 }, + ], + ]], + ["~0.0.1", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 1, prerelease: [] }, + { operator: "<", major: 0, minor: 1, patch: 0 }, + ], + ]], + ["~2.4", [ + [ + { operator: ">=", major: 2, minor: 4, patch: 0 }, + { operator: "<", major: 2, minor: 5, patch: 0 }, + ], + ]], + ["~>3.2.1", [ + [ + { operator: ">=", major: 3, minor: 2, patch: 1, prerelease: [] }, + { operator: "<", major: 3, minor: 3, patch: 0 }, + ], + ]], + ["~1", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["~>1", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["~1.0", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 1, minor: 1, patch: 0 }, + ], + ]], + ["<1", [[{ operator: "<", major: 1, minor: 0, patch: 0 }]]], + [">=1.2", [[{ operator: ">=", major: 1, minor: 2, patch: 0 }]]], + ["~v0.5.4-beta", [ + [ + { + operator: ">=", + major: 0, + minor: 5, + patch: 4, + prerelease: ["beta"], + }, + { operator: "<", major: 0, minor: 6, patch: 0 }, + ], + ]], + ["<0.7.x", [[{ operator: "<", major: 0, minor: 7, patch: 0 }]]], + ["^0.0.1", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 1, prerelease: [] }, + { operator: "<", major: 0, minor: 0, patch: 2 }, + ], + ]], + ["blerg", [ + [ + { + operator: "<", + major: 0, + minor: 0, + patch: 0, + prerelease: [], + build: [], + semver: { major: 0, minor: 0, patch: 0, prerelease: [], build: [] }, + }, + ], + ]], + ["^1.2.3", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ]; + + for (const [r, expected] of ranges) { + const range = parseRange(r); + assertEquals(range, expected, 'call to parseRange("' + r + '") failed'); + } +}); + +Deno.test("parseRange() parse ranges with hyphens", () => { + const ranges: [string, Range][] = [ + ["1.2.3 - 2.3.4", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + { + operator: "<=", + major: 2, + minor: 3, + patch: 4, + prerelease: [], + build: [], + }, + ], + ]], + ["1.2 - 2.3.4", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 0, + prerelease: [], + build: [], + }, + { + operator: "<=", + major: 2, + minor: 3, + patch: 4, + prerelease: [], + build: [], + }, + ], + ]], + ["1.2.3 - 2.3", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + { + operator: "<", + major: 2, + minor: 4, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + ["1.2.3 - 2", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: [], + build: [], + }, + { + operator: "<", + major: 3, + minor: 0, + patch: 0, + prerelease: [], + build: [], + }, + ], + ]], + ]; + + for (const [r, expected] of ranges) { + const range = parseRange(r); + assertEquals(range, expected, 'call to parseRange("' + r + '") failed'); + } +}); + +Deno.test("parseRange() parses ranges with x", () => { + const ranges: [string, Range][] = [ + ["*", [ + [ + { + operator: "", + major: NaN, + minor: NaN, + patch: NaN, + prerelease: [], + build: [], + semver: { + major: NaN, + minor: NaN, + patch: NaN, + prerelease: [], + build: [], + }, + }, + ], + ]], + ["1.x", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["1.2.x", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ["", [ + [ + { + operator: undefined, + major: NaN, + minor: NaN, + patch: NaN, + prerelease: [], + build: [], + semver: { + major: NaN, + minor: NaN, + patch: NaN, + prerelease: [], + build: [], + }, + }, + ], + ]], + ["1", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["1.2", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ]; + + for (const [r, expected] of ranges) { + const range = parseRange(r); + assertEquals(range, expected, 'call to parseRange("' + r + '") failed'); + } +}); + +Deno.test("parseRanges() parses ranges with tilde", () => { + const ranges: [string, Range][] = [ + ["~1.2.3", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ["~1.2", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ["~1", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["~0.2.3", [ + [ + { operator: ">=", major: 0, minor: 2, patch: 3, prerelease: [] }, + { operator: "<", major: 0, minor: 3, patch: 0 }, + ], + ]], + ["~0.2", [ + [ + { operator: ">=", major: 0, minor: 2, patch: 0 }, + { operator: "<", major: 0, minor: 3, patch: 0 }, + ], + ]], + ["~0", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 0 }, + { operator: "<", major: 1, minor: 0, patch: 0 }, + ], + ]], + ["~1.2.3-beta.2", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: ["beta", 2], + }, + { operator: "<", major: 1, minor: 3, patch: 0 }, + ], + ]], + ]; + + for (const [r, expected] of ranges) { + const range = parseRange(r); + assertEquals(range, expected, 'call to parseRange("' + r + '") failed'); + } +}); + +Deno.test("parseRange() parses ranges with caret", () => { + const ranges: [string, Range][] = [ + ["^1.2.3", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 3, prerelease: [] }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["^0.2.3", [ + [ + { operator: ">=", major: 0, minor: 2, patch: 3, prerelease: [] }, + { operator: "<", major: 0, minor: 3, patch: 0 }, + ], + ]], + ["^0.0.3", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 3, prerelease: [] }, + { operator: "<", major: 0, minor: 0, patch: 4 }, + ], + ]], + ["^1.2.3-beta.2", [ + [ + { + operator: ">=", + major: 1, + minor: 2, + patch: 3, + prerelease: ["beta", 2], + }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["^0.0.3-beta", [ + [ + { + operator: ">=", + major: 0, + minor: 0, + patch: 3, + prerelease: ["beta"], + }, + { operator: "<", major: 0, minor: 0, patch: 4 }, + ], + ]], + ["^1.2.x", [ + [ + { operator: ">=", major: 1, minor: 2, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["^0.0.x", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 0 }, + { operator: "<", major: 0, minor: 1, patch: 0 }, + ], + ]], + ["^0.0", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 0 }, + { operator: "<", major: 0, minor: 1, patch: 0 }, + ], + ]], + ["^1.x", [ + [ + { operator: ">=", major: 1, minor: 0, patch: 0 }, + { operator: "<", major: 2, minor: 0, patch: 0 }, + ], + ]], + ["^0.x", [ + [ + { operator: ">=", major: 0, minor: 0, patch: 0 }, + { operator: "<", major: 1, minor: 0, patch: 0 }, + ], + ]], + ]; + + for (const [r, expected] of ranges) { + const range = parseRange(r); + assertEquals(range, expected, 'call to parseRange("' + r + '") failed'); + } +}); From 6e6eff5d59f5c9b40a010bae4796c469b00406d6 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Fri, 23 Feb 2024 01:47:28 +0100 Subject: [PATCH 51/63] refactor(semver): rename `comparatorFormat()` to `formatComparator()` (#4373) initial commit --- .../{_comparator_format.ts => _format_comparator.ts} | 2 +- semver/comparator_test.ts | 10 +++++----- semver/format_range.ts | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) rename semver/{_comparator_format.ts => _format_comparator.ts} (87%) diff --git a/semver/_comparator_format.ts b/semver/_format_comparator.ts similarity index 87% rename from semver/_comparator_format.ts rename to semver/_format_comparator.ts index ae3e2f459516..c75769e2e018 100644 --- a/semver/_comparator_format.ts +++ b/semver/_format_comparator.ts @@ -8,7 +8,7 @@ import { format } from "./format.ts"; * @param comparator * @returns A string representation of the comparator */ -export function comparatorFormat(comparator: Comparator): string { +export function formatComparator(comparator: Comparator): string { const { semver, operator } = comparator; return `${operator === undefined ? "" : operator}${ format(semver ?? comparator) diff --git a/semver/comparator_test.ts b/semver/comparator_test.ts index 358b1ea6a8a4..ee6de92e4757 100644 --- a/semver/comparator_test.ts +++ b/semver/comparator_test.ts @@ -5,7 +5,7 @@ import { parseRange } from "./parse_range.ts"; import { parse } from "./parse.ts"; import { testRange } from "./test_range.ts"; import { parseComparator } from "./_parse_comparator.ts"; -import { comparatorFormat } from "./_comparator_format.ts"; +import { formatComparator } from "./_format_comparator.ts"; import { Comparator } from "./types.ts"; Deno.test({ @@ -164,11 +164,11 @@ Deno.test({ Deno.test("comparatorFormat() handles semver inheritance", function () { assertEquals( - comparatorFormat(parseComparator(">= v1.2.3")), + formatComparator(parseComparator(">= v1.2.3")), ">=1.2.3", ); assertEquals( - comparatorFormat(parseComparator(">= v1.2.3-pre.1+b.2")), + formatComparator(parseComparator(">= v1.2.3-pre.1+b.2")), ">=1.2.3-pre.1+b.2", ); }); @@ -176,7 +176,7 @@ Deno.test("comparatorFormat() handles semver inheritance", function () { Deno.test("comparatorFormat() handles deprecated Comparator.semver property", function () { const c1 = parseComparator(">= v1.2.3"); assertEquals( - comparatorFormat( + formatComparator( { operator: c1.operator, semver: c1.semver } as Comparator, ), ">=1.2.3", @@ -184,7 +184,7 @@ Deno.test("comparatorFormat() handles deprecated Comparator.semver property", fu const c2 = parseComparator(">= v1.2.3-pre.1+b.2"); assertEquals( - comparatorFormat( + formatComparator( { operator: c2.operator, semver: c2.semver } as Comparator, ), ">=1.2.3-pre.1+b.2", diff --git a/semver/format_range.ts b/semver/format_range.ts index 837c3e3b4c97..6a648be3127c 100644 --- a/semver/format_range.ts +++ b/semver/format_range.ts @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import type { Range } from "./types.ts"; -import { comparatorFormat } from "./_comparator_format.ts"; +import { formatComparator } from "./_format_comparator.ts"; /** * Formats the range into a string @@ -9,6 +9,6 @@ import { comparatorFormat } from "./_comparator_format.ts"; * @returns A string representation of the range */ export function formatRange(range: Range): string { - return range.map((c) => c.map((c) => comparatorFormat(c)).join(" ")) + return range.map((c) => c.map((c) => formatComparator(c)).join(" ")) .join("||"); } From 333c4db28345b1e81b2e04ac0c87ac67bc6a5d65 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 23 Feb 2024 13:39:50 +0900 Subject: [PATCH 52/63] chore(semver): move breaking versions (#4372) --- semver/gtr.ts | 2 +- semver/ltr.ts | 2 +- semver/reverse_sort.ts | 2 +- semver/types.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/semver/gtr.ts b/semver/gtr.ts index 9342ee8ac989..a2028a3cc51f 100644 --- a/semver/gtr.ts +++ b/semver/gtr.ts @@ -5,7 +5,7 @@ import { greaterThan } from "./greater_than.ts"; /** * Checks to see if the version is greater than all possible versions of the range. - * @deprecated (will be removed after 0.217.0) See + * @deprecated (will be removed in 0.219.0) See * {@link https://github.com/denoland/deno_std/issues/4273 | deno_std#4273} * for details. */ diff --git a/semver/ltr.ts b/semver/ltr.ts index ef3fdf7ffae3..3cf238864252 100644 --- a/semver/ltr.ts +++ b/semver/ltr.ts @@ -5,7 +5,7 @@ import { rangeMin } from "./range_min.ts"; /** * Less than range comparison - * @deprecated (will be removed after 0.217.0) See + * @deprecated (will be removed in 0.219.0) See * {@link https://github.com/denoland/deno_std/issues/4273 | deno_std#4273} * for details. */ diff --git a/semver/reverse_sort.ts b/semver/reverse_sort.ts index d8ea1e40690d..f867ffde0fe9 100644 --- a/semver/reverse_sort.ts +++ b/semver/reverse_sort.ts @@ -4,7 +4,7 @@ import { compare } from "./compare.ts"; /** * Sorts a list of semantic versions in descending order. - * @deprecated (will be removed after 0.217.0) Use `versions.sort((a, b) => compare(b, a))` instead. + * @deprecated (will be removed in 0.219.0) Use `versions.sort((a, b) => compare(b, a))` instead. */ export function reverseSort( versions: SemVer[], diff --git a/semver/types.ts b/semver/types.ts index 8e0f1e9bdfd4..4713d8a43365 100644 --- a/semver/types.ts +++ b/semver/types.ts @@ -29,7 +29,7 @@ export type Operator = typeof OPERATORS[number]; export interface Comparator extends SemVer { operator?: Operator; /** - * @deprecated (will be removed after 0.217.0) {@linkcode Comparator} extends {@linkcode SemVer}. Use `major`, `minor`, `patch`, `prerelease`, and `build` properties instead. + * @deprecated (will be removed in 0.219.0) {@linkcode Comparator} extends {@linkcode SemVer}. Use `major`, `minor`, `patch`, `prerelease`, and `build` properties instead. */ semver?: SemVer; } From 513805661bcbc56b7b6e84eca7bb83a450ab5fc0 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Fri, 23 Feb 2024 10:35:19 +0100 Subject: [PATCH 53/63] chore(semver): remove legacy `Range.ranges` object definition (#4374) * initial commit * remove obsolete type * minify * update --- semver/parse_range.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/semver/parse_range.ts b/semver/parse_range.ts index c429d1a02760..88e49847886a 100644 --- a/semver/parse_range.ts +++ b/semver/parse_range.ts @@ -279,6 +279,5 @@ export function parseRange(range: string): Range { const ranges = range .split(/\s*\|\|\s*/) .map((range) => parseHyphenRange(range).flatMap(parseRangeString)); - Object.defineProperty(ranges, "ranges", { value: ranges }); - return ranges as Range; + return ranges; } From 58cb4ba9f3aac3528bb107db43e1d44cfe4c1522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Hern=C3=A1ndez?= <73640929+javihernant@users.noreply.github.com> Date: Sat, 24 Feb 2024 01:51:17 +0100 Subject: [PATCH 54/63] chore: fix .editorconfig syntax (#4376) --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 15be5da03788..e15635cb78e6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ root = true -[*.ts,*.js] +[*.{ts,js}] charset = utf-8 end_of_line = lf insert_final_newline = true From 271a100e8f72ab5810362c6ee2a20ebdb5ea02f2 Mon Sep 17 00:00:00 2001 From: Gabriele Belluardo Date: Sat, 24 Feb 2024 21:22:50 +0100 Subject: [PATCH 55/63] refactor(streams): prepare for `noUncheckedIndexedAccess` (#4377) --- streams/_common.ts | 2 +- streams/delimiter_stream.ts | 10 +++++----- streams/merge_readable_streams.ts | 4 ++-- streams/text_delimiter_stream.ts | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/streams/_common.ts b/streams/_common.ts index 978ffcda008c..031915257c7b 100644 --- a/streams/_common.ts +++ b/streams/_common.ts @@ -20,7 +20,7 @@ export function createLPS(pat: Uint8Array): Uint8Array { lps[i] = 0; i++; } else { - prefixEnd = lps[prefixEnd - 1]; + prefixEnd = lps[prefixEnd - 1]!; } } return lps; diff --git a/streams/delimiter_stream.ts b/streams/delimiter_stream.ts index 5d7acdf61113..b7a77ad49fbe 100644 --- a/streams/delimiter_stream.ts +++ b/streams/delimiter_stream.ts @@ -116,7 +116,7 @@ export class DelimiterStream extends TransformStream { // they are (with concatenation). if (bufs.length === 1) { // Concat not needed when a single buffer is passed. - controller.enqueue(bufs[0]); + controller.enqueue(bufs[0]!); } else { controller.enqueue(concat(bufs)); } @@ -134,7 +134,7 @@ export class DelimiterStream extends TransformStream { } else if (delimitedChunkEnd < 0 && bufs.length > 0) { // Our chunk started by finishing a partial delimiter match. const lastIndex = bufs.length - 1; - const last = bufs[lastIndex]; + const last = bufs[lastIndex]!; const lastSliceIndex = last.byteLength + delimitedChunkEnd; const lastSliced = last.subarray(0, lastSliceIndex); if (lastIndex === 0) { @@ -173,7 +173,7 @@ export class DelimiterStream extends TransformStream { // but now got a new 'A', then we'll drop down to having matched // just 'A'. The while loop will turn around again and we'll rematch // to 'AA' and proceed onwards to try and match on 'B' again. - matchIndex = lps[matchIndex - 1]; + matchIndex = lps[matchIndex - 1]!; } } // Save match index. @@ -231,7 +231,7 @@ export class DelimiterStream extends TransformStream { // they are (with concatenation). if (bufs.length === 1) { // Concat not needed when a single buffer is passed. - controller.enqueue(bufs[0]); + controller.enqueue(bufs[0]!); } else { controller.enqueue(concat(bufs)); } @@ -275,7 +275,7 @@ export class DelimiterStream extends TransformStream { if (length === 0) { controller.enqueue(new Uint8Array()); } else if (length === 1) { - controller.enqueue(bufs[0]); + controller.enqueue(bufs[0]!); } else { controller.enqueue(concat(bufs)); } diff --git a/streams/merge_readable_streams.ts b/streams/merge_readable_streams.ts index 3d258c67a4f7..2ee8d2a1a835 100644 --- a/streams/merge_readable_streams.ts +++ b/streams/merge_readable_streams.ts @@ -40,9 +40,9 @@ export function mergeReadableStreams( } controller.enqueue(data); } - resolvePromises[index].resolve(); + resolvePromises[index]!.resolve(); } catch (error) { - resolvePromises[index].reject(error); + resolvePromises[index]!.reject(error); } })(); } diff --git a/streams/text_delimiter_stream.ts b/streams/text_delimiter_stream.ts index 2025cc33226d..90bb913d4ed4 100644 --- a/streams/text_delimiter_stream.ts +++ b/streams/text_delimiter_stream.ts @@ -73,7 +73,7 @@ export class TextDelimiterStream extends TransformStream { this.#inspectIndex++; localIndex++; } else { - this.#matchIndex = this.#delimLPS[this.#matchIndex - 1]; + this.#matchIndex = this.#delimLPS[this.#matchIndex - 1]!; } } } From 8693c81d58a32429c5bc0b5c8d70637015e450d8 Mon Sep 17 00:00:00 2001 From: cinchen Date: Sun, 25 Feb 2024 04:24:08 +0800 Subject: [PATCH 56/63] refactor(encoding): prepare for `noUncheckedIndexedAccess` (#4275) --- encoding/ascii85.ts | 8 ++-- encoding/ascii85_test.ts | 12 ++--- encoding/base32.ts | 91 ++++++++++++++++++-------------------- encoding/base32_test.ts | 2 +- encoding/base58.ts | 4 +- encoding/base58_test.ts | 2 +- encoding/base64.ts | 27 +++++++---- encoding/base64_test.ts | 2 +- encoding/base64url_test.ts | 2 +- encoding/hex.ts | 12 ++--- encoding/varint.ts | 4 +- 11 files changed, 87 insertions(+), 79 deletions(-) diff --git a/encoding/ascii85.ts b/encoding/ascii85.ts index 1c186f96ac91..c6feba603ef7 100644 --- a/encoding/ascii85.ts +++ b/encoding/ascii85.ts @@ -44,9 +44,9 @@ export interface Ascii85Options { delimiter?: boolean; } const rfc1924 = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~" as const; const Z85 = - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"; + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#" as const; /** * Converts data into an ascii58-encoded string. @@ -114,10 +114,10 @@ export function encodeAscii85( } break; case "RFC 1924": - output = output.map((val) => rfc1924[val.charCodeAt(0) - 33]); + output = output.map((val) => rfc1924[val.charCodeAt(0) - 33]!); break; case "Z85": - output = output.map((val) => Z85[val.charCodeAt(0) - 33]); + output = output.map((val) => Z85[val.charCodeAt(0) - 33]!); break; } return output.slice(0, output.length - difference).join(""); diff --git a/encoding/ascii85_test.ts b/encoding/ascii85_test.ts index ad5e302e4577..e5b73e17a411 100644 --- a/encoding/ascii85_test.ts +++ b/encoding/ascii85_test.ts @@ -123,7 +123,7 @@ for (const [standard, tests] of Object.entries(testCasesNoDelimiter)) { fn() { for (const [bin, b85] of tests) { assertEquals( - encodeAscii85(bin, { + encodeAscii85(bin as string, { standard: standard as Ascii85Standard, }), b85, @@ -137,7 +137,9 @@ for (const [standard, tests] of Object.entries(testCasesNoDelimiter)) { fn() { for (const [bin, b85] of tests) { assertEquals( - decodeAscii85(b85, { standard: standard as Ascii85Standard }), + decodeAscii85(b85 as string, { + standard: standard as Ascii85Standard, + }), utf8encoder.encode(bin), ); } @@ -151,7 +153,7 @@ for (const [standard, tests] of Object.entries(testCasesDelimiter)) { fn() { for (const [bin, b85] of tests) { assertEquals( - encodeAscii85(bin, { + encodeAscii85(bin as string, { standard: standard as Ascii85Standard, delimiter: true, }), @@ -166,7 +168,7 @@ for (const [standard, tests] of Object.entries(testCasesDelimiter)) { fn() { for (const [bin, b85] of tests) { assertEquals( - decodeAscii85(b85, { + decodeAscii85(b85 as string, { standard: standard as Ascii85Standard, delimiter: true, }), @@ -200,7 +202,7 @@ Deno.test({ ["<~FCfN8Bl7P~>", "testing"], ["<~A7]XsCgh3l~>", "denoland"], ["<~@<5pmBfIsm@:X:cAH~>", "ascii85 adobe"], - ]; + ] as const; for (const [input, expect] of tests) { assertEquals( diff --git a/encoding/base32.ts b/encoding/base32.ts index acbe0089f3a6..893cab2ab582 100644 --- a/encoding/base32.ts +++ b/encoding/base32.ts @@ -16,15 +16,9 @@ import { validateBinaryLike } from "./_util.ts"; -const lookup: string[] = []; +const lookup: string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".split(""); const revLookup: number[] = []; - -// RFC4648 base32 -const code = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; -for (let i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i]; - revLookup[code.charCodeAt(i)] = i; -} +lookup.forEach((c, i) => revLookup[c.charCodeAt(0)] = i); const placeHolderPadLookup = [0, 1, , 2, 3, , 4]; function _getPadLen(placeHoldersLen: number): number { @@ -79,55 +73,55 @@ export function decodeBase32(b32: string): Uint8Array { let i: number; for (i = 0; i < len; i += 8) { - tmp = (revLookup[b32.charCodeAt(i)] << 20) | - (revLookup[b32.charCodeAt(i + 1)] << 15) | - (revLookup[b32.charCodeAt(i + 2)] << 10) | - (revLookup[b32.charCodeAt(i + 3)] << 5) | - revLookup[b32.charCodeAt(i + 4)]; + tmp = (revLookup[b32.charCodeAt(i)]! << 20) | + (revLookup[b32.charCodeAt(i + 1)]! << 15) | + (revLookup[b32.charCodeAt(i + 2)]! << 10) | + (revLookup[b32.charCodeAt(i + 3)]! << 5) | + revLookup[b32.charCodeAt(i + 4)]!; arr[curByte++] = (tmp >> 17) & 0xff; arr[curByte++] = (tmp >> 9) & 0xff; arr[curByte++] = (tmp >> 1) & 0xff; tmp = ((tmp & 1) << 15) | - (revLookup[b32.charCodeAt(i + 5)] << 10) | - (revLookup[b32.charCodeAt(i + 6)] << 5) | - revLookup[b32.charCodeAt(i + 7)]; + (revLookup[b32.charCodeAt(i + 5)]! << 10) | + (revLookup[b32.charCodeAt(i + 6)]! << 5) | + revLookup[b32.charCodeAt(i + 7)]!; arr[curByte++] = (tmp >> 8) & 0xff; arr[curByte++] = tmp & 0xff; } if (placeHoldersLen === 1) { - tmp = (revLookup[b32.charCodeAt(i)] << 20) | - (revLookup[b32.charCodeAt(i + 1)] << 15) | - (revLookup[b32.charCodeAt(i + 2)] << 10) | - (revLookup[b32.charCodeAt(i + 3)] << 5) | - revLookup[b32.charCodeAt(i + 4)]; + tmp = (revLookup[b32.charCodeAt(i)]! << 20) | + (revLookup[b32.charCodeAt(i + 1)]! << 15) | + (revLookup[b32.charCodeAt(i + 2)]! << 10) | + (revLookup[b32.charCodeAt(i + 3)]! << 5) | + revLookup[b32.charCodeAt(i + 4)]!; arr[curByte++] = (tmp >> 17) & 0xff; arr[curByte++] = (tmp >> 9) & 0xff; arr[curByte++] = (tmp >> 1) & 0xff; tmp = ((tmp & 1) << 7) | - (revLookup[b32.charCodeAt(i + 5)] << 2) | - (revLookup[b32.charCodeAt(i + 6)] >> 3); + (revLookup[b32.charCodeAt(i + 5)]! << 2) | + (revLookup[b32.charCodeAt(i + 6)]! >> 3); arr[curByte++] = tmp & 0xff; } else if (placeHoldersLen === 3) { - tmp = (revLookup[b32.charCodeAt(i)] << 19) | - (revLookup[b32.charCodeAt(i + 1)] << 14) | - (revLookup[b32.charCodeAt(i + 2)] << 9) | - (revLookup[b32.charCodeAt(i + 3)] << 4) | - (revLookup[b32.charCodeAt(i + 4)] >> 1); + tmp = (revLookup[b32.charCodeAt(i)]! << 19) | + (revLookup[b32.charCodeAt(i + 1)]! << 14) | + (revLookup[b32.charCodeAt(i + 2)]! << 9) | + (revLookup[b32.charCodeAt(i + 3)]! << 4) | + (revLookup[b32.charCodeAt(i + 4)]! >> 1); arr[curByte++] = (tmp >> 16) & 0xff; arr[curByte++] = (tmp >> 8) & 0xff; arr[curByte++] = tmp & 0xff; } else if (placeHoldersLen === 4) { - tmp = (revLookup[b32.charCodeAt(i)] << 11) | - (revLookup[b32.charCodeAt(i + 1)] << 6) | - (revLookup[b32.charCodeAt(i + 2)] << 1) | - (revLookup[b32.charCodeAt(i + 3)] >> 4); + tmp = (revLookup[b32.charCodeAt(i)]! << 11) | + (revLookup[b32.charCodeAt(i + 1)]! << 6) | + (revLookup[b32.charCodeAt(i + 2)]! << 1) | + (revLookup[b32.charCodeAt(i + 3)]! >> 4); arr[curByte++] = (tmp >> 8) & 0xff; arr[curByte++] = tmp & 0xff; } else if (placeHoldersLen === 6) { - tmp = (revLookup[b32.charCodeAt(i)] << 3) | - (revLookup[b32.charCodeAt(i + 1)] >> 2); + tmp = (revLookup[b32.charCodeAt(i)]! << 3) | + (revLookup[b32.charCodeAt(i + 1)]! >> 2); arr[curByte++] = tmp & 0xff; } @@ -138,16 +132,16 @@ function encodeChunk(uint8: Uint8Array, start: number, end: number): string { let tmp: number; const output = []; for (let i = start; i < end; i += 5) { - tmp = ((uint8[i] << 16) & 0xff0000) | - ((uint8[i + 1] << 8) & 0xff00) | - (uint8[i + 2] & 0xff); + tmp = ((uint8[i]! << 16) & 0xff0000) | + ((uint8[i + 1]! << 8) & 0xff00) | + (uint8[i + 2]! & 0xff); output.push(lookup[(tmp >> 19) & 0x1f]); output.push(lookup[(tmp >> 14) & 0x1f]); output.push(lookup[(tmp >> 9) & 0x1f]); output.push(lookup[(tmp >> 4) & 0x1f]); tmp = ((tmp & 0xf) << 16) | - ((uint8[i + 3] << 8) & 0xff00) | - (uint8[i + 4] & 0xff); + ((uint8[i + 3]! << 8) & 0xff00) | + (uint8[i + 4]! & 0xff); output.push(lookup[(tmp >> 15) & 0x1f]); output.push(lookup[(tmp >> 10) & 0x1f]); output.push(lookup[(tmp >> 5) & 0x1f]); @@ -191,22 +185,22 @@ export function encodeBase32(data: ArrayBuffer | Uint8Array | string): string { // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 4) { - tmp = ((uint8[len2] & 0xff) << 16) | - ((uint8[len2 + 1] & 0xff) << 8) | - (uint8[len2 + 2] & 0xff); + tmp = ((uint8[len2]! & 0xff) << 16) | + ((uint8[len2 + 1]! & 0xff) << 8) | + (uint8[len2 + 2]! & 0xff); parts.push(lookup[(tmp >> 19) & 0x1f]); parts.push(lookup[(tmp >> 14) & 0x1f]); parts.push(lookup[(tmp >> 9) & 0x1f]); parts.push(lookup[(tmp >> 4) & 0x1f]); - tmp = ((tmp & 0xf) << 11) | (uint8[len2 + 3] << 3); + tmp = ((tmp & 0xf) << 11) | (uint8[len2 + 3]! << 3); parts.push(lookup[(tmp >> 10) & 0x1f]); parts.push(lookup[(tmp >> 5) & 0x1f]); parts.push(lookup[tmp & 0x1f]); parts.push("="); } else if (extraBytes === 3) { - tmp = ((uint8[len2] & 0xff) << 17) | - ((uint8[len2 + 1] & 0xff) << 9) | - ((uint8[len2 + 2] & 0xff) << 1); + tmp = ((uint8[len2]! & 0xff) << 17) | + ((uint8[len2 + 1]! & 0xff) << 9) | + ((uint8[len2 + 2]! & 0xff) << 1); parts.push(lookup[(tmp >> 20) & 0x1f]); parts.push(lookup[(tmp >> 15) & 0x1f]); parts.push(lookup[(tmp >> 10) & 0x1f]); @@ -214,14 +208,15 @@ export function encodeBase32(data: ArrayBuffer | Uint8Array | string): string { parts.push(lookup[tmp & 0x1f]); parts.push("==="); } else if (extraBytes === 2) { - tmp = ((uint8[len2] & 0xff) << 12) | ((uint8[len2 + 1] & 0xff) << 4); + tmp = ((uint8[len2]! & 0xff) << 12) | + ((uint8[len2 + 1]! & 0xff) << 4); parts.push(lookup[(tmp >> 15) & 0x1f]); parts.push(lookup[(tmp >> 10) & 0x1f]); parts.push(lookup[(tmp >> 5) & 0x1f]); parts.push(lookup[tmp & 0x1f]); parts.push("===="); } else if (extraBytes === 1) { - tmp = (uint8[len2] & 0xff) << 2; + tmp = (uint8[len2]! & 0xff) << 2; parts.push(lookup[(tmp >> 5) & 0x1f]); parts.push(lookup[tmp & 0x1f]); parts.push("======"); diff --git a/encoding/base32_test.ts b/encoding/base32_test.ts index a7d5bba8e439..ffb3455c807c 100644 --- a/encoding/base32_test.ts +++ b/encoding/base32_test.ts @@ -85,7 +85,7 @@ const testCases = [ "f2fc2319bd29457ccd01e8e194ee9bd7e97298b6610df4ab0f3d5baa0b2d7ccf69829edb74edef", "6L6CGGN5FFCXZTIB5DQZJ3U327UXFGFWMEG7JKYPHVN2UCZNPTHWTAU63N2O33Y=", ], -]; +] as const; Deno.test({ name: "encodeBase32()", diff --git a/encoding/base58.ts b/encoding/base58.ts index b9886ae86944..ed94669717d0 100644 --- a/encoding/base58.ts +++ b/encoding/base58.ts @@ -81,7 +81,9 @@ export function encodeBase58(data: ArrayBuffer | Uint8Array | string): string { strResult.fill("1", 0, zeroes); } - b58Encoding.forEach((byteValue) => strResult.push(base58alphabet[byteValue])); + b58Encoding.forEach((byteValue) => + strResult.push(base58alphabet[byteValue]!) + ); return strResult.join(""); } diff --git a/encoding/base58_test.ts b/encoding/base58_test.ts index 24088f336f0f..36bf569d050e 100644 --- a/encoding/base58_test.ts +++ b/encoding/base58_test.ts @@ -26,7 +26,7 @@ const testSetString = [ ]), "HNZata7iMYWmk5RvZRTiAsSDhV8366zq2YGb3tLH5Upf74F", ], -]; +] as const; const testSetBinary = testSetString.map(([data, b58]) => { if (typeof data === "string") { diff --git a/encoding/base64.ts b/encoding/base64.ts index b229f136022d..6485af4b0119 100644 --- a/encoding/base64.ts +++ b/encoding/base64.ts @@ -99,22 +99,31 @@ export function encodeBase64(data: ArrayBuffer | Uint8Array | string): string { i; const l = uint8.length; for (i = 2; i < l; i += 3) { - result += base64abc[uint8[i - 2] >> 2]; - result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; - result += base64abc[((uint8[i - 1] & 0x0f) << 2) | (uint8[i] >> 6)]; - result += base64abc[uint8[i] & 0x3f]; + result += base64abc[(uint8[i - 2]!) >> 2]; + result += base64abc[ + (((uint8[i - 2]!) & 0x03) << 4) | + ((uint8[i - 1]!) >> 4) + ]; + result += base64abc[ + (((uint8[i - 1]!) & 0x0f) << 2) | + ((uint8[i]!) >> 6) + ]; + result += base64abc[(uint8[i]!) & 0x3f]; } if (i === l + 1) { // 1 octet yet to write - result += base64abc[uint8[i - 2] >> 2]; - result += base64abc[(uint8[i - 2] & 0x03) << 4]; + result += base64abc[(uint8[i - 2]!) >> 2]; + result += base64abc[((uint8[i - 2]!) & 0x03) << 4]; result += "=="; } if (i === l) { // 2 octets yet to write - result += base64abc[uint8[i - 2] >> 2]; - result += base64abc[((uint8[i - 2] & 0x03) << 4) | (uint8[i - 1] >> 4)]; - result += base64abc[(uint8[i - 1] & 0x0f) << 2]; + result += base64abc[(uint8[i - 2]!) >> 2]; + result += base64abc[ + (((uint8[i - 2]!) & 0x03) << 4) | + ((uint8[i - 1]!) >> 4) + ]; + result += base64abc[((uint8[i - 1]!) & 0x0f) << 2]; result += "="; } return result; diff --git a/encoding/base64_test.ts b/encoding/base64_test.ts index a35152c370e7..9e95bcfe9da4 100644 --- a/encoding/base64_test.ts +++ b/encoding/base64_test.ts @@ -12,7 +12,7 @@ const testsetString = [ ["foob", "Zm9vYg=="], ["fooba", "Zm9vYmE="], ["foobar", "Zm9vYmFy"], -]; +] as const; const testsetBinary = testsetString.map(([str, b64]) => [ new TextEncoder().encode(str), diff --git a/encoding/base64url_test.ts b/encoding/base64url_test.ts index 1416a21b7ae8..dfd5ad7b3620 100644 --- a/encoding/base64url_test.ts +++ b/encoding/base64url_test.ts @@ -29,7 +29,7 @@ const testsetInvalid = [ Deno.test("encodeBase64Url() encodes string", () => { for (const [input, output] of testsetString) { - assertEquals(encodeBase64Url(input), output); + assertEquals(encodeBase64Url(input!), output); } }); diff --git a/encoding/hex.ts b/encoding/hex.ts index 4f21681a27e0..60cd2f9cafed 100644 --- a/encoding/hex.ts +++ b/encoding/hex.ts @@ -70,9 +70,9 @@ export function encodeHex(src: string | Uint8Array | ArrayBuffer): string { const dst = new Uint8Array(u8.length * 2); for (let i = 0; i < dst.length; i++) { - const v = u8[i]; - dst[i * 2] = hexTable[v >> 4]; - dst[i * 2 + 1] = hexTable[v & 0x0f]; + const v = u8[i]!; + dst[i * 2] = hexTable[v >> 4]!; + dst[i * 2 + 1] = hexTable[v & 0x0f]!; } return textDecoder.decode(dst); } @@ -92,15 +92,15 @@ export function decodeHex(src: string): Uint8Array { const u8 = textEncoder.encode(src); const dst = new Uint8Array(u8.length / 2); for (let i = 0; i < dst.length; i++) { - const a = fromHexChar(u8[i * 2]); - const b = fromHexChar(u8[i * 2 + 1]); + const a = fromHexChar(u8[i * 2]!); + const b = fromHexChar(u8[i * 2 + 1]!); dst[i] = (a << 4) | b; } if (u8.length % 2 === 1) { // Check for invalid char before reporting bad length, // since the invalid char (if present) is an earlier problem. - fromHexChar(u8[dst.length * 2]); + fromHexChar(u8[dst.length * 2]!); throw errLength(); } diff --git a/encoding/varint.ts b/encoding/varint.ts index 07e411ecd091..40b4b39583c4 100644 --- a/encoding/varint.ts +++ b/encoding/varint.ts @@ -53,7 +53,7 @@ export function decode(buf: Uint8Array, offset = 0): [bigint, number] { let byte; do { // Get a single byte from the buffer - byte = buf[i]; + byte = buf[i]!; // 1. Take the lower 7 bits of the byte. // 2. Shift the bits into the correct position. @@ -120,7 +120,7 @@ export function decode32(buf: Uint8Array, offset = 0): [number, number] { i <= len; i += 1, shift += SHIFT ) { - const byte = buf[i]; + const byte = buf[i]!; decoded += (byte & REST) * Math.pow(2, shift); if (!(byte & MSB)) return [decoded, i + 1]; } From 9882fbfb09f2e47791c2fe14405031ba836eb448 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Sat, 24 Feb 2024 23:00:35 +0100 Subject: [PATCH 57/63] chore(msgpack): format test names (#4381) --- msgpack/decode_test.ts | 30 +++++++++++++++--------------- msgpack/encode_test.ts | 20 ++++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/msgpack/decode_test.ts b/msgpack/decode_test.ts index 06518351051c..d60fd6c6978d 100644 --- a/msgpack/decode_test.ts +++ b/msgpack/decode_test.ts @@ -3,20 +3,20 @@ import { assertEquals, assertThrows } from "../assert/mod.ts"; import { decode } from "./decode.ts"; -Deno.test("positive fixint", () => { +Deno.test("decode() handles positive fixint", () => { for (let i = 0; i <= 0x7f; i++) { assertEquals(decode(Uint8Array.of(i)), i); } }); -Deno.test("fixmap", () => { +Deno.test("decode() handles fixmap", () => { const map = { "a": 2, "b": 3 }; const encodedMap = [0b1010_0001, 97, 2, 0b1010_0001, 98, 3]; assertEquals(decode(Uint8Array.of(0b10000000 | 2, ...encodedMap)), map); }); -Deno.test("fixarray", () => { +Deno.test("decode() handles fixarray", () => { const array = [0, 1, 2, 3, 4, 5, 6]; assertEquals( @@ -25,7 +25,7 @@ Deno.test("fixarray", () => { ); }); -Deno.test("fixstr", () => { +Deno.test("decode() handles fixstr", () => { const str = "hello world!"; const encoded = new TextEncoder().encode(str); @@ -35,14 +35,14 @@ Deno.test("fixstr", () => { ); }); -Deno.test("nil, (never used), false, true", () => { +Deno.test("decode() handles nil, (never used), false, true", () => { assertEquals(decode(Uint8Array.of(0xc0)), null); // nil assertThrows(() => decode(Uint8Array.of(0xc1))); // (never used) assertEquals(decode(Uint8Array.of(0xc2)), false); // false assertEquals(decode(Uint8Array.of(0xc3)), true); // true }); -Deno.test("bin 8, bin 16, bin 32", () => { +Deno.test("decode() handles bin 8, bin 16, bin 32", () => { const arr = Uint8Array.of(0, 1, 2, 3, 4, 5, 6, 7); assertEquals(decode(Uint8Array.of(0xc4, arr.length, ...arr)), arr); assertEquals(decode(Uint8Array.of(0xc5, 0, arr.length, ...arr)), arr); @@ -52,13 +52,13 @@ Deno.test("bin 8, bin 16, bin 32", () => { ); }); -Deno.test("ext 8, ext 16, ext 32", () => { +Deno.test("decode() handles ext 8, ext 16, ext 32", () => { assertThrows(() => decode(Uint8Array.of(0xc7))); assertThrows(() => decode(Uint8Array.of(0xc8))); assertThrows(() => decode(Uint8Array.of(0xc9))); }); -Deno.test("float 32, float 64", () => { +Deno.test("decode() handles float 32, float 64", () => { assertEquals( decode(Uint8Array.of(0xca, 0x43, 0xd2, 0x58, 0x52)), 420.69000244140625, @@ -71,7 +71,7 @@ Deno.test("float 32, float 64", () => { ); }); -Deno.test("uint8, uint16, uint32, uint64", () => { +Deno.test("decode() handles uint8, uint16, uint32, uint64", () => { assertEquals(decode(Uint8Array.of(0xcc, 0xff)), 255); assertEquals(decode(Uint8Array.of(0xcd, 0xff, 0xff)), 65535); assertEquals( @@ -86,7 +86,7 @@ Deno.test("uint8, uint16, uint32, uint64", () => { ); }); -Deno.test("int8, int16, int32, int64", () => { +Deno.test("decode() handles int8, int16, int32, int64", () => { assertEquals(decode(Uint8Array.of(0xd0, 0x80)), -128); assertEquals(decode(Uint8Array.of(0xd1, 0x80, 0x00)), -32768); assertEquals( @@ -101,7 +101,7 @@ Deno.test("int8, int16, int32, int64", () => { ); }); -Deno.test("fixext 1, fixext 2, fixext 4, fixext 8, fixext 16", () => { +Deno.test("decode() handles fixext 1, fixext 2, fixext 4, fixext 8, fixext 16", () => { assertThrows(() => decode(Uint8Array.of(0xd4))); assertThrows(() => decode(Uint8Array.of(0xd5))); assertThrows(() => decode(Uint8Array.of(0xd6))); @@ -109,7 +109,7 @@ Deno.test("fixext 1, fixext 2, fixext 4, fixext 8, fixext 16", () => { assertThrows(() => decode(Uint8Array.of(0xd8))); }); -Deno.test("str 8, str 16, str 32", () => { +Deno.test("decode() handles str 8, str 16, str 32", () => { const str = "hello world!"; const encoded = new TextEncoder().encode(str); @@ -124,7 +124,7 @@ Deno.test("str 8, str 16, str 32", () => { ); }); -Deno.test("array 16, array 32", () => { +Deno.test("decode() handles array 16, array 32", () => { const array = [0, 1, 2, 3, 4, 5, 6]; assertEquals( @@ -137,7 +137,7 @@ Deno.test("array 16, array 32", () => { ); }); -Deno.test("map 16, map 32", () => { +Deno.test("decode() handles map 16, map 32", () => { const map = { "a": 2, "b": 3 }; const encodedMap = [0b1010_0001, 97, 2, 0b1010_0001, 98, 3]; @@ -145,7 +145,7 @@ Deno.test("map 16, map 32", () => { assertEquals(decode(Uint8Array.of(0xdf, 0, 0, 0, 2, ...encodedMap)), map); }); -Deno.test("negative fixint", () => { +Deno.test("decode() handles negative fixint", () => { for (let i = -32; i <= -1; i++) { assertEquals(decode(Uint8Array.of(i)), i); } diff --git a/msgpack/encode_test.ts b/msgpack/encode_test.ts index 2c840c1c7d30..baebe1f5ec4a 100644 --- a/msgpack/encode_test.ts +++ b/msgpack/encode_test.ts @@ -7,7 +7,7 @@ import { decode, encode } from "./mod.ts"; const moduleDir = path.dirname(path.fromFileUrl(import.meta.url)); const testdataDir = path.resolve(moduleDir, "testdata"); -Deno.test("testdata", () => { +Deno.test("encode() handles testdata", () => { const one = JSON.parse( Deno.readTextFileSync(path.join(testdataDir, "1.json")), ); @@ -34,7 +34,7 @@ Deno.test("testdata", () => { assertEquals(decode(encode(five)), five); }); -Deno.test("positive numbers", () => { +Deno.test("encode() handles positive numbers", () => { assertEquals(encode(1), Uint8Array.of(1)); assertEquals(decode(encode(1)), 1); @@ -54,7 +54,7 @@ Deno.test("positive numbers", () => { assertEquals(decode(encode(20000000000)), 20000000000); }); -Deno.test("negative numbers", () => { +Deno.test("encode() handles negative numbers", () => { assertEquals(encode(-1), Uint8Array.of(255)); assertEquals(decode(encode(-1)), -1); @@ -74,7 +74,7 @@ Deno.test("negative numbers", () => { assertEquals(decode(encode(-600000000000)), -600000000000); }); -Deno.test("floats", () => { +Deno.test("encode() handles floats", () => { assertEquals( encode(0.3), Uint8Array.of(0xcb, 63, 211, 51, 51, 51, 51, 51, 51), @@ -82,7 +82,7 @@ Deno.test("floats", () => { assertEquals(decode(encode(0.3)), 0.3); }); -Deno.test("bigints", () => { +Deno.test("encode() handles bigints", () => { assertEquals(encode(0n), Uint8Array.of(0xcf, 0, 0, 0, 0, 0, 0, 0, 0)); assertEquals(decode(encode(0n)), 0n); assertEquals( @@ -102,7 +102,7 @@ Deno.test("bigints", () => { assertThrows(() => encode(-99999999999999999999999n)); }); -Deno.test("strings", () => { +Deno.test("encode() handles strings", () => { assertEquals( encode("hello world"), Uint8Array.of(171, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100), @@ -138,7 +138,7 @@ Deno.test("strings", () => { assertEquals(decode(encode(reallyLongString)), reallyLongString); }); -Deno.test("arrays", () => { +Deno.test("encode() handles arrays", () => { const arr0: never[] = []; assertEquals(decode(encode(arr0)), arr0); @@ -152,7 +152,7 @@ Deno.test("arrays", () => { assertEquals(decode(encode(nestedArr)), nestedArr); }); -Deno.test("maps", () => { +Deno.test("encode() handles maps", () => { const map0 = {}; assertEquals(decode(encode(map0)), map0); @@ -163,7 +163,7 @@ Deno.test("maps", () => { assertEquals(decode(encode(nestedMap)), nestedMap); }); -Deno.test("huge array with 100k objects", () => { +Deno.test("encode() handles huge array with 100k objects", () => { const bigArray = []; for (let i = 0; i < 100000; i++) { bigArray.push({ a: { i: `${i}` }, i: i }); @@ -173,7 +173,7 @@ Deno.test("huge array with 100k objects", () => { assertEquals(decode(encode(bigObject)), bigObject); }); -Deno.test("huge object with 100k properties", () => { +Deno.test("encode() handles huge object with 100k properties", () => { const bigObject = {}; for (let i = 0; i < 100000; i++) { const _ = Object.defineProperty(bigObject, `prop_${i}`, { From 987fc72fe9ff863f2fa02f4d4072bce6ed173c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=9Blisue=20=28Ali=20sue=E3=83=BB=E3=81=82=E3=82=8A?= =?UTF-8?q?=E3=81=99=E3=81=88=29?= Date: Sun, 25 Feb 2024 20:51:37 +0900 Subject: [PATCH 58/63] feat(collections): add `pick` and `omit` (#4218) Co-authored-by: Kenta Moriuchi --- collections/mod.ts | 2 ++ collections/omit.ts | 26 ++++++++++++++++++++++++++ collections/omit_test.ts | 38 ++++++++++++++++++++++++++++++++++++++ collections/pick.ts | 22 ++++++++++++++++++++++ collections/pick_test.ts | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 collections/omit.ts create mode 100644 collections/omit_test.ts create mode 100644 collections/pick.ts create mode 100644 collections/pick_test.ts diff --git a/collections/mod.ts b/collections/mod.ts index 93760b045bec..f8f2135d86fc 100644 --- a/collections/mod.ts +++ b/collections/mod.ts @@ -54,3 +54,5 @@ export * from "./drop_last_while.ts"; export * from "./reduce_groups.ts"; export * from "./sample.ts"; export * from "./running_reduce.ts"; +export * from "./pick.ts"; +export * from "./omit.ts"; diff --git a/collections/omit.ts b/collections/omit.ts new file mode 100644 index 000000000000..06565eca0081 --- /dev/null +++ b/collections/omit.ts @@ -0,0 +1,26 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +/** + * Creates a new object by excluding the specified keys from the provided object. + * + * @example + * ```ts + * import { omit } from "https://deno.land/std@$STD_VERSION/collections/omit.ts"; + * import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts"; + * + * const obj = { a: 5, b: 6, c: 7, d: 8 }; + * const omitted = omit(obj, ["a", "c"]); + * + * assertEquals(omitted, { b: 6, d: 8 }); + * ``` + */ +export function omit( + obj: Readonly, + keys: readonly K[], +): Omit { + const excludes = new Set(keys); + const has = excludes.has.bind(excludes); + return Object.fromEntries( + Object.entries(obj).filter(([k, _]) => !has(k as K)), + ) as Omit; +} diff --git a/collections/omit_test.ts b/collections/omit_test.ts new file mode 100644 index 000000000000..cd2b701d2b52 --- /dev/null +++ b/collections/omit_test.ts @@ -0,0 +1,38 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { assertEquals, assertNotStrictEquals } from "../assert/mod.ts"; +import { omit } from "./omit.ts"; + +Deno.test({ + name: "omit() returns a new object from the provided object", + fn() { + const obj = { a: 5, b: 6, c: 7, d: 8 }; + const omitted = omit(obj, []); + + assertEquals(omitted, { a: 5, b: 6, c: 7, d: 8 }); + assertNotStrictEquals(omitted, obj); + }, +}); + +Deno.test({ + name: + "omit() returns a new object from the provided object without the provided keys", + fn() { + const obj = { a: 5, b: 6, c: 7, d: 8 }; + const omitted = omit(obj, ["a", "c"]); + + assertEquals(omitted, { b: 6, d: 8 }); + assertNotStrictEquals(omitted, obj); + }, +}); + +Deno.test({ + name: "omit() returns an empty object when the provided keys is empty", + fn() { + const obj = { a: 5, b: 6, c: 7, d: 8 }; + const omitted = omit(obj, ["a", "b", "c", "d"]); + + assertEquals(omitted, {}); + assertNotStrictEquals(omitted, obj); + }, +}); diff --git a/collections/pick.ts b/collections/pick.ts new file mode 100644 index 000000000000..e508635d922d --- /dev/null +++ b/collections/pick.ts @@ -0,0 +1,22 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +/** + * Creates a new object by including the specified keys from the provided object. + * + * @example + * ```ts + * import { pick } from "https://deno.land/std@$STD_VERSION/collections/pick.ts"; + * import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts"; + * + * const obj = { a: 5, b: 6, c: 7, d: 8 }; + * const picked = pick(obj, ["a", "c"]); + * + * assertEquals(picked, { a: 5, c: 7 }); + * ``` + */ +export function pick( + obj: Readonly, + keys: readonly K[], +): Pick { + return Object.fromEntries(keys.map((k) => [k, obj[k]])) as Pick; +} diff --git a/collections/pick_test.ts b/collections/pick_test.ts new file mode 100644 index 000000000000..1af6d6f3a90c --- /dev/null +++ b/collections/pick_test.ts @@ -0,0 +1,39 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { assertEquals, assertNotStrictEquals } from "../assert/mod.ts"; +import { pick } from "./pick.ts"; + +Deno.test({ + name: "pick() returns a new empty object when no keys are provided", + fn() { + const obj = { a: 5, b: 6, c: 7, d: 8 }; + const picked = pick(obj, []); + + assertEquals(picked, {}); + assertNotStrictEquals(picked, obj); + }, +}); + +Deno.test({ + name: + "pick() returns a new object from the provided object with the provided keys", + fn() { + const obj = { a: 5, b: 6, c: 7, d: 8 }; + const picked = pick(obj, ["a", "c"]); + + assertEquals(picked, { a: 5, c: 7 }); + assertNotStrictEquals(picked, obj); + }, +}); + +Deno.test({ + name: + "pick() returns a new object from the provided object with the provided keys (all keys are provided)", + fn() { + const obj = { a: 5, b: 6, c: 7, d: 8 }; + const picked = pick(obj, ["a", "b", "c", "d"]); + + assertEquals(picked, { a: 5, b: 6, c: 7, d: 8 }); + assertNotStrictEquals(picked, obj); + }, +}); From 7fb8c5f8187a276225a729563a7f351dccd23756 Mon Sep 17 00:00:00 2001 From: Jesse Jackson Date: Sun, 25 Feb 2024 14:16:11 -0600 Subject: [PATCH 59/63] docs: clarify underscore guidance in README (#4385) * docs: clarify underscore guidance in README * add explanation to symbol list item --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 192dc5ac6cd2..0f5493eb1ab2 100644 --- a/README.md +++ b/README.md @@ -45,18 +45,25 @@ Check out the documentation [here](https://deno.land/std?doc). import * as fs from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; ``` -1. Do not import symbols with an underscore in the name. +1. Do not import symbols with a name _prefixed_ by an underscore (they're not + intended for public use). Bad: ```ts import { _format } from "https://deno.land/std@$STD_VERSION/path/_common/format.ts"; ``` -1. Do not import modules with an underscore in the path. +1. Do not import modules with a directory or filename _prefixed_ by an + underscore (they're not intended for public use). Bad: ```ts - import { filterInPlace } from "https://deno.land/std@$STD_VERSION/collections/_utils.ts"; + import { createLPS } from "https://deno.land/std@$STD_VERSION/streams/_common.ts"; + ``` + + Good: + ```ts + import { TextLineStream } from "https://deno.land/std@$STD_VERSION/streams/text_line_stream.ts"; ``` 1. Do not import test modules or test data. From eac60e654519a8259199e6e24410365ef4e2eba8 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Sun, 25 Feb 2024 23:25:12 +0100 Subject: [PATCH 60/63] chore(media_types): format test names (#4380) --- media_types/_util_test.ts | 6 +++--- media_types/content_type_test.ts | 4 ++-- media_types/extension_test.ts | 2 +- media_types/extensions_by_type_test.ts | 2 +- media_types/format_media_type_test.ts | 2 +- media_types/get_charset_test.ts | 2 +- media_types/parse_media_type_test.ts | 2 +- media_types/type_by_extension_test.ts | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/media_types/_util_test.ts b/media_types/_util_test.ts index 8899c9d486cd..afcf81cf1633 100644 --- a/media_types/_util_test.ts +++ b/media_types/_util_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { consumeMediaParam, consumeToken, consumeValue } from "./_util.ts"; Deno.test({ - name: "media_types::util - consumeToken()", + name: "consumeToken()", fn() { const fixtures = [ ["foo bar", "foo", " bar"], @@ -19,7 +19,7 @@ Deno.test({ }); Deno.test({ - name: "media_types::util - consumeValue()", + name: "consumeValue()", fn() { const fixtures = [ ["foo bar", "foo", " bar"], @@ -44,7 +44,7 @@ Deno.test({ }); Deno.test({ - name: "media_types::util - consumeMediaParam()", + name: "consumeMediaParam()", fn() { const fixtures = [ [" ; foo=bar", "foo", "bar", ""], diff --git a/media_types/content_type_test.ts b/media_types/content_type_test.ts index 39ce2a0b005c..8eeaed408f35 100644 --- a/media_types/content_type_test.ts +++ b/media_types/content_type_test.ts @@ -4,7 +4,7 @@ import { contentType } from "./content_type.ts"; import { assertEquals } from "../assert/mod.ts"; Deno.test({ - name: "media_types - contentType()", + name: "contentType()", fn() { const fixtures = [ [".json", "application/json; charset=UTF-8"], @@ -22,7 +22,7 @@ Deno.test({ }); Deno.test({ - name: "media_types - contentType()", + name: "contentType() implies types", fn() { let _str: string; // For well-known content types, the return type is a string. diff --git a/media_types/extension_test.ts b/media_types/extension_test.ts index ca3918a757ed..166e7d88a3d7 100644 --- a/media_types/extension_test.ts +++ b/media_types/extension_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { extension } from "./mod.ts"; Deno.test({ - name: "media_types - extension()", + name: "extension()", fn() { const fixtures: [string, string | undefined][] = [ ["image/gif", "gif"], diff --git a/media_types/extensions_by_type_test.ts b/media_types/extensions_by_type_test.ts index 1b1185c865e8..7306ecbd75bb 100644 --- a/media_types/extensions_by_type_test.ts +++ b/media_types/extensions_by_type_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { extensionsByType } from "./extensions_by_type.ts"; Deno.test({ - name: "media_types - extensionsByType()", + name: "extensionsByType()", fn() { const fixtures: [string, string[] | undefined][] = [ ["image/gif", ["gif"]], diff --git a/media_types/format_media_type_test.ts b/media_types/format_media_type_test.ts index d39e9974121a..4ceb97322f25 100644 --- a/media_types/format_media_type_test.ts +++ b/media_types/format_media_type_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { formatMediaType } from "./mod.ts"; Deno.test({ - name: "media_types - formatMediaType", + name: "formatMediaType()", fn() { const fixtures = [ ["noslash", { X: "Y" }, "noslash; x=Y"], diff --git a/media_types/get_charset_test.ts b/media_types/get_charset_test.ts index 3dd5f6671db5..466ea7f3be23 100644 --- a/media_types/get_charset_test.ts +++ b/media_types/get_charset_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { getCharset } from "./mod.ts"; Deno.test({ - name: "media-types - getCharset()", + name: "getCharset()", fn() { const fixtures = [ ["text/plain", "UTF-8"], diff --git a/media_types/parse_media_type_test.ts b/media_types/parse_media_type_test.ts index a0595e38407f..5195578149d8 100644 --- a/media_types/parse_media_type_test.ts +++ b/media_types/parse_media_type_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { parseMediaType } from "./mod.ts"; Deno.test({ - name: "media_types - parseMediaType()", + name: "parseMediaType()", fn() { const nameFoo = { "name": "foo" }; const fixtures: [string, string, Record | undefined][] = [ diff --git a/media_types/type_by_extension_test.ts b/media_types/type_by_extension_test.ts index aabee80519d2..f9a94e12da61 100644 --- a/media_types/type_by_extension_test.ts +++ b/media_types/type_by_extension_test.ts @@ -4,7 +4,7 @@ import { assertEquals } from "../assert/mod.ts"; import { typeByExtension } from "./mod.ts"; Deno.test({ - name: "media_types - typeByExtension", + name: "typeByExtension()", fn() { const fixtures = [ ["js", "application/javascript"], From ce719de1a75158f2abca8590d3901a3125d30238 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Mon, 26 Feb 2024 19:46:10 +1100 Subject: [PATCH 61/63] docs: ignore bad snippet examples (#4388) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f5493eb1ab2..c4d6bccaa422 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Check out the documentation [here](https://deno.land/std?doc). intended for public use). Bad: - ```ts + ```ts, ignore import { _format } from "https://deno.land/std@$STD_VERSION/path/_common/format.ts"; ``` @@ -57,7 +57,7 @@ Check out the documentation [here](https://deno.land/std?doc). underscore (they're not intended for public use). Bad: - ```ts + ```ts, ignore import { createLPS } from "https://deno.land/std@$STD_VERSION/streams/_common.ts"; ``` From 0f62d4c1e414716b48060eb5058fac8eb2ff0db9 Mon Sep 17 00:00:00 2001 From: Tim Reichen Date: Mon, 26 Feb 2024 14:22:21 +0100 Subject: [PATCH 62/63] chore(log): sync `level` and `levelName` in BaseHandler (#4393) --- log/base_handler.ts | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/log/base_handler.ts b/log/base_handler.ts index 6b68e01fe1bc..3eb65c118de4 100644 --- a/log/base_handler.ts +++ b/log/base_handler.ts @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { getLevelByName, LevelName } from "./levels.ts"; +import { getLevelByName, getLevelName, LevelName, LogLevel } from "./levels.ts"; import type { LogRecord } from "./logger.ts"; export type FormatterFunction = (logRecord: LogRecord) => string; @@ -11,14 +11,33 @@ export interface BaseHandlerOptions { } export class BaseHandler { - level: number; - levelName: LevelName; + #levelName: LevelName; + #level: LogLevel; formatter: FormatterFunction; - constructor(levelName: LevelName, options: BaseHandlerOptions = {}) { - this.level = getLevelByName(levelName); - this.levelName = levelName; - this.formatter = options.formatter || DEFAULT_FORMATTER; + constructor( + levelName: LevelName, + { formatter = DEFAULT_FORMATTER }: BaseHandlerOptions = {}, + ) { + this.#levelName = levelName; + this.#level = getLevelByName(levelName); + this.formatter = formatter; + } + + get level() { + return this.#level; + } + set level(level: LogLevel) { + this.#level = level; + this.#levelName = getLevelName(level); + } + + get levelName() { + return this.#levelName; + } + set levelName(levelName: LevelName) { + this.#levelName = levelName; + this.#level = getLevelByName(levelName); } handle(logRecord: LogRecord) { From 27517a8578cfbed025167ccee7e71082a23af3c6 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Tue, 27 Feb 2024 05:58:17 +1100 Subject: [PATCH 63/63] docs: link to `assertThrows()` and `assertRejects()` (#4395) --- assert/assert_rejects.ts | 4 ++++ assert/assert_throws.ts | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/assert/assert_rejects.ts b/assert/assert_rejects.ts index 859fc30b28e3..a23963dedd0f 100644 --- a/assert/assert_rejects.ts +++ b/assert/assert_rejects.ts @@ -5,6 +5,8 @@ import { assertIsError } from "./assert_is_error.ts"; /** * Executes a function which returns a promise, expecting it to reject. * + * To assert that a synchronous function throws, use {@linkcode assertThrows}. + * * @example * ```ts * import { assertRejects } from "https://deno.land/std@$STD_VERSION/assert/assert_rejects.ts"; @@ -22,6 +24,8 @@ export function assertRejects( * If it does not, then it throws. An error class and a string that should be * included in the error message can also be asserted. * + * To assert that a synchronous function throws, use {@linkcode assertThrows}. + * * @example * ```ts * import { assertRejects } from "https://deno.land/std@$STD_VERSION/assert/assert_rejects.ts"; diff --git a/assert/assert_throws.ts b/assert/assert_throws.ts index e52674fae1bd..7f29e26feda4 100644 --- a/assert/assert_throws.ts +++ b/assert/assert_throws.ts @@ -6,6 +6,9 @@ import { AssertionError } from "./assertion_error.ts"; * Executes a function, expecting it to throw. If it does not, then it * throws. * + * To assert that an asynchronous function rejects, use + * {@linkcode assertRejects}. + * * @example * ```ts * import { assertThrows } from "https://deno.land/std@$STD_VERSION/assert/assert_throws.ts"; @@ -23,6 +26,9 @@ export function assertThrows( * throws. An error class and a string that should be included in the * error message can also be asserted. * + * To assert that an asynchronous function rejects, use + * {@linkcode assertRejects}. + * * @example * ```ts * import { assertThrows } from "https://deno.land/std@$STD_VERSION/assert/assert_throws.ts";