@ccheney/modern-javascript

Proactively apply when creating web applications, Node.js services, or any JavaScript project. Triggers on JavaScript, ES6, ES2020, ES2022, ES2024, modern JS, refactor legacy, array methods, async/await, optional chaining, nullish coalescing, destructuring, spread, rest, template literals, arrow functions, toSorted, toReversed, at, groupBy, Promise, functional programming. Use when writing new JavaScript code, refactoring legacy code, modernizing codebases, implementing functional patterns, or reviewing JS for performance and readability. Modern JavaScript (ES6-ES2025) patterns and best practices.

View in AI SkillSafe app
Scanned · no findings
0 downloads
0 stars
0 demos
SKILL.md
namemodern-javascript
descriptionWrite, modernize, and review JavaScript against real ECMAScript language features and explicit runtime targets. Use for JavaScript or Node.js code, ES edition attribution (ES2015-ES2026), compatibility and polyfill/transpile decisions, array/iterator/Set/Map/Promise/RegExp/TypedArray APIs, modules, async code, Temporal, explicit resource management, decorators, or replacing stale and withdrawn proposal syntax. Prefer standardized features, while permitting mature proposals when the required maintained transform or polyfill is stated.

Modern JavaScript

Use current JavaScript without confusing specification status, runtime support, and toolchain support. Treat these as three separate questions:

  1. Is it standardized? Check the frozen annual ECMA-262 edition or TC39's current proposal tracker.
  2. Does the target run it? Check the project's declared Node/browser targets and current compatibility data.
  3. Can tooling bridge the gap? Syntax may need a transform; built-ins need a polyfill. One does not imply the other.

Workflow

  1. Inspect package.json (engines, browserslist, dependencies), runtime/deployment config, tsconfig.json, and Babel/bundler config. Do not invent a baseline.
  2. Select the simplest standardized feature supported by that baseline.
  3. For a newer standard or mature proposal, state the required runtime, transform, or polyfill in the implementation or handoff.
  4. Preserve observable behavior while modernizing: mutation, evaluation order, iterator consumption, concurrency, cancellation, property descriptors, and error propagation matter more than shorter syntax.
  5. Run the project's formatter, type-checker, linter, and tests. Exercise both the native path and compatibility path when both ship.

Read references/COMPATIBILITY.md whenever support is uncertain, the feature is newer than ES2023, or a proposal is involved.

Status Rules

  • Use the frozen ECMAScript 2026 specification for ES2026 attribution and the living draft for already-integrated future features.
  • Use TC39's finished-proposals table for Stage 4 publication-year mapping and its active tracker for current stages.
  • Do not infer an edition from the year a browser shipped a feature. Array.fromAsync, for example, shipped before its ES2026 publication.
  • Do not describe Stage 3 or 2.7 syntax as standard JavaScript. It can still be a sound project choice when a maintained toolchain implements the selected proposal revision.
  • Do not emit withdrawn Records & Tuples syntax (#{} / #[]).

Edition Map

This is a routing index, not a substitute for the detailed references.

Edition Representative additions
ES2015 let/const, classes, modules, arrow functions, destructuring, promises, generators, Map/Set, Proxy
ES2016 exponentiation, Array.prototype.includes
ES2017 async functions, Object.values/entries, string padding, shared memory and Atomics
ES2018 object rest/spread, async iteration, Promise.prototype.finally, major RegExp additions
ES2019 flat/flatMap, Object.fromEntries, optional catch binding, stable sort
ES2020 optional chaining, nullish coalescing, BigInt, Promise.allSettled, dynamic import(), globalThis
ES2021 logical assignment, Promise.any, replaceAll, numeric separators, WeakRef
ES2022 .at, Object.hasOwn, top-level await, class fields/private elements/static blocks, error cause, RegExp indices
ES2023 array change-by-copy methods, findLast/findLastIndex, hashbang grammar, symbols as weak keys
ES2024 grouping, Promise.withResolvers, well-formed strings, RegExp v, resizable/transferable buffers, Atomics.waitAsync
ES2025 Set methods, sync iterator helpers, RegExp.escape, Promise.try, import attributes/JSON modules, RegExp modifiers, Float16
ES2026 Array.fromAsync, Error.isError, Math.sumPrecise, Uint8Array base64/hex, Iterator.concat, Map/WeakMap upsert, JSON source access

Already Stage 4 with publication expected in ES2027: Temporal, explicit resource management (using / await using), Atomics.pause, and Iterator.zip / zipKeyed. See references/UPCOMING.md.

Choose by Semantics

Collections

Need Prefer Important behavior
Transform/filter an array map, filter, flatMap Eager; creates arrays
Process a large/infinite sync source iterator helpers Lazy; consumes the iterator
Find from the end findLast, findLastIndex Does not reverse or copy
Change without mutating the source toSorted, toReversed, toSpliced, with Shallow copy
Group under string/symbol keys Object.groupBy Returns a null-prototype object
Group under identity keys Map.groupBy Preserves key identity
Collect an async iterable Array.fromAsync Pulls and awaits sequentially
Run already-created work concurrently Promise.all Rejects early; does not cancel inputs

Do not replace mutation mechanically. A private, newly allocated array can be mutated efficiently without exposing mutable shared state. Use change-by-copy methods when preserving the source is part of the contract.

const ranked = scores.toSorted((a, b) => b.points - a.points);

const byTeam = Object.groupBy(players, player => player.team);
if (Object.hasOwn(byTeam, requestedTeam)) {
  render(byTeam[requestedTeam]);
}

Nullish and Property Checks

const city = user?.address?.city ?? 'Unknown';

// `??` preserves 0, false, and ''. Use `||` only when all falsy values mean absent.
settings.timeout ??= 5_000;

// Safe for overwritten or null-prototype objects.
if (Object.hasOwn(record, 'id')) use(record.id);

Async Work

// Independent work: concurrent.
const [user, permissions] = await Promise.all([
  fetchUser(id),
  fetchPermissions(id),
]);

// Ordered source: sequential consumption.
const pages = await Array.fromAsync(fetchPages());

// A loop is correct when each step depends on the previous one.
for (const migration of migrations) {
  await migration.run();
}

Never use forEach(async () => ...) when completion must be awaited. Read references/PROMISES.md for combinators and references/CONCURRENCY.md for bounded concurrency and cancellation.

Modules

Use with for import attributes; the older assert spelling is not current ECMAScript.

import config from './config.json' with { type: 'json' };

const locale = await import(`./locales/${language}.js`);

Import attributes and JSON modules are ES2025, but module loading remains host-sensitive. Verify Node, browser, bundler, and test-runner support together.

Exact API Boundaries

  • structuredClone, fetch, streams, AbortController, and DOM APIs are host/web APIs, not ECMA-262 language features.
  • Intl.* is standardized in ECMA-402, not ECMA-262.
  • TypeScript syntax and types are not JavaScript runtime features.
  • A TypeScript lib entry supplies type declarations, not a runtime implementation.
  • Babel syntax transforms do not automatically install missing globals or prototype methods.

Compatibility Paths

Prefer native support when the target has it. Otherwise choose deliberately:

Feature kind Compatibility mechanism
Syntax (using, decorators) Babel/TypeScript transform that matches the selected proposal revision
Built-in (Iterator.concat, Map#getOrInsert) Runtime upgrade or maintained polyfill such as current core-js
Namespace API (Temporal) Runtime upgrade or a maintained Temporal polyfill
Shared-memory primitive (Atomics.pause) Native support only; feature-detect and keep a fallback algorithm

TypeScript 7.0 is released, but it is not a polyfill and 7.0 has no stable programmatic compiler API. Projects whose framework/linter embeds TypeScript may need TypeScript 6 alongside it. See references/COMPATIBILITY.md.

Review Traps

  • .sort(), .reverse(), .splice(), Map#set, Set#add, and most TypedArray methods mutate. That is not automatically wrong; make it intentional.
  • Object/array spread is shallow and invokes ordinary property access; it does not preserve prototypes or descriptors.
  • structuredClone is a host API and cannot clone functions, weak collections, or every platform object.
  • Object.groupBy has no inherited hasOwnProperty or toString.
  • Iterator helpers are lazy and single-pass; arrays are reusable and eager.
  • Promise.all does not cancel remaining operations after rejection. Pass AbortSignal when cancellation is required.
  • Math.sumPrecise accurately sums the binary Number inputs; it does not make decimal money exact.
  • Error.isError is cross-realm-safe for ECMAScript Error objects; host error types can have runtime-specific behavior.
  • Temporal is not part of ES2026. Its Stage 4 publication target is ES2027.
  • Standard decorators are not legacy TypeScript experimentalDecorators.

References

Load only what the task needs.

Reference Use for
ES2016-ES2017.md early annual additions, async functions, shared memory
ES2018-ES2019.md async iteration, object spread, RegExp, flattening
ES2022-ES2023.md classes, .at, change-by-copy, weak symbol keys
ES2024.md grouping, resolvers, Unicode sets, buffers
ES2025.md Set/iterator helpers, modules, RegExp, Float16
ES2026.md all seven finalized ES2026 feature proposals
UPCOMING.md Stage 4 ES2027 set, selected mature proposals, withdrawn syntax
COMPATIBILITY.md runtime matrices, Babel/TypeScript/core-js/polyfill decisions
PROMISES.md promise semantics and anti-patterns
CONCURRENCY.md pools, retries, cancellation, async iteration
CHEATSHEET.md compact syntax lookup

Authority Order

  1. Frozen annual ECMA-262 editions for edition membership
  2. Living ECMA-262 plus TC39 proposal tracker/spec repositories for future status and semantics
  3. Test262 for conformance cases
  4. MDN Browser Compatibility Data and official engine/runtime releases for availability
  5. Official TypeScript, Babel, and polyfill documentation for compatibility paths

Embed badges

Add these to your README to show the skill's verification status.

SkillSafe verified badge
Verified badge
[![SkillSafe verified badge](https://api.skillsafe.ai/v1/badge/@ccheney/modern-javascript/verified)](https://skillsafe.ai/skill/@ccheney/modern-javascript/)
Installs badge
Installs badge
[![Installs badge](https://api.skillsafe.ai/v1/badge/@ccheney/modern-javascript/installs)](https://skillsafe.ai/skill/@ccheney/modern-javascript/)
Scan badge
Scan badge
[![Scan badge](https://api.skillsafe.ai/v1/badge/@ccheney/modern-javascript/scan)](https://skillsafe.ai/skill/@ccheney/modern-javascript/)
Eval pass rate badge
Eval pass rate
[![Eval pass rate badge](https://api.skillsafe.ai/v1/badge/@ccheney/modern-javascript/eval)](https://skillsafe.ai/skill/@ccheney/modern-javascript/)