All skills
ccheney avatar

/modern-javascript

@00695ba

Implement or debug JavaScript language behavior, including promise completion, async iteration, mutation, and runtime compatibility. Use for ECMAScript semantics or polyfill/transform choices; not unrelated framework or TypeScript type design.

Use this Skill: https://skilld.dev/gh/ccheney/robust-skills/modern-javascript

This session only. Nothing lands on disk.

referencesES2025.md

≈2.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

ES2025 Features

Set methods, sync iterator helpers, Iterator.from, RegExp.escape, RegExp inline modifiers, duplicate named capture groups, Promise.try, import attributes + JSON modules, Float16 (Float16Array, Math.f16round, DataView methods). Plus Intl.DurationFormat (ECMA-402).

Moved out of this file because they are not ES2025: Array.fromAsync and Error.isError are ES2026 (see ES2026.md); using/await using is Stage 4 for ES2027 (see UPCOMING.md).

Contents

Set Methods

Mathematical set operations. Arguments can be any "set-like" (has size, has, keys), not just a Set.

const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);

// Union: elements in either set
setA.union(setB);
// Set {1, 2, 3, 4, 5, 6}

// Intersection: elements in both sets
setA.intersection(setB);
// Set {3, 4}

// Difference: elements in A but not B
setA.difference(setB);
// Set {1, 2}

// Symmetric difference: elements in either but not both
setA.symmetricDifference(setB);
// Set {1, 2, 5, 6}

// Subset check
const setC = new Set([1, 2]);
setC.isSubsetOf(setA);      // true
setA.isSupersetOf(setC);    // true

// Disjoint check (no common elements)
const setD = new Set([7, 8]);
setA.isDisjointFrom(setD);  // true

All of these return new Sets (or booleans); the originals are never mutated.

Practical example:

const userPermissions = new Set(['read', 'write']);
const requiredPermissions = new Set(['read', 'delete']);

// Check what's missing
const missing = requiredPermissions.difference(userPermissions);
// Set {'delete'}

// Check if has all required
const hasAll = requiredPermissions.isSubsetOf(userPermissions);
// false

Iterator Helpers

Process iterators lazily without converting to arrays. These live on the shared Iterator.prototype used by array iterators, generators, and Map/Set iterators — they are not array methods, and they consume the iterator.

// Create iterator
const numbers = [1, 2, 3, 4, 5].values();

// map() on iterator
const doubled = numbers.map(n => n * 2);
// Iterator yielding 2, 4, 6, 8, 10

// filter() on iterator
const evens = [1, 2, 3, 4, 5].values().filter(n => n % 2 === 0);
// Iterator yielding 2, 4

// take() - limit results
const firstThree = [1, 2, 3, 4, 5].values().take(3);
// Iterator yielding 1, 2, 3

// drop() - skip results
const afterTwo = [1, 2, 3, 4, 5].values().drop(2);
// Iterator yielding 3, 4, 5

// flatMap()
const flattened = [[1, 2], [3, 4]].values().flatMap(arr => arr);
// Iterator yielding 1, 2, 3, 4

// reduce()
const sum = [1, 2, 3, 4, 5].values().reduce((a, b) => a + b, 0);
// 15

// toArray() - convert to array
const arr = [1, 2, 3].values().map(n => n * 2).toArray();
// [2, 4, 6]

// forEach()
[1, 2, 3].values().forEach(n => console.log(n));

// some() / every()
[1, 2, 3].values().some(n => n > 2);   // true
[1, 2, 3].values().every(n => n > 0);  // true

// find()
[1, 2, 3, 4].values().find(n => n > 2);  // 3

Lazy evaluation benefits:

// Process large datasets without materializing intermediate arrays
function* generateLargeDataset() {
  for (let i = 0; i < 1000000; i++) {
    yield { id: i, value: Math.random() };
  }
}

// Stops pulling from the generator after 10 matches
const firstTen = generateLargeDataset()
  .filter(item => item.value > 0.9)
  .take(10)
  .toArray();

These are the sync iterator helpers. Async iterator helpers (AsyncIterator.prototype.map etc.) are a separate proposal that has not reached Stage 4 — for async sources use for await...of or Array.fromAsync (ES2026).

Iterator.from()

Create iterators from any iterable or iterator-like object.

// Convert iterable to iterator with helpers
const setIterator = Iterator.from(new Set([1, 2, 3]));

// Now has all iterator helper methods
setIterator
  .filter(n => n > 1)
  .map(n => n * 2)
  .toArray();
// [4, 6]

// Works with any iterable
const mapIter = Iterator.from(new Map([['a', 1], ['b', 2]]));
const stringIter = Iterator.from('hello');

Built-in iterables (arrays, Maps, Sets, generators) already inherit the helpers — Iterator.from is mainly for third-party "iterator protocol" objects that don't extend Iterator.prototype.

RegExp.escape()

Safely escape strings for use in dynamically built regexes.

const userInput = 'price: $100 (USD)';

// ❌ Before: Manual escaping (error-prone, misses edge cases)
const escapedManually = userInput.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

// ✅ After: Built-in escape
const escaped = RegExp.escape(userInput);
// '\\x70rice\\x3a\\x20\\$100\\x20\\(USD\\)'
// Leading ASCII alphanumerics, spaces, and punctuators become hex
// escapes so the result is safe in ANY regex context (even inside
// character classes) — it looks odd but matches the original string
// exactly.

const pattern = new RegExp(escaped);
pattern.test('price: $100 (USD)');  // true

Practical example: Safe search:

function createSearchPattern(searchTerm) {
  return new RegExp(RegExp.escape(searchTerm), 'gi');
}

const query = 'C++ (language)';
const searchPattern = createSearchPattern(query);
// Safely matches "C++ (language)" in text

RegExp.escape only accepts strings — it throws a TypeError for anything else (no implicit coercion), which catches bugs like passing a number.

RegExp Pattern Modifiers (Inline Flags)

Apply i, m, or s to part of a pattern instead of the whole thing.

// Apply case-insensitivity only to part of pattern
const pattern = /^(?i:hello) world$/;

pattern.test('hello world');   // true
pattern.test('HELLO world');   // true
pattern.test('Hello World');   // false (World not modified)

// Remove a flag for part of a pattern
const mixed = /(?i:abc)(?-i:DEF)/;
// abc is case-insensitive, DEF must be exact case

// Useful for partial matching
const filePattern = /(?i:readme)\.md$/;
filePattern.test('README.md');  // true
filePattern.test('ReadMe.md');  // true
filePattern.test('readme.MD');  // false (.md must be lowercase)

Only i, m, and s can be toggled inline; flags like g, u, v, y apply to the whole regex by nature.

Duplicate Named Capture Groups

Reuse a capture group name across different | alternatives (previously a SyntaxError).

// ✅ Same names allowed in different alternatives
const datePattern = /(?<year>\d{4})-(?<month>\d{2})|(?<month>\d{2})\/(?<year>\d{4})/;

// Both formats produce the same group names
'2024-03'.match(datePattern).groups;
// { year: '2024', month: '03' }

'03/2024'.match(datePattern).groups;
// { year: '2024', month: '03' }

The same name still cannot appear twice within one alternative. Only the groups of the alternative that matched are populated; the duplicates from the other branch are undefined.

Promise.try()

Start a promise chain from a function that might throw synchronously — sync exceptions become rejections instead of escaping.

// ❌ Before: Wrap in Promise.resolve().then()
const result = await Promise.resolve().then(() => {
  return riskyOperation();  // Might throw synchronously
});
// ✅ After: Direct wrapping
const result = await Promise.try(() => {
  return riskyOperation();  // Sync throws become rejections
});

// Handles both sync and async functions uniformly
Promise.try(() => syncOrAsyncFunction())
  .then(result => console.log(result))
  .catch(error => console.error(error));

// Extra arguments are forwarded to the callback
Promise.try(fetchUser, userId).then(user => console.log(user));

Unlike Promise.resolve().then(fn), Promise.try(fn) calls fn synchronously (its side effects happen immediately); only the settlement is async.

Import Attributes and JSON Modules

Specify module type explicitly with with. ES2025 standardizes both the syntax and JSON modules. The older assert { type: 'json' } spelling is not in the current standard; some older runtimes accept it, but new code should use with.

// Import JSON (part of ES2025)
import config from './config.json' with { type: 'json' };

// Dynamic import with attributes
const data = await import('./data.json', { with: { type: 'json' } });

// Re-export with attributes
export { default as settings } from './settings.json' with { type: 'json' };

CSS module scripts (with { type: 'css' }) are an HTML-spec feature for browsers, not part of ECMAScript, and are not supported in Node.js.

Float16 Support

Half-precision floating point, useful for GPU/ML interop and pixel data.

// Float16Array
const f16 = new Float16Array([1.5, 2.5, 3.5]);

// Math.f16round()
Math.f16round(1.337);  // 1.3369140625 (nearest float16 value)

// DataView methods
const buffer = new ArrayBuffer(2);
const view = new DataView(buffer);
view.setFloat16(0, 1.5);
view.getFloat16(0);  // 1.5

Intl.DurationFormat (ECMA-402)

Format time durations with locale support. Technically part of the Intl (ECMA-402) spec rather than ECMA-262, finalized in the same era.

const duration = { hours: 1, minutes: 46, seconds: 40 };

// Different styles
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "1 hour, 46 minutes, 40 seconds"

new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min, 40 sec"

new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
// "1h 46m 40s"

new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"

// Localized
new Intl.DurationFormat('fr', { style: 'long' }).format(duration);
// "1 heure, 46 minutes et 40 secondes"

Browser/Node.js Support

First versions with unflagged support (source: MDN browser-compat-data, 2026):

Feature Chrome Firefox Safari Node.js
Set methods 122+ 127+ 17+ 22+
Iterator helpers / Iterator.from 122+ 131+ 18.4+ 22+
RegExp.escape 136+ 134+ 18.2+ 24+
RegExp inline modifiers 125+ 132+ 26+ 23+
Duplicate named capture groups 125+ 129+ 17+ 23+
Promise.try 128+ 134+ 18.2+ 23+
Import attributes (with) 123+ 138+ 17.2+ 20.10+
Float16Array / Math.f16round 135+ 129+ 18.2+ 24+
Intl.DurationFormat 129+ 136+ 16.4+ 23+

Practical baseline: Node 24 LTS and current evergreen browsers cover all of ES2025. On Node 22, RegExp.escape, Float16, inline modifiers, duplicate named groups, and Promise.try are missing. Re-check MDN Browser Compatibility Data against the project's targets.

Source: SKILL.md on GitHub

No alerts14d4 checks · Risk SAFE
  • Gen Agent Trust Hub14d

    The skill provides a technical reference for modern JavaScript features and toolchains. It includes an indirect prompt injection surface by directing the agent to read and analyze project files, such as lockfiles and build configurations, which may contain untrusted data that could influence the agent's code generation logic.

  • Socket14d

    No alerts

  • Snyk14d

    Risk: LOW · No issues

  • Runlayer7mo

    12 files scanned · No issues

Signed by skilld at 00695ba. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 weeks ago.

Activeupdated 3 weeks ago

README badge

README badge for ccheney/robust-skills/modern-javascript