web-utilities-native-js-8dcf47 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited web-utilities-native-js-8dcf47 (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Quick Guide: Most utility-library calls now have a native equivalent with no bundle cost. The four that change how code is written arestructuredClonefor deep copies, the ES2023 immutable array methods (toSorted,toReversed,toSpliced,with),Object.groupBy/Map.groupBy, and the ES2025 Set operations. The two facts that catch people out: a structured clone drops prototypes and throws on functions, and the immutable array methods copy one level deep.
Detailed Resources:
<critical_requirements>
Reach for the native method before adding a dependency. The lodash-to-native table in reference.md settles most of it in one lookup, and the native call ships nothing.
Deep-copy with `structuredClone`. A JSON round trip turns a Date into a string and a Map or Set into {}, and it does so silently — the failure surfaces later, at the first .getTime().
*Use the `to array methods where the array is shared.** sort, reverse and splice rewrite the array in place, so a function that "returns a sorted copy" with sort` has changed its caller's data.
Convert to a `Set` before repeated membership checks. includes inside a filter is O(n²), and the difference shows up at a few thousand elements.
</critical_requirements>
Auto-detection: structuredClone, Object.groupBy, Map.groupBy, toSorted, toReversed, toSpliced, Array.prototype.with, findLast, findLastIndex, at(-1), Object.hasOwn, Object.fromEntries, Set.prototype.union, Set.prototype.intersection, Set.prototype.difference, symmetricDifference, isSubsetOf, isDisjointFrom, lodash alternative, native JavaScript utilities
Applies to:
Handled elsewhere:
Date alone does not cover it<decision_framework>
Three cases, in order:
chunk, pick, omit,compact, deepMerge, debounce, throttle, memoize and once are all in this skill, written out and typed.
cancel, flush andleading/trailing edges; a deep merge with per-key array strategies; lazy evaluation over a dataset large enough that intermediate arrays matter. Reimplementing these badly costs more than the bytes.
</decision_framework>
<patterns>
Preserves Date, Map, Set, RegExp, typed arrays and circular references — everything a JSON round trip destroys.
const snapshot = structuredClone(state);
// Preserved: Date, Map, Set, RegExp, ArrayBuffer, circular refs
// Throws on: functions, DOM nodes, Proxy, symbols
// Silently lost: the prototype — a class instance clones to a plain objectFull code: examples/core.md
Four to* methods return a new array where the classic method rewrote the old one.
items.toSorted((a, b) => a.price - b.price); // vs .sort()
items.toReversed(); // vs .reverse()
items.toSpliced(index, 1); // vs .splice()
items.with(index, { ...items[index], done: true }); // vs items[i] = xThe copy is shallow: the new array holds the same element objects, which is why the update above spreads before writing.
Full code: examples/core.md
const byStatus = Object.groupBy(orders, (order) => order.status);
// { pending: [...], shipped: [...] } — null-prototype, values are `T[] | undefined`
const byCustomer = Map.groupBy(orders, (order) => order.customer);
// Map keyed by the object itself — use this when the key is not a stringObject.groupBy coerces the key to a string and returns a null-prototype object, so reach for Object.hasOwn(byStatus, key) rather than byStatus.hasOwnProperty(key).
Full code: examples/arrays.md
setA.union(setB);
setA.intersection(setB);
setA.difference(setB); // in A, not in B
setA.symmetricDifference(setB);
setA.isSubsetOf(setB);
setA.isSupersetOf(setB);
setA.isDisjointFrom(setB);Each returns a Set, so spread when an array is wanted. The argument is any set-like with size, has and keys — a Map qualifies, a plain array does not.
Full code: examples/arrays.md
logs.findLast((log) => log.level === "error"); // ES2023, single pass
logs.findLastIndex((log) => log.level === "error");
items.at(-1); // ES2022, undefined when empty
"file.backup.txt".split(".").at(-1); // "txt" — strings tooFull code: examples/core.md
entries → map/filter → fromEntries covers pick, omit, invert, mapValues, mapKeys and array-to-lookup in one shape, so those helpers are four lines each rather than a dependency.
const keyed = Object.fromEntries(items.map((item) => [item.id, item]));
const withTax = Object.fromEntries(
Object.entries(prices).map(([k, v]) => [k, v * 1.1]),
);
const passing = Object.fromEntries(
Object.entries(scores).filter(([, score]) => score >= 90),
);Full code: examples/objects.md
</patterns>
<red_flags>
Breaks at runtime:
structuredClone on anything holding a function, a DOM node or a Proxy throws DataCloneError — clone the data separately from the behaviour.JSON.parse(JSON.stringify(x)) does not throw; it corrupts. A Date becomes a string, a Map or Set becomes {}, undefined members vanish, and the first method call on the result is where it surfaces.Object.groupBy returns a null-prototype object, so result.hasOwnProperty(...) throws. Use Object.hasOwn.size, has and keys.Surprising behaviour:
structuredClone discards the prototype. A class instance clones to a plain object with the same fields and none of the methods.toSorted() with no comparator sorts by string, so [10, 9, 1].toSorted() is [1, 10, 9] — exactly as sort() always did.to* methods copy one level. Editing an element of the new array edits the same object in the old one.arr.at(-1) types as T | undefined whatever the compiler options, so the empty case has to be handled. arr[arr.length - 1] types as T unless noUncheckedIndexedAccess is on — that is the form that lets an undefined flow on unchecked.structuredClone on an Error succeeds and keeps the standard fields, but a code, a status or anything else attached to it is not in the copy.filter(Boolean) drops 0, "" and false along with the nullish values, and TypeScript does not narrow the result — filter((x): x is T => x != null) does both jobs correctly.Object.freeze is shallow, and outside strict mode a write to a frozen object fails silently rather than throwing.Object.keys returns integer-like keys first in ascending numeric order, whatever the insertion order — only string keys keep insertion order.</red_flags>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.