From 88a87578a4f38bf03bb96433a90de2c79e1cd4eb Mon Sep 17 00:00:00 2001 From: Marcello Date: Thu, 9 Jul 2026 15:21:20 -0400 Subject: [PATCH] Pin npm CLI for publish workflow --- .github/workflows/publish_jsr.yml | 4 ++++ .github/workflows/publish_npm.yml | 12 +++++++---- deno.json | 2 +- src/core.ts | 33 ++++++++++++++----------------- src/core_test.ts | 14 +++++++++++++ 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish_jsr.yml b/.github/workflows/publish_jsr.yml index f659c1d..4751942 100644 --- a/.github/workflows/publish_jsr.yml +++ b/.github/workflows/publish_jsr.yml @@ -13,4 +13,8 @@ jobs: id-token: write # The OIDC ID token is used for authentication with JSR. steps: - uses: actions/checkout@v5 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 26 - run: npx jsr publish diff --git a/.github/workflows/publish_npm.yml b/.github/workflows/publish_npm.yml index facc02c..95be418 100644 --- a/.github/workflows/publish_npm.yml +++ b/.github/workflows/publish_npm.yml @@ -26,13 +26,17 @@ jobs: run: deno -A scripts/build_npm.ts - name: Setup Node.js and npm - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 26 registry-url: https://registry.npmjs.org/ - - name: Update npm - run: npm install -g npm@latest + # Avoid npm@latest provenance regression that fails with MODULE_NOT_FOUND for sigstore. + - name: Pin npm CLI + run: npm install -g npm@11.4.2 + + - name: Verify npm CLI version + run: npm --version - name: Publish to NPM run: cd npm && npm publish --access public diff --git a/deno.json b/deno.json index a63001e..7433c96 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@bytebury/toolkit", - "version": "2.2.0", + "version": "2.3.0", "exports": { ".": "./mod.ts", "./core": "./src/core.ts", diff --git a/src/core.ts b/src/core.ts index bbde9f7..2dbaaec 100644 --- a/src/core.ts +++ b/src/core.ts @@ -757,29 +757,26 @@ export function move(list: T[], from: number, to: number): T[] { } /** - * Checks whether a collection contains **exactly** the specified values. + * Checks whether a list contains only the specified values. * - * The order of values does not matter, but the set of values must match - * exactly. Duplicate values are ignored, since both the collection and the - * expected values are compared as sets. + * The order of values does not matter, but the list must contain every + * specified value and must not contain any additional values. Duplicate values + * are ignored, since both the list and expected values are compared as sets. * - * @template T The type of values in the collection. - * @param collection The collection to compare. - * @param values The expected values. - * @returns `true` if the collection contains exactly the specified values; - * otherwise, `false`. + * @template T The type of values in the list. + * @param list The list to compare. + * @param values The values the list must contain. + * @returns `true` if the list contains only the specified values; otherwise, + * `false`. * * @example - * includesOnly([1], 1); // true - * includesOnly([1], 1, 2); // false - * includesOnly([2, 1], 1, 2); // true - * includesOnly(new Set(["a", "b"]), "b", "a"); // true + * hasOnly([1, 2, 3], 1, 2, 3); // true + * hasOnly([1], 1, 2); // false + * hasOnly([2, 1], 1, 2); // true + * hasOnly([1, 1], 1); // true */ -export function includesOnly( - collection: Iterable, - ...values: T[] -): boolean { - const actual = new Set(collection); +export function hasOnly(list: T[], ...values: T[]): boolean { + const actual = new Set(list); const expected = new Set(values); if (actual.size !== expected.size) { diff --git a/src/core_test.ts b/src/core_test.ts index 15f442b..6361bfe 100644 --- a/src/core_test.ts +++ b/src/core_test.ts @@ -16,6 +16,7 @@ import { falsy, first, groupBy, + hasOnly, includes, includesAny, intersection, @@ -440,6 +441,19 @@ Deno.test("includesAny list in list", () => { assertFalse(includesAny(["a", "b", "c"], [])); }); +Deno.test("hasOnly returns true when a list contains only the specified values", () => { + assert(hasOnly([1, 2, 3], 1, 2, 3)); + assert(hasOnly([2, 1], 1, 2)); + assert(hasOnly([1, 1], 1)); + assert(hasOnly([])); +}); + +Deno.test("hasOnly returns false when values are missing or additional", () => { + assertFalse(hasOnly([1], 1, 2)); + assertFalse(hasOnly([1, 2, 3], 1, 2)); + assertFalse(hasOnly([1, 2])); +}); + Deno.test("includes returns false for null or undefined inputs", () => { assertFalse(includes(null, "hello")); assertFalse(includes(undefined, "hello"));