@e18e/mcp 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/docs.json +97 -98
- package/dist/docs/index.js.map +1 -1
- package/dist/icons/generated.d.ts +15 -2
- package/dist/icons/generated.js +10 -9
- package/dist/icons/generated.js.map +1 -1
- package/dist/icons/index.d.ts +1 -1
- package/dist/icons/index.js +1 -1
- package/dist/icons/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/prompts/task/index.js.map +1 -1
- package/dist/resources/replacement-docs/index.js.map +1 -1
- package/dist/setup.js.map +1 -1
- package/dist/tools/code-checker/index.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/lookup-replacement/index.d.ts +2 -0
- package/dist/tools/lookup-replacement/index.js +30 -0
- package/dist/tools/lookup-replacement/index.js.map +1 -0
- package/dist/tools/npm-i-checker/index.js.map +1 -1
- package/dist/tools/utils.d.ts +10 -0
- package/dist/tools/utils.js +99 -14
- package/dist/tools/utils.js.map +1 -1
- package/package.json +4 -4
package/dist/docs/docs.json
CHANGED
|
@@ -1,120 +1,119 @@
|
|
|
1
1
|
{
|
|
2
|
+
"portal-vue.md": "---\ndescription: Modern alternatives to the `portal-vue` package for making portals in Vue applications\n---\n\n# Replacements for `portal-vue`\n\n## Vue `Teleport` API\n\nSince Vue 3, the [Teleport](https://vuejs.org/guide/built-ins/teleport.html) component has been introduced which replaces portal-vue for most use cases, especially modals and overlays.\n\n`<Teleport>` only moves DOM nodes to an existing target — it does not manage destinations, layouts, or component structure.\n\n```html\n<!-- Using a modal -->\n<div class=\"outer\">\n <h3>Vue Teleport Example</h3>\n <div>\n <MyModal />\n </div>\n</div>\n```\n\n```html\n<!-- MyModal.vue -->\n<Teleport to=\"body\">\n <p>The content inside of Teleport will render in html body</p>\n</Teleport>\n```\n",
|
|
3
|
+
"read-package-up.md": "---\ndescription: Modern alternatives to the read-package-up package for reading package.json files up the directory tree\n---\n\n# Replacements for `read-package-up`\n\n## `pkg-types`\n\n[`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types.\n\nFor example:\n\n```ts\nimport { readPackageJSON } from 'pkg-types' // [!code ++]\nimport { readPackageUp } from 'read-package-up' // [!code --]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJson = await readPackageJSON() // [!code ++]\n```\n\nSimilarly, you can get hold of the path via `resolvePackageJSON`:\n\n```ts\nimport { resolvePackageJSON } from 'pkg-types'\n\nconst packageJsonPath = await resolvePackageJSON()\n```\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nIt can be combined with `node:fs` to read `package.json` files:\n\n```ts\nimport fs from 'node:fs/promises' // [!code ++]\nimport * as pkg from 'empathic' // [!code ++]\nimport { readPackageUp } from 'read-package-up' // [!code --]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJsonPath = pkg.up() // [!code ++]\nconst packageJson = packageJsonPath // [!code ++]\n ? JSON.parse(await readFile(packageJsonPath, 'utf8')) // [!code ++]\n : undefined // [!code ++]\n```\n\n> [!NOTE]\n> This is of course a more manual way to read the `package.json` file, so one of the other options may be more attractive.\n",
|
|
4
|
+
"resolve.md": "---\ndescription: Modern alternatives to the resolve package\n---\n\n# Replacements for `resolve`\n\n## `import.meta.resolve` (native)\n\n[`import.meta.resolve`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve) is built into browsers and Node.js (>= 20).\n\nExample:\n\n```ts\nconst path = import.meta.resolve('my-module')\n```\n\n## `exsolve`\n\n[`exsolve`](https://github.com/unjs/exsolve)\n\n```ts\nimport { resolveModulePath } from 'exsolve'\n\nconst path = resolveModulePath('my-module')\n```\n\n## `oxc-resolver`\n\n[`oxc-resolver`](https://github.com/oxc-project/oxc-resolver)\n\n```ts\nimport { ResolverFactory } from 'oxc-resolver'\n\nconst resolver = new ResolverFactory()\nconst { path } = resolver.sync(process.cwd(), 'my-module')\n```\n",
|
|
5
|
+
"sort-object.md": "---\ndescription: Modern alternatives to the sort-object package for sorting object keys\n---\n\n# Replacements for `sort-object`\n\n## `Object.entries` and `Array.sort` (native)\n\nFor simple cases:\n\n<!-- prettier-ignore -->\n```ts\nimport sortObj from 'sort-object' // [!code --]\n\nconst sorted = sortObj(object) // [!code --]\n\n// Ascending A→Z\nconst sorted = Object.fromEntries( // [!code ++]\n Object.entries(object).sort((a, b) => a[0].localeCompare(b[0])) // [!code ++]\n) // [!code ++]\n```\n\nReplicating `sortBy` (function returns an ordered key list):\n\n<!-- prettier-ignore -->\n```ts\nimport sortObj from 'sort-object' // [!code --]\n\nconst sorted = sortObj(object, { // [!code --]\n sortBy: (obj) => { // [!code --]\n const arr = [] // [!code --]\n Object.keys(obj).forEach((k) => { // [!code --]\n if (obj[k].startsWith('a')) // [!code --]\n arr.push(k) // [!code --]\n }) // [!code --]\n return arr.reverse() // [!code --]\n } // [!code --]\n}) // [!code --]\n\nconst sortBy = (obj) => // [!code ++]\n Object.keys(obj) // [!code ++]\n .filter((k) => obj[k].startsWith('a')) // [!code ++]\n .reverse() // [!code ++]\nconst sorted = Object.fromEntries( // [!code ++]\n sortBy(object).map((k) => [k, object[k]]) // [!code ++]\n) // [!code ++]\n```\n\n## `sort-object-keys`\n\n[`sort-object-keys`](https://github.com/keithamus/sort-object-keys) is zero‑dependency and matches common `sort-object` use cases (custom order array or comparator).\n\n```ts\nimport sortObj from 'sort-object' // [!code --]\nimport sortObjectKeys from 'sort-object-keys' // [!code ++]\n\n// Default A→Z\nconst sorted = sortObj(object) // [!code --]\nconst sorted = sortObjectKeys(object) // [!code ++]\n\n// With comparator\nconst sortedByCmp = sortObj(object, { sort: (a, b) => a.localeCompare(b) }) // [!code --]\nconst sortedByCmp = sortObjectKeys(object, (a, b) => a.localeCompare(b)) // [!code ++]\n```\n\n## `sortobject`\n\n[`sortobject`](https://github.com/bevry/sortobject) is zero‑dependency and deeply sorts nested objects.\n\n```ts\nimport sortObj from 'sort-object' // [!code --]\nimport sortobject from 'sortobject' // [!code ++]\n\nconst sorted = sortObj(object) // [!code --]\nconst sorted = sortobject(object) // [!code ++]\n```\n",
|
|
6
|
+
"read-pkg-up.md": "---\ndescription: Modern alternatives to the read-pkg-up package for reading package.json files up the directory tree\n---\n\n# Replacements for `read-pkg-up`\n\n## `pkg-types`\n\n[`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types.\n\nFor example:\n\n```ts\nimport { readPackageUp } from 'read-pkg-up' // [!code --]\nimport { readPackageJSON } from 'pkg-types' // [!code ++]\n\nconst packageJson = await readPackageJSON() // [!code ++]\nconst packageJson = await readPackageUp() // [!code --]\n```\n\nSimilarly, you can get hold of the path via `resolvePackageJSON`:\n\n```ts\nimport { resolvePackageJSON } from 'pkg-types'\n\nconst packageJsonPath = await resolvePackageJSON()\n```\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nIt can be combined with `node:fs` to read `package.json` files:\n\n```ts\nimport { readPackageUp } from 'read-pkg-up' // [!code --]\nimport fs from 'node:fs/promises' // [!code ++]\nimport * as pkg from 'empathic' // [!code ++]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJsonPath = pkg.up() // [!code ++]\nconst packageJson = packageJsonPath // [!code ++]\n ? JSON.parse(await readFile(packageJsonPath, 'utf8')) // [!code ++]\n : undefined // [!code ++]\n```\n\n> [!NOTE]\n> This is of course a more manual way to read the `package.json` file, so one of the other options may be more attractive.\n",
|
|
7
|
+
"faker.md": "---\ndescription: Modern replacements for the unmaintained faker package generating massive amounts of fake (but realistic) data\n---\n\n# Replacements for `faker`\n\n## `@faker-js/faker`\n\n[`@faker-js/faker`](https://github.com/faker-js/faker) is a direct, community‑maintained fork of `faker` with new features, bugfixes, modern ESM/CJS builds, and updated data/locales.\n\n```ts\nconst faker = require('faker') // [!code --]\nconst { faker } = require('@faker-js/faker') // [!code ++]\n\nfaker.datatype.boolean()\n\nfaker.image.avatar()\n```\n",
|
|
8
|
+
"dot-prop.md": "---\ndescription: Modern alternatives to the dot-prop package for getting, setting, and deleting nested object properties using dot notation\n---\n\n# Replacements for `dot-prop`\n\n## `dlv` and `dset`\n\n[`dlv`](https://github.com/developit/dlv) gets nested values with default fallbacks and [`dset`](https://github.com/lukeed/dset) sets nested values with automatic intermediate object creation.\n\n```ts\nimport { getProperty, setProperty } from 'dot-prop' // [!code --]\nimport delve from 'dlv' // [!code ++]\nimport { dset } from 'dset' // [!code ++]\n\nconst value = getProperty(obj, 'foo.bar.baz') // [!code --]\nconst value = delve(obj, 'foo.bar.baz') // [!code ++]\n\nsetProperty(obj, 'foo.bar.baz', 'value') // [!code --]\ndset(obj, 'foo.bar.baz', 'value') // [!code ++]\n```\n\n## `String.prototype.split` + `Array.prototype.reduce` (native)\n\nIf you only need to get a nested value you can use a simple function:\n\n```js\nfunction getProperty(obj, key) {\n return key.split('.').reduce((acc, k) => acc?.[k], obj)\n}\n\nconst value = getProperty(obj, 'foo.bar.baz')\n```\n\n> [!NOTE]\n> This assumes that you do not consume dot paths as user input.\n> If you do, ensure you sanitize keys before accessing them (e.g. through `Object.hasOwn`).\n",
|
|
9
|
+
"debug.md": "---\ndescription: Modern alternatives to the debug package\n---\n\n# Replacements for `debug`\n\n## `obug`\n\n[`obug`](https://github.com/sxzz/obug) is a lightweight JavaScript debugging utility, forked from debug, featuring TypeScript and ESM support.\n\n`obug` v1 retains compatibility with debug, but drops support for older browsers and Node.js versions, making it a drop-in replacement.\n\n`obug` v2 refactors some API imports and usage for better support of ESM and TypeScript, easier customization, and an even smaller package size.\n\n```ts\nimport debug from 'debug' // [!code --]\nimport { createDebug } from 'obug' // [!code ++]\n\nconst logger = debug('name') // [!code --]\nconst logger = createDebug('name') // [!code ++]\n```\n",
|
|
10
|
+
"fetch.md": "---\ndescription: Shared alternatives and examples for fetch based HTTP clients used across related modules\n---\n\n# Fetch-based HTTP clients (shared)\n\nThis page contains the common, recommended alternatives and examples for fetch based HTTP clients used by `axios`, `node-fetch`, and `cross-fetch` replacement docs.\n\n## `fetch` API (native)\n\nThe native [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) API is available in Node.js (since v18.x) and all modern browsers. For many use cases it replaces `axios`/`node-fetch`/`cross-fetch` without adding dependencies.\n\n> [!TIP]\n> Node.js provides a codemod which can migrate some of this automatically, see the docs at [@nodejs/axios-to-whatwg-fetch](https://app.codemod.com/registry/@nodejs/axios-to-whatwg-fetch) for more details.\n\nExample:\n\n```ts\n// GET\nconst res = await fetch('https://api.example.com/data')\nconst data = await res.json()\n\n// POST\nawait fetch('https://api.example.com/data', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ key: 'value' })\n})\n```\n\n## `ofetch`\n\n[`ofetch`](https://github.com/unjs/ofetch) is a small fetch wrapper with automatic JSON parsing, request/response interceptors, and retry support.\n\nExample:\n\n```ts\nimport { ofetch } from 'ofetch'\n\nconst api = ofetch.create({ baseURL: 'https://api.example.com' })\n\nconst data = await api('/user', { query: { id: 123 } })\nconst created = await api('/items', { method: 'POST', body: { name: 'A' } })\n```\n\n## `ky`\n\n[`ky`](https://github.com/sindresorhus/ky) is a lightweight HTTP client built on top of the Fetch API. It adds convenience features like timeouts, hooks (interceptors), and a simpler API surface.\n\nExample:\n\n```ts\nimport ky from 'ky'\n\nconst api = ky.create({\n prefixUrl: 'https://api.example.com',\n timeout: 5000 // ms\n})\n\nconst data = await api.get('users').json()\n```\n",
|
|
11
|
+
"deep-equal.md": "---\ndescription: Modern alternatives to the deep-equal package for deep object comparison\n---\n\n# Replacements for `deep-equal`\n\n## `util.isDeepStrictEqual` (native, since Node.js v9.0.0)\n\nNode.js has a builtin function [`isDeepStrictEqual`](https://nodejs.org/api/util.html#utilisdeepstrictequalval1-val2-options). Consider using that if you don’t need browser support.\n\nExample:\n\n```ts\nimport equal from 'deep-equal' // [!code --]\nimport { isDeepStrictEqual } from 'node:util' // [!code ++]\n\nconst a = { foo: 'bar' }\nconst b = { foo: 'bar' }\n\nequal(a, b) // true [!code --]\nisDeepStrictEqual(a, b) // true [!code ++]\n```\n\n## `dequal`\n\n[`dequal`](https://github.com/lukeed/dequal) has the same simple API as `deep-equal`.\n\nExample:\n\n```ts\nimport equal from 'deep-equal' // [!code --]\nimport dequal from 'dequal' // [!code ++]\n\nconst a = { foo: 'bar' }\nconst b = { foo: 'bar' }\n\nequal(a, b) // true [!code --]\ndequal(a, b) // true [!code ++]\n```\n\n## `Bun.deepEquals` (native, Bun)\n\nBun has a built-in [`Bun.deepEquals`](https://bun.com/docs/runtime/utils#bun-deepequals) function. It accepts two values to compare, and an optional `strict` flag (default `false`).\n\nExample:\n\n```ts\nimport equal from 'deep-equal' // [!code --]\n\nconst a = { foo: 'bar' }\nconst b = { foo: 'bar' }\n\nequal(a, b) // true [!code --]\nBun.deepEquals(a, b) // true [!code ++]\n\n// Strict Mode\nequal(a, b, { strict: true }) // true [!code --]\nBun.deepEquals(a, b, true) // true [!code ++]\n```\n",
|
|
12
|
+
"materialize-css.md": "---\ndescription: Modern alternatives to materialize-css (Materialize) and modern Material Design UI libraries\n---\n\n# Replacements for `materialize-css`\n\n## `@materializecss/materialize`\n\n[`@materializecss/materialize`](https://github.com/materializecss/materialize) is a community-maintained fork of [`Materialize`](https://github.com/Dogfalo/materialize). Acts as a practical replacement for the original materialize-css package.\n\n## `@material/web`\n\n> [!NOTE]\n> The project is currently in maintenance mode pending new maintainers.\n\nModern Web Components implementing Material Design 3.\n\n[Project Page](https://github.com/material-components/material-web)\n",
|
|
13
|
+
"find-cache-directory.md": "---\ndescription: Modern alternatives to the find-cache-directory package for locating cache directories\n---\n\n# Replacements for `find-cache-directory`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nExample:\n\n```ts\nimport * as pkg from 'empathic' // [!code ++]\nimport findCacheDirectory from 'find-cache-directory' // [!code --]\n\nfindCacheDirectory({ name: 'foo' }) // [!code --]\npkg.cache('foo') // [!code ++]\n```\n",
|
|
14
|
+
"through.md": "---\ndescription: Modern alternatives to the through package\n---\n\n# Replacements for `through`\n\n## `stream.Writable` (native, Node.js)\n\nThe native [`stream.Writable`](https://nodejs.org/api/stream.html#class-streamwritable) class can be used to create writable streams. It is a suitable replacement when `through` is being used only as a sink that consumes data, rather than as a duplex/transform stream that forwards data.\n\n<!-- prettier-ignore -->\n```ts\nimport through from 'through' // [!code --]\nimport { Writable } from 'node:stream' // [!code ++]\n\nthrough(fn) // [!code --]\nnew Writable({ // [!code ++]\n write: (chunk, encoding, callback) => { // [!code ++]\n fn(chunk) // [!code ++]\n callback() // [!code ++]\n } // [!code ++]\n}) // [!code ++]\n```\n",
|
|
15
|
+
"uri-js.md": "---\ndescription: Modern alternatives to uri-js for RFC 3986 URI parsing, resolving, and normalization\n---\n\n# Replacements for `uri-js`\n\n[`uri-js`](https://github.com/garycourt/uri-js) is unmaintained and triggers deprecation warnings on modern Node.js ([due to `punycode`](https://github.com/garycourt/uri-js/pull/95)).\n\n## `URL` (native)\n\nGood for standard web URLs (http/https/ws/wss/file/mailto, etc.).\n\n- MDN URL: https://developer.mozilla.org/en-US/docs/Web/API/URL\n- Node.js URL: https://nodejs.org/api/url.html#class-url\n\nExample:\n\n```ts\nimport * as URI from 'uri-js' // [!code --]\n\nURI.resolve('https://a/b/c/d?q', '../../g') // [!code --]\nnew URL('../../g', 'https://a/b/c/d?q').href // [!code ++]\n```\n\n> [!NOTE]\n> [WHATWG URL](https://url.spec.whatwg.org/) differs from [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) in some details and may not cover arbitrary custom schemes/URNs.\n\n## `uri-js-replace`\n\n[`uri-js-replace`](https://github.com/andreinwald/uri-js-replace) is a drop-in, zero-dependency replacement for `uri-js` with the same API and no deprecation warnings.\n\n```ts\nimport * as URI from 'uri-js' // [!code --]\nimport * as URI from 'uri-js-replace' // [!code ++]\n\nconst parsed = URI.parse('uri://user:pass@example.com:123/one/two?q=a#f')\nconst out = URI.serialize({\n scheme: 'http',\n host: 'example.com',\n fragment: 'footer'\n})\nconst norm = URI.normalize('URI://www.example.org/red%09ros\\xE9#red')\n```\n\n## `fast-uri`\n\n[`fast-uri`](https://github.com/fastify/fast-uri) is a zero-dependency, high-performance RFC 3986 URI toolbox (parse/serialize/resolve/equal) with options similar to `uri-js`.\n\n```ts\nimport * as uri from 'uri-js' // [!code --]\nimport * as uri from 'fast-uri' // [!code ++]\n\nuri.parse('uri://user:pass@example.com:123/one/two.three?q1=a1#a')\nuri.serialize({ scheme: 'http', host: 'example.com', fragment: 'footer' })\nuri.resolve('uri://a/b/c/d?q', '../../g')\nuri.equal('example://a/b/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d')\n```\n",
|
|
16
|
+
"md5.md": "---\ndescription: Native Node.js alternatives to the md5 package for MD5 hash generation\n---\n\n# Replacements for `md5`\n\n## `crypto` (native)\n\nIf you're using the [`md5`](https://github.com/pvorb/node-md5) package, _strongly_ consider moving to a stronger algorithm if your usage is security-sensitive (for example, passwords). MD5 is [not secure](https://en.wikipedia.org/wiki/MD5#Security) and hasn't been secure for many years.\n\nIf you must keep MD5 for compatibility, Node.js provides a native alternative via the [`crypto` module](https://nodejs.org/api/crypto.html#crypto).\n\n```ts\nimport crypto from 'node:crypto' // [!code ++]\nimport md5 from 'md5' // [!code --]\n\nmd5('message') // [!code --]\ncrypto.createHash('md5').update('message').digest('hex') // [!code ++]\n```\n",
|
|
2
17
|
"bcrypt.md": "---\ndescription: Modern alternatives to the bcrypt package for password hashing\n---\n\n# Replacements for `bcrypt`\n\nThe `bcrypt` package can be replaced by native functionality in most runtimes, or more performant packages.\n\n## `bcryptjs`\n\n[`bcryptjs`](https://github.com/dcodeIO/bcrypt.js) is a widely used pure JavaScript implementation with a very similar API surface to `bcrypt`.\n\n```ts\nimport bcrypt from 'bcrypt' // [!code --]\nimport bcrypt from 'bcryptjs' // [!code ++]\n\nconst salt = await bcrypt.genSalt(10)\n\nconst hash = await bcrypt.hash('password', salt)\n```\n\n## `node:crypto` (native, Node.js built-in)\n\nNode provides [`node:crypto`](https://nodejs.org/api/crypto.html) for secure password hashing primitives (for example `scrypt` and `pbkdf2`). This is not a drop-in `bcrypt` API replacement, but is a good option if you can switch to a more secure cryptographic algorithm it supports.\n\n## Web Crypto API (native)\n\nThe [Web Crypto API](https://developer.mozilla.org/docs/Web/API/Web_Crypto_API) provides native functionality for cryptographic operations in both web browsers and Node.\n\n> [!NOTE]\n> A few legacy algorithms are intentionally omitted for security reasons (e.g. MD5).\n\n## Bun (built-in)\n\nBun supports the Web Crypto API natively, and also provides support for streaming hashing via [`Bun.CryptoHasher`](https://bun.sh/docs/api/hashing).\n\nAs with the Web Crypto API, many legacy algorithms are intentionally omitted for security reasons (e.g. MD5).\n",
|
|
3
|
-
"bluebird-q.md": "---\ndescription: Modern alternatives to the Bluebird and Q Promise libraries for async control flow in JavaScript\n---\n\n# Replacements for `bluebird` / `q`\n\n## `Promise` (native)\n\n[`bluebird`](https://github.com/petkaantonov/bluebird?tab=readme-ov-file#%EF%B8%8Fnote%EF%B8%8F) and [`q`](https://github.com/kriskowal/q#note) recommend switching away from them to native promises.\n\n## `nativebird`\n\n[`NativeBird`](https://github.com/doodlewind/nativebird) is an ultralight native `Promise` extension that provides Bluebird-like helpers if you miss a few conveniences from Bluebird.\n",
|
|
4
18
|
"buf-compare.md": "---\ndescription: Native Node.js alternatives to the buf-compare package for buffer comparison\n---\n\n# Replacements for `buf-compare`\n\n## `Buffer.compare` (native)\n\n[`Buffer.compare`](https://nodejs.org/api/buffer.html#static-method-buffercomparebuf1-buf2) is a native method which achieves the same result as `buf-compare`, available since Node v0.11.13.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufCompare from 'buf-compare' // [!code --]\n\nconst buf1 = Buffer.from('303')\nconst buf2 = Buffer.from('808')\n\nbufCompare(buf1, buf2) // [!code --]\nBuffer.compare(buf1, buf2) // [!code ++]\n```\n",
|
|
5
|
-
"body-parser.md": "---\ndescription: Modern alternatives to the body-parser package for parsing HTTP request bodies in Node.js servers\n---\n\n# Replacements for `body-parser`\n\n## `milliparsec`\n\n[`milliparsec`](https://github.com/tinyhttp/milliparsec) is a lightweight alternative to [`body-parser`](https://github.com/expressjs/body-parser) with a smaller footprint.\n\nExample:\n\n```ts\nimport bodyParser from 'body-parser' // [!code --]\nimport { json, urlencoded } from 'milliparsec' // [!code ++]\nimport express from 'express'\n\nconst app = express()\n\napp.use(bodyParser.json()) // [!code --]\napp.use(bodyParser.urlencoded({ extended: true })) // [!code --]\n\napp.use(json()) // [!code ++]\napp.use(urlencoded()) // [!code ++]\n```\n\nFor API differences and feature comparison, see the [migration.md](https://github.com/tinyhttp/milliparsec/blob/master/migration.md).\n",
|
|
6
|
-
"buffer-equals.md": "---\ndescription: Native Node.js alternatives to the buffer-equals package for buffer equality checks\n---\n\n# Replacements for `buffer-equals`\n\n## `Buffer#equals` (native)\n\nBuffers have an [`equals`](https://nodejs.org/api/buffer.html#bufequalsotherbuffer) method since Node v0.12.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufferEquals from 'buffer-equals' // [!code --]\n\nconst buf1 = Buffer.from('303')\nconst buf2 = Buffer.from('303')\n\nbufferEquals(buf1, buf2) // [!code --]\nbuf1.equals(buf2) // [!code ++]\n```\n",
|
|
7
|
-
"chalk.md": "---\ndescription: Modern alternatives to the chalk package for terminal string styling and colors, with notes on browser console support\n---\n\n# Replacements for `chalk`\n\n## `styleText` (native)\n\nSince Node 20.x, you can use the [`styleText`](https://nodejs.org/api/util.html#utilstyletextformat-text-options) function from the `node:util` module to style text in the terminal.\n\n> [!TIP]\n> Node.js provides a codemod which can migrate some of this automatically, see the docs at [@nodejs/chalk-to-util-styletext](https://app.codemod.com/registry/@nodejs/chalk-to-util-styletext) for more details.\n\nExample:\n\n```ts\nimport { styleText } from 'node:util' // [!code ++]\nimport chalk from 'chalk' // [!code --]\n\nconsole.log(`Hello ${chalk.blue('blue')} world!`) // [!code --]\nconsole.log(`Hello ${styleText('blue', 'blue')} world!`) // [!code ++]\nconsole.log(`I am ${chalk.hex('#ec8f5e')('hex color')}!`) // [!code --]\nconsole.log(`I am ${styleText('#ec8f5e', 'hex color')}!`) // [!code ++]\n```\n\nWhen using multiple styles, you can pass an array to `styleText`:\n\n```ts\nconsole.log(`I am ${chalk.blue.bgRed('blue on red')}!`) // [!code --]\nconsole.log(`I am ${styleText(['blue', 'bgRed'], 'blue on red')}!`) // [!code ++]\n```\n\n> [!NOTE]\n> Before Node v26.1.0, `styleText` did not support hex colors or RGB colors (e.g. `#EFEFEF` or `255, 239, 235`). Hex colors are supported starting in v26.1.0, but RGB colors are still not supported. You can view the available styles in the [Node documentation](https://nodejs.org/api/util.html#modifiers).\n\n## `picocolors`\n\n[`picocolors`](https://github.com/alexeyraspopov/picocolors) follows a similar API but without chaining:\n\n```ts\nimport chalk from 'chalk' // [!code --]\nimport picocolors from 'picocolors' // [!code ++]\n\nconsole.log(`Hello ${chalk.blue('blue')} world!`) // [!code --]\nconsole.log(`Hello ${picocolors.blue('blue')} world!`) // [!code ++]\n\n// A chained example\nconsole.log(chalk.blue.bgRed('blue on red')) // [!code --]\nconsole.log(picocolors.blue(picocolors.bgRed('blue on red'))) // [!code ++]\n```\n\n> [!NOTE]\n> `picocolors` currently does not support RGB and hex colors (e.g. `#EFEFEF` or `255, 239, 235`).\n\n## `ansis`\n\n[`ansis`](https://github.com/webdiscus/ansis/) supports a chaining syntax similar to chalk and supports both RGB, and hex colors.\n\nExample:\n\n```ts\nimport ansis from 'ansis' // [!code ++]\nimport chalk from 'chalk' // [!code --]\n\nconsole.log(`Hello ${chalk.blue('blue')} world!`) // [!code --]\nconsole.log(`Hello ${ansis.blue('blue')} world!`) // [!code ++]\n```\n\nWhen using multiple styles, you can chain them just like in chalk:\n\n```ts\nconsole.log(chalk.blue.bgRed('blue on red')) // [!code --]\nconsole.log(ansis.blue.bgRed('blue on red')) // [!code ++]\n```\n\nSimilarly, you can use RGB and hex colors:\n\n```ts\nconsole.log(chalk.rgb(239, 239, 239)('Hello world!')) // [!code --]\nconsole.log(ansis.rgb(239, 239, 239)('Hello world!')) // [!code ++]\n```\n\n## Browser support\n\nWhile these libraries are primarily designed for terminal output, some projects may need colored output in browser environments.\n\nFollowing [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output), the native approach is `%c` directive in `console.log`:\n\n```ts\nconsole.log(\n 'Hello %ce%c1%c8%ce',\n 'color: #ec8f5e;',\n 'color: #f2ca60;',\n 'color: #bece57;',\n 'color: #7bb560;',\n 'Ecosystem Performance'\n)\n```\n\nLibrary support:\n\n- [`ansis`](https://github.com/webdiscus/ansis#browser-compatibility-for-ansi-codes) - colors are supported in _Chromium_ browsers\n- `picocolors` - strips colors in browser environments\n- `node:util` - is not available in browsers\n",
|
|
8
|
-
"clean-webpack-plugin.md": "---\ndescription: Modern alternatives to the clean-webpack-plugin package\n---\n\n# Replacements for `clean-webpack-plugin`\n\n## `output.clean` (built-in, since webpack 5)\n\nExample:\n\n```js\nconst { CleanWebpackPlugin } = require('clean-webpack-plugin') // [!code --]\n\nmodule.exports = {\n plugins: [new CleanWebpackPlugin()], // [!code --]\n output: { clean: true } // [!code ++]\n}\n```\n",
|
|
9
|
-
"cli-builders.md": "---\ndescription: Modern alternatives to packages for building CLI applications\n---\n\n# Replacements for CLI builders\n\n## `sade`\n\n[`sade`](https://github.com/lukeed/sade) is a small but powerful tool for building CLI applications for Node.js\n\n```ts\nimport sade from 'sade'\n\nconst prog = sade('my-cli')\n\nprog\n .version('1.0.5')\n .option('--global, -g', 'An example global flag')\n .option('-c, --config', 'Provide path to custom config', 'foo.config.js')\n\nprog\n .command('build <src> <dest>')\n .describe('Build the source directory. Expects an `index.js` entry file.')\n .option('-o, --output', 'Change the name of the output file', 'bundle.js')\n .example('build src build --global --config my-conf.js')\n .example('build app public -o main.js')\n .action((src, dest, opts) => {\n console.log(`> building from ${src} to ${dest}`)\n console.log('> these are extra opts', opts)\n })\n\nprog.parse(process.argv)\n```\n\n## `cleye`\n\n[`cleye`](https://github.com/privatenumber/cleye) is another powerful tool for building CLI applications for Node.js\n\n```ts\nimport { cli } from 'cleye'\n\n// Parse argv\nconst argv = cli({\n name: 'greet.js',\n\n // Define parameters\n parameters: [\n '<first name>', // First name is required\n '[last name]' // Last name is optional\n ],\n\n // Define flags/options\n flags: {\n // Parses `--time` as a string\n time: {\n type: String,\n description: 'Time of day to greet (morning or evening)',\n default: 'morning'\n }\n }\n})\n\nconst name = [argv._.firstName, argv._.lastName].filter(Boolean).join(' ')\n\nif (argv.flags.time === 'morning') {\n console.log(`Good morning ${name}!`)\n} else {\n console.log(`Good evening ${name}!`)\n}\n```\n\n## Argument parsers\n\nIf you only need an argument parser, check the [argument parsers page](https://e18e.dev/docs/replacements/parseargs).\n",
|
|
10
19
|
"clipboardy.md": "---\ndescription: Modern alternatives to the clipboardy package for copy/pasting on Node.js and in the browser\n---\n\n# Replacements for `clipboardy`\n\n## `tinyclip`\n\n[`tinyclip`](https://github.com/tinylibs/tinyclip) provides cross-platform clipboard functionality to Node.js.\n\n```js\nimport clipboard from 'clipboardy' // [!code --]\nimport * as clipboard from 'tinyclip' // [!code ++]\n\nawait clipboard.write('hello world') // [!code --]\nawait clipboard.writeText('hello world') // [!code ++]\nawait clipboard.read() // [!code --]\nawait clipboard.readText() // [!code ++]\n```\n\n> [!NOTE]\n> `writeSync()` and `readSync()` do not have any equivalent in `tinyclip`, we recommend you migrate to their async versions.\n\n## Clipboard API (native, browser)\n\nLearn more about the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API).\n\n```js\nimport clipboard from 'clipboardy' // [!code --]\n\nawait clipboard.write('hello world') // [!code --]\nawait navigator.clipboard.writeText('hello world') // [!code ++]\nawait clipboard.read() // [!code --]\nawait navigator.clipboard.readText() // [!code ++]\n```\n\n> [!NOTE]\n> `writeSync()` and `readSync()` do not have an equivalent in browsers.\n",
|
|
11
|
-
"
|
|
12
|
-
"cosmiconfig.md": "---\ndescription: Modern alternatives to the cosmiconfig package\n---\n\n# Replacements for `cosmiconfig`\n\n## `lilconfig`\n\n[`lilconfig`](https://github.com/antonk52/lilconfig) is a zero-dependency alternative to cosmiconfig with the same API\n\n> [!NOTE]\n> `lilconfig` does not support YAML files out of the box unless you provide custom loaders.\n\n### Example\n\n```js\nimport { lilconfig, lilconfigSync } from 'lilconfig'\n\nconst options = {\n searchPlaces: [\n 'package.json', // Will use \"myapp\" field\n '.myapprc',\n '.myapprc.json',\n 'myapp.config.js'\n ]\n}\n\nawait lilconfig('myapp', options).search()\n\n// Sync version\nlilconfigSync('myapp', options).search()\n```\n\n### Loading YAML files\n\n```js\nimport { lilconfig } from 'lilconfig'\nimport { parse } from 'yaml'\n\nconst yamlLoader = (filepath, content) => parse(content)\n\nconst options = {\n searchPlaces: [\n 'package.json',\n '.myapprc',\n '.myapprc.yaml',\n '.myapprc.yml',\n 'myapp.config.js'\n ],\n loaders: {\n '.yaml': yamlLoader,\n '.yml': yamlLoader,\n noExt: yamlLoader\n }\n}\n\nawait lilconfig('myapp', options).search()\n```\n",
|
|
20
|
+
"buffer-equal-constant-time.md": "---\ndescription: Native Node.js alternatives to the buffer-equal-constant-time package for safe buffer equality checks\n---\n\n# Replacements for `buffer-equal-constant-time`\n\n## `crypto.timingSafeEqual` (native)\n\nYou can use the [`timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b) function from the `node:crypto` module.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufferEqual from 'buffer-equal-constant-time' // [!code --]\nimport * as crypto from 'node:crypto' // [!code ++]\n\nconst bufUser = Buffer.from('303')\nconst bufSecret = Buffer.from('303')\n\nbufferEqual(bufUser, bufSecret) // [!code --]\nbufUser.length === bufSecret.length // [!code ++]\n ? crypto.timingSafeEqual(bufUser, bufSecret) // [!code ++]\n : !crypto.timingSafeEqual(bufUser, bufUser) // [!code ++]\n```\n",
|
|
13
21
|
"create-hmac.md": "---\ndescription: Modern alternatives to the `create-hmac` package for HMAC\n---\n\n# Replacements for `create-hmac`\n\n## `crypto.createHmac` (native, Node.js)\n\n```js\nimport { createHmac } from 'node:crypto' // [!code ++]\nimport createHmac from 'create-hmac' // [!code --]\n\nconst secret = 'secret-key'\nconst data = 'message-to-sign'\n\nconst hash = createHmac('sha256', secret).update(data).digest('hex')\n```\n\n## `crypto.subtle.sign` (native, browser)\n\n```js\nconst encoder = new TextEncoder()\n\nasync function generateHMAC(secret, data) {\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data))\n\n return new Uint8Array(signature).toHex()\n}\n\nconst secret = 'secret-key'\nconst data = 'message-to-sign'\n\nconst hash = await generateHMAC(secret, data)\n```\n\n## `@noble/hashes`\n\n```js\nimport { hmac } from '@noble/hashes/hmac.js' // [!code ++]\nimport { sha256 } from '@noble/hashes/sha256.js' // [!code ++]\nimport { bytesToHex } from '@noble/hashes/utils.js' // [!code ++]\nimport createHmac from 'create-hmac' // [!code --]\n\nconst secret = 'secret-key'\nconst data = 'message-to-sign'\n\nconst hash = createHmac('sha256', secret).update(data).digest('hex') // [!code --]\nconst hash = bytesToHex(hmac(sha256, secret, data)) // [!code ++]\n```\n",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"deep-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"dot-prop.md": "---\ndescription: Modern alternatives to the dot-prop package for getting, setting, and deleting nested object properties using dot notation\n---\n\n# Replacements for `dot-prop`\n\n## `dlv` and `dset`\n\n[`dlv`](https://github.com/developit/dlv) gets nested values with default fallbacks and [`dset`](https://github.com/lukeed/dset) sets nested values with automatic intermediate object creation.\n\n```ts\nimport { getProperty, setProperty } from 'dot-prop' // [!code --]\nimport delve from 'dlv' // [!code ++]\nimport { dset } from 'dset' // [!code ++]\n\nconst value = getProperty(obj, 'foo.bar.baz') // [!code --]\nconst value = delve(obj, 'foo.bar.baz') // [!code ++]\n\nsetProperty(obj, 'foo.bar.baz', 'value') // [!code --]\ndset(obj, 'foo.bar.baz', 'value') // [!code ++]\n```\n\n## `String.prototype.split` + `Array.prototype.reduce` (native)\n\nIf you only need to get a nested value you can use a simple function:\n\n```js\nfunction getProperty(obj, key) {\n return key.split('.').reduce((acc, k) => acc?.[k], obj)\n}\n\nconst value = getProperty(obj, 'foo.bar.baz')\n```\n\n> [!NOTE]\n> This assumes that you do not consume dot paths as user input.\n> If you do, ensure you sanitize keys before accessing them (e.g. through `Object.hasOwn`).\n",
|
|
21
|
-
"duplexer.md": "---\ndescription: Modern alternatives to the duplexer package\n---\n\n# Replacements for `duplexer`\n\n## `Duplex.from` (native, Node.js)\n\n<!-- prettier-ignore -->\n```js\nimport duplexer from 'duplexer' // [!code --]\nimport { Duplex } from 'node:stream' // [!code ++]\n\nduplexer(writableStream, readableStream) // [!code --]\n\nDuplex.from({ // [!code ++]\n writable: writableStream, // [!code ++]\n readable: readableStream // [!code ++]\n}) // [!code ++]\n```\n",
|
|
22
|
-
"emoji-regex.md": "---\ndescription: Modern alternatives to the emoji-regex package for emoji detection and matching\n---\n\n# Replacements for `emoji-regex`\n\n## `emoji-regex-xs`\n\n[`emoji-regex-xs`](https://github.com/slevithan/emoji-regex-xs) offers the same API and features whilst being 98% smaller.\n\n```ts\nimport emojiRegex from 'emoji-regex' // [!code --]\nimport emojiRegex from 'emoji-regex-xs' // [!code ++]\n\nconst text = `\n\\u{231A}: ⌚ default emoji presentation character (Emoji_Presentation)\n\\u{2194}\\u{FE0F}: ↔️ default text presentation character rendered as emoji\n\\u{1F469}: 👩 emoji modifier base (Emoji_Modifier_Base)\n\\u{1F469}\\u{1F3FF}: 👩🏿 emoji modifier base followed by a modifier\n`\n\nconst regex = emojiRegex()\nfor (const match of text.matchAll(regex)) {\n const emoji = match[0]\n console.log(`Matched sequence ${emoji} — code points: ${[...emoji].length}`)\n}\n```\n\n## Unicode RegExp (native)\n\nIf your target runtime supports ES2024 Unicode property sets, you can use the native [`\\p{RGI_Emoji}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape) property in a regular expression. This relies on the engine's built‑in Unicode handling.\n\n```ts\nimport emojiRegex from 'emoji-regex' // [!code --]\n\nconst regex = emojiRegex() // [!code --]\nconst regex = /\\p{RGI_Emoji}/gv // [!code ++]\n\nfor (const match of text.matchAll(regex)) {\n const emoji = match[0]\n console.log(`Matched sequence ${emoji} — code points: ${[...emoji].length}`)\n}\n```\n",
|
|
23
|
-
"eslint-plugin-eslint-comments.md": "---\ndescription: Modern alternatives to the eslint-plugin-eslint-comments package for ESLint comment linting\n---\n\n# Replacements for `eslint-plugin-eslint-comments`\n\n## `@eslint-community/eslint-plugin-eslint-comments`\n\n[`@eslint-community/eslint-plugin-eslint-comments`](https://github.com/eslint-community/eslint-plugin-eslint-comments) is the actively maintained successor with updated dependencies, flat config support, and continued development.\n\n```ts\nimport eslintComments from 'eslint-plugin-eslint-comments' // [!code --]\nimport commentsCommunity from '@eslint-community/eslint-plugin-eslint-comments/configs' // [!code ++]\n\nexport default [\n commentsCommunity.recommended, // [!code ++]\n {\n plugins: {\n 'eslint-comments': eslintComments // [!code --]\n },\n rules: {\n 'eslint-comments/no-unused-disable': 'error', // [!code --]\n '@eslint-community/eslint-comments/no-unused-disable': 'error' // [!code ++]\n }\n }\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:eslint-comments/recommended', // [!code --]\n 'plugin:@eslint-community/eslint-comments/recommended' // [!code ++]\n ],\n rules: {\n 'eslint-comments/no-unused-disable': 'error', // [!code --]\n '@eslint-community/eslint-comments/no-unused-disable': 'error' // [!code ++]\n }\n}\n```\n",
|
|
24
|
-
"eslint-plugin-import.md": "---\ndescription: Modern alternative to eslint-plugin-import, which helps with linting of ES6+ import/export syntax\n---\n\n# Replacements for `eslint-plugin-import`\n\n## `eslint-plugin-import-x`\n\n[`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x) is a modern fork of [`eslint-plugin-import`](https://github.com/import-js/eslint-plugin-import). `import-x` focuses on having a smaller dependency footprint and faster module resolution via a Rust-based resolver.\n\n### Flat config\n\n<!-- prettier-ignore -->\n```ts\nimport importPlugin from 'eslint-plugin-import' // [!code --]\nimport { createNodeResolver, importX } from 'eslint-plugin-import-x' // [!code ++]\nimport { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript' // [!code ++]\n\nexport default [\n importPlugin.flatConfigs.recommended, // [!code --]\n importX.flatConfigs.recommended, // [!code ++]\n {\n settings: {\n 'import/resolver': { typescript: true }, // [!code --]\n 'import-x/resolver-next': [ // [!code ++]\n createTypeScriptImportResolver(), // [!code ++]\n createNodeResolver() // [!code ++]\n ] // [!code ++]\n },\n rules: {\n 'import/no-unresolved': 'error', // [!code --]\n 'import-x/no-unresolved': 'error', // [!code ++]\n 'import/no-nodejs-modules': 'warn', // [!code --]\n 'import-x/no-nodejs-modules': 'warn' // [!code ++]\n }\n }\n]\n```\n\n### Legacy config\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:import/recommended', // [!code --]\n 'plugin:import-x/recommended', // [!code ++]\n 'plugin:import/typescript', // [!code --]\n 'plugin:import-x/typescript' // [!code ++]\n ],\n plugins: [\n 'import', // [!code --]\n 'import-x' // [!code ++]\n ],\n settings: {\n 'import/resolver': { typescript: true }, // [!code --]\n 'import-x/resolver': { typescript: true } // [!code ++]\n },\n rules: {\n 'import/no-unresolved': 'error', // [!code --]\n 'import-x/no-unresolved': 'error' // [!code ++]\n }\n}\n```\n\n## Oxlint\n\n[Oxlint](https://oxc.rs/docs/guide/usage/linter.html) is a high-performance linter for JavaScript and TypeScript, built on the Rust-based `Oxc` compiler stack. It's intended to be fully backwards-compatible with ESLint, having ported most of the ESLint rules, as well as those from popular plugins including `eslint-plugin-import`.\n\nThe migration process from ESLint is covered in [the Oxlint documentation](https://oxc.rs/docs/guide/usage/linter/migrate-from-eslint.html), and can be done automatically from an ESLint flat config using [`npx @oxlint/migrate`](https://github.com/oxc-project/oxlint-migrate).\n\n> [!NOTE]\n> Oxlint is not necessarily a full drop-in replacement, as not all of the `eslint-plugin-import` rules have been, or will be, implemented. Check [the GitHub issue](https://github.com/oxc-project/oxc/issues/1117) to view the progress.\n",
|
|
25
|
-
"eslint-plugin-jest-dom.md": "---\ndescription: Modern alternatives to the eslint-plugin-vitest package for jest-dom-specific linting rules\n---\n\n# Replacements for `eslint-plugin-jest-dom`\n\n## `eslint-plugin-jest-dom-ya`\n\n[`eslint-plugin-jest-dom-ya`](https://github.com/G-Rath/eslint-plugin-jest-dom-ya) is the actively maintained successor forked by an established contributor, with ESLint v10 support and continued development.\n\n```ts\nimport jestDomPlugin from 'eslint-plugin-jest-dom' // [!code --]\nimport jestDomYaPlugin from 'eslint-plugin-jest-dom-ya' // [!code ++]\n\nexport default [\n jestDomPlugin.configs[\"flat/recommended\"], // [!code --]\n jestDomYaPlugin.configs[\"flat/recommended\"], // [!code ++]\n {\n plugins: {\n 'jest-dom': jestDomPlugin // [!code --]\n 'jest-dom-ya': jestDomYaPlugin // [!code ++]\n },\n rules: {\n \"jest-dom/prefer-checked\": \"error\", // [!code --]\n \"jest-dom-ya/prefer-checked\": \"error\", // [!code ++]\n \"jest-dom/prefer-enabled-disabled\": \"error\", // [!code --]\n \"jest-dom-ya/prefer-enabled-disabled\": \"error\" // [!code ++]\n }\n }\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:jest-dom/recommended', // [!code --]\n 'plugin:jest-dom-ya/recommended' // [!code ++]\n ],\n rules: {\n 'jest-dom/prefer-checked': 'error', // [!code --]\n 'jest-dom-ya/prefer-checked': 'error' // [!code ++]\n }\n}\n```\n",
|
|
26
|
-
"eslint-plugin-node.md": "---\ndescription: Modern alternatives to the eslint-plugin-node package for Node.js-specific linting rules\n---\n\n# Replacements for `eslint-plugin-node`\n\n## `eslint-plugin-n`\n\n[`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n) is a direct fork which is actively maintained. It has new features, bugfixes and updated dependencies.\n\n```ts\nimport nPlugin from 'eslint-plugin-n' // [!code ++]\nimport nodePlugin from 'eslint-plugin-node' // [!code --]\n\nexport default [\n {\n files: ['**/*.js'], // or any other pattern\n plugins: {\n node: nodePlugin, // [!code --]\n n: nPlugin // [!code ++]\n },\n rules: {\n ...nodePlugin.configs['recommended-script'].rules, // [!code --]\n ...nPlugin.configs['recommended-script'].rules, // [!code ++]\n 'node/exports-style': ['error', 'module.exports'], // [!code --]\n 'n/exports-style': ['error', 'module.exports'] // [!code ++]\n }\n }\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:node/recommended', // [!code --]\n 'plugin:n/recommended' // [!code ++]\n ]\n}\n```\n",
|
|
27
|
-
"eslint-plugin-vitest.md": "---\ndescription: Modern alternatives to the eslint-plugin-vitest package for Vitest-specific linting rules\n---\n\n# Replacements for `eslint-plugin-vitest`\n\n## `@vitest/eslint-plugin`\n\n[`@vitest/eslint-plugin`](https://github.com/vitest-dev/eslint-plugin-vitest) is the same project as `eslint-plugin-vitest` but re-published under a different name. `eslint-plugin-vitest` is no longer maintained because the [original maintainer has lost access to their old npm account](https://github.com/vitest-dev/eslint-plugin-vitest/issues/537).\n\n```ts\nimport vitest from '@vitest/eslint-plugin' // [!code ++]\nimport vitest from 'eslint-plugin-vitest' // [!code --]\n\nexport default [\n {\n files: ['tests/**'], // or any other pattern\n plugins: {\n vitest\n },\n rules: {\n ...vitest.configs.recommended.rules, // you can also use vitest.configs.all.rules to enable all rules\n 'vitest/max-nested-describe': ['error', { max: 3 }] // you can also modify rules' behavior using option like this\n }\n }\n]\n```\n",
|
|
22
|
+
"clean-webpack-plugin.md": "---\ndescription: Modern alternatives to the clean-webpack-plugin package\n---\n\n# Replacements for `clean-webpack-plugin`\n\n## `output.clean` (built-in, since webpack 5)\n\nExample:\n\n```js\nconst { CleanWebpackPlugin } = require('clean-webpack-plugin') // [!code --]\n\nmodule.exports = {\n plugins: [new CleanWebpackPlugin()], // [!code --]\n output: { clean: true } // [!code ++]\n}\n```\n",
|
|
23
|
+
"buffer-equals.md": "---\ndescription: Native Node.js alternatives to the buffer-equals package for buffer equality checks\n---\n\n# Replacements for `buffer-equals`\n\n## `Buffer#equals` (native)\n\nBuffers have an [`equals`](https://nodejs.org/api/buffer.html#bufequalsotherbuffer) method since Node v0.12.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufferEquals from 'buffer-equals' // [!code --]\n\nconst buf1 = Buffer.from('303')\nconst buf2 = Buffer.from('303')\n\nbufferEquals(buf1, buf2) // [!code --]\nbuf1.equals(buf2) // [!code ++]\n```\n",
|
|
24
|
+
"cpx.md": "---\ndescription: Modern alternatives to the cpx package for copying file globs with watch mode\n---\n\n# Replacements for `cpx`\n\n## `cpx2`\n\n[`cpx`](https://github.com/mysticatea/cpx) is unmaintained. [`cpx2`](https://github.com/bcomnes/cpx2) is an actively maintained fork that keeps the same CLI bin name (`cpx`), so it works as a drop-in replacement for CLI usage. For the Node API, switch your import to `cpx2`.\n\n```sh\nnpm i -D cpx # [!code --]\nnpm i -D cpx2 # [!code ++]\n\n# CLI stays the same (bin name is still \"cpx\")\ncpx \"src/**/*.{html,png,jpg}\" app --watch\n```\n\nNode API replacement:\n\n<!-- eslint-skip -->\n\n```ts\nconst cpx = require('cpx') // [!code --]\nconst cpx = require('cpx2') // [!code ++]\n\ncpx.copy('src/**/*.js', 'dist', (err) => {\n if (err) throw err\n})\n```\n",
|
|
25
|
+
"deep-merge.md": "---\ndescription: Modern alternatives to packages for deep merging objects\n---\n\n# Replacements for deep merge packages\n\n## `defu`\n\nIf you need to deep merge two objects, you can use [`defu`](https://github.com/unjs/defu):\n\n```ts\nimport { defu } from 'defu'\n\nconst options = defu(object, defaults)\n```\n\n## `@fastify/deepmerge`\n\nThe [`@fastify/deepmerge`](https://github.com/fastify/deepmerge) package is another fast and small alternative.\n\nIt also offers more options for customizing the merge behavior than other libraries.\n\n```ts\nimport deepMerge from '@fastify/deepmerge'\n\nconst options = deepMerge(object, defaults)\n```\n",
|
|
26
|
+
"collection-map.md": "---\ndescription: Native alternatives to the collection-map package\n---\n\n# Replacements for `collection-map`\n\n## Objects\n\n<!-- prettier-ignore -->\n```js\nconst map = require('collection-map') // [!code --]\nconst data = { a: 'foo', b: 'bar', c: 'baz' }\n\n// Mapping values\nconst res = map(data, (item) => item) // [!code --]\nconst res = Object.values(data).map((item) => item) // [!code ++]\n\n// Mapping keys\nconst res = map(data, (item, key) => key) // [!code --]\nconst res = Object.keys(data).map((key) => key) // [!code ++]\n\n// Mapping keys and values\nconst res = map(data, (item, key) => fn(item, key)) // [!code --]\nconst res = Object.fromEntries( // [!code ++]\n Object.entries(data).map(([key, value]) => fn(value, key)) // [!code ++]\n) // [!code ++]\n```\n\n## Arrays\n\n```js\nconst map = require('collection-map') // [!code --]\nconst data = ['foo', 'bar', 'baz']\n\n// Mapping items\nconst res = map(data, (item) => item) // [!code --]\nconst res = data.map((item) => item) // [!code ++]\n\n// Mapping indices\nconst res = map(data, (item, index) => index) // [!code --]\nconst res = data.map((_, index) => index) // [!code ++]\n\n// Mapping items indices\nconst res = map(data, (item, index) => fn(item, index)) // [!code --]\nconst res = data.map((item, index) => fn(item, index)) // [!code ++]\n```\n\n## Property Strings\n\nWhen passing a string to extract a specific property, use a standard map with property access.\n\n```js\nconst map = require('collection-map') // [!code --]\n\nconst obj = {\n a: { aaa: 'one', bbb: 'four', ccc: 'seven' },\n b: { aaa: 'two', bbb: 'five', ccc: 'eight' },\n c: { aaa: 'three', bbb: 'six', ccc: 'nine' }\n}\n\n// Objects: Map values to property\nmap(obj, 'aaa') // [!code --]\nObject.values(obj).map((item) => item.aaa) // [!code ++]\n\n// Arrays: Map items to property\nconst array = [obj.a, obj.b, obj.c]\nmap(array, 'bbb') // [!code --]\narray.map((item) => item.bbb) // [!code ++]\n```\n\n## `thisArg` (Context)\n\nNative `.map()` supports a second argument for `thisArg`.\n\n<!-- prettier-ignore -->\n```js\nconst map = require('collection-map') // [!code --]\n\nconst array = ['a', 'b', 'c']\nconst ctx = { a: 'aaa', b: 'bbb', c: 'ccc' }\n\nconst res = map(array, function(item) { // [!code --]\nconst res = array.map(function(item) { // [!code ++]\n return this[item]\n}, ctx)\n```\n",
|
|
27
|
+
"builtin-modules.md": "---\ndescription: Native Node.js alternatives to the builtin-modules package for listing built-in modules\n---\n\n# Replacements for `builtin-modules`\n\n## `builtinModules` (native, since Node.js 6.x)\n\nFor getting the list of built-in modules, you can use [`builtinModules`](https://nodejs.org/api/module.html#modulebuiltinmodules):\n\n```ts\nimport builtinModulesList from 'builtin-modules' // [!code --]\nimport { builtinModules } from 'node:module' // [!code ++]\n\nbuiltinModulesList.includes('fs') // true [!code --]\nbuiltinModules.includes('fs') // true [!code ++]\n```\n",
|
|
28
28
|
"execa.md": "---\ndescription: Modern alternatives to the execa package for running child processes\n---\n\n# Replacements for `execa`\n\n## `tinyexec`\n\n[`tinyexec`](https://github.com/tinylibs/tinyexec) is a minimal process execution library.\n\nExample:\n\n```ts\nimport { execa } from 'execa' // [!code --]\nimport { x } from 'tinyexec' // [!code ++]\n\nconst { stdout } = await execa('ls', ['-l']) // [!code --]\nconst { stdout } = await x('ls', ['-l'], { throwOnError: true }) // [!code ++]\n```\n\n## `nanoexec`\n\nIf you prefer a very thin wrapper over `child_process.spawn` (including full spawn options and optional shell), [`nanoexec`](https://github.com/fabiospampinato/nanoexec) is another light alternative. Its `stdout`/`stderr` are Buffers.\n\nExample:\n\n```ts\nimport { execa } from 'execa' // [!code --]\nimport exec from 'nanoexec' // [!code ++]\n\nconst { stdout } = await execa('echo', ['example']) // [!code --]\nconst res = await exec('echo', ['example']) // [!code ++]\nconst stdout = res.stdout.toString('utf8') // [!code ++]\n```\n\n## Bun\n\nIf you’re on Bun, its built-in [`$`](https://bun.com/reference/bun/$) template tag can replace `execa`’s script-style usage:\n\nExample:\n\n```ts\nimport { $ } from 'execa' // [!code --]\nimport { $ } from 'bun' // [!code ++]\n\nconst { stdout } = await $`echo \"Hello\"` // [!code --]\nconst stdout = await $`echo \"Hello\"`.text() // [!code ++]\n```\n",
|
|
29
|
-
"ez-spawn.md": "---\ndescription: Modern alternatives to the ez-spawn package for spawning child processes\n---\n\n# Replacements for `@jsdevtools/ez-spawn`\n\n## `tinyexec`\n\n`ez-spawn` accepts shell-like command strings, which `tinyexec` does not.\n\nFor example:\n\n```ts\nimport ezSpawn from '@jsdevtools/ez-spawn' // [!code --]\nimport { x } from 'tinyexec' // [!code ++]\n\nawait ezSpawn.async('ls -l') // [!code --]\nawait x('ls', ['-l']) // [!code ++]\n```\n\nAlternatively, you can use [`args-tokenizer`](https://github.com/TrySound/args-tokenizer/) to convert a shell string to a command and arguments:\n\n```ts\nimport ezSpawn from '@jsdevtools/ez-spawn' // [!code --]\nimport { tokenizeArgs } from 'args-tokenizer' // [!code ++]\nimport { x } from 'tinyexec' // [!code ++]\n\nconst [command, ...args] = tokenizeArgs('ls -l') // [!code ++]\nawait ezSpawn.async('ls -l') // [!code --]\nawait x(command, args) // [!code ++]\n```\n",
|
|
30
29
|
"feather.md": "---\ndescription: Modern alternatives to feather packages\n---\n\n# Replacements for `feather-icons` and `react-feather`\n\n## `lucide` for `feather-icons`\n\n[`lucide`](https://lucide.dev/) is a community-maintained fork of Feather Icons.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport feather from 'feather-icons' // [!code --]\nimport { icons } from 'lucide' // [!code ++]\n\nfeather.icons.x.toSvg({ class: 'icon icon-x' }) // [!code --]\nicons.x.toSvg({ class: 'icon icon-x' }) // [!code ++]\n```\n\n## `lucide-react` for `react-feather`\n\n[`lucide-react`](https://lucide.dev/guide/packages/lucide-react) provides React components for the Lucide icon set and is the natural replacement for `react-feather`.\n\nExample:\n\n<!-- prettier-ignore -->\n```jsx\nimport { Camera, ArrowRight } from 'react-feather' // [!code --]\nimport { Camera, ArrowRight } from 'lucide-react' // [!code ++]\n\nexport function Header() {\n return (\n <>\n <Camera size={18} />\n <ArrowRight className=\"cta-icon\" />\n </>\n )\n}\n```\n\n> [!NOTE]\n> Lucide provides information on the [comparison](https://lucide.dev/guide/comparison#lucide-vs-feather-icons) of it vs feather-icons\n",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
30
|
+
"eslint-plugin-import.md": "---\ndescription: Modern alternative to eslint-plugin-import, which helps with linting of ES6+ import/export syntax\n---\n\n# Replacements for `eslint-plugin-import`\n\n## `eslint-plugin-import-x`\n\n[`eslint-plugin-import-x`](https://github.com/un-ts/eslint-plugin-import-x) is a modern fork of [`eslint-plugin-import`](https://github.com/import-js/eslint-plugin-import). `import-x` focuses on having a smaller dependency footprint and faster module resolution via a Rust-based resolver.\n\n### Flat config\n\n<!-- prettier-ignore -->\n```ts\nimport importPlugin from 'eslint-plugin-import' // [!code --]\nimport { createNodeResolver, importX } from 'eslint-plugin-import-x' // [!code ++]\nimport { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript' // [!code ++]\n\nexport default [\n importPlugin.flatConfigs.recommended, // [!code --]\n importX.flatConfigs.recommended, // [!code ++]\n {\n settings: {\n 'import/resolver': { typescript: true }, // [!code --]\n 'import-x/resolver-next': [ // [!code ++]\n createTypeScriptImportResolver(), // [!code ++]\n createNodeResolver() // [!code ++]\n ] // [!code ++]\n },\n rules: {\n 'import/no-unresolved': 'error', // [!code --]\n 'import-x/no-unresolved': 'error', // [!code ++]\n 'import/no-nodejs-modules': 'warn', // [!code --]\n 'import-x/no-nodejs-modules': 'warn' // [!code ++]\n }\n }\n]\n```\n\n### Legacy config\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:import/recommended', // [!code --]\n 'plugin:import-x/recommended', // [!code ++]\n 'plugin:import/typescript', // [!code --]\n 'plugin:import-x/typescript' // [!code ++]\n ],\n plugins: [\n 'import', // [!code --]\n 'import-x' // [!code ++]\n ],\n settings: {\n 'import/resolver': { typescript: true }, // [!code --]\n 'import-x/resolver': { typescript: true } // [!code ++]\n },\n rules: {\n 'import/no-unresolved': 'error', // [!code --]\n 'import-x/no-unresolved': 'error' // [!code ++]\n }\n}\n```\n\n## Oxlint\n\n[Oxlint](https://oxc.rs/docs/guide/usage/linter.html) is a high-performance linter for JavaScript and TypeScript, built on the Rust-based `Oxc` compiler stack. It's intended to be fully backwards-compatible with ESLint, having ported most of the ESLint rules, as well as those from popular plugins including `eslint-plugin-import`.\n\nThe migration process from ESLint is covered in [the Oxlint documentation](https://oxc.rs/docs/guide/usage/linter/migrate-from-eslint.html), and can be done automatically from an ESLint flat config using [`npx @oxlint/migrate`](https://github.com/oxc-project/oxlint-migrate).\n\n> [!NOTE]\n> Oxlint is not necessarily a full drop-in replacement, as not all of the `eslint-plugin-import` rules have been, or will be, implemented. Check [the GitHub issue](https://github.com/oxc-project/oxc/issues/1117) to view the progress.\n",
|
|
31
|
+
"ez-spawn.md": "---\ndescription: Modern alternatives to the ez-spawn package for spawning child processes\n---\n\n# Replacements for `@jsdevtools/ez-spawn`\n\n## `tinyexec`\n\n`ez-spawn` accepts shell-like command strings, which `tinyexec` does not.\n\nFor example:\n\n```ts\nimport ezSpawn from '@jsdevtools/ez-spawn' // [!code --]\nimport { x } from 'tinyexec' // [!code ++]\n\nawait ezSpawn.async('ls -l') // [!code --]\nawait x('ls', ['-l']) // [!code ++]\n```\n\nAlternatively, you can use [`args-tokenizer`](https://github.com/TrySound/args-tokenizer/) to convert a shell string to a command and arguments:\n\n```ts\nimport ezSpawn from '@jsdevtools/ez-spawn' // [!code --]\nimport { tokenizeArgs } from 'args-tokenizer' // [!code ++]\nimport { x } from 'tinyexec' // [!code ++]\n\nconst [command, ...args] = tokenizeArgs('ls -l') // [!code ++]\nawait ezSpawn.async('ls -l') // [!code --]\nawait x(command, args) // [!code ++]\n```\n",
|
|
32
|
+
"chalk.md": "---\ndescription: Modern alternatives to the chalk package for terminal string styling and colors, with notes on browser console support\n---\n\n# Replacements for `chalk`\n\n## `styleText` (native)\n\nSince Node 20.x, you can use the [`styleText`](https://nodejs.org/api/util.html#utilstyletextformat-text-options) function from the `node:util` module to style text in the terminal.\n\n> [!TIP]\n> Node.js provides a codemod which can migrate some of this automatically, see the docs at [@nodejs/chalk-to-util-styletext](https://app.codemod.com/registry/@nodejs/chalk-to-util-styletext) for more details.\n\nExample:\n\n```ts\nimport { styleText } from 'node:util' // [!code ++]\nimport chalk from 'chalk' // [!code --]\n\nconsole.log(`Hello ${chalk.blue('blue')} world!`) // [!code --]\nconsole.log(`Hello ${styleText('blue', 'blue')} world!`) // [!code ++]\nconsole.log(`I am ${chalk.hex('#ec8f5e')('hex color')}!`) // [!code --]\nconsole.log(`I am ${styleText('#ec8f5e', 'hex color')}!`) // [!code ++]\n```\n\nWhen using multiple styles, you can pass an array to `styleText`:\n\n```ts\nconsole.log(`I am ${chalk.blue.bgRed('blue on red')}!`) // [!code --]\nconsole.log(`I am ${styleText(['blue', 'bgRed'], 'blue on red')}!`) // [!code ++]\n```\n\n> [!NOTE]\n> Before Node v26.1.0, `styleText` did not support hex colors or RGB colors (e.g. `#EFEFEF` or `255, 239, 235`). Hex colors are supported starting in v26.1.0, but RGB colors are still not supported. You can view the available styles in the [Node documentation](https://nodejs.org/api/util.html#modifiers).\n\n## `picocolors`\n\n[`picocolors`](https://github.com/alexeyraspopov/picocolors) follows a similar API but without chaining:\n\n```ts\nimport chalk from 'chalk' // [!code --]\nimport picocolors from 'picocolors' // [!code ++]\n\nconsole.log(`Hello ${chalk.blue('blue')} world!`) // [!code --]\nconsole.log(`Hello ${picocolors.blue('blue')} world!`) // [!code ++]\n\n// A chained example\nconsole.log(chalk.blue.bgRed('blue on red')) // [!code --]\nconsole.log(picocolors.blue(picocolors.bgRed('blue on red'))) // [!code ++]\n```\n\n> [!NOTE]\n> `picocolors` currently does not support RGB and hex colors (e.g. `#EFEFEF` or `255, 239, 235`).\n\n## `ansis`\n\n[`ansis`](https://github.com/webdiscus/ansis/) supports a chaining syntax similar to chalk and supports both RGB, and hex colors.\n\nExample:\n\n```ts\nimport ansis from 'ansis' // [!code ++]\nimport chalk from 'chalk' // [!code --]\n\nconsole.log(`Hello ${chalk.blue('blue')} world!`) // [!code --]\nconsole.log(`Hello ${ansis.blue('blue')} world!`) // [!code ++]\n```\n\nWhen using multiple styles, you can chain them just like in chalk:\n\n```ts\nconsole.log(chalk.blue.bgRed('blue on red')) // [!code --]\nconsole.log(ansis.blue.bgRed('blue on red')) // [!code ++]\n```\n\nSimilarly, you can use RGB and hex colors:\n\n```ts\nconsole.log(chalk.rgb(239, 239, 239)('Hello world!')) // [!code --]\nconsole.log(ansis.rgb(239, 239, 239)('Hello world!')) // [!code ++]\n```\n\n## Browser support\n\nWhile these libraries are primarily designed for terminal output, some projects may need colored output in browser environments.\n\nFollowing [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output), the native approach is `%c` directive in `console.log`:\n\n```ts\nconsole.log(\n 'Hello %ce%c1%c8%ce',\n 'color: #ec8f5e;',\n 'color: #f2ca60;',\n 'color: #bece57;',\n 'color: #7bb560;',\n 'Ecosystem Performance'\n)\n```\n\nLibrary support:\n\n- [`ansis`](https://github.com/webdiscus/ansis#browser-compatibility-for-ansi-codes) - colors are supported in _Chromium_ browsers\n- `picocolors` - strips colors in browser environments\n- `node:util` - is not available in browsers\n",
|
|
33
|
+
"eslint-plugin-node.md": "---\ndescription: Modern alternatives to the eslint-plugin-node package for Node.js-specific linting rules\n---\n\n# Replacements for `eslint-plugin-node`\n\n## `eslint-plugin-n`\n\n[`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n) is a direct fork which is actively maintained. It has new features, bugfixes and updated dependencies.\n\n```ts\nimport nPlugin from 'eslint-plugin-n' // [!code ++]\nimport nodePlugin from 'eslint-plugin-node' // [!code --]\n\nexport default [\n {\n files: ['**/*.js'], // or any other pattern\n plugins: {\n node: nodePlugin, // [!code --]\n n: nPlugin // [!code ++]\n },\n rules: {\n ...nodePlugin.configs['recommended-script'].rules, // [!code --]\n ...nPlugin.configs['recommended-script'].rules, // [!code ++]\n 'node/exports-style': ['error', 'module.exports'], // [!code --]\n 'n/exports-style': ['error', 'module.exports'] // [!code ++]\n }\n }\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:node/recommended', // [!code --]\n 'plugin:n/recommended' // [!code ++]\n ]\n}\n```\n",
|
|
34
|
+
"core-util-is.md": "---\ndescription: Native Node.js alternatives to the core-util-is package\n---\n\n# Replacements for `core-util-is`\n\n## `util.types` (native, Node.js)\n\n[`util.types`](https://nodejs.org/api/util.html#utiltypes) is an official, cross‑realm type checks for built-in objects (Date, RegExp, Error, typed arrays, etc.)\n\nExample:\n\n```ts\nimport * as cui from 'core-util-is' // [!code --]\nimport { types } from 'node:util' // [!code ++]\n\nconst isDate = cui.isDate(value) // [!code --]\nconst isDate = types.isDate(value) // [!code ++]\n```\n",
|
|
35
35
|
"event-stream.md": "---\ndescription: Modern alternatives to the event-stream package\n---\n\n# Replacements for `event-stream`\n\n## `es.pipeline()` replacement\n\n```ts\nimport es from 'event-stream' // [!code --]\nimport { pipeline } from 'node:stream/promises' // [!code ++]\n\nes.pipeline(s1, s2, s3) // [!code --]\nawait pipeline(s1, s2, s3) // [!code ++]\n```\n\n## `es.split()` replacement\n\n```ts\nimport es from 'event-stream' // [!code --]\nimport { createReadStream } from 'node:fs' // [!code ++]\nimport { createInterface } from 'node:readline' // [!code ++]\n\ncreateReadStream('file.txt').pipe(es.split()) // [!code --]\nconst lines = createInterface({ input: createReadStream('file.txt') }) // [!code ++]\n```\n\n## `es.map()` replacement\n\n<!-- prettier-ignore -->\n```ts\nimport es from 'event-stream' // [!code --]\n\nreadableStream.pipe( // [!code --]\n es.map((data, cb) => cb(null, fn(data))) // [!code --]\n) // [!code --]\n\nreadableStream.map((data) => fn(data)) // [!code ++]\n```\n\n## `es.merge()` replacement\n\n```ts\nimport es from 'event-stream' // [!code --]\nimport { PassThrough } from 'node:stream' // [!code ++]\n\nes.merge([s1, s2]) // [!code --]\nconst combined = new PassThrough() // [!code ++]\ns1.pipe(combined, { end: false }) // [!code ++]\ns2.pipe(combined, { end: false }) // [!code ++]\n```\n",
|
|
36
|
-
"
|
|
37
|
-
"find-cache-directory.md": "---\ndescription: Modern alternatives to the find-cache-directory package for locating cache directories\n---\n\n# Replacements for `find-cache-directory`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nExample:\n\n```ts\nimport * as pkg from 'empathic' // [!code ++]\nimport findCacheDirectory from 'find-cache-directory' // [!code --]\n\nfindCacheDirectory({ name: 'foo' }) // [!code --]\npkg.cache('foo') // [!code ++]\n```\n",
|
|
38
|
-
"fs-extra.md": "---\ndescription: Modern alternatives to the fs-extra package for working with the file system\n---\n\n# Replacements for `fs-extra`\n\n## `fs` and `fs/promises` (native, Node.js)\n\nModern Node.js includes built-in [`fs`](https://nodejs.org/api/fs.html) and [`fs/promises`](https://nodejs.org/api/fs.html#promises-api) APIs that cover what [`fs-extra`](https://github.com/jprichardson/node-fs-extra) historically provided.\n\n```js\nimport fsExtra from 'fs-extra' // [!code --]\nimport * as fs from 'node:fs' // [!code ++]\nimport * as fsPromises from 'node:fs/promises' // [!code ++]\n```\n\n### `copy`\n\n```js\nawait fsExtra.copy(src, dest) // [!code --]\nawait fsPromises.cp(src, dest, { recursive: true }) // [!code ++]\n```\n\n> [!NOTE]\n> If src is a file and dest is an existing directory, `fs-extra` throws; `fs.cp` copies into the directory.\n\n### `copySync`\n\n```js\nfsExtra.copySync(src, dest) // [!code --]\nfs.cpSync(src, dest, { recursive: true }) // [!code ++]\n```\n\n### `remove`\n\n```js\nawait fsExtra.remove(path) // [!code --]\nawait fsPromises.rm(path, { recursive: true, force: true }) // [!code ++]\n```\n\n> [!IMPORTANT]\n> Remember to set `{ recursive: true, force: true }` to match the behavior of `fs-extra`.\n\n```js\nfsExtra.removeSync(path) // [!code --]\nfs.rmSync(path, { recursive: true, force: true }) // [!code ++]\n```\n\n### `mkdirs` / `mkdirp` / `ensureDir`\n\n```js\nawait fsExtra.mkdirs(dir) // [!code --]\nawait fsPromises.mkdir(dir, { recursive: true }) // [!code ++]\n```\n\n### `mkdirsSync` / `mkdirpSync` / `ensureDirSync`\n\n```js\nfsExtra.mkdirsSync(dir) // [!code --]\nfs.mkdirSync(dir, { recursive: true }) // [!code ++]\n```\n\n### `pathExists`\n\n<!-- prettier-ignore -->\n```js\nawait fsExtra.pathExists(path) // [!code --]\nawait fsPromises.access(path).then(() => true, () => false) // [!code ++]\n```\n\n### `pathExistsSync`\n\n```js\nfsExtra.pathExistsSync(path) // [!code --]\nfs.existsSync(path) // [!code ++]\n```\n\n### `outputFile`\n\n```js\nawait fsExtra.outputFile(file, data) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(file), { recursive: true }) // [!code ++]\nawait fsPromises.writeFile(file, data) // [!code ++]\n```\n\n### `outputFileSync`\n\n```js\nfsExtra.outputFileSync(file, data) // [!code --]\n\nfs.mkdirSync(path.dirname(file), { recursive: true }) // [!code ++]\nfs.writeFileSync(file, data) // [!code ++]\n```\n\n### `readJson`\n\n```js\nawait fsExtra.readJson(file) // [!code --]\nawait fsPromises.readFile(file, 'utf8').then(JSON.parse) // [!code ++]\n```\n\n### `writeJson` / `outputJson`\n\n```js\nawait fsExtra.writeJson(file, obj) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(file), { recursive: true }) // [!code ++]\nawait fsPromises.writeFile(file, JSON.stringify(obj, null, 2)) // [!code ++]\n```\n\n### `ensureFile` / `createFile`\n\n```js\nawait fsExtra.ensureFile(file) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(file), { recursive: true }) // [!code ++]\nawait fsPromises.access(file).catch(() => fsPromises.writeFile(file, '')) // [!code ++]\n```\n\n### `ensureFileSync` / `createFileSync`\n\n```js\nfsExtra.ensureFileSync(file) // [!code --]\n\nfs.mkdirSync(path.dirname(file), { recursive: true }) // [!code ++]\nfs.writeFileSync(file, '') // [!code ++]\n```\n\n### `ensureLink` / `createLink`\n\n```js\nawait fsExtra.ensureLink(src, dest) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(dest), { recursive: true }) // [!code ++]\nawait fsPromises.link(src, dest) // [!code ++]\n```\n\n### `ensureLinkSync` / `createLinkSync`\n\n```js\nfsExtra.ensureLinkSync(src, dest) // [!code --]\nfs.mkdirSync(path.dirname(dest), { recursive: true }) // [!code ++]\nfs.linkSync(src, dest) // [!code ++]\n```\n\n### `ensureSymlink` / `createSymlink`\n\n```js\nawait fsExtra.ensureSymlink(src, dest) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(dest), { recursive: true }) // [!code ++]\nawait fsPromises.symlink(src, dest) // [!code ++]\n```\n\n### `ensureSymlinkSync` / `createSymlinkSync`\n\n```js\nfsExtra.ensureSymlinkSync(src, dest) // [!code --]\n\nfs.mkdirSync(path.dirname(dest), { recursive: true }) // [!code ++]\nfs.symlinkSync(src, dest) // [!code ++]\n```\n\n### `emptyDir` / `emptydir`\n\n```js\nawait fsExtra.emptyDir(dir) // [!code --]\n\nawait fsPromises.rm(dir, { recursive: true, force: true }) // [!code ++]\nawait fsPromises.mkdir(dir, { recursive: true }) // [!code ++]\n```\n\n### `move`\n\n```js\nawait fsExtra.move(src, dest) // [!code --]\nawait fsPromises.rename(src, dest) // [!code ++]\n```\n\n> [!NOTE]\n> Does not work cross-device; add `cp` + `rm` fallback.\n\nFor example:\n\n```js\ntry {\n await fsPromises.rename(src, dest)\n} catch (err) {\n if (err.code === 'EXDEV') {\n await fsPromises.cp(src, dest, { recursive: true })\n await fsPromises.rm(src, { recursive: true, force: true })\n } else {\n throw err\n }\n}\n```\n",
|
|
36
|
+
"tsc.md": "---\ndescription: Modern alternatives to the tsc package for the TypeScript compiler\n---\n\n# Replacements for `tsc`\n\nThe npm package [`tsc`](https://github.com/basarat/tsc) is **not** the TypeScript compiler — it is a deprecated stub that prints _\"This is not the tsc command you are looking for\"_ when run.\n\n## `typescript`\n\nThe [`typescript`](https://github.com/microsoft/TypeScript) package is the official compiler and provides the real `tsc` binary via `node_modules/.bin`. Replace `tsc` in your dependencies:\n\n```json\n{\n \"devDependencies\": {\n \"tsc\": \"^2.0.4\", // [!code --]\n \"typescript\": \"^5.9.0\" // [!code ++]\n }\n}\n```\n\nExisting `\"build\": \"tsc\"` scripts work unchanged once `typescript` is installed. For `npx` or global installs, use `typescript` — not `tsc`:\n\n```bash\nnpx tsc --init # [!code --]\nnpx --package typescript tsc --init # [!code ++]\n\nnpm install -g tsc # [!code --]\nnpm install -g typescript # [!code ++]\n```\n",
|
|
39
37
|
"graphemer.md": "---\ndescription: Modern alternatives to the grapheme-splitter and graphemer packages for splitting strings into Unicode grapheme clusters\n---\n\n# Replacements for `grapheme-splitter` / `graphemer`\n\n## `Intl.Segmenter` (native)\n\n[`Intl.Segmenter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) is the modern native JavaScript API for text segmentation, available in Node.js 16+, Chrome 87+, Safari 14.1+, and Firefox 132+.\n\n```ts\nimport GraphemeSplitter from 'grapheme-splitter' // [!code --]\n\nconst splitter = new GraphemeSplitter() // [!code --]\nconst segmenter = new Intl.Segmenter() // [!code ++]\n\nconst graphemes = splitter.splitGraphemes(text) // [!code --]\nconst graphemes = [...segmenter.segment(text)].map((s) => s.segment) // [!code ++]\n\nconst count = splitter.countGraphemes(text) // [!code --]\nconst count = [...segmenter.segment(text)].length // [!code ++]\n```\n\n## `unicode-segmenter`\n\n[`unicode-segmenter`](https://github.com/cometkim/unicode-segmenter) is a lightweight, fast alternative with zero dependencies and excellent browser compatibility.\n\n```ts\nimport GraphemeSplitter from 'grapheme-splitter' // [!code --]\nimport { countGraphemes, splitGraphemes } from 'unicode-segmenter/grapheme' // [!code ++]\n\nconst splitter = new GraphemeSplitter() // [!code --]\n\nconst graphemes = splitter.splitGraphemes(text) // [!code --]\nconst graphemes = [...splitGraphemes(text)] // [!code ++]\n\nconst count = splitter.countGraphemes(text) // [!code --]\nconst count = countGraphemes(text) // [!code ++]\n```\n\nYou can also use it as an `Intl.Segmenter` polyfill:\n\n```ts\nimport 'unicode-segmenter/intl-polyfill'\n\nconst segmenter = new Intl.Segmenter()\nconst graphemes = [...segmenter.segment(text)].map((s) => s.segment)\n```\n",
|
|
40
|
-
"
|
|
41
|
-
"inherits.md": "---\ndescription: Modern alternatives to the inherits package\n---\n\n# Replacements for `inherits`\n\n## ES6 classes `extends` syntax\n\nES6 classes [`extends`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) syntax is a native way to implement prototype inheritance.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport EventEmitter from 'node:events'\nimport inherits from 'inherits' // [!code --]\n\nfunction MyStream() { // [!code --]\n EventEmitter.call(this) // [!code --]\n} // [!code --]\n\nMyStream.prototype.write = function (data) { // [!code --]\n this.emit('data', data) // [!code --]\n} // [!code --]\n\ninherits(MyStream, EventEmitter) // [!code --]\n\nclass MyStream extends EventEmitter { // [!code ++]\n write(data) { // [!code ++]\n this.emit('data', data) // [!code ++]\n } // [!code ++]\n} // [!code ++]\n\nconst stream = new MyStream()\n\nstream.on('data', (data) => {\n console.log(`Received data: \"${data}\"`)\n})\nstream.write('Hello world!')\n```\n\n## `utils.inherits` (native, since Node.js v5.0.0)\n\n[`utils.inherits`](https://nodejs.org/docs/latest/api/util.html#utilinheritsconstructor-superconstructor) is a native legacy Node.js api.\n\nExample:\n\n```js\nimport inherits from 'inherits' // [!code --]\nimport { inherits } from 'node:util' // [!code ++]\n\ninherits(Target, Base)\n```\n\n## `Object.create` (native)\n\n[`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) allows you to implement inheritance.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport inherits from 'inherits' // [!code --]\n\ninherits(Target, Base) // [!code --]\n\nTarget.prototype = Object.create(Base.prototype, { // [!code ++]\n constructor: { // [!code ++]\n value: Target, // [!code ++]\n enumerable: false, // [!code ++]\n writable: true, // [!code ++]\n configurable: true // [!code ++]\n } // [!code ++]\n}) // [!code ++]\n```\n",
|
|
38
|
+
"jsx-ast-utils.md": "---\ndescription: Modern alternatives to the jsx-ast-utils package for statically analyzing JSX ASTs\n---\n\n# Replacements for `jsx-ast-utils`\n\n## `jsx-ast-utils-x`\n\n[`jsx-ast-utils-x`](https://github.com/eslinter/jsx-ast-utils-x) is a zero‑dependency alternative to [`jsx-ast-utils`](https://github.com/jsx-eslint/jsx-ast-utils) that aims to maintain API compatibility while reducing package size.\n\n```ts\nimport { hasProp } from 'jsx-ast-utils' // [!code --]\nimport { hasProp } from 'jsx-ast-utils-x' // [!code ++]\n\nimport hasProp from 'jsx-ast-utils/hasProp' // [!code --]\nimport hasProp from 'jsx-ast-utils-x/hasProp' // [!code ++]\n\nmodule.exports = (context) => ({\n JSXOpeningElement: (node) => {\n const onChange = hasProp(node.attributes, 'onChange')\n if (onChange) {\n context.report({ node, message: 'No onChange!' })\n }\n }\n})\n```\n",
|
|
42
39
|
"micromatch.md": "---\ndescription: Modern alternatives to the micromatch package for glob pattern matching\n---\n\n# Replacements for `micromatch`\n\n## `path.matchesGlob` (native, since Node 20.17 / 22.5)\n\n[`path.matchesGlob`](https://nodejs.org/api/path.html#pathmatchesglobpath-pattern-options) is built into modern versions of Node. Use it when you only need to test whether a path matches a single glob pattern.\n\nExample:\n\n```ts\nimport micromatch from 'micromatch' // [!code --]\nimport path from 'node:path' // [!code ++]\n\nmicromatch.isMatch('foo.bar', '*.bar') // [!code --]\npath.matchesGlob('foo.bar', '*.bar') // [!code ++]\n```\n\nFor multiple patterns, test each pattern explicitly:\n\n```ts\nconst patterns = ['*.js', '*.ts']\nconst matches = patterns.some((pattern) => path.matchesGlob(file, pattern))\n```\n\n## `picomatch`\n\n[`picomatch`](https://github.com/micromatch/picomatch) is the matcher micromatch is built on. It is a strong drop-in for most `isMatch` and list-filtering use cases.\n\nExample:\n\n```ts\nimport micromatch from 'micromatch' // [!code --]\nimport picomatch from 'picomatch' // [!code ++]\n\nmicromatch.isMatch('foo.bar', '*.bar') // [!code --]\npicomatch.isMatch('foo.bar', '*.bar') // [!code ++]\n```\n\nFor a reusable matcher function:\n\n```ts\nconst isMatch = picomatch('*.js')\nisMatch('a.js') // true\n```\n\n## `zeptomatch`\n\n[`zeptomatch`](https://github.com/fabiospampinato/zeptomatch) is a tiny glob matcher with brace expansion, ranges, and negation. Note that its argument order is **glob first, path second**.\n\nExample:\n\n```ts\nimport micromatch from 'micromatch' // [!code --]\nimport zeptomatch from 'zeptomatch' // [!code ++]\n\nmicromatch.isMatch('foo.bar', '*.bar') // [!code --]\nzeptomatch('*.bar', 'foo.bar') // [!code ++]\n```\n\nZeptomatch also supports partial matching for filesystem walks and brace expansion:\n\n```ts\nzeptomatch('foo/bar/*.js', 'foo', { partial: true }) // true\nzeptomatch('{a,b}.js', 'a.js') // true\nzeptomatch('!*.test.js', 'foo.js') // true\n```\n",
|
|
43
|
-
"
|
|
40
|
+
"strip-ansi.md": "---\ndescription: Native Node.js alternatives to the strip-ansi package for removing ANSI escape codes from strings\n---\n\n# Replacements for `strip-ansi`\n\n## `util.stripVTControlCharacters` (native, Node.js)\n\nAdded in v16.11.0, [`util.stripVTControlCharacters`](https://nodejs.org/api/util.html#utilstripvtcontrolcharactersstr) can be used to strip ANSI escape codes from a string.\n\n```ts\nimport stripAnsi from 'strip-ansi' // [!code --]\nimport { stripVTControlCharacters } from 'node:util' // [!code ++]\n\nconsole.log(stripAnsi('\\u001B[4me18e\\u001B[0m')) // [!code --]\nconsole.log(stripVTControlCharacters('\\u001B[4me18e\\u001B[0m')) // [!code ++]\n```\n\n> [!NOTE]\n> Due to [a bug](https://github.com/nodejs/node/issues/53697), in older Node versions this utility doesn't handle ANSI hyperlinks correctly. This behavior has been fixed as of NodeJS v22.10.\n\n## Deno\n\nDeno implements the Node `util` API, and also provides [`util.stripVTControlCharacters`](https://docs.deno.com/api/node/util/~/stripVTControlCharacters). The usage is identical:\n\n```ts\nimport stripAnsi from 'strip-ansi' // [!code --]\nimport { stripVTControlCharacters } from 'node:util' // [!code ++]\n\nconsole.log(stripAnsi('\\u001B[4me18e\\u001B[0m')) // [!code --]\nconsole.log(stripVTControlCharacters('\\u001B[4me18e\\u001B[0m')) // [!code ++]\n```\n\n## Bun\n\n### Using Node‑compatible API\n\nBun also implements Node’s [`util.stripVTControlCharacters`](https://bun.sh/reference/node/util/stripVTControlCharacters) through its Node compat layer:\n\n```ts\nimport stripAnsi from 'strip-ansi' // [!code --]\nimport { stripVTControlCharacters } from 'node:util' // [!code ++]\n\nconsole.log(stripAnsi('\\u001B[1mHello\\u001B[0m')) // [!code --]\nconsole.log(stripVTControlCharacters('\\u001B[1mHello\\u001B[0m')) // [!code ++]\n```\n\n### Using Bun's native API (>=1.2.21)\n\nSince Bun v1.2.21, you can use the built-in [`Bun.stripANSI`](https://bun.com/blog/release-notes/bun-v1.2.21#bun-stripansi-simd-accelerated-ansi-escape-removal) method.\n\n```ts\nimport stripAnsi from 'strip-ansi' // [!code --]\nimport { stripANSI } from 'bun' // [!code ++]\n\nconsole.log(stripAnsi('\\u001B[31mHello World\\u001B[0m')) // [!code --]\nconsole.log(Bun.stripANSI('\\u001B[31mHello World\\u001B[0m')) // [!code ++]\n```\n",
|
|
41
|
+
"http-proxy.md": "---\ndescription: Modern alternatives to the http-proxy package for HTTP and WebSocket proxying in Node.js\n---\n\n# Replacements for `http-proxy`\n\n[`http-proxy`](https://github.com/http-party/node-http-proxy) has not been maintained since 2020 and has known crashes, memory leaks, and socket issues on modern Node.js versions.\n\n## `httpxy`\n\n[`httpxy`](https://github.com/unjs/httpxy) is a maintained fork of `http-proxy` with critical upstream bug fixes, zero dependencies, and additional helpers such as `proxyFetch` and `proxyUpgrade`.\n\nExample:\n\n```ts\nimport httpProxy from 'http-proxy' // [!code --]\nimport { createProxyServer } from 'httpxy' // [!code ++]\nimport { createServer } from 'node:http'\n\nconst proxy = httpProxy.createProxyServer({}) // [!code --]\nconst proxy = createProxyServer({}) // [!code ++]\n\nconst server = createServer((req, res) => {\n proxy.web(req, res, { target: 'http://localhost:8080' }) // [!code --]\n proxy.web(req, res, { target: 'http://localhost:8080' }) // [!code ++]\n})\n\nserver.on('upgrade', (req, socket, head) => {\n proxy.ws(req, socket, head, { target: 'http://localhost:8080' }) // [!code --]\n proxy.ws(req, socket, { target: 'http://localhost:8080' }, head) // [!code ++]\n})\n```\n\n## `http-proxy-3`\n\n[`http-proxy-3`](https://github.com/sagemathinc/http-proxy-3) is a TypeScript rewrite with API compatibility, HTTP/2 support, and production use in Vite, JupyterHub, and CoCalc.\n\nExample:\n\n```ts\nimport httpProxy from 'http-proxy' // [!code --]\nimport { createProxyServer } from 'http-proxy-3' // [!code ++]\nimport { createServer } from 'node:http'\n\nconst proxy = httpProxy.createProxyServer({}) // [!code --]\nconst proxy = createProxyServer({}) // [!code ++]\n\nconst server = createServer((req, res) => {\n proxy.web(req, res, { target: 'http://localhost:8080' })\n})\n\nserver.on('upgrade', (req, socket, head) => {\n proxy.ws(req, socket, head, { target: 'http://localhost:8080' }) // [!code --]\n proxy.ws(req, socket, { target: 'http://localhost:8080' }, head) // [!code ++]\n})\n```\n",
|
|
42
|
+
"ora.md": "---\ndescription: Modern alternatives to the ora package for displaying elegant terminal spinners with status indicators\n---\n\n# Replacements for `ora`\n\n## `nanospinner`\n\n[`nanospinner`](https://github.com/usmanyunusov/nanospinner) provides simple start/success/error/warning methods with one dependency (`picocolors`).\n\n```ts\nimport ora from 'ora' // [!code --]\nimport { createSpinner } from 'nanospinner' // [!code ++]\n\nconst spinner = ora('Loading...').start() // [!code --]\nconst spinner = createSpinner('Loading...').start() // [!code ++]\n\nspinner.succeed('Done!') // [!code --]\nspinner.success('Done!') // [!code ++]\n\nspinner.fail('Error!') // [!code --]\nspinner.error('Error!') // [!code ++]\n```\n\n## `picospinner`\n\n[`picospinner`](https://github.com/tinylibs/picospinner) has zero dependencies with support for custom symbols, frames, and colors through Node.js built-in styling.\n\n```ts\nimport ora from 'ora' // [!code --]\nimport { Spinner } from 'picospinner' // [!code ++]\n\nconst spinner = ora('Loading...').start() // [!code --]\nconst spinner = new Spinner('Loading...') // [!code ++]\nspinner.start() // [!code ++]\n```\n\nIf you want to customize the color of the spinner, you can specify this when creating an instance:\n\n```ts\nconst spinner = new Spinner('Loading...', { colors: { spinner: 'yellow' } })\n```\n",
|
|
43
|
+
"wrap-ansi.md": "---\ndescription: Modern replacement for the wrap-ansi package for wrapping terminal strings (including ANSI-colored output)\n---\n\n# Replacements for `wrap-ansi`\n\n## `fast-wrap-ansi`\n\n[`fast-wrap-ansi`](https://github.com/43081j/fast-wrap-ansi) is a drop‑in replacement for `wrap-ansi` that’s faster and smaller.\n\n```ts\nimport wrapAnsi from 'wrap-ansi' // [!code --]\nimport wrapAnsi from 'fast-wrap-ansi' // [!code ++]\n\nconst value = '\\u001B[36mhello-super-long-token-without-spaces\\u001B[39m'\n\nconsole.log(wrapAnsi(value, 12, { hard: true, trim: false }))\n```\n",
|
|
44
|
+
"pbkdf2.md": "---\ndescription: Native alternatives to the pbkdf2 package for secure, iterative password-based key derivation\n---\n\n# Replacements for `pbkdf2`\n\n## `crypto.subtle.deriveBits` (native)\n\nFrom [`MDN documentation`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits#pbkdf2):\n\n```ts\nasync function deriveKey(password: string, salt: Uint8Array) {\n const enc = new TextEncoder()\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n enc.encode(password),\n 'PBKDF2',\n false,\n ['deriveBits']\n )\n const derivedBits = await crypto.subtle.deriveBits(\n { name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-512' },\n keyMaterial,\n 256\n )\n return new Uint8Array(derivedBits)\n}\n\nconst salt = crypto.getRandomValues(new Uint8Array(16))\nconst derivedKey = await deriveKey('password', salt)\n```\n\n## `crypto.pbkdf2` (native, since Node.js v0.5.5)\n\n<!-- prettier-ignore -->\n```ts\nimport pbkdf2 from 'pbkdf2' // [!code --]\nimport * as crypto from 'node:crypto' // [!code ++]\n\nconst salt = crypto.getRandomValues(new Uint8Array(16))\nconst iterations = 100000\nconst keylen = 32\n\nconst derivedKey = pbkdf2.pbkdf2Sync('password', salt, iterations, keylen, 'sha512') // [!code --]\nconst derivedKey = crypto.pbkdf2Sync('password', salt, iterations, keylen, 'sha512') // [!code ++]\n```\n",
|
|
45
|
+
"wellknown.md": "---\ndescription: Modern replacements for the wellknown package, a WKT parser and stringifier\n---\n\n# Replacements for `wellknown`\n\n## `betterknown`\n\n[`betterknown`](https://github.com/placemark/betterknown) is a maintained alternative for `wellknown` package.\n\nExample:\n\n```js\nimport wellknown from 'wellknown' // [!code --]\nimport { wktToGeoJSON, geoJSONToWkt } from 'betterknown' // [!code ++]\n\nwellknown.parse('POINT(1 2)') // [!code --]\nwktToGeoJSON('POINT(1 2)') // [!code ++]\n\nwellknown.stringify({ // [!code --]\ngeoJSONToWkt({ // [!code ++]\n type: 'Point',\n coordinates: [1, 2]\n})\n\nwellknown.stringify({ // [!code --]\ngeoJSONToWkt({ // [!code ++]\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [1, 2] },\n properties: {}\n})\n```\n",
|
|
46
|
+
"string-width.md": "---\ndescription: Modern alternatives to the string-width package for measuring the visual width of a string\n---\n\n# Replacements for `string-width`\n\n## `fast-string-width`\n\n[`fast-string-width`](https://github.com/fabiospampinato/fast-string-width) is a drop‑in replacement for `string-width` that’s faster and smaller.\n\n```ts\nimport stringWidth from 'string-width' // [!code --]\nimport stringWidth from 'fast-string-width' // [!code ++]\n\nconsole.log(stringWidth('abc')) // 3\nconsole.log(stringWidth('👩👩👧👦')) // 1\nconsole.log(stringWidth('\\u001B[31mhello\\u001B[39m')) // 5\n```\n\n## Bun API (native)\n\nIf you’re on Bun ≥ 1.0.29, you can use the built‑in [`stringWidth`](https://bun.com/reference/bun/stringWidth):\n\n```ts\nimport stringWidth from 'string-width' // [!code --]\nimport { stringWidth } from 'bun' // [!code ++]\n\nconsole.log(stringWidth('abc')) // 3\nconsole.log(stringWidth('👩👩👧👦')) // 1\nconsole.log(stringWidth('\\u001B[31mhello\\u001B[39m')) // 5\nconsole.log(\n stringWidth('\\u001B[31mhello\\u001B[39m', { countAnsiEscapeCodes: false })\n) // 5\n```\n",
|
|
47
|
+
"bluebird-q.md": "---\ndescription: Modern alternatives to the Bluebird and Q Promise libraries for async control flow in JavaScript\n---\n\n# Replacements for `bluebird` / `q`\n\n## `Promise` (native)\n\n[`bluebird`](https://github.com/petkaantonov/bluebird?tab=readme-ov-file#%EF%B8%8Fnote%EF%B8%8F) and [`q`](https://github.com/kriskowal/q#note) recommend switching away from them to native promises.\n\n## `nativebird`\n\n[`NativeBird`](https://github.com/doodlewind/nativebird) is an ultralight native `Promise` extension that provides Bluebird-like helpers if you miss a few conveniences from Bluebird.\n",
|
|
48
|
+
"path-exists.md": "---\ndescription: Modern alternatives to the path-exists package for checking if a path exists\n---\n\n# Replacements for `path-exists`\n\n## Async `fs.access` (native, Node.js)\n\nUse [`fs/promises.access`](https://nodejs.org/docs/latest/api/fs.html#fspromisesaccesspath-mode) and return a boolean.\n\n<!-- prettier-ignore -->\n```ts\nimport pathExists from 'path-exists' // [!code --]\nimport { access } from 'node:fs/promises' // [!code ++]\n\nconst exists = await pathExists('/etc/passwd') // [!code --]\nconst exists = await access('/etc/passwd').then( // [!code ++]\n () => true, // [!code ++]\n () => false // [!code ++]\n) // [!code ++]\n```\n\n## Sync `fs.existsSync` (native, Node.js)\n\nAdded in v0.1.21: synchronous path/file existence check via [`fs.existsSync`](https://nodejs.org/docs/latest/api/fs.html#fsexistssyncpath).\n\n```ts\nimport pathExists from 'path-exists' // [!code --]\nimport { existsSync } from 'node:fs' // [!code ++]\n\nconst exists = await pathExists('/etc/passwd') // [!code --]\nconst exists = existsSync('/etc/passwd') // [!code ++]\n```\n\n## Bun\n\n[`Bun.file()`](https://bun.sh/reference/bun/BunFile) returns a BunFile with an `.exists()` method.\n\n```ts\nimport pathExists from 'path-exists' // [!code --]\n\nconst path = '/path/to/package.json'\nconst exists = await pathExists(path) // [!code --]\nconst file = Bun.file(path) // [!code ++]\nconst exists = await file.exists() // boolean [!code ++]\n```\n",
|
|
49
|
+
"get-stream.md": "---\ndescription: Modern alternatives to the get-stream package\n---\n\n# Replacements for `get-stream`\n\n## Converting stream to string\n\nYou can convert a stream to a string by using `Buffer.from` and a `for await`:\n\n```ts\nasync function streamToString(stream) {\n const chunks = []\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk))\n }\n return Buffer.concat(chunks).toString('utf-8')\n}\n```\n\n## Converting stream to Array\n\nYou can convert a stream to an array using [`Array.fromAsync`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync) in Node 22+:\n\n```ts\nawait Array.fromAsync(stream)\n\n// or before Node 22\n\nasync function streamToArray(stream) {\n const chunks = []\n for await (const chunk of stream) {\n chunks.push(chunk)\n }\n return chunks\n}\n```\n\n## Converting stream to Buffer\n\nYou can convert a stream to a `Buffer` using [`Array.fromAsync`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync) with a mapper:\n\n```ts\nasync function streamToBuffer(stream) {\n const chunks = await Array.fromAsync(stream, (chunk) => Buffer.from(chunk))\n return Buffer.concat(chunks)\n}\n\n// or before Node 22\n\nasync function streamToBuffer(stream) {\n const chunks = []\n for await (const chunk of stream) {\n chunks.push(Buffer.from(chunk))\n }\n return Buffer.concat(chunks)\n}\n```\n",
|
|
50
|
+
"eslint-plugin-vitest.md": "---\ndescription: Modern alternatives to the eslint-plugin-vitest package for Vitest-specific linting rules\n---\n\n# Replacements for `eslint-plugin-vitest`\n\n## `@vitest/eslint-plugin`\n\n[`@vitest/eslint-plugin`](https://github.com/vitest-dev/eslint-plugin-vitest) is the same project as `eslint-plugin-vitest` but re-published under a different name. `eslint-plugin-vitest` is no longer maintained because the [original maintainer has lost access to their old npm account](https://github.com/vitest-dev/eslint-plugin-vitest/issues/537).\n\n```ts\nimport vitest from '@vitest/eslint-plugin' // [!code ++]\nimport vitest from 'eslint-plugin-vitest' // [!code --]\n\nexport default [\n {\n files: ['tests/**'], // or any other pattern\n plugins: {\n vitest\n },\n rules: {\n ...vitest.configs.recommended.rules, // you can also use vitest.configs.all.rules to enable all rules\n 'vitest/max-nested-describe': ['error', { max: 3 }] // you can also modify rules' behavior using option like this\n }\n }\n]\n```\n",
|
|
51
|
+
"duplexer.md": "---\ndescription: Modern alternatives to the duplexer package\n---\n\n# Replacements for `duplexer`\n\n## `Duplex.from` (native, Node.js)\n\n<!-- prettier-ignore -->\n```js\nimport duplexer from 'duplexer' // [!code --]\nimport { Duplex } from 'node:stream' // [!code ++]\n\nduplexer(writableStream, readableStream) // [!code --]\n\nDuplex.from({ // [!code ++]\n writable: writableStream, // [!code ++]\n readable: readableStream // [!code ++]\n}) // [!code ++]\n```\n",
|
|
52
|
+
"buffer-equal.md": "---\ndescription: Native Node.js alternatives to the buffer-equal package for buffer equality checks\n---\n\n# Replacements for `buffer-equal`\n\n## `Buffer#equals` (native)\n\nBuffers have an [`equals`](https://nodejs.org/api/buffer.html#bufequalsotherbuffer) method since Node v0.12.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufferEqual from 'buffer-equal' // [!code --]\n\nconst buf1 = Buffer.from('303')\nconst buf2 = Buffer.from('303')\n\nbufferEqual(buf1, buf2) // [!code --]\nbuf1.equals(buf2) // [!code ++]\n```\n",
|
|
53
|
+
"express.md": "---\ndescription: Modern alternatives to the express package\n---\n\n# Replacements for `express`\n\nExpress has been the industry standard for years, but the ecosystem has shifted toward ESM-first, type-safe, and runtime-agnostic frameworks that offer significantly better performance and developer experience.\n\n## `h3`\n\n[`h3`](https://github.com/h3js/h3) is a minimal H(TTP) framework built for high performance and portability.\n\nExample:\n\n<!-- prettier-ignore -->\n```ts\nimport express from 'express' // [!code --]\nimport { H3, defineHandler, toNodeHandler } from 'h3' // [!code ++]\nimport { createServer } from 'node:http' // [!code ++]\n\nconst app = express() // [!code --]\nconst app = new H3() // [!code ++]\n\napp.get('/', (req, res) => res.send('Hello world')) // [!code --]\napp.get('/', defineHandler(() => 'Hello world')) // [!code ++]\n\napp.listen(3000) // [!code --]\ncreateServer(toNodeHandler(app)).listen(3000) // [!code ++]\n```\n\n## `tinyhttp`\n\n[`tinyhttp`](https://github.com/tinyhttp/tinyhttp) is designed to be a drop-in replacement remaining compatible with many Express middlewares.\n\nExample:\n\n```ts\nimport express from 'express' // [!code --]\nimport { App } from '@tinyhttp/app' // [!code ++]\n\nconst app = express() // [!code --]\nconst app = new App() // [!code ++]\n\napp.get('/', (req, res) => res.send('Hello world'))\n\napp.listen(3000)\n```\n\n## `hono`\n\n[`hono`](https://github.com/honojs/hono) is a small, simple, and fast web framework for the Edges.\n\nExample:\n\n```ts\nimport express from 'express' // [!code --]\nimport { Hono } from 'hono' // [!code ++]\n\nconst app = express() // [!code --]\nconst app = new Hono() // [!code ++]\n\napp.get('/', (req, res) => res.send('Hello world')) // [!code --]\napp.get('/', (context) => context.text('Hello world')) // [!code ++]\n\nexport default app // [!code ++]\n```\n\n## `elysia`\n\nIf you are using Bun, [`elysia`](https://github.com/elysiajs/elysia) is often the best choice as it is specifically optimized for the Bun runtime.\n\nExample:\n\n```ts\nimport express from 'express' // [!code --]\nimport { Elysia } from 'elysia' // [!code ++]\n\nconst app = express() // [!code --]\nconst app = new Elysia() // [!code ++]\n\napp.get('/', (req, res) => res.send('Hello world')) // [!code --]\napp.get('/', () => 'Hello world') // [!code ++]\n\napp.listen(3000)\n```\n",
|
|
54
|
+
"rimraf.md": "---\ndescription: Native Node.js alternatives to the rimraf package for recursive directory removal\n---\n\n# Replacements for `rimraf`\n\n## `fs.rm` (native, Node.js)\n\nNode.js v14.14.0 and above provide a native alternative: [`fs.rm`](https://nodejs.org/api/fs.html#fspromisesrmpath-options) and [`fs.rmSync`](https://nodejs.org/api/fs.html#fsrmsyncpath-options). It supports recursive deletion and works as a direct replacement.\n\n### Async methods\n\n```ts\nimport rimraf from 'rimraf' // [!code --]\nimport { rm } from 'node:fs/promises' // [!code ++]\n\nawait rimraf('./dist') // [!code --]\nawait rm('./dist', { recursive: true, force: true }) // [!code ++]\n```\n\n### Sync methods\n\n```ts\nimport rimraf from 'rimraf' // [!code --]\nimport * as fs from 'node:fs' // [!code ++]\n\nrimraf.sync('./dist') // [!code --]\nfs.rmSync('./dist', { recursive: true, force: true }) // [!code ++]\n```\n\n> [!IMPORTANT]\n> Remember to set `{ recursive: true, force: true }` to match the behavior of rimraf.\n\n## `fs.rmdir` (native, Node.js before v14.14.0)\n\nIf you need to support Node.js 12 up to 14.13, you can use [`fs.rmdir`](https://nodejs.org/api/fs.html#fsrmdirpath-options-callback) with the recursive option. This was added in Node v12.10.0, though it’s deprecated as of Node v14.\n\n```ts\nimport rimraf from 'rimraf' // [!code --]\nimport { rmdir } from 'node:fs/promises' // [!code ++]\n\nawait rimraf('./dist') // [!code --]\nawait rmdir('./dist', { recursive: true }) // [!code ++]\n```\n\n## CLI usage\n\nTo replace `rimraf` inside npm scripts, you can run Node directly in eval mode:\n\n```sh\nnode -e \"require('fs').rmSync('./dist', { recursive: true, force: true, maxRetries: process.platform === 'win32' ? 10 : 0 })\"\n```\n\n## `premove`\n\nIf you are on an older Node.js version (before v12.10) or you specifically need a CLI replacement, you can use [`premove`](https://github.com/lukeed/premove). It provides both an API and a CLI and works on Node.js v8 and newer.\n\n```json\n{\n \"scripts\": {\n \"clean\": \"rimraf lib\", // [!code --]\n \"clean\": \"premove lib\" // [!code ++]\n }\n}\n```\n",
|
|
55
|
+
"eslint-plugin-es.md": "---\ndescription: Modern alternatives to the eslint-plugin-es package for ECMAScript feature linting\n---\n\n# Replacements for `eslint-plugin-es`\n\n## `eslint-plugin-es-x`\n\n[eslint-plugin-es-x](https://github.com/eslint-community/eslint-plugin-es-x) is a direct fork which is actively maintained. It has new features, bugfixes and updated dependencies.\n\n```ts\nimport { FlatCompat } from '@eslint/eslintrc' // [!code --]\nimport pluginES from 'eslint-plugin-es' // [!code --]\nimport pluginESx from 'eslint-plugin-es-x' // [!code ++]\n\nconst compat = new FlatCompat() // [!code --]\n\nexport default [\n {\n files: ['**/*.js'],\n languageOptions: {\n ecmaVersion: 2020\n },\n plugins: {\n es: pluginES, // [!code --]\n 'es-x': pluginESx // [!code ++]\n },\n rules: {\n 'es/no-regexp-lookbehind-assertions': 'error', // [!code --]\n 'es-x/no-regexp-lookbehind-assertions': 'error' // [!code ++]\n }\n },\n\n ...compat.extends('plugin:es/restrict-to-es2018'), // [!code --]\n pluginESx.configs['flat/restrict-to-es2018'] // [!code ++]\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:es/restrict-to-es2018', // [!code --]\n 'plugin:es-x/restrict-to-es2018' // [!code ++]\n ],\n plugins: [\n 'es', // [!code --]\n 'es-x' // [!code ++]\n ],\n rules: {\n 'es/no-regexp-lookbehind-assertions': 'error', // [!code --]\n 'es-x/no-regexp-lookbehind-assertions': 'error' // [!code ++]\n }\n}\n```\n",
|
|
56
|
+
"find-pkg.md": "---\ndescription: Modern alternatives to the find-pkg package for finding package.json files\n---\n\n# Replacements for `find-pkg`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nThe main difference is that `empathic` is _synchronous_, so you should no longer `await` the result.\n\nExample:\n\n```ts\nimport * as pkg from 'empathic/package' // [!code ++]\nimport findPkg from 'find-pkg' // [!code --]\n\nawait findPkg(path) // [!code --]\npkg.up(path) // [!code ++]\n```\n",
|
|
57
|
+
"body-parser.md": "---\ndescription: Modern alternatives to the body-parser package for parsing HTTP request bodies in Node.js servers\n---\n\n# Replacements for `body-parser`\n\n## `milliparsec`\n\n[`milliparsec`](https://github.com/tinyhttp/milliparsec) is a lightweight alternative to [`body-parser`](https://github.com/expressjs/body-parser) with a smaller footprint.\n\nExample:\n\n```ts\nimport bodyParser from 'body-parser' // [!code --]\nimport { json, urlencoded } from 'milliparsec' // [!code ++]\nimport express from 'express'\n\nconst app = express()\n\napp.use(bodyParser.json()) // [!code --]\napp.use(bodyParser.urlencoded({ extended: true })) // [!code --]\n\napp.use(json()) // [!code ++]\napp.use(urlencoded()) // [!code ++]\n```\n\nFor API differences and feature comparison, see the [migration.md](https://github.com/tinyhttp/milliparsec/blob/master/migration.md).\n",
|
|
58
|
+
"tokml.md": "---\ndescription: Modern replacements for the tokml package for converting GeoJSON to KML\n---\n\n# Replacements for `tokml`\n\n## `@placemarkio/tokml`\n\n[`@placemarkio/tokml`](https://github.com/placemark/tokml) is a maintained alternative for `tokml` package.\n\nExample:\n\n```js\nimport tokml from 'tokml' // [!code --]\nimport { toKML } from '@placemarkio/tokml' // [!code ++]\n\nconst geojson = {\n type: 'FeatureCollection',\n features: [\n {\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [1, 2] },\n properties: { name: 'Marker' }\n }\n ]\n}\n\nconst kml = tokml(geojson) // [!code --]\nconst kml = toKML(geojson) // [!code ++]\n```\n",
|
|
59
|
+
"stream-buffers.md": "---\ndescription: Modern alternatives to the stream-buffers package for buffering and generating streams in Node.js\n---\n\n# Replacements for `stream-buffers`\n\n## Utility Consumers (native, Node.js)\n\nSince Node.js ≥ 16.7.0 [Utility Consumers](https://nodejs.org/api/webstreams.html#webstreams_utility_consumers) let you consume a Readable stream fully into memory (`Buffer`/`string`/`JSON`/`Blob`/`ArrayBuffer`).\n\nExample:\n\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { pipeline } from 'node:stream/promises' // [!code --]\nimport { buffer } from 'node:stream/consumers' // [!code ++]\n\nconst sink = new streamBuffers.WritableStreamBuffer() // [!code --]\nawait pipeline(readable, sink) // [!code --]\n\nconst out = sink.getContents() // [!code --]\nconst out = await buffer(readable) // [!code ++]\n```\n\nCapturing output when an API expects a Writable example:\n\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { PassThrough } from 'node:stream' // [!code ++]\nimport { buffer, text } from 'node:stream/consumers' // [!code ++]\n\nconst sink = new streamBuffers.WritableStreamBuffer() // [!code --]\nconst sink = new PassThrough() // [!code ++]\n\nconst outPromise = buffer(sink) // [!code ++]\nawait someFnThatWritesTo(sink)\nconst out = sink.getContents() // [!code --]\nsink.end() // [!code ++]\nconst out = await outPromise // [!code ++]\n```\n\nPush data over time example:\n\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { Readable } from 'node:stream' // [!code ++]\n\nconst rs = new streamBuffers.ReadableStreamBuffer() // [!code --]\nconst rs = new Readable({ read() {} }) // [!code ++]\n\nrs.put('first chunk') // [!code --]\nrs.push('first chunk') // [!code ++]\n\nrs.put(Buffer.from('second chunk')) // [!code --]\nrs.push(Buffer.from('second chunk')) // [!code ++]\n\nrs.stop() // [!code --]\nrs.push(null) // [!code ++]\n```\n\nControl chunk size and frequency example:\n\n<!-- prettier-ignore -->\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { Readable } from 'node:stream' // [!code ++]\nimport { setTimeout } from 'node:timers/promises' // [!code ++]\n\nconst data = Buffer.from('...your data...')\nconst frequencyMs = 10\nconst chunkSize = 2048\n\nconst rs = new streamBuffers.ReadableStreamBuffer({ frequency: frequencyMs, chunkSize: chunkSize }) // [!code --]\nrs.put(data) // [!code --]\nrs.stop() // [!code --]\n\nconst rs = Readable.from(async function* () { // [!code ++]\n for (let i = 0; i < data.length; i += chunkSize) { // [!code ++]\n yield data.slice(i, i + chunkSize) // [!code ++]\n await setTimeout(frequencyMs) // [!code ++]\n } // [!code ++]\n}()) // [!code ++]\n```\n",
|
|
60
|
+
"traverse.md": "---\ndescription: Modern alternative to the traverse package to traverse and transform objects by visiting every node on a recursive walk\n---\n\n# Replacements for `traverse`\n\n## `neotraverse`\n\n[`neotraverse`](https://github.com/puruvj/neotraverse) is a TypeScript rewrite of [`traverse`](https://github.com/ljharb/js-traverse) with no dependencies. It offers a drop‑in compatible build as well as a modern API.\n\n```ts\nimport traverse from 'traverse' // [!code --]\nimport traverse from 'neotraverse' // [!code ++]\n\nconst obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }]\n\ntraverse(obj).forEach(function (x) {\n if (x < 0) this.update(x + 128)\n})\n\nconsole.log(obj)\n```\n",
|
|
61
|
+
"cwd.md": "---\ndescription: Modern alternatives to the cwd package for resolving project-relative paths\n---\n\n# Replacements for `cwd`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\n[`cwd`](https://github.com/jonschlinkert/cwd) is not `process.cwd()`. It finds the nearest `package.json` and returns an absolute path anchored to that package root. Unlike [`pkg-dir`](./pkg-dir.md), which returns the package root directory, `cwd` returns a resolved path relative to that root.\n\nThe main difference is that `empathic` is _synchronous_, so you should no longer `await` the result.\n\nExample:\n\n```ts\nimport { resolve, dirname } from 'node:path' // [!code ++]\nimport * as pkg from 'empathic/package' // [!code ++]\nimport cwd from 'cwd' // [!code --]\n\nconst filepath = resolve('one/two.js') // [!code ++]\nconst pkgPath = pkg.up({ cwd: filepath }) // [!code ++]\nconst result = cwd('one/two.js') // [!code --]\nconst result = pkgPath ? resolve(dirname(pkgPath), filepath) : filepath // [!code ++]\n```\n",
|
|
44
62
|
"html-minifier.md": "---\ndescription: Modern replacement for the html-minifier package for minifying HTML with embedded CSS, JavaScript, and SVG\n---\n\n# Replacements for `html-minifier`\n\n## `html-minifier-next`\n\n[`html-minifier-next`](https://github.com/j9t/html-minifier-next) is the official successor to [`html-minifier`](https://github.com/kangax/html-minifier). It is actively maintained, faster, and adds features such as SVG minification and preset configurations.\n\n```ts\nimport minify from 'html-minifier' // [!code --]\nimport { minify } from 'html-minifier-next' // [!code ++]\n\nconst html = '<p title=\"example\">foo</p>'\n\nconst result = minify(html, { collapseWhitespace: true }) // [!code --]\nconst result = await minify(html, { collapseWhitespace: true }) // [!code ++]\n```\n",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"mkdirp.md": "---\ndescription: Modern alternatives to the mkdirp and make-dir packages for recursively creating directories in Node.js\n---\n\n# Replacements for `mkdirp` / `make-dir`\n\n## Recursive `fs.mkdir` (native, since Node.js v10.12.0)\n\nNode.js v10.12.0 and up supports the `recursive` option in the [`fs.mkdir`](https://nodejs.org/api/fs.html#fsmkdirpath-options-callback) function, which allows parent directories to be created automatically.\n\nExample migration from [`mkdirp`](https://github.com/isaacs/node-mkdirp):\n\n```ts\nimport { mkdirp } from 'mkdirp' // [!code --]\nimport { mkdir, mkdirSync } from 'node:fs' // [!code ++]\nimport { mkdir as mkdirAsync } from 'node:fs/promises' // [!code ++]\n\n// Async\nawait mkdirp('/tmp/foo/bar/baz') // [!code --]\nawait mkdirAsync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n\n// Sync\nmkdirp.sync('/tmp/foo/bar/baz') // [!code --]\nmkdirSync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n```\n\nExample migration from [`make-dir`](https://github.com/sindresorhus/make-dir):\n\n```ts\nimport { makeDirectory, makeDirectorySync } from 'make-dir' // [!code --]\nimport { mkdir, mkdirSync } from 'node:fs' // [!code ++]\nimport { mkdir as mkdirAsync } from 'node:fs/promises' // [!code ++]\n\n// Async\nawait makeDirectory('/tmp/foo/bar/baz') // [!code --]\nawait mkdirAsync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n\n// Sync\nmakeDirectorySync('/tmp/foo/bar/baz') // [!code --]\nmkdirSync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n```\n",
|
|
51
|
-
"md5.md": "---\ndescription: Native Node.js alternatives to the md5 package for MD5 hash generation\n---\n\n# Replacements for `md5`\n\n## `crypto` (native)\n\nIf you're using the [`md5`](https://github.com/pvorb/node-md5) package, _strongly_ consider moving to a stronger algorithm if your usage is security-sensitive (for example, passwords). MD5 is [not secure](https://en.wikipedia.org/wiki/MD5#Security) and hasn't been secure for many years.\n\nIf you must keep MD5 for compatibility, Node.js provides a native alternative via the [`crypto` module](https://nodejs.org/api/crypto.html#crypto).\n\n```ts\nimport crypto from 'node:crypto' // [!code ++]\nimport md5 from 'md5' // [!code --]\n\nmd5('message') // [!code --]\ncrypto.createHash('md5').update('message').digest('hex') // [!code ++]\n```\n",
|
|
52
|
-
"invariant.md": "---\ndescription: Modern alternatives to the invariant package for runtime assertions\n---\n\n# Replacements for `invariant`\n\n## `tiny-invariant`\n\n[`tiny-invariant`](https://github.com/alexreardon/tiny-invariant) provides a similar API with zero dependencies.\n\nFor example:\n\n```ts\nimport invariant from 'invariant' // [!code --]\nimport invariant from 'tiny-invariant' // [!code ++]\n\ninvariant(ok, 'Hello %s, code %d', name, code) // [!code --]\ninvariant(ok, `Hello ${name}, code ${code}`) // [!code ++]\n```\n\nSimilarly, you can lazily compute messages to avoid unnecessary work:\n\n```ts\nimport invariant from 'invariant' // [!code --]\nimport invariant from 'tiny-invariant' // [!code ++]\n\ninvariant(value, getExpensiveMessage()) // [!code --]\ninvariant(value, () => getExpensiveMessage()) // [!code ++]\n```\n",
|
|
63
|
+
"cli-builders.md": "---\ndescription: Modern alternatives to packages for building CLI applications\n---\n\n# Replacements for CLI builders\n\n## `sade`\n\n[`sade`](https://github.com/lukeed/sade) is a small but powerful tool for building CLI applications for Node.js\n\n```ts\nimport sade from 'sade'\n\nconst prog = sade('my-cli')\n\nprog\n .version('1.0.5')\n .option('--global, -g', 'An example global flag')\n .option('-c, --config', 'Provide path to custom config', 'foo.config.js')\n\nprog\n .command('build <src> <dest>')\n .describe('Build the source directory. Expects an `index.js` entry file.')\n .option('-o, --output', 'Change the name of the output file', 'bundle.js')\n .example('build src build --global --config my-conf.js')\n .example('build app public -o main.js')\n .action((src, dest, opts) => {\n console.log(`> building from ${src} to ${dest}`)\n console.log('> these are extra opts', opts)\n })\n\nprog.parse(process.argv)\n```\n\n## `cleye`\n\n[`cleye`](https://github.com/privatenumber/cleye) is another powerful tool for building CLI applications for Node.js\n\n```ts\nimport { cli } from 'cleye'\n\n// Parse argv\nconst argv = cli({\n name: 'greet.js',\n\n // Define parameters\n parameters: [\n '<first name>', // First name is required\n '[last name]' // Last name is optional\n ],\n\n // Define flags/options\n flags: {\n // Parses `--time` as a string\n time: {\n type: String,\n description: 'Time of day to greet (morning or evening)',\n default: 'morning'\n }\n }\n})\n\nconst name = [argv._.firstName, argv._.lastName].filter(Boolean).join(' ')\n\nif (argv.flags.time === 'morning') {\n console.log(`Good morning ${name}!`)\n} else {\n console.log(`Good evening ${name}!`)\n}\n```\n\n## Argument parsers\n\nIf you only need an argument parser, check the [argument parsers page](https://e18e.dev/docs/replacements/parseargs).\n",
|
|
64
|
+
"mockdate.md": "---\ndescription: Modern alternatives to the mockdate package for mocking time in tests\n---\n\n# Replacements for `mockdate`\n\n`mockdate` is mainly used in tests, and modern test runners already include built-in APIs for mocking time without pulling in an extra dependency.\n\n## `vitest`\n\n[`vitest`](https://vitest.dev/guide/mocking.html#mock-the-current-date) provides `vi.useFakeTimers()` and `vi.setSystemTime()` for mocking the current date during tests.\n\n```ts\nimport MockDate from 'mockdate' // [!code --]\nimport { vi, test, expect } from 'vitest' // [!code ++]\n\ntest('freeze date', () => {\n MockDate.set('2026-01-01') // [!code --]\n vi.useFakeTimers() // [!code ++]\n vi.setSystemTime(new Date('2026-01-01')) // [!code ++]\n\n expect(new Date().toISOString()).toBe('2026-01-01T00:00:00.000Z')\n\n MockDate.reset() // [!code --]\n vi.useRealTimers() // [!code ++]\n})\n```\n\n## `node:test`\n\n[`node:test`](https://nodejs.org/en/learn/test-runner/mocking#time) supports mocking time via `mock.timers` since node 20.4.0 and later.\n\n```ts\nimport MockDate from 'mockdate' // [!code --]\nimport { test } from 'node:test' // [!code ++]\nimport assert from 'node:assert/strict' // [!code ++]\n\ntest('freeze date', (t) => {\n MockDate.set('2026-01-01') // [!code --]\n t.mock.timers.enable({ apis: ['Date'], now: new Date('2026-01-01') }) // [!code ++]\n\n assert.equal(new Date().toISOString(), '2026-01-01T00:00:00.000Z')\n\n MockDate.reset() // [!code --]\n})\n```\n\n## `bun:test`\n\n[`bun:test`](https://bun.com/docs/guides/test/mock-clock) provides `mock.timers.enable()` for mocking time in tests.\n\n```ts\nimport MockDate from 'mockdate' // [!code --]\nimport { test, expect, mock } from 'bun:test' // [!code ++]\n\ntest('freeze date', () => {\n MockDate.set('2026-01-01') // [!code --]\n mock.timers.enable({ now: new Date('2026-01-01') }) // [!code ++]\n\n expect(new Date().toISOString()).toBe('2026-01-01T00:00:00.000Z')\n\n MockDate.reset() // [!code --]\n mock.timers.reset() // [!code ++]\n})\n```\n",
|
|
65
|
+
"find-cache-dir.md": "---\ndescription: Modern alternatives to the find-cache-dir package for locating cache directories\n---\n\n# Replacements for `find-cache-dir`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nExample:\n\n```ts\nimport * as pkg from 'empathic' // [!code ++]\nimport findCacheDirectory from 'find-cache-dir' // [!code --]\n\nfindCacheDirectory({ name: 'foo' }) // [!code --]\npkg.cache('foo') // [!code ++]\n```\n",
|
|
66
|
+
"inherits.md": "---\ndescription: Modern alternatives to the inherits package\n---\n\n# Replacements for `inherits`\n\n## ES6 classes `extends` syntax\n\nES6 classes [`extends`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) syntax is a native way to implement prototype inheritance.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport EventEmitter from 'node:events'\nimport inherits from 'inherits' // [!code --]\n\nfunction MyStream() { // [!code --]\n EventEmitter.call(this) // [!code --]\n} // [!code --]\n\nMyStream.prototype.write = function (data) { // [!code --]\n this.emit('data', data) // [!code --]\n} // [!code --]\n\ninherits(MyStream, EventEmitter) // [!code --]\n\nclass MyStream extends EventEmitter { // [!code ++]\n write(data) { // [!code ++]\n this.emit('data', data) // [!code ++]\n } // [!code ++]\n} // [!code ++]\n\nconst stream = new MyStream()\n\nstream.on('data', (data) => {\n console.log(`Received data: \"${data}\"`)\n})\nstream.write('Hello world!')\n```\n\n## `utils.inherits` (native, since Node.js v5.0.0)\n\n[`utils.inherits`](https://nodejs.org/docs/latest/api/util.html#utilinheritsconstructor-superconstructor) is a native legacy Node.js api.\n\nExample:\n\n```js\nimport inherits from 'inherits' // [!code --]\nimport { inherits } from 'node:util' // [!code ++]\n\ninherits(Target, Base)\n```\n\n## `Object.create` (native)\n\n[`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) allows you to implement inheritance.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport inherits from 'inherits' // [!code --]\n\ninherits(Target, Base) // [!code --]\n\nTarget.prototype = Object.create(Base.prototype, { // [!code ++]\n constructor: { // [!code ++]\n value: Target, // [!code ++]\n enumerable: false, // [!code ++]\n writable: true, // [!code ++]\n configurable: true // [!code ++]\n } // [!code ++]\n}) // [!code ++]\n```\n",
|
|
67
|
+
"find-file-up.md": "---\ndescription: Modern alternatives to the find-file-up package for finding files by walking up parent directories\n---\n\n# Replacements for `find-file-up`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nThe main difference is that `empathic` is _synchronous_, so you should no longer `await` the result.\n\nExample:\n\n```ts\nimport * as find from 'empathic/find' // [!code ++]\nimport findUp from 'find-file-up' // [!code --]\n\nawait findUp('package.json', cwd) // [!code --]\nfind.file('package.json', { cwd }) // [!code ++]\n```\n",
|
|
53
68
|
"node-telegram-bot-api.md": "---\ndescription: Modern alternatives to the node-telegram-bot-api package\n---\n\n# Replacements for `node-telegram-bot-api`\n\n## `grammy`\n\n[`grammy`](https://grammy.dev) is a modern library for creating telegram bots.\n\nExample:\n\n```ts\nimport { Bot } from 'grammy'\n\nconst bot = new Bot(process.env.TOKEN)\n\nbot.on('message', (ctx) => ctx.reply('Hi there!'))\n\nbot.start()\n```\n",
|
|
54
|
-
"js
|
|
69
|
+
"crypto-js.md": "---\ndescription: Modern alternatives to the `crypto-js` package for cryptographic operations\n---\n\n# Replacements for `crypto-js`\n\n`crypto-js` is no longer actively maintained and has been discontinued since engines now come with this functionality built-in.\n\n## `node:crypto` (native, Node.js built-in)\n\nNode provides a [`node:crypto`](https://nodejs.org/api/crypto.html) module as part of its standard library.\n\nThis supports hashes/HMAC, AES-GCM, PBKDF2/scrypt, RSA/ECDSA/Ed25519, and secure RNG.\n\n```ts\nimport sha256 from 'crypto-js/sha256' // [!code --]\nimport { createHash } from 'node:crypto' // [!code ++]\n\nconst secret = 'abcdefg'\nconst hash = sha256(secret).toString() // [!code --]\nconst hash = createHash('sha256') // [!code ++]\n .update(secret) // [!code ++]\n .digest('hex') // [!code ++]\n```\n\n## Web Crypto API (native)\n\nThe [Web Crypto API](https://developer.mozilla.org/docs/Web/API/Web_Crypto_API) provides native functionality for cryptographic operations in both web browsers and Node.\n\n> [!NOTE]\n> A few legacy algorithms are intentionally omitted for security reasons (e.g. MD5).\n\n## Bun (built-in)\n\nBun supports the Web Crypto API natively, and also provides support for streaming hashing via [`Bun.CryptoHasher`](https://bun.sh/docs/api/hashing).\n\nAs with the Web Crypto API, many legacy algorithms are intentionally omitted for security reasons (e.g. MD5).\n",
|
|
70
|
+
"cosmiconfig.md": "---\ndescription: Modern alternatives to the cosmiconfig package\n---\n\n# Replacements for `cosmiconfig`\n\n## `lilconfig`\n\n[`lilconfig`](https://github.com/antonk52/lilconfig) is a zero-dependency alternative to cosmiconfig with the same API\n\n> [!NOTE]\n> `lilconfig` does not support YAML files out of the box unless you provide custom loaders.\n\n### Example\n\n```js\nimport { lilconfig, lilconfigSync } from 'lilconfig'\n\nconst options = {\n searchPlaces: [\n 'package.json', // Will use \"myapp\" field\n '.myapprc',\n '.myapprc.json',\n 'myapp.config.js'\n ]\n}\n\nawait lilconfig('myapp', options).search()\n\n// Sync version\nlilconfigSync('myapp', options).search()\n```\n\n### Loading YAML files\n\n```js\nimport { lilconfig } from 'lilconfig'\nimport { parse } from 'yaml'\n\nconst yamlLoader = (filepath, content) => parse(content)\n\nconst options = {\n searchPlaces: [\n 'package.json',\n '.myapprc',\n '.myapprc.yaml',\n '.myapprc.yml',\n 'myapp.config.js'\n ],\n loaders: {\n '.yaml': yamlLoader,\n '.yml': yamlLoader,\n noExt: yamlLoader\n }\n}\n\nawait lilconfig('myapp', options).search()\n```\n",
|
|
71
|
+
"mississippi.md": "---\ndescription: Modern alternatives to the mississippi package\n---\n\n# Replacements for `mississippi`\n\n`mississippi` exposes stream helpers as `miss.pipe`, `miss.each`, `miss.pipeline`, and so on. Each export wraps a separate npm package internally, but migration targets the **`miss.*` call sites** and replaces each with the corresponding native `node:stream` API below.\n\n## `miss.pipe`\n\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { pipeline } from 'node:stream/promises' // [!code ++]\n\nmiss.pipe(s1, s2, s3, cb) // [!code --]\nawait pipeline(s1, s2, s3) // [!code ++]\n```\n\nFor callback-style usage, use [`stream.pipeline`](https://nodejs.org/api/stream.html#streampipelinestreams-callback).\n\n## `miss.each`\n\n<!-- prettier-ignore -->\n```ts\nimport miss from 'mississippi' // [!code --]\n \nmiss.each(stream, (data, cb) => { // [!code --]\n fn(data) // [!code --]\n cb() // [!code --]\n}) // [!code --]\n \nfor await (const data of stream) { // [!code ++]\n fn(data) // [!code ++]\n} // [!code ++]\n```\n\nNote that `miss.each` reports stream errors through its done callback, while `for await` throws them wrap the loop in `try/catch` to handle errors.\n\n## `miss.pipeline`\n\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { compose } from 'node:stream' // [!code ++]\n\nmiss.pipeline(s1, s2, s3) // [!code --]\ncompose(s1, s2, s3) // [!code ++]\n```\n\nRequires Node.js ≥ 16.9.0.\n\n## `miss.duplex`\n\nSee also [duplexer replacements](./duplexer.md).\n\n<!-- prettier-ignore -->\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { Duplex } from 'node:stream' // [!code ++]\n \nmiss.duplex(writableStream, readableStream) // [!code --]\nDuplex.from({ // [!code ++]\n writable: writableStream, // [!code ++]\n readable: readableStream // [!code ++]\n}) // [!code ++]\n```\n\nRequires Node.js ≥ 16.8.0 for `Duplex.from`.\n\n## `miss.through`\n\nSee also [through replacements](./through.md).\n\n<!-- prettier-ignore -->\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { Transform } from 'node:stream' // [!code ++]\n \nmiss.through((chunk, enc, cb) => { // [!code --]\n cb(null, fn(chunk)) // [!code --]\n}) // [!code --]\nnew Transform({ // [!code ++]\n transform(chunk, encoding, callback) { // [!code ++]\n callback(null, fn(chunk)) // [!code ++]\n } // [!code ++]\n}) // [!code ++]\n```\n\n## `miss.concat`\n\nSee also [get-stream replacements](./get-stream.md).\n\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { buffer } from 'node:stream/consumers' // [!code ++]\n\nstream.pipe(miss.concat((data) => fn(data))) // [!code --]\nconst data = await buffer(stream) // [!code ++]\nfn(data) // [!code ++]\n```\n\nUnlike `miss.concat`, which adapts its output to the input type, `buffer` always returns a `Buffer`. `node:stream/consumers` also exports `text`, `json`, and `arrayBuffer` for those cases.\n\nRequires Node.js ≥ 16.7.0 for `node:stream/consumers`.\n\n## `miss.finished`\n\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { finished } from 'node:stream/promises' // [!code ++]\n\nmiss.finished(stream, cb) // [!code --]\nawait finished(stream) // [!code ++]\n```\n\nFor callback-style usage, use [`stream.finished`](https://nodejs.org/api/stream.html#streamfinishedstream-options-callback).\n\n## `miss.from`\n\n<!-- prettier-ignore -->\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { Readable } from 'node:stream' // [!code ++]\n \nmiss.from((size, cb) => cb(null, chunk)) // [!code --]\nReadable.from( // [!code ++]\n (async function* () { // [!code ++]\n yield chunk // [!code ++]\n })() // [!code ++]\n) // [!code ++]\n```\n\n## `miss.to`\n\n<!-- prettier-ignore -->\n```ts\nimport miss from 'mississippi' // [!code --]\nimport { Writable } from 'node:stream' // [!code ++]\n \nmiss.to( // [!code --]\n (chunk, enc, cb) => cb(), // [!code --]\n (cb) => cb() // [!code --]\n) // [!code --]\nnew Writable({ // [!code ++]\n write(chunk, encoding, callback) { // [!code ++]\n callback() // [!code ++]\n }, // [!code ++]\n final(callback) { // [!code ++]\n callback() // [!code ++]\n } // [!code ++]\n}) // [!code ++]\n```\n\n## `miss.parallel`\n\n<!-- prettier-ignore -->\n```ts\nimport miss from 'mississippi' // [!code --]\n \nstream.pipe( // [!code --]\n miss.parallel(10, (data, cb) => cb(null, fn(data))) // [!code --]\n) // [!code --]\nstream.map((data) => fn(data), { concurrency: 10 }) // [!code ++]\n```\n\nLike `miss.parallel`, `map` preserves the order of the input stream.\n\nRequires Node.js >= 17.4.0 for `Readable.prototype.map`.\n",
|
|
72
|
+
"moment.md": "---\ndescription: Modern alternatives to moment.js for date manipulation and formatting\n---\n\n# Replacements for `Moment.js`\n\n## `day.js`\n\n[Day.js](https://github.com/iamkun/dayjs/) provides a similar API to Moment.js with a much smaller footprint.\n\nExample:\n\n```ts\nimport moment from 'moment' // [!code --]\nimport dayjs from 'dayjs' // [!code ++]\n\nconst now = moment() // [!code --]\nconst now = dayjs() // [!code ++]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = dayjs().format('YYYY-MM-DD') // [!code ++]\n```\n\n## `date-fns`\n\n[date-fns](https://github.com/date-fns/date-fns) offers tree-shakable functions for working with native JavaScript dates.\n\nExample:\n\n```ts\nimport moment from 'moment' // [!code --]\nimport { addDays, format, subWeeks } from 'date-fns' // [!code ++]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = format(new Date(), 'yyyy-MM-dd') // [!code ++]\n\nconst tomorrow = moment().add(1, 'day') // [!code --]\nconst tomorrow = addDays(new Date(), 1) // [!code ++]\n\nconst lastWeek = moment().subtract(1, 'week') // [!code --]\nconst lastWeek = subWeeks(new Date(), 1) // [!code ++]\n```\n\n## `luxon`\n\n[Luxon](https://github.com/moment/luxon) is created by a Moment.js maintainer and offers powerful internationalization support.\n\nExample:\n\n```ts\nimport moment from 'moment' // [!code --]\nimport { DateTime } from 'luxon' // [!code ++]\n\nconst now = moment() // [!code --]\nconst now = DateTime.now() // [!code ++]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = DateTime.now().toFormat('yyyy-MM-dd') // [!code ++]\n\nconst tomorrow = moment().add(1, 'day') // [!code --]\nconst tomorrow = DateTime.now().plus({ days: 1 }) // [!code ++]\n```\n\n## `Date` (native)\n\nFor simple use cases, native JavaScript [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) and [`Intl`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) APIs may be sufficient:\n\n<!-- prettier-ignore -->\n```ts\nimport moment from 'moment' // [!code --]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = new Date().toISOString().split('T')[0] // [!code ++]\n\nconst localized = moment().format('MMMM Do YYYY') // [!code --]\nconst localized = new Intl.DateTimeFormat('en-US', { // [!code ++]\n year: 'numeric', // [!code ++]\n month: 'long', // [!code ++]\n day: 'numeric' // [!code ++]\n}).format(new Date()) // [!code ++]\n```\n",
|
|
73
|
+
"uuidv4.md": "---\ndescription: Native alternatives to the uuidv4 package for UUID v4 generation\n---\n\n# Replacements for `uuidv4`\n\n## `crypto.randomUUID` (native)\n\nYou can use [`crypto.randomUUID`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) for UUID v4 generation.\n\nExample:\n\n```ts\nconst uuid = crypto.randomUUID()\n```\n\nOr in Node.js via [`node:crypto`](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions):\n\n```ts\nimport * as crypto from 'node:crypto'\n\nconst uuid = crypto.randomUUID()\n```\n",
|
|
74
|
+
"detect-package-manager.md": "---\ndescription: Lightweight alternative to detect-package-manager for detecting the package manager with zero subdependencies\n---\n\n# Replacements for `detect-package-manager`\n\n## `package-manager-detector`\n\n[`package-manager-detector`](https://github.com/antfu-collective/package-manager-detector) is a lightweight alternative for detecting the package manager being used in a project.\n\n### Key differences\n\n- **Zero subdependencies** compared to 16 in `detect-package-manager`\n- **ESM-only**, while `detect-package-manager` is primarily CJS (with ESM support)\n- **Smaller bundle size** due to the lack of dependencies\n\n### Migration example\n\n```ts\nimport { detect } from 'detect-package-manager' // [!code --]\nimport { detect } from 'package-manager-detector' // [!code ++]\n\nconst pm = await detect() // [!code --]\nconst result = await detect() // [!code ++]\nconst pm = result?.name // [!code ++]\n```\n\n> [!NOTE]\n> `package-manager-detector` returns an object with `name` and `agent` properties, while `detect-package-manager` returns a string directly.\n\nBoth packages can detect npm, yarn, pnpm, and bun package managers in your project by analyzing lock files. Additionally, `package-manager-detector` also supports deno.\n",
|
|
75
|
+
"fs-extra.md": "---\ndescription: Modern alternatives to the fs-extra package for working with the file system\n---\n\n# Replacements for `fs-extra`\n\n## `fs` and `fs/promises` (native, Node.js)\n\nModern Node.js includes built-in [`fs`](https://nodejs.org/api/fs.html) and [`fs/promises`](https://nodejs.org/api/fs.html#promises-api) APIs that cover what [`fs-extra`](https://github.com/jprichardson/node-fs-extra) historically provided.\n\n```js\nimport fsExtra from 'fs-extra' // [!code --]\nimport * as fs from 'node:fs' // [!code ++]\nimport * as fsPromises from 'node:fs/promises' // [!code ++]\n```\n\n### `copy`\n\n```js\nawait fsExtra.copy(src, dest) // [!code --]\nawait fsPromises.cp(src, dest, { recursive: true }) // [!code ++]\n```\n\n> [!NOTE]\n> If src is a file and dest is an existing directory, `fs-extra` throws; `fs.cp` copies into the directory.\n\n### `copySync`\n\n```js\nfsExtra.copySync(src, dest) // [!code --]\nfs.cpSync(src, dest, { recursive: true }) // [!code ++]\n```\n\n### `remove`\n\n```js\nawait fsExtra.remove(path) // [!code --]\nawait fsPromises.rm(path, { recursive: true, force: true }) // [!code ++]\n```\n\n> [!IMPORTANT]\n> Remember to set `{ recursive: true, force: true }` to match the behavior of `fs-extra`.\n\n```js\nfsExtra.removeSync(path) // [!code --]\nfs.rmSync(path, { recursive: true, force: true }) // [!code ++]\n```\n\n### `mkdirs` / `mkdirp` / `ensureDir`\n\n```js\nawait fsExtra.mkdirs(dir) // [!code --]\nawait fsPromises.mkdir(dir, { recursive: true }) // [!code ++]\n```\n\n### `mkdirsSync` / `mkdirpSync` / `ensureDirSync`\n\n```js\nfsExtra.mkdirsSync(dir) // [!code --]\nfs.mkdirSync(dir, { recursive: true }) // [!code ++]\n```\n\n### `pathExists`\n\n<!-- prettier-ignore -->\n```js\nawait fsExtra.pathExists(path) // [!code --]\nawait fsPromises.access(path).then(() => true, () => false) // [!code ++]\n```\n\n### `pathExistsSync`\n\n```js\nfsExtra.pathExistsSync(path) // [!code --]\nfs.existsSync(path) // [!code ++]\n```\n\n### `outputFile`\n\n```js\nawait fsExtra.outputFile(file, data) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(file), { recursive: true }) // [!code ++]\nawait fsPromises.writeFile(file, data) // [!code ++]\n```\n\n### `outputFileSync`\n\n```js\nfsExtra.outputFileSync(file, data) // [!code --]\n\nfs.mkdirSync(path.dirname(file), { recursive: true }) // [!code ++]\nfs.writeFileSync(file, data) // [!code ++]\n```\n\n### `readJson`\n\n```js\nawait fsExtra.readJson(file) // [!code --]\nawait fsPromises.readFile(file, 'utf8').then(JSON.parse) // [!code ++]\n```\n\n### `writeJson` / `outputJson`\n\n```js\nawait fsExtra.writeJson(file, obj) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(file), { recursive: true }) // [!code ++]\nawait fsPromises.writeFile(file, JSON.stringify(obj, null, 2)) // [!code ++]\n```\n\n### `ensureFile` / `createFile`\n\n```js\nawait fsExtra.ensureFile(file) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(file), { recursive: true }) // [!code ++]\nawait fsPromises.access(file).catch(() => fsPromises.writeFile(file, '')) // [!code ++]\n```\n\n### `ensureFileSync` / `createFileSync`\n\n```js\nfsExtra.ensureFileSync(file) // [!code --]\n\nfs.mkdirSync(path.dirname(file), { recursive: true }) // [!code ++]\nfs.writeFileSync(file, '') // [!code ++]\n```\n\n### `ensureLink` / `createLink`\n\n```js\nawait fsExtra.ensureLink(src, dest) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(dest), { recursive: true }) // [!code ++]\nawait fsPromises.link(src, dest) // [!code ++]\n```\n\n### `ensureLinkSync` / `createLinkSync`\n\n```js\nfsExtra.ensureLinkSync(src, dest) // [!code --]\nfs.mkdirSync(path.dirname(dest), { recursive: true }) // [!code ++]\nfs.linkSync(src, dest) // [!code ++]\n```\n\n### `ensureSymlink` / `createSymlink`\n\n```js\nawait fsExtra.ensureSymlink(src, dest) // [!code --]\n\nawait fsPromises.mkdir(path.dirname(dest), { recursive: true }) // [!code ++]\nawait fsPromises.symlink(src, dest) // [!code ++]\n```\n\n### `ensureSymlinkSync` / `createSymlinkSync`\n\n```js\nfsExtra.ensureSymlinkSync(src, dest) // [!code --]\n\nfs.mkdirSync(path.dirname(dest), { recursive: true }) // [!code ++]\nfs.symlinkSync(src, dest) // [!code ++]\n```\n\n### `emptyDir` / `emptydir`\n\n```js\nawait fsExtra.emptyDir(dir) // [!code --]\n\nawait fsPromises.rm(dir, { recursive: true, force: true }) // [!code ++]\nawait fsPromises.mkdir(dir, { recursive: true }) // [!code ++]\n```\n\n### `move`\n\n```js\nawait fsExtra.move(src, dest) // [!code --]\nawait fsPromises.rename(src, dest) // [!code ++]\n```\n\n> [!NOTE]\n> Does not work cross-device; add `cp` + `rm` fallback.\n\nFor example:\n\n```js\ntry {\n await fsPromises.rename(src, dest)\n} catch (err) {\n if (err.code === 'EXDEV') {\n await fsPromises.cp(src, dest, { recursive: true })\n await fsPromises.rm(src, { recursive: true, force: true })\n } else {\n throw err\n }\n}\n```\n",
|
|
55
76
|
"lodash-underscore.md": "---\ndescription: Modern alternatives for Lodash for array/object manipulation and common programming tasks\n---\n\n# `lodash` / `underscore`\n\n## You don’t (may not) need Lodash/Underscore\n\nHere you could read how to replace Lodash or Underscore in your project.\n\n[Website](https://you-dont-need.github.io/You-Dont-Need-Lodash-Underscore)\n\n## es-toolkit\n\n[es-toolkit](https://es-toolkit.dev/) is a utility library similar to lodash that is designed to replace lodash by offering a seamless compat layer. It supports tree shaking out of the box and offers better performances for modern JavaScript runtimes.\n",
|
|
56
|
-
"
|
|
77
|
+
"gray-matter.md": "---\ndescription: Modern alternatives to the gray-matter package for parsing front matter\n---\n\n# Replacements for `gray-matter`\n\n`gray-matter` has not been maintained since 2019 and carries known security issues, including eval-based JavaScript front matter (RCE) and an outdated `js-yaml` dependency with DoS vulnerabilities. [`@11ty/gray-matter`](https://github.com/11ty/gray-matter) is a maintained fork used by Eleventy v4 and Docusaurus.\n\n## `@11ty/gray-matter`\n\n[`@11ty/gray-matter`](https://github.com/11ty/gray-matter) upgrades `js-yaml` to v4, uses `Uint8Array` internally for better runtime compatibility, and removes the built-in JavaScript front matter engine that relied on `eval`.\n\nExample:\n\n```ts\nimport matter from 'gray-matter' // [!code --]\nimport matter from '@11ty/gray-matter' // [!code ++]\n\nconst { data, content } = matter('---\\ntitle: Hello\\n---\\n\\nBody')\n```\n",
|
|
78
|
+
"qs.md": "---\ndescription: Modern alternatives to the qs package for parsing and serializing query strings\n---\n\n# Replacements for `qs`\n\n## `URLSearchParams` (native)\n\n[`URLSearchParams`](https://developer.mozilla.org/docs/Web/API/URLSearchParams) is built into browsers and Node.js (>= 10). Use it when you don’t need nested objects or automatic array parsing. It preserves multiple values via `getAll`, and `toString()` gives you a URL-safe query string.\n\nExample:\n\n```ts\nimport qs from 'qs' // [!code --]\n\nconst query = 'a=1&a=2&b=3'\n\nconst obj = qs.parse(query) // [!code --]\nconst sp = new URLSearchParams(query) // [!code ++]\nconst obj = Object.fromEntries(sp) // [!code ++]\nconst a = sp.getAll('a') // [!code ++]\n```\n\n## `fast-querystring`\n\n[`fast-querystring`](https://github.com/anonrig/fast-querystring) is tiny and very fast. It handles flat key/value pairs and repeated keys as arrays; it does not support nested objects. Use it when you need arrays but not nesting.\n\nExample:\n\n```ts\nimport qs from 'qs' // [!code --]\nimport fqs from 'fast-querystring' // [!code ++]\n\nconst obj = qs.parse('tag=a&tag=b') // [!code --]\nconst obj = fqs.parse('tag=a&tag=b') // [!code ++]\n\nconst str = qs.stringify({ tag: ['a', 'b'], q: 'x y' }) // [!code --]\nconst str = fqs.stringify({ tag: ['a', 'b'], q: 'x y' }) // [!code ++]\n```\n\n## `picoquery`\n\n[`picoquery`](https://github.com/43081j/picoquery) supports nesting and arrays with a fast single‑pass parser and configurable syntax. v2.x and above are ESM‑only; v1.x is CommonJS and will be maintained with non‑breaking changes. `nestingSyntax: 'js'` offers the highest compatibility with `qs`, though you can pick other syntaxes for performance.\n\nExample:\n\n<!-- prettier-ignore -->\n```ts\nimport qs from 'qs' // [!code --]\nimport { parse, stringify } from 'picoquery' // [!code ++]\n\nconst opts = { // [!code ++]\n nestingSyntax: 'js', // [!code ++]\n arrayRepeat: true, // [!code ++]\n arrayRepeatSyntax: 'bracket' // [!code ++]\n} // [!code ++]\n\nconst obj = qs.parse('user[name]=foo&tags[]=bar&tags[]=baz') // [!code --]\nconst obj = parse('user[name]=foo&tags[]=bar&tags[]=baz', opts) // [!code ++]\n\nconst str = qs.stringify( // [!code --]\n { user: { name: 'foo' }, tags: ['bar', 'baz'] }, // [!code --]\n { arrayFormat: 'brackets' } // [!code --]\n) // [!code --]\nconst str = stringify({ user: { name: 'foo' }, tags: ['bar', 'baz'] }, opts) // [!code ++]\n```\n\n## `neoqs`\n\n[`neoqs`](https://github.com/PuruVJ/neoqs) is a fork of `qs` without legacy polyfills, with TypeScript types included, and with both ESM and CommonJS builds (plus a legacy ES5 mode). Choose it when you want `qs`‑level compatibility with modern packaging options.\n\nExample:\n\n```ts\nimport qs from 'qs' // [!code --]\nimport * as qs from 'neoqs' // [!code ++]\n\nconst obj = qs.parse('a[b][c]=1&arr[]=2&arr[]=3')\nconst str = qs.stringify(obj, { arrayFormat: 'brackets' })\n```\n",
|
|
57
79
|
"jsonwebtoken.md": "---\ndescription: Modern alternatives to the jsonwebtoken package for JWT signing and verification\n---\n\n# Replacements for `jsonwebtoken`\n\n## `jose`\n\n[`jose`](https://github.com/panva/jose) implements the full JOSE standard (JWK, JWS, JWE, JWT, JWKS) using the Web Crypto API\n\nCompared to `jsonwebtoken`, it works everywhere globalThis.crypto is available: Node.js 18+, Deno, Bun, Cloudflare Workers, and browsers.\n\n```ts\nimport jwt from 'jsonwebtoken' // [!code --]\nimport { SignJWT, jwtVerify } from 'jose' // [!code ++]\n\nconst secret = 'mysecretkey'\nconst payload = { userId: 123 }\n\nconst token = jwt.sign(payload, secret, { expiresIn: '1h' }) // [!code --]\nconst decoded = jwt.verify(token, secret) // [!code --]\n\nconst joseSecret = new TextEncoder().encode(secret) // [!code ++]\n\nconst token = await new SignJWT(payload) // [!code ++]\n .setProtectedHeader({ alg: 'HS256' }) // [!code ++]\n .setExpirationTime('1h') // [!code ++]\n .sign(joseSecret) // [!code ++]\n\nconst { payload: decoded } = await jwtVerify(token, joseSecret) // [!code ++]\n```\n",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
80
|
+
"lint-staged.md": "---\ndescription: Modern alternatives to lint-staged for running commands on staged Git files\n---\n\n# Replacements for `lint-staged`\n\n## `nano-staged`\n\n[`nano-staged`](https://github.com/usmanyunusov/nano-staged) is a tiny pre-commit runner for staged (and more) files; much smaller and faster than `lint-staged`, with a simple config.\n\npackage.json config:\n\n<!-- eslint-skip -->\n\n```json\n{\n \"lint-staged\": { // [!code --]\n \"nano-staged\": { // [!code ++]\n \"*.{js,ts}\": [\"prettier --write\"]\n },\n}\n```\n\n> [!NOTE]\n> Differences to be aware of:\n>\n> - `lint-staged` has advanced features like backup stashing, partial-staging handling, per-directory configs in monorepos, and detailed concurrency controls.\n> - `nano-staged` focuses on simplicity and speed. If you rely on `lint-staged`’s stash/partial-staging features, keep using `lint-staged`.\n",
|
|
81
|
+
"eslint-plugin-react.md": "---\ndescription: Modern alternatives to the eslint-plugin-react package for React/JSX-specific linting rules\n---\n\n# Replacements for `eslint-plugin-react`\n\n## `@eslint-react/eslint-plugin`\n\n[`@eslint-react/eslint-plugin`](https://github.com/Rel1cx/eslint-react) is not a drop-in replacement, but a feature‑rich alternative that covers many of the same (and additional) rules.\n\nFlat config example:\n\n```ts\nimport eslintReact from '@eslint-react/eslint-plugin' // [!code ++]\nimport reactPlugin from 'eslint-plugin-react' // [!code --]\n\nexport default [\n {\n files: ['**/*.{jsx,tsx}'],\n plugins: {\n react: reactPlugin, // [!code --]\n '@eslint-react': eslintReact // [!code ++]\n },\n rules: {\n ...reactPlugin.configs.recommended.rules, // [!code --]\n ...eslintReact.configs.recommended.rules, // [!code ++]\n\n 'react/no-unknown-property': 'error', // [!code --]\n '@eslint-react/dom/no-unknown-property': 'error' // [!code ++]\n }\n }\n]\n```\n\n> [!NOTE]\n> `@eslint-react/eslint-plugin` is not a drop‑in replacement. Use [their migration guide](https://www.eslint-react.xyz/docs/migrating-from-eslint-plugin-react) to map rules/options and automate changes where possible.\n\n## Oxlint\n\n[Oxlint](https://oxc.rs/docs/guide/usage/linter.html) is a high-performance linter for JavaScript and TypeScript, built on the Rust-based `Oxc` compiler stack. It's intended to be fully backwards-compatible with ESLint, having ported most of the ESLint rules, as well as those from popular plugins including `eslint-plugin-react`.\n\nThe migration process from ESLint is covered in [the Oxlint documentation](https://oxc.rs/docs/guide/usage/linter/migrate-from-eslint.html), and can be done automatically from an ESLint flat config using [`npx @oxlint/migrate`](https://github.com/oxc-project/oxlint-migrate).\n\n> [!NOTE]\n> Oxlint is not necessarily a full drop-in replacement, as not all of the `eslint-plugin-react` rules have been, or will be, implemented. Check [the GitHub issue](https://github.com/oxc-project/oxc/issues/1022) to view the progress.\n",
|
|
82
|
+
"eslint-config-airbnb.md": "---\ndescription: Modern, maintained alternative to the eslint-config-airbnb shared config\n---\n\n# Replacements for `eslint-config-airbnb`\n\n## `eslint-config-airbnb-extended`\n\n[`eslint-config-airbnb-extended`](https://github.com/eslint-config/airbnb-extended) is a more modern, actively maintained successor to [`eslint-config-airbnb`](https://github.com/airbnb/javascript). It supports both JavaScript and TypeScript, and includes rules for React, JSX, and React Hooks, and supports ESLint v9/10 configs.\n\nIt consolidates `eslint-config-airbnb-base`, `eslint-config-airbnb`, and `eslint-config-airbnb-typescript` into a single config, only supports flat config (`eslint.config.mjs`), and uses a faster, modern equivalent of the `import` plugin (`eslint-plugin-import-x`).\n\nThe upstream project provides an official [migration guide](https://eslint-airbnb-extended.nishargshah.dev/migration/upgrade-to-extended) and a CLI scaffolder to set up a new config.\n\nNote that any rules referencing the old `import/*` plugin will need to be updated to use the `import-x/*` equivalents (e.g. `import/no-unresolved` -> `import-x/no-unresolved`).\n",
|
|
83
|
+
"globby.md": "---\ndescription: Modern alternatives to the globby package for globbing and .gitignore support\n---\n\n# Replacements for `globby`\n\n## `tinyglobby`\n\n[`globby`](https://github.com/sindresorhus/globby) is a convenience wrapper around [`fast-glob`](https://github.com/mrmlnc/fast-glob).\n\nYou can follow roughly the same migration process as documented in the [`fast-glob`](./fast-glob.md) replacement guide, since `globby` is built on top of it and the main differences are its extra conveniences.\n\nIf you don’t need `.gitignore` handling, prefer [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby/) - it’s smaller and faster. If you do need `.gitignore` behavior, pair `tinyglobby` with a small git-based helper. For most cases, this will likely be good enough:\n\n```ts\nimport { execSync } from 'node:child_process'\nimport { glob, escapePath } from 'tinyglobby'\n\nasync function globWithGitignore(patterns, options = {}) {\n const { cwd = process.cwd(), ...restOptions } = options\n\n try {\n const gitIgnored = execSync(\n 'git ls-files --others --ignored --exclude-standard --directory',\n { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }\n )\n .split('\\n')\n .filter(Boolean)\n .map((p) => escapePath(p))\n\n return glob(patterns, {\n ...restOptions,\n cwd,\n ignore: [...(restOptions.ignore || []), ...gitIgnored]\n })\n } catch {\n return glob(patterns, options)\n }\n}\n\nconst paths = await globWithGitignore(['**/*'], { cwd })\n```\n",
|
|
84
|
+
"mime.md": "---\ndescription: Lighter alternative to the mime package for looking up MIME types from file extensions\n---\n\n# Replacements for `mime`\n\n## `mrmime`\n\n[`mrmime`](https://github.com/lukeed/mrmime) is a smaller alternative to [`mime`](https://github.com/broofa/mime) for looking up MIME types from extensions or filenames. It only includes standard MIME types; experimental and vendor-specific types are omitted.\n\nExample:\n\n```js\nimport mime from 'mime' // [!code --]\nimport { lookup } from 'mrmime' // [!code ++]\n\nmime.getType('txt') // [!code --]\nlookup('txt') // [!code ++]\n// also works: lookup('.txt'), lookup('a.txt')\n```\n",
|
|
85
|
+
"tempy.md": "---\ndescription: Modern alternatives to the temp and tempy packages for creating temporary files and directories\n---\n\n# Replacements for `temp` / `tempy`\n\n## `fs.mkdtemp` (native, since Node.js v14.x)\n\nNode.js has the [`fs.mkdtemp`](https://nodejs.org/api/fs.html#fsmkdtempprefix-options-callback) function for creating a unique temporary directory. Directory cleanup can be done by passing `{recursive: true}` to [`fs.rm`](https://nodejs.org/api/fs.html#fsrmpath-options-callback).\n\nExample:\n\n```ts\nimport temp from 'temp' // [!code --]\nimport { mkdtemp, realpath } from 'node:fs/promises' // [!code ++]\nimport { join } from 'node:path' // [!code ++]\nimport { tmpdir } from 'node:os' // [!code ++]\n\nconst tempDirPath = temp.mkdirSync('foo') // [!code --]\nconst tempDirPath = await mkdtemp(join(await realpath(tmpdir()), 'foo-')) // [!code ++]\n```\n\n## `fs.mkdtempDisposable` (native, since Node.js v24.4.0)\n\nNode.js now provides [`fs.mkdtempDisposable`](https://nodejs.org/api/fs.html#fspromisesmkdtempdisposableprefix-options) which leverages the `using` keyword for automatic cleanup. This eliminates the need for `temp.track()` or manual cleanup logic.\n\nExample:\n\n```ts\nimport temp from 'temp' // [!code --]\nimport { mkdtempDisposable } from 'node:fs/promises' // [!code ++]\nimport { join } from 'node:path' // [!code ++]\nimport { tmpdir } from 'node:os' // [!code ++]\n\ntemp.track() // [!code --]\nconst tempDirPath = temp.mkdirSync('foo') // [!code --]\nawait using tempDir = await mkdtempDisposable(join(tmpdir(), 'foo-')) // [!code ++]\nconst tempDirPath = tempDir.path // [!code ++]\n```\n\n## Deno\n\nDeno provides built-in [`Deno.makeTempDir`](https://docs.deno.com/api/deno/~/Deno.makeTempDir) and [`Deno.makeTempFile`](https://docs.deno.com/api/deno/~/Deno.makeTempFile) for creating unique temporary directories and files in the system temp directory (or a custom `dir`). You can also set `prefix` and `suffix`. Both return the full path and require `--allow-write`.\n\n```ts\nimport { temporaryDirectory } from 'tempy' // [!code --]\n\nconst tempDir = temporaryDirectory({ prefix: 'foo-' }) // [!code --]\nconst tempDir = await Deno.makeTempDir({ prefix: 'foo-' }) // [!code ++]\n```\n\n```ts\nimport { temporaryFile } from 'tempy' // [!code --]\n\nconst tempFile = temporaryFile({ extension: 'txt' }) // [!code --]\nconst tempFile = await Deno.makeTempFile({ suffix: '.txt' }) // [!code ++]\n```\n\n> [!NOTE]\n> See also: [secure tempfiles in Node.js without dependencies (Advanced Web Machinery)](https://advancedweb.hu/secure-tempfiles-in-nodejs-without-dependencies)\n",
|
|
86
|
+
"find-up.md": "---\ndescription: Modern alternatives to the find-up package for finding files by walking up parent directories\n---\n\n# Replacements for `find-up`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nThe main difference is that `empathic` is _synchronous_, so you should no longer `await` the result.\n\nExample:\n\n```ts\nimport * as find from 'empathic/find' // [!code ++]\nimport { findUp } from 'find-up' // [!code --]\n\nawait findUp('package.json') // [!code --]\nfind.up('package.json') // [!code ++]\n```\n\n### `findUpMultiple`\n\nWhen finding multiple files, you can use `find.any`:\n\n```ts\nimport * as find from 'empathic/find' // [!code ++]\nimport { findUpMultiple } from 'find-up' // [!code --]\n\nconst files = await findUpMultiple(['package.json', 'tsconfig.json']) // [!code --]\nconst files = find.any(['package.json', 'tsconfig.json']) // [!code ++]\n```\n\n### Options\n\n#### `type`\n\nThe `type` option can be replaced by using the equivalent function.\n\nFor example, finding a file:\n\n```ts\nimport * as find from 'empathic/find' // [!code ++]\nimport { findUp } from 'find-up' // [!code --]\n\nawait findUp('package.json', { type: 'file' }) // [!code --]\nfind.file('package.json') // [!code ++]\n```\n\n#### `cwd`\n\nThis option is supported just the same:\n\n```ts\nfind.file('package.json', { cwd })\n```\n\n#### `stopAt`\n\nThis option is replaced by `last`:\n\n<!-- eslint-skip -->\n\n```ts\nimport { findUp } from 'find-up' // [!code --]\nimport * as find from 'empathic/find' // [!code ++]\n\nawait findUp( // [!code --]\nfind.file( // [!code ++]\n 'package.json',\n { stopAt: '/some/dir' }, // [!code --]\n { last: '/some/dir' }, // [!code ++]\n)\n```\n\n## `pkg-types`\n\n[`pkg-types`](https://github.com/unjs/pkg-types) provides utilities for reading and writing package.json, tsconfig.json, and other configuration files with TypeScript support.\n\n```ts\nimport { findUp } from 'find-up' // [!code --]\nimport { readPackageJSON } from 'pkg-types' // [!code ++]\n\nconst packagePath = await findUp('package.json') // [!code --]\nconst packageJson = await readPackageJSON() // [!code ++]\n```\n",
|
|
87
|
+
"is-builtin-module.md": "---\ndescription: Native Node.js alternatives to the is-builtin-module package for checking built-in modules\n---\n\n# Replacements for `is-builtin-module`\n\n## `isBuiltin` (native, since Node.js 16.x)\n\nFor determining if a module is built-in or not, you can use [isBuiltin](https://nodejs.org/api/module.html#moduleisbuiltinmodulename):\n\n```ts\nimport { isBuiltin } from 'node:module' // [!code ++]\nimport isBuiltinModule from 'is-builtin-module' // [!code --]\n\nisBuiltin('fs') // true [!code ++]\nisBuiltinModule('fs') // true [!code --]\n```\n\n## `builtInModules` (native, since Node.js 6.x and 15.x)\n\nBefore Node.js 16.x, `isBuiltin` was not available, so you need to implement your own check using [builtinModules](https://nodejs.org/api/module.html#modulebuiltinmodules):\n\n<!-- prettier-ignore -->\n```ts\nimport { builtinModules } from 'node:module' // [!code ++]\nimport isBuiltinModule from 'is-builtin-module' // [!code --]\n\nfunction isBuiltin(moduleName) { // [!code ++]\n const name = moduleName.startsWith('node:') // [!code ++]\n ? moduleName.slice(5) // [!code ++]\n : moduleName // [!code ++]\n return builtinModules.includes(name) // [!code ++]\n} // [!code ++]\n\nisBuiltin('fs') // true [!code ++]\nisBuiltinModule('fs') // true [!code --]\n```\n",
|
|
88
|
+
"js-yaml.md": "---\ndescription: Modern alternatives to js-yaml for YAML parsing and stringifying\n---\n\n# Replacements for `js-yaml`\n\n`js-yaml` appears to be unmaintained and has known spec-compliance issues.\n\n## `yaml`\n\n[`yaml`](https://github.com/eemeli/yaml) is a well maintained YAML 1.2/1.1 parser/stringifier with better spec compliance, comment/AST support, and no deps.\n\nParse (load):\n\n```ts\nimport yaml from 'js-yaml' // [!code --]\nimport { parse } from 'yaml' // [!code ++]\n\nconst obj = yaml.load(src) // [!code --]\nconst obj = parse(src) // [!code ++]\n```\n\nStringify (dump):\n\n```ts\nimport yaml from 'js-yaml' // [!code --]\nimport { stringify } from 'yaml' // [!code ++]\n\nconst text = yaml.dump(obj) // [!code --]\nconst text = stringify(obj) // [!code ++]\n```\n\nMulti-document:\n\n```ts\nimport yaml from 'js-yaml' // [!code --]\nimport { parseAllDocuments } from 'yaml' // [!code ++]\n\nconst out: any[] = [] // [!code --]\nyaml.loadAll(src, (d) => out.push(d)) // [!code --]\nconst out = parseAllDocuments(src).map((d) => d.toJSON()) // [!code ++]\n```\n\n## Bun `YAML` API\n\n[Native YAML parsing](https://bun.com/docs/runtime/yaml) is supported in Bun since [v1.2.21](https://bun.com/blog/release-notes/bun-v1.2.21#native-yaml-support).\n\nExample:\n\n```ts\nimport yaml from 'js-yaml' // [!code --]\nimport { YAML } from 'bun' // [!code ++]\n\nyaml.load(src) // [!code --]\nYAML.parse(src) // [!code ++]\n```\n",
|
|
66
89
|
"gzip-size.md": "---\ndescription: Native Node.js alternatives to the gzip-size for calculating gzipped size of a string or buffer\n---\n\n# Replacements for `gzip-size`\n\n## `gzipSync` (native, since Node.js 9.4.0)\n\nTo calculate the gzipped size of a string or an `ArrayBuffer`, you can use [gzipSync](https://nodejs.org/api/zlib.html#zlibgzipsync) which exist inside the `zlib` module:\n\n### Synchronous\n\n```ts\nimport { gzipSizeSync } from 'gzip-size' // [!code --]\nimport { gzipSync } from 'node:zlib' // [!code ++]\n\nconst text = 'Lorem ipsum dolor sil amet'\n\nconsole.log(gzipSizeSync(text)) // [!code --]\nconsole.log(gzipSync(text).length) // [!code ++]\n```\n\n### Asynchronous\n\n```ts\nimport { gzipSize } from 'gzip-size' // [!code --]\nimport { gzipSync } from 'node:zlib' // [!code ++]\nimport { promisify } from 'node:util' // [!code ++]\n\nconst gzipAsync = promisify(gzip) // [!code ++]\n\nconst text = 'Lorem ipsum dolor sil amet'\n\nconsole.log(await gzipSize(text)) // [!code --]\nconsole.log((await gzipAsync(text)).length) // [!code ++]\n```\n\n### Calculating from a file\n\n```ts\nimport { gzipSizeFromFileSync } from 'gzip-size' // [!code --]\nimport { gzipSync } from 'node:zlib' // [!code ++]\nimport { readFileSync } from 'node:fs' // [!code ++]\n\nconst path = '/path/to/file'\n\nconsole.log(gzipSizeFromFileSync(path)) // [!code --]\nconsole.log(gzipSync(readFileSync(path)).length) // [!code ++]\n```\n",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"source-map-explorer.md": "---\ndescription: Modern alternatives to the source-map-explorer package for exploring bundle sourcemaps\n---\n\n# Replacements for `source-map-explorer`\n\n## `rollup-plugin-visualizer`\n\n[`rollup-plugin-visualizer`](https://github.com/btd/rollup-plugin-visualizer) allows you to visualize rollup, rolldown, and vite bundles\n\n### Rollup (`rollup.config.js`)\n\n```js\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default {\n plugins: [\n // Keep it last.\n visualizer()\n ]\n}\n```\n\n### Rolldown (`rolldown.config.ts`)\n\n```js\nimport { defineConfig, type RolldownPlugin } from 'rolldown'\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default defineConfig({\n plugins: [visualizer() as RolldownPlugin]\n})\n```\n\n### Vite (`vite.config.js`)\n\n```js\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default {\n plugins: [visualizer()]\n}\n```\n\n### Vite + TypeScript (`vite.config.ts`)\n\n```ts\nimport { defineConfig, type PluginOption } from 'vite'\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default defineConfig({\n plugins: [visualizer() as PluginOption]\n})\n```\n\n## `sonda`\n\n[`sonda`](https://github.com/filipsobol/sonda) allows you to visualize vite, rollup, rolldown, esbuild, webpack, and rspack bundles\n\nExample:\n\n```js\nimport { defineConfig } from 'vite'\nimport Sonda from 'sonda/vite'\n\nexport default defineConfig({\n build: {\n sourcemap: true\n },\n plugins: [Sonda()]\n})\n```\n\nFor full docs check their [website](https://sonda.dev/getting-started).\n\n## `webpack-bundle-analyzer`\n\n[`webpack-bundle-analyzer`](https://github.com/webpack/webpack-bundle-analyzer) allows you to visualize webpack bundles\n\nExample:\n\n```js\nimport { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'\n\nmodule.exports = {\n plugins: [new BundleAnalyzerPlugin()]\n}\n```\n",
|
|
71
|
-
"tokml.md": "---\ndescription: Modern replacements for the tokml package for converting GeoJSON to KML\n---\n\n# Replacements for `tokml`\n\n## `@placemarkio/tokml`\n\n[`@placemarkio/tokml`](https://github.com/placemark/tokml) is a maintained alternative for `tokml` package.\n\nExample:\n\n```js\nimport tokml from 'tokml' // [!code --]\nimport { toKML } from '@placemarkio/tokml' // [!code ++]\n\nconst geojson = {\n type: 'FeatureCollection',\n features: [\n {\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [1, 2] },\n properties: { name: 'Marker' }\n }\n ]\n}\n\nconst kml = tokml(geojson) // [!code --]\nconst kml = toKML(geojson) // [!code ++]\n```\n",
|
|
72
|
-
"sort-object.md": "---\ndescription: Modern alternatives to the sort-object package for sorting object keys\n---\n\n# Replacements for `sort-object`\n\n## `Object.entries` and `Array.sort` (native)\n\nFor simple cases:\n\n<!-- prettier-ignore -->\n```ts\nimport sortObj from 'sort-object' // [!code --]\n\nconst sorted = sortObj(object) // [!code --]\n\n// Ascending A→Z\nconst sorted = Object.fromEntries( // [!code ++]\n Object.entries(object).sort((a, b) => a[0].localeCompare(b[0])) // [!code ++]\n) // [!code ++]\n```\n\nReplicating `sortBy` (function returns an ordered key list):\n\n<!-- prettier-ignore -->\n```ts\nimport sortObj from 'sort-object' // [!code --]\n\nconst sorted = sortObj(object, { // [!code --]\n sortBy: (obj) => { // [!code --]\n const arr = [] // [!code --]\n Object.keys(obj).forEach((k) => { // [!code --]\n if (obj[k].startsWith('a')) // [!code --]\n arr.push(k) // [!code --]\n }) // [!code --]\n return arr.reverse() // [!code --]\n } // [!code --]\n}) // [!code --]\n\nconst sortBy = (obj) => // [!code ++]\n Object.keys(obj) // [!code ++]\n .filter((k) => obj[k].startsWith('a')) // [!code ++]\n .reverse() // [!code ++]\nconst sorted = Object.fromEntries( // [!code ++]\n sortBy(object).map((k) => [k, object[k]]) // [!code ++]\n) // [!code ++]\n```\n\n## `sort-object-keys`\n\n[`sort-object-keys`](https://github.com/keithamus/sort-object-keys) is zero‑dependency and matches common `sort-object` use cases (custom order array or comparator).\n\n```ts\nimport sortObj from 'sort-object' // [!code --]\nimport sortObjectKeys from 'sort-object-keys' // [!code ++]\n\n// Default A→Z\nconst sorted = sortObj(object) // [!code --]\nconst sorted = sortObjectKeys(object) // [!code ++]\n\n// With comparator\nconst sortedByCmp = sortObj(object, { sort: (a, b) => a.localeCompare(b) }) // [!code --]\nconst sortedByCmp = sortObjectKeys(object, (a, b) => a.localeCompare(b)) // [!code ++]\n```\n\n## `sortobject`\n\n[`sortobject`](https://github.com/bevry/sortobject) is zero‑dependency and deeply sorts nested objects.\n\n```ts\nimport sortObj from 'sort-object' // [!code --]\nimport sortobject from 'sortobject' // [!code ++]\n\nconst sorted = sortObj(object) // [!code --]\nconst sorted = sortobject(object) // [!code ++]\n```\n",
|
|
90
|
+
"glob.md": "---\ndescription: Modern alternatives to the glob package for file pattern matching and globbing\n---\n\n# Replacements for `glob`\n\n## `tinyglobby`\n\n[`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) provides a similar API.\n\nExample:\n\n```ts\nimport { glob } from 'glob' // [!code --]\nimport { glob } from 'tinyglobby' // [!code ++]\n\nconst files = await glob('**/*.ts')\n```\n\nMost options available to `glob` are available in `tinyglobby`, read more at the [tinyglobby documentation](https://superchupu.dev/tinyglobby/documentation).\n\n## `fs.glob` (native, since Node 22.x)\n\n[`fs.glob`](https://nodejs.org/api/fs.html#fspromisesglobpattern-options) is built into modern versions of Node.\n\nExample:\n\n<!-- eslint-skip -->\n\n```ts\nimport { glob } from 'glob' // [!code --]\nimport { glob } from 'node:fs/promises' // [!code ++]\n\nconst files = await glob('src/**/*.ts', { // [!code --]\nconst files = await Array.fromAsync(glob('src/**/*.ts', { // [!code ++]\n cwd,\n}) // [!code --]\n})) // [!code ++]\n```\n\nYou can also iterate over the results asynchronously:\n\n```ts\nfor await (const result of glob('src/**/*.ts', { cwd })) {\n // result is an individual path\n console.log(result)\n}\n```\n\n> [!NOTE]\n> Node's built-in `glob` is more minimal and does not support negation patterns or fine-grained options like setting a max depth out of the box.\n\n## `fdir`\n\n[`fdir`](https://github.com/thecodrr/fdir/) offers similar functionality but through a different API (and `tinyglobby` is actually built on top of it).\n\nExample:\n\n<!-- eslint-skip -->\n\n```ts\nimport { fdir } from 'fdir' // [!code ++]\nimport { glob } from 'glob' // [!code --]\n\nconst files = new fdir() // [!code ++]\n .withBasePath() // [!code ++]\n .glob('src/**/*.ts') // [!code ++]\n .crawl(cwd) // [!code ++]\n .withPromise() // [!code ++]\nconst files = await glob('src/**/*.ts', { cwd, maxDepth: 6 }) // [!code --]\n```\n",
|
|
91
|
+
"portfinder.md": "---\ndescription: Modern alternatives to the portfinder package for finding an available port\n---\n\n# Replacements for `portfinder`\n\n## `get-port`\n\n[`get-port`](https://github.com/sindresorhus/get-port) is a lighter and more modern package for finding an available port.\n\nExample:\n\n```ts\nimport portfinder from 'portfinder' // [!code --]\nimport getPort from 'get-port' // [!code ++]\n\nconst port = await portfinder.getPortPromise() // [!code --]\nconst port = await getPort() // [!code ++]\n```\n",
|
|
92
|
+
"emoji-regex.md": "---\ndescription: Modern alternatives to the emoji-regex package for emoji detection and matching\n---\n\n# Replacements for `emoji-regex`\n\n## `emoji-regex-xs`\n\n[`emoji-regex-xs`](https://github.com/slevithan/emoji-regex-xs) offers the same API and features whilst being 98% smaller.\n\n```ts\nimport emojiRegex from 'emoji-regex' // [!code --]\nimport emojiRegex from 'emoji-regex-xs' // [!code ++]\n\nconst text = `\n\\u{231A}: ⌚ default emoji presentation character (Emoji_Presentation)\n\\u{2194}\\u{FE0F}: ↔️ default text presentation character rendered as emoji\n\\u{1F469}: 👩 emoji modifier base (Emoji_Modifier_Base)\n\\u{1F469}\\u{1F3FF}: 👩🏿 emoji modifier base followed by a modifier\n`\n\nconst regex = emojiRegex()\nfor (const match of text.matchAll(regex)) {\n const emoji = match[0]\n console.log(`Matched sequence ${emoji} — code points: ${[...emoji].length}`)\n}\n```\n\n## Unicode RegExp (native)\n\nIf your target runtime supports ES2024 Unicode property sets, you can use the native [`\\p{RGI_Emoji}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Unicode_character_class_escape) property in a regular expression. This relies on the engine's built‑in Unicode handling.\n\n```ts\nimport emojiRegex from 'emoji-regex' // [!code --]\n\nconst regex = emojiRegex() // [!code --]\nconst regex = /\\p{RGI_Emoji}/gv // [!code ++]\n\nfor (const match of text.matchAll(regex)) {\n const emoji = match[0]\n console.log(`Matched sequence ${emoji} — code points: ${[...emoji].length}`)\n}\n```\n",
|
|
73
93
|
"tsup.md": "---\ndescription: Modern alternative to tsup for bundling TypeScript libraries\n---\n\n# Replacements for `tsup`\n\n## `tsdown`\n\n[tsdown](https://github.com/rolldown/tsdown) is the successor recommended by [tsup's own README](https://github.com/egoist/tsup). The project is effectively in maintenance mode. tsdown is built on Rolldown and is typically faster for library builds, with a largely drop-in config surface.\n\n### Config migration\n\nMost `tsup.config.ts` files map 1:1 to `tsdown.config.ts`:\n\n```ts\nimport { defineConfig } from 'tsup' // [!code --]\nimport { defineConfig } from 'tsdown' // [!code ++]\n\nexport default defineConfig({\n entry: ['src/index.ts'],\n format: ['esm', 'cjs'],\n dts: true,\n clean: true\n})\n```\n\n### Package scripts\n\n```json\n{\n \"scripts\": {\n \"build\": \"tsup\" // [!code --]\n \"build\": \"tsdown\" // [!code ++]\n }\n}\n```\n\n### Automated migration\n\n- `npx tsdown-migrate`\n- `npx skills add rolldown/tsdown --skill tsdown-migrate`\n",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"lint-staged.md": "---\ndescription: Modern alternatives to lint-staged for running commands on staged Git files\n---\n\n# Replacements for `lint-staged`\n\n## `nano-staged`\n\n[`nano-staged`](https://github.com/usmanyunusov/nano-staged) is a tiny pre-commit runner for staged (and more) files; much smaller and faster than `lint-staged`, with a simple config.\n\npackage.json config:\n\n<!-- eslint-skip -->\n\n```json\n{\n \"lint-staged\": { // [!code --]\n \"nano-staged\": { // [!code ++]\n \"*.{js,ts}\": [\"prettier --write\"]\n },\n}\n```\n\n> [!NOTE]\n> Differences to be aware of:\n>\n> - `lint-staged` has advanced features like backup stashing, partial-staging handling, per-directory configs in monorepos, and detailed concurrency controls.\n> - `nano-staged` focuses on simplicity and speed. If you rely on `lint-staged`’s stash/partial-staging features, keep using `lint-staged`.\n",
|
|
78
|
-
"toml.md": "---\ndescription: Modern alternatives to toml for TOML parsing and stringifying\n---\n\n# Replacements for `toml`\n\n`toml` appears to be unmaintained and has known spec-compliance issues.\n\n## `smol-toml`\n\n[`smol-toml`](https://github.com/squirrelchat/smol-toml) is a well maintained TOML v1.1.0 parser/stringifier with full spec compliance, comment/AST support, and no deps.\n\nParse (load):\n\n```ts\nimport toml from 'toml' // [!code --]\nimport { parse } from 'smol-toml' // [!code ++]\n\nconst obj = toml.parse(src) // [!code --]\nconst obj = parse(src) // [!code ++]\n```\n\nStringify:\n\n```ts\nimport { stringify } from 'smol-toml'\n\nconst text = stringify(obj)\n```\n\n## Bun `TOML` API (native)\n\n[Native TOML parsing](https://bun.com/docs/runtime/toml#runtime-api) is supported in Bun.\n\nExample:\n\n```ts\nimport toml from 'toml' // [!code --]\nimport { TOML } from 'bun' // [!code ++]\n\ntoml.parse(src) // [!code --]\nTOML.parse(src) // [!code ++]\n```\n",
|
|
79
|
-
"portal-vue.md": "---\ndescription: Modern alternatives to the `portal-vue` package for making portals in Vue applications\n---\n\n# Replacements for `portal-vue`\n\n## Vue `Teleport` API\n\nSince Vue 3, the [Teleport](https://vuejs.org/guide/built-ins/teleport.html) component has been introduced which replaces portal-vue for most use cases, especially modals and overlays.\n\n`<Teleport>` only moves DOM nodes to an existing target — it does not manage destinations, layouts, or component structure.\n\n```html\n<!-- Using a modal -->\n<div class=\"outer\">\n <h3>Vue Teleport Example</h3>\n <div>\n <MyModal />\n </div>\n</div>\n```\n\n```html\n<!-- MyModal.vue -->\n<Teleport to=\"body\">\n <p>The content inside of Teleport will render in html body</p>\n</Teleport>\n```\n",
|
|
94
|
+
"eslint-plugin-jest-dom.md": "---\ndescription: Modern alternatives to the eslint-plugin-vitest package for jest-dom-specific linting rules\n---\n\n# Replacements for `eslint-plugin-jest-dom`\n\n## `eslint-plugin-jest-dom-ya`\n\n[`eslint-plugin-jest-dom-ya`](https://github.com/G-Rath/eslint-plugin-jest-dom-ya) is the actively maintained successor forked by an established contributor, with ESLint v10 support and continued development.\n\n```ts\nimport jestDomPlugin from 'eslint-plugin-jest-dom' // [!code --]\nimport jestDomYaPlugin from 'eslint-plugin-jest-dom-ya' // [!code ++]\n\nexport default [\n jestDomPlugin.configs[\"flat/recommended\"], // [!code --]\n jestDomYaPlugin.configs[\"flat/recommended\"], // [!code ++]\n {\n plugins: {\n 'jest-dom': jestDomPlugin // [!code --]\n 'jest-dom-ya': jestDomYaPlugin // [!code ++]\n },\n rules: {\n \"jest-dom/prefer-checked\": \"error\", // [!code --]\n \"jest-dom-ya/prefer-checked\": \"error\", // [!code ++]\n \"jest-dom/prefer-enabled-disabled\": \"error\", // [!code --]\n \"jest-dom-ya/prefer-enabled-disabled\": \"error\" // [!code ++]\n }\n }\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:jest-dom/recommended', // [!code --]\n 'plugin:jest-dom-ya/recommended' // [!code ++]\n ],\n rules: {\n 'jest-dom/prefer-checked': 'error', // [!code --]\n 'jest-dom-ya/prefer-checked': 'error' // [!code ++]\n }\n}\n```\n",
|
|
95
|
+
"npm-run-all.md": "---\ndescription: Modern alternatives to the npm-run-all package for running multiple npm scripts\n---\n\n# Replacements for `npm-run-all`\n\n## `npm-run-all2`\n\n[npm-run-all2](https://github.com/bcomnes/npm-run-all2) is an actively maintained fork with important fixes, dependency updates.\n\n```json\n{\n \"scripts\": {\n \"build\": \"npm-run-all clean lint compile\"\n }\n}\n```\n\nThe commands remain the same: `npm-run-all`, `run-s`, and `run-p`.\n\n## `concurrently`\n\nAnother option is [concurrently](https://github.com/open-cli-tools/concurrently), which focuses on running scripts in parallel with colored output and process control. It uses a slightly different syntax but works well for replacing the `--parallel` use case.\n\n```json\n{\n \"scripts\": {\n \"dev\": \"npm-run-all --parallel \\\"watch-*\\\" start\", // [!code --]\n \"dev\": \"concurrently \\\"npm:watch-*\\\" \\\"npm:start\\\"\" // [!code ++]\n }\n}\n```\n\n## `wireit`\n\nFor more advanced workflows, consider [Wireit](https://github.com/google/wireit). It integrates directly into `package.json` to add caching, dependency graphs, watch mode, and incremental builds. Unlike `npm-run-all`, Wireit upgrades your existing `npm run` experience instead of providing a separate CLI.\n\n```json\n{\n \"scripts\": {\n \"build\": \"wireit\",\n \"compile\": \"wireit\",\n \"bundle\": \"wireit\"\n },\n \"wireit\": {\n \"build\": {\n \"dependencies\": [\"compile\", \"bundle\"]\n },\n \"compile\": {\n \"command\": \"tsc\",\n \"files\": [\"src/**/*.ts\"],\n \"output\": [\"lib/**\"]\n },\n \"bundle\": {\n \"command\": \"rollup -c\",\n \"dependencies\": [\"compile\"],\n \"files\": [\"rollup.config.js\"],\n \"output\": [\"dist/**\"]\n }\n }\n}\n```\n\n## `bun run --parallel` / `bun run --sequential`\n\nIf you are using bun you can use [`bun run --parallel`](https://bun.com/docs/runtime#param-parallel) and [`bun run --sequential`](https://bun.com/docs/runtime#param-sequential).\n\n### Parallel\n\n```json\n{\n \"scripts\": {\n \"dev\": \"npm-run-all --parallel \\\"dev:*\\\"\", // [!code --]\n \"dev\": \"bun run --parallel dev:*\" // [!code ++]\n }\n}\n```\n\n### Sequential\n\n```json\n{\n \"scripts\": {\n \"build\": \"run-s clean lint compile\", // [!code --]\n \"build\": \"bun run --sequential clean lint compile\" // [!code ++]\n }\n}\n```\n",
|
|
96
|
+
"jquery.md": "---\ndescription: Modern alternatives to the jQuery library for DOM traversal, events, and AJAX\n---\n\n# Replacements for `jQuery`\n\n## You might not need jQuery\n\n[You might not need jQuery](https://youmightnotneedjquery.com/) is a side‑by‑side catalog of native JavaScript equivalents for common jQuery patterns (selectors, traversal, manipulation, events, AJAX), with concise before/after examples.\n\n## You (Might) Don't Need jQuery\n\n[You‑Dont‑Need‑jQuery](https://github.com/camsong/You-Dont-Need-jQuery) is a community‑maintained guide that shows how to handle querying, styling, DOM manipulation, AJAX, and events with plain JavaScript.\n",
|
|
80
97
|
"pkg-dir.md": "---\ndescription: Modern alternatives to the pkg-dir package for finding package root directories\n---\n\n# Replacements for `pkg-dir`\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nThe main difference is that `empathic` is _synchronous_, so you should no longer `await` the result.\n\nExample:\n\n```ts\nimport { dirname } from 'node:path' // [!code ++]\nimport * as pkg from 'empathic/package' // [!code ++]\nimport { packageDirectory } from 'pkg-dir' // [!code --]\n\nconst dir = await packageDirectory() // [!code --]\nconst dir = dirname(pkg.up()) // [!code ++]\n```\n",
|
|
81
|
-
"split.md": "---\ndescription: Native Node.js alternatives to the split package for splitting stream by lines\n---\n\n# Replacements for `split`\n\n## `readline.createInterface` (native, since Node.js v6.6.0)\n\nThe [`readline.createInterface`](https://nodejs.org/api/readline.html#readlinecreateinterfaceoptions)\nmethod can be used to read a stream line by line, effectively replacing the functionality of the `split` package.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport split from 'split' // [!code --]\nimport { createInterface } from 'node:readline' // [!code ++]\nimport * as fs from 'node:fs'\n\nconst input = fs.createReadStream('file.txt')\n\nconst stream = input.pipe(split()) // [!code --]\nstream.on('data', (line) => { // [!code --]\n fn(line) // [!code --]\n}) // [!code --]\n\nconst lines = createInterface({ input, crlfDelay: Infinity }) // [!code ++]\n\nfor await (const line of lines) { // [!code ++]\n fn(line) // [!code ++]\n} // [!code ++]\n```\n",
|
|
82
|
-
"resolve.md": "---\ndescription: Modern alternatives to the resolve package\n---\n\n# Replacements for `resolve`\n\n## `import.meta.resolve` (native)\n\n[`import.meta.resolve`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta/resolve) is built into browsers and Node.js (>= 20).\n\nExample:\n\n```ts\nconst path = import.meta.resolve('my-module')\n```\n\n## `exsolve`\n\n[`exsolve`](https://github.com/unjs/exsolve)\n\n```ts\nimport { resolveModulePath } from 'exsolve'\n\nconst path = resolveModulePath('my-module')\n```\n\n## `oxc-resolver`\n\n[`oxc-resolver`](https://github.com/oxc-project/oxc-resolver)\n\n```ts\nimport { ResolverFactory } from 'oxc-resolver'\n\nconst resolver = new ResolverFactory()\nconst { path } = resolver.sync(process.cwd(), 'my-module')\n```\n",
|
|
83
|
-
"react-helmet.md": "---\ndescription: Modern alternatives to the react-helmet package\n---\n\n# Replacements for `react-helmet`\n\n## Support for Document Metadata (native, since React 19)\n\n[Support for Document Metadata](https://react.dev/blog/2024/12/05/react-19#support-for-metadata-tags) is available since React 19\n\nExample:\n\n```jsx\nfunction BlogPost({ post }) {\n return (\n <article>\n <h1>{post.title}</h1>\n <title>{post.title}</title>\n <meta name=\"keywords\" content={post.keywords} />\n <p>Eee equals em-see-squared...</p>\n </article>\n )\n}\n```\n\n## `react-helmet-async`\n\n[`react-helmet-async`](https://github.com/staylor/react-helmet-async) is a fork of `react-helmet`.\n\nExample:\n\n<!-- prettier-ignore -->\n```jsx\nimport { Helmet } from 'react-helmet' // [!code --]\nimport { Helmet, HelmetProvider } from 'react-helmet-async' // [!code ++]\n\nconst app = (\n <HelmetProvider> // [!code ++]\n <App>\n <Helmet>\n <title>Hello World</title>\n <link rel=\"canonical\" href=\"https://e18e.dev/\" />\n </Helmet>\n <h1>Hello World</h1>\n </App>\n </HelmetProvider> // [!code ++]\n)\n```\n",
|
|
84
|
-
"qs.md": "---\ndescription: Modern alternatives to the qs package for parsing and serializing query strings\n---\n\n# Replacements for `qs`\n\n## `URLSearchParams` (native)\n\n[`URLSearchParams`](https://developer.mozilla.org/docs/Web/API/URLSearchParams) is built into browsers and Node.js (>= 10). Use it when you don’t need nested objects or automatic array parsing. It preserves multiple values via `getAll`, and `toString()` gives you a URL-safe query string.\n\nExample:\n\n```ts\nimport qs from 'qs' // [!code --]\n\nconst query = 'a=1&a=2&b=3'\n\nconst obj = qs.parse(query) // [!code --]\nconst sp = new URLSearchParams(query) // [!code ++]\nconst obj = Object.fromEntries(sp) // [!code ++]\nconst a = sp.getAll('a') // [!code ++]\n```\n\n## `fast-querystring`\n\n[`fast-querystring`](https://github.com/anonrig/fast-querystring) is tiny and very fast. It handles flat key/value pairs and repeated keys as arrays; it does not support nested objects. Use it when you need arrays but not nesting.\n\nExample:\n\n```ts\nimport qs from 'qs' // [!code --]\nimport fqs from 'fast-querystring' // [!code ++]\n\nconst obj = qs.parse('tag=a&tag=b') // [!code --]\nconst obj = fqs.parse('tag=a&tag=b') // [!code ++]\n\nconst str = qs.stringify({ tag: ['a', 'b'], q: 'x y' }) // [!code --]\nconst str = fqs.stringify({ tag: ['a', 'b'], q: 'x y' }) // [!code ++]\n```\n\n## `picoquery`\n\n[`picoquery`](https://github.com/43081j/picoquery) supports nesting and arrays with a fast single‑pass parser and configurable syntax. v2.x and above are ESM‑only; v1.x is CommonJS and will be maintained with non‑breaking changes. `nestingSyntax: 'js'` offers the highest compatibility with `qs`, though you can pick other syntaxes for performance.\n\nExample:\n\n<!-- prettier-ignore -->\n```ts\nimport qs from 'qs' // [!code --]\nimport { parse, stringify } from 'picoquery' // [!code ++]\n\nconst opts = { // [!code ++]\n nestingSyntax: 'js', // [!code ++]\n arrayRepeat: true, // [!code ++]\n arrayRepeatSyntax: 'bracket' // [!code ++]\n} // [!code ++]\n\nconst obj = qs.parse('user[name]=foo&tags[]=bar&tags[]=baz') // [!code --]\nconst obj = parse('user[name]=foo&tags[]=bar&tags[]=baz', opts) // [!code ++]\n\nconst str = qs.stringify( // [!code --]\n { user: { name: 'foo' }, tags: ['bar', 'baz'] }, // [!code --]\n { arrayFormat: 'brackets' } // [!code --]\n) // [!code --]\nconst str = stringify({ user: { name: 'foo' }, tags: ['bar', 'baz'] }, opts) // [!code ++]\n```\n\n## `neoqs`\n\n[`neoqs`](https://github.com/PuruVJ/neoqs) is a fork of `qs` without legacy polyfills, with TypeScript types included, and with both ESM and CommonJS builds (plus a legacy ES5 mode). Choose it when you want `qs`‑level compatibility with modern packaging options.\n\nExample:\n\n```ts\nimport qs from 'qs' // [!code --]\nimport * as qs from 'neoqs' // [!code ++]\n\nconst obj = qs.parse('a[b][c]=1&arr[]=2&arr[]=3')\nconst str = qs.stringify(obj, { arrayFormat: 'brackets' })\n```\n",
|
|
85
|
-
"tar-fs.md": "---\ndescription: Lighter alternative to the tar-fs package for packing and extracting tar archives on the filesystem\n---\n\n# Replacements for `tar-fs`\n\n## `modern-tar`\n\n[`tar-fs`](https://github.com/mafintosh/tar-fs) provides filesystem bindings on top of [`tar-stream`](https://github.com/mafintosh/tar-stream). [`modern-tar`](https://github.com/ayuhito/modern-tar) covers the same workflows through [`modern-tar/fs`](https://github.com/ayuhito/modern-tar), with zero dependencies and built-in TypeScript types.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport tar from 'tar-fs' // [!code --]\nimport { createReadStream, createWriteStream } from 'node:fs' // [!code ++]\nimport { packTar, unpackTar } from 'modern-tar/fs' // [!code ++]\nimport { pipeline } from 'node:stream/promises' // [!code ++]\n\ntar.pack('./my-directory').pipe(createWriteStream('my-tarball.tar')) // [!code --]\nawait pipeline(packTar('./my-directory'), createWriteStream('my-tarball.tar')) // [!code ++]\n\ncreateReadStream('my-other-tarball.tar').pipe( // [!code --]\n tar.extract('./my-other-directory') // [!code --]\n) // [!code --]\nawait pipeline( // [!code ++]\n createReadStream('my-other-tarball.tar'), // [!code ++]\n unpackTar('./my-other-directory') // [!code ++]\n) // [!code ++]\n```\n",
|
|
86
|
-
"tempy.md": "---\ndescription: Modern alternatives to the temp and tempy packages for creating temporary files and directories\n---\n\n# Replacements for `temp` / `tempy`\n\n## `fs.mkdtemp` (native, since Node.js v14.x)\n\nNode.js has the [`fs.mkdtemp`](https://nodejs.org/api/fs.html#fsmkdtempprefix-options-callback) function for creating a unique temporary directory. Directory cleanup can be done by passing `{recursive: true}` to [`fs.rm`](https://nodejs.org/api/fs.html#fsrmpath-options-callback).\n\nExample:\n\n```ts\nimport temp from 'temp' // [!code --]\nimport { mkdtemp, realpath } from 'node:fs/promises' // [!code ++]\nimport { join } from 'node:path' // [!code ++]\nimport { tmpdir } from 'node:os' // [!code ++]\n\nconst tempDirPath = temp.mkdirSync('foo') // [!code --]\nconst tempDirPath = await mkdtemp(join(await realpath(tmpdir()), 'foo-')) // [!code ++]\n```\n\n## `fs.mkdtempDisposable` (native, since Node.js v24.4.0)\n\nNode.js now provides [`fs.mkdtempDisposable`](https://nodejs.org/api/fs.html#fspromisesmkdtempdisposableprefix-options) which leverages the `using` keyword for automatic cleanup. This eliminates the need for `temp.track()` or manual cleanup logic.\n\nExample:\n\n```ts\nimport temp from 'temp' // [!code --]\nimport { mkdtempDisposable } from 'node:fs/promises' // [!code ++]\nimport { join } from 'node:path' // [!code ++]\nimport { tmpdir } from 'node:os' // [!code ++]\n\ntemp.track() // [!code --]\nconst tempDirPath = temp.mkdirSync('foo') // [!code --]\nawait using tempDir = await mkdtempDisposable(join(tmpdir(), 'foo-')) // [!code ++]\nconst tempDirPath = tempDir.path // [!code ++]\n```\n\n## Deno\n\nDeno provides built-in [`Deno.makeTempDir`](https://docs.deno.com/api/deno/~/Deno.makeTempDir) and [`Deno.makeTempFile`](https://docs.deno.com/api/deno/~/Deno.makeTempFile) for creating unique temporary directories and files in the system temp directory (or a custom `dir`). You can also set `prefix` and `suffix`. Both return the full path and require `--allow-write`.\n\n```ts\nimport { temporaryDirectory } from 'tempy' // [!code --]\n\nconst tempDir = temporaryDirectory({ prefix: 'foo-' }) // [!code --]\nconst tempDir = await Deno.makeTempDir({ prefix: 'foo-' }) // [!code ++]\n```\n\n```ts\nimport { temporaryFile } from 'tempy' // [!code --]\n\nconst tempFile = temporaryFile({ extension: 'txt' }) // [!code --]\nconst tempFile = await Deno.makeTempFile({ suffix: '.txt' }) // [!code ++]\n```\n\n> [!NOTE]\n> See also: [secure tempfiles in Node.js without dependencies (Advanced Web Machinery)](https://advancedweb.hu/secure-tempfiles-in-nodejs-without-dependencies)\n",
|
|
87
|
-
"uri-js.md": "---\ndescription: Modern alternatives to uri-js for RFC 3986 URI parsing, resolving, and normalization\n---\n\n# Replacements for `uri-js`\n\n[`uri-js`](https://github.com/garycourt/uri-js) is unmaintained and triggers deprecation warnings on modern Node.js ([due to `punycode`](https://github.com/garycourt/uri-js/pull/95)).\n\n## `URL` (native)\n\nGood for standard web URLs (http/https/ws/wss/file/mailto, etc.).\n\n- MDN URL: https://developer.mozilla.org/en-US/docs/Web/API/URL\n- Node.js URL: https://nodejs.org/api/url.html#class-url\n\nExample:\n\n```ts\nimport * as URI from 'uri-js' // [!code --]\n\nURI.resolve('https://a/b/c/d?q', '../../g') // [!code --]\nnew URL('../../g', 'https://a/b/c/d?q').href // [!code ++]\n```\n\n> [!NOTE]\n> [WHATWG URL](https://url.spec.whatwg.org/) differs from [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) in some details and may not cover arbitrary custom schemes/URNs.\n\n## `uri-js-replace`\n\n[`uri-js-replace`](https://github.com/andreinwald/uri-js-replace) is a drop-in, zero-dependency replacement for `uri-js` with the same API and no deprecation warnings.\n\n```ts\nimport * as URI from 'uri-js' // [!code --]\nimport * as URI from 'uri-js-replace' // [!code ++]\n\nconst parsed = URI.parse('uri://user:pass@example.com:123/one/two?q=a#f')\nconst out = URI.serialize({\n scheme: 'http',\n host: 'example.com',\n fragment: 'footer'\n})\nconst norm = URI.normalize('URI://www.example.org/red%09ros\\xE9#red')\n```\n\n## `fast-uri`\n\n[`fast-uri`](https://github.com/fastify/fast-uri) is a zero-dependency, high-performance RFC 3986 URI toolbox (parse/serialize/resolve/equal) with options similar to `uri-js`.\n\n```ts\nimport * as uri from 'uri-js' // [!code --]\nimport * as uri from 'fast-uri' // [!code ++]\n\nuri.parse('uri://user:pass@example.com:123/one/two.three?q1=a1#a')\nuri.serialize({ scheme: 'http', host: 'example.com', fragment: 'footer' })\nuri.resolve('uri://a/b/c/d?q', '../../g')\nuri.equal('example://a/b/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d')\n```\n",
|
|
88
98
|
"shortid.md": "---\ndescription: Modern, secure alternatives to the shortid package for generating URL‑friendly unique IDs\n---\n\n# Replacements for `shortid`\n\n## `nanoid`\n\n[`nanoid`](https://github.com/ai/nanoid) is a tiny, secure, URL‑friendly, unique string ID generator. It’s also faster than [`shortid`](https://github.com/dylang/shortid).\n\n:::info Good to know before migration\n\n- `shortid.isValid(id)`: there’s no direct equivalent. Validate with a regex that matches your chosen alphabet and length, e.g. `/^[A-Za-z0-9_-]{21}$/`.\n\n- `shortid.seed()`/`shortid.worker()`: not needed and not provided by `nanoid` (it uses a secure random source). Avoid seeded/deterministic IDs for security.\n\n:::\n\n### Basic migration\n\n```ts\nimport shortid from 'shortid' // [!code --]\nimport { nanoid } from 'nanoid' // [!code ++]\n\nconst id = shortid.generate() // [!code --]\nconst id = nanoid() // [!code ++] => \"V1StGXR8_Z5jdHi6B-myT\"\n```\n\n### Control length\n\n```ts\n// shortid produced ~7-14 chars; with nanoid you pick the size explicitly:\nnanoid(10) // e.g., \"NG3oYbq9qE\"\n```\n\n### Custom alphabet (replacement for `shortid.characters`)\n\n<!-- eslint-skip -->\n<!-- prettier-ignore -->\n```ts\nshortid.characters('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$@') // [!code --]\nimport { customAlphabet } from 'nanoid' // [!code ++]\n\nconst alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$@' // [!code ++]\nconst makeId = customAlphabet(alphabet, 12) // [!code ++]\nconst id = makeId() // [!code ++]\n```\n",
|
|
89
|
-
"
|
|
90
|
-
"traverse.md": "---\ndescription: Modern alternative to the traverse package to traverse and transform objects by visiting every node on a recursive walk\n---\n\n# Replacements for `traverse`\n\n## `neotraverse`\n\n[`neotraverse`](https://github.com/puruvj/neotraverse) is a TypeScript rewrite of [`traverse`](https://github.com/ljharb/js-traverse) with no dependencies. It offers a drop‑in compatible build as well as a modern API.\n\n```ts\nimport traverse from 'traverse' // [!code --]\nimport traverse from 'neotraverse' // [!code ++]\n\nconst obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }]\n\ntraverse(obj).forEach(function (x) {\n if (x < 0) this.update(x + 128)\n})\n\nconsole.log(obj)\n```\n",
|
|
91
|
-
"wrap-ansi.md": "---\ndescription: Modern replacement for the wrap-ansi package for wrapping terminal strings (including ANSI-colored output)\n---\n\n# Replacements for `wrap-ansi`\n\n## `fast-wrap-ansi`\n\n[`fast-wrap-ansi`](https://github.com/43081j/fast-wrap-ansi) is a drop‑in replacement for `wrap-ansi` that’s faster and smaller.\n\n```ts\nimport wrapAnsi from 'wrap-ansi' // [!code --]\nimport wrapAnsi from 'fast-wrap-ansi' // [!code ++]\n\nconst value = '\\u001B[36mhello-super-long-token-without-spaces\\u001B[39m'\n\nconsole.log(wrapAnsi(value, 12, { hard: true, trim: false }))\n```\n",
|
|
92
|
-
"tsc.md": "---\ndescription: Modern alternatives to the tsc package for the TypeScript compiler\n---\n\n# Replacements for `tsc`\n\nThe npm package [`tsc`](https://github.com/basarat/tsc) is **not** the TypeScript compiler — it is a deprecated stub that prints _\"This is not the tsc command you are looking for\"_ when run.\n\n## `typescript`\n\nThe [`typescript`](https://github.com/microsoft/TypeScript) package is the official compiler and provides the real `tsc` binary via `node_modules/.bin`. Replace `tsc` in your dependencies:\n\n```json\n{\n \"devDependencies\": {\n \"tsc\": \"^2.0.4\", // [!code --]\n \"typescript\": \"^5.9.0\" // [!code ++]\n }\n}\n```\n\nExisting `\"build\": \"tsc\"` scripts work unchanged once `typescript` is installed. For `npx` or global installs, use `typescript` — not `tsc`:\n\n```bash\nnpx tsc --init # [!code --]\nnpx --package typescript tsc --init # [!code ++]\n\nnpm install -g tsc # [!code --]\nnpm install -g typescript # [!code ++]\n```\n",
|
|
93
|
-
"readable-stream.md": "---\ndescription: Modern alternatives to the readable-stream package for working with streaming data in Node.js\n---\n\n# Replacements for `readable-stream`\n\n[`readable-stream`](https://github.com/nodejs/readable-stream) mirrors Node’s core streams and works in browsers. In most cases, prefer native options.\n\n## `node:stream` (native, since Node.js v0.9.4)\n\nUse the built-in `stream` module ([Node Streams docs](https://nodejs.org/api/stream.html)).\n\n```ts\nimport { Duplex, Readable, Transform, Writable } from 'readable-stream' // [!code --]\nimport { Duplex, Readable, Transform, Writable } from 'node:stream' // [!code ++]\n```\n\n## Web Streams (native, browsers and Node.js 16.5.0+)\n\nUse the [Web Streams API (MDN)](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) in browsers and modern Node. It’s global in Node 18+ ([Node Web Streams docs](https://nodejs.org/api/webstreams.html)); on 16.5–17.x import from `stream/web` ([details](https://nodejs.org/api/webstreams.html#streamweb-the-web-streams-api)). Interop with Node streams is available via [Readable.toWeb](https://nodejs.org/api/stream.html#streamreadabletowebstreamreadable-options) and [Writable.fromWeb](https://nodejs.org/api/stream.html#streamwritablefromwebwritablestream-options).\n\nExample: convert a Web ReadableStream (from fetch) to a Node stream and pipe it to a file.\n\n```ts\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { createWriteStream } from 'node:fs'\n\nconst res = await fetch('https://example.com/data.txt') // Web ReadableStream\nconst nodeReadable = Readable.fromWeb(res.body)\nawait pipeline(nodeReadable, createWriteStream('data.txt'))\n```\n",
|
|
94
|
-
"stream-buffers.md": "---\ndescription: Modern alternatives to the stream-buffers package for buffering and generating streams in Node.js\n---\n\n# Replacements for `stream-buffers`\n\n## Utility Consumers (native, Node.js)\n\nSince Node.js ≥ 16.7.0 [Utility Consumers](https://nodejs.org/api/webstreams.html#webstreams_utility_consumers) let you consume a Readable stream fully into memory (`Buffer`/`string`/`JSON`/`Blob`/`ArrayBuffer`).\n\nExample:\n\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { pipeline } from 'node:stream/promises' // [!code --]\nimport { buffer } from 'node:stream/consumers' // [!code ++]\n\nconst sink = new streamBuffers.WritableStreamBuffer() // [!code --]\nawait pipeline(readable, sink) // [!code --]\n\nconst out = sink.getContents() // [!code --]\nconst out = await buffer(readable) // [!code ++]\n```\n\nCapturing output when an API expects a Writable example:\n\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { PassThrough } from 'node:stream' // [!code ++]\nimport { buffer, text } from 'node:stream/consumers' // [!code ++]\n\nconst sink = new streamBuffers.WritableStreamBuffer() // [!code --]\nconst sink = new PassThrough() // [!code ++]\n\nconst outPromise = buffer(sink) // [!code ++]\nawait someFnThatWritesTo(sink)\nconst out = sink.getContents() // [!code --]\nsink.end() // [!code ++]\nconst out = await outPromise // [!code ++]\n```\n\nPush data over time example:\n\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { Readable } from 'node:stream' // [!code ++]\n\nconst rs = new streamBuffers.ReadableStreamBuffer() // [!code --]\nconst rs = new Readable({ read() {} }) // [!code ++]\n\nrs.put('first chunk') // [!code --]\nrs.push('first chunk') // [!code ++]\n\nrs.put(Buffer.from('second chunk')) // [!code --]\nrs.push(Buffer.from('second chunk')) // [!code ++]\n\nrs.stop() // [!code --]\nrs.push(null) // [!code ++]\n```\n\nControl chunk size and frequency example:\n\n<!-- prettier-ignore -->\n```ts\nimport streamBuffers from 'stream-buffers' // [!code --]\nimport { Readable } from 'node:stream' // [!code ++]\nimport { setTimeout } from 'node:timers/promises' // [!code ++]\n\nconst data = Buffer.from('...your data...')\nconst frequencyMs = 10\nconst chunkSize = 2048\n\nconst rs = new streamBuffers.ReadableStreamBuffer({ frequency: frequencyMs, chunkSize: chunkSize }) // [!code --]\nrs.put(data) // [!code --]\nrs.stop() // [!code --]\n\nconst rs = Readable.from(async function* () { // [!code ++]\n for (let i = 0; i < data.length; i += chunkSize) { // [!code ++]\n yield data.slice(i, i + chunkSize) // [!code ++]\n await setTimeout(frequencyMs) // [!code ++]\n } // [!code ++]\n}()) // [!code ++]\n```\n",
|
|
95
|
-
"utf8.md": "---\ndescription: Modern alternatives to the utf8 package for UTF-8 encoding and decoding\n---\n\n# Replacements for `utf8`\n\nModern Node and browsers provide native UTF-8 APIs, so this dependency is rarely needed.\n\n## TextEncoder/TextDecoder (native)\n\nThe built-in [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) and [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) APIs provide a native way to handle UTF-8 encoding and decoding.\n\n```ts\nconst text = '€'\nconst encoder = new TextEncoder()\nconst utf8Bytes = encoder.encode(text) // Uint8Array of UTF-8 bytes\n\n// and to decode:\n\nconst decoder = new TextDecoder('utf-8', { fatal: true })\nconst decodedText = decoder.decode(utf8Bytes) // \"€\"\n```\n\n## Buffer (native)\n\nNode's built-in [`Buffer`](https://nodejs.org/api/buffer.html) provides both `Buffer.from(str, 'utf8')` and `buf.toString('utf8')` methods for UTF-8 encoding and decoding.\n\n```ts\nimport { Buffer } from 'node:buffer'\n\nconst text = '€'\nconst utf8Buffer = Buffer.from(text, 'utf8') // Buffer of UTF-8 bytes\n```\n",
|
|
96
|
-
"wellknown.md": "---\ndescription: Modern replacements for the wellknown package, a WKT parser and stringifier\n---\n\n# Replacements for `wellknown`\n\n## `betterknown`\n\n[`betterknown`](https://github.com/placemark/betterknown) is a maintained alternative for `wellknown` package.\n\nExample:\n\n```js\nimport wellknown from 'wellknown' // [!code --]\nimport { wktToGeoJSON, geoJSONToWkt } from 'betterknown' // [!code ++]\n\nwellknown.parse('POINT(1 2)') // [!code --]\nwktToGeoJSON('POINT(1 2)') // [!code ++]\n\nwellknown.stringify({ // [!code --]\ngeoJSONToWkt({ // [!code ++]\n type: 'Point',\n coordinates: [1, 2]\n})\n\nwellknown.stringify({ // [!code --]\ngeoJSONToWkt({ // [!code ++]\n type: 'Feature',\n geometry: { type: 'Point', coordinates: [1, 2] },\n properties: {}\n})\n```\n",
|
|
97
|
-
"string-width.md": "---\ndescription: Modern alternatives to the string-width package for measuring the visual width of a string\n---\n\n# Replacements for `string-width`\n\n## `fast-string-width`\n\n[`fast-string-width`](https://github.com/fabiospampinato/fast-string-width) is a drop‑in replacement for `string-width` that’s faster and smaller.\n\n```ts\nimport stringWidth from 'string-width' // [!code --]\nimport stringWidth from 'fast-string-width' // [!code ++]\n\nconsole.log(stringWidth('abc')) // 3\nconsole.log(stringWidth('👩👩👧👦')) // 1\nconsole.log(stringWidth('\\u001B[31mhello\\u001B[39m')) // 5\n```\n\n## Bun API (native)\n\nIf you’re on Bun ≥ 1.0.29, you can use the built‑in [`stringWidth`](https://bun.com/reference/bun/stringWidth):\n\n```ts\nimport stringWidth from 'string-width' // [!code --]\nimport { stringWidth } from 'bun' // [!code ++]\n\nconsole.log(stringWidth('abc')) // 3\nconsole.log(stringWidth('👩👩👧👦')) // 1\nconsole.log(stringWidth('\\u001B[31mhello\\u001B[39m')) // 5\nconsole.log(\n stringWidth('\\u001B[31mhello\\u001B[39m', { countAnsiEscapeCodes: false })\n) // 5\n```\n",
|
|
98
|
-
"uuidv4.md": "---\ndescription: Native alternatives to the uuidv4 package for UUID v4 generation\n---\n\n# Replacements for `uuidv4`\n\n## `crypto.randomUUID` (native)\n\nYou can use [`crypto.randomUUID`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) for UUID v4 generation.\n\nExample:\n\n```ts\nconst uuid = crypto.randomUUID()\n```\n\nOr in Node.js via [`node:crypto`](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions):\n\n```ts\nimport * as crypto from 'node:crypto'\n\nconst uuid = crypto.randomUUID()\n```\n",
|
|
99
|
-
"sqlite3.md": "---\ndescription: Modern alternatives to the sqlite3 package for working with SQLite in Node.js\n---\n\n# Replacements for `sqlite3`\n\n## `node:sqlite` (native, since Node.js 22.13.0)\n\nNode.js ships a built-in SQLite module, [`node:sqlite`](https://nodejs.org/api/sqlite.html), which is the preferred option when you can target a recent Node runtime.\n\nExample:\n\n```ts\nimport sqlite3 from 'sqlite3' // [!code --]\nimport { DatabaseSync } from 'node:sqlite' // [!code ++]\n\nconst db = new sqlite3.Database('app.db') // [!code --]\nconst db = new DatabaseSync('app.db') // [!code ++]\n\ndb.all('SELECT * FROM users', (err, rows) => {}) // [!code --]\nconst rows = db.prepare('SELECT * FROM users').all() // [!code ++]\n```\n\n## `better-sqlite3`\n\n[`better-sqlite3`](https://github.com/WiseLibs/better-sqlite3) is a popular and actively maintained SQLite library for Node.js.\n\nExample:\n\n```ts\nimport sqlite3 from 'sqlite3' // [!code --]\nimport Database from 'better-sqlite3' // [!code ++]\n\nconst db = new sqlite3.Database('app.db') // [!code --]\nconst db = new Database('app.db') // [!code ++]\n\ndb.all('SELECT * FROM users', (err, rows) => {}) // [!code --]\nconst rows = db.prepare('SELECT * FROM users').all() // [!code ++]\n```\n",
|
|
99
|
+
"object-hash.md": "---\ndescription: Modern alternatives to object-hash for hashing objects and values\n---\n\n# Replacements for `object-hash`\n\n## `ohash`\n\n[`ohash`](https://github.com/unjs/ohash) is actively maintained and provides hashing, stable serialization, equality checks, and diffs. It uses stable serialization + SHA-256, returning Base64URL by default. Its serializer was originally based on `object-hash`.\n\nExample:\n\n```ts\nimport objectHash from 'object-hash' // [!code --]\nimport { hash } from 'ohash' // [!code ++]\n\nconst h = objectHash(obj) // [!code --]\nconst h = hash(obj) // [!code ++]\n```\n\n## Web Crypto\n\nUse the standard [`SubtleCrypto.digest`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest) available in modern runtimes. Pair it with a stable serializer (e.g., [`safe-stable-stringify`](https://github.com/BridgeAR/safe-stable-stringify)) to ensure deterministic key ordering.\n\nExample:\n\n```ts\nimport objectHash from 'object-hash' // [!code --]\nimport stringify from 'safe-stable-stringify' // [!code ++]\n\nconst h = objectHash(obj, { algorithm: 'sha256' }) // [!code --]\nconst data = new TextEncoder().encode(stringify(obj)) // [!code ++]\nconst buf = await crypto.subtle.digest('SHA-256', data) // [!code ++]\nconst h = Array.from(new Uint8Array(buf)) // [!code ++]\n .map((b) => b.toString(16).padStart(2, '0')) // [!code ++]\n .join('') // [!code ++]\n```\n\n## Bun `CryptoHasher`\n\nBun provides a native incremental hasher (e.g., SHA-256). Combine it with a stable serializer for object hashing. For fast non-crypto fingerprints, see [`Bun.hash`](https://bun.com/reference/bun/hash).\n\nDocs: https://bun.com/reference/bun/CryptoHasher\n\nExample:\n\n```ts\nimport objectHash from 'object-hash' // [!code --]\nimport stringify from 'safe-stable-stringify' // [!code ++]\n\nconst h = objectHash(obj, { algorithm: 'sha256' }) // [!code --]\nconst hasher = new CryptoHasher('sha256') // [!code ++]\nhasher.update(stringify(obj)) // [!code ++]\nconst h = hasher.digest('hex') // [!code ++]\n```\n",
|
|
100
100
|
"xmldom.md": "---\ndescription: Modern alternatives to the xmldom package for XML DOM parsing and serialization\n---\n\n# Replacements for `xmldom`\n\n## `@xmldom/xmldom`\n\n[`@xmldom/xmldom`](https://github.com/xmldom/xmldom) is the maintained fork of the original `xmldom`.\n\nFor example:\n\n```ts\nimport { DOMParser, XMLSerializer } from 'xmldom' // [!code --]\nimport { DOMParser, XMLSerializer } from '@xmldom/xmldom' // [!code ++]\n\nconst doc = new DOMParser().parseFromString(source, 'text/xml')\nconst xml = new XMLSerializer().serializeToString(doc)\n```\n\nCommonJS:\n\n```ts\nconst { DOMParser, XMLSerializer } = require('xmldom') // [!code --]\nconst { DOMParser, XMLSerializer } = require('@xmldom/xmldom') // [!code ++]\n```\n",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"read-package-up.md": "---\ndescription: Modern alternatives to the read-package-up package for reading package.json files up the directory tree\n---\n\n# Replacements for `read-package-up`\n\n## `pkg-types`\n\n[`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types.\n\nFor example:\n\n```ts\nimport { readPackageJSON } from 'pkg-types' // [!code ++]\nimport { readPackageUp } from 'read-package-up' // [!code --]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJson = await readPackageJSON() // [!code ++]\n```\n\nSimilarly, you can get hold of the path via `resolvePackageJSON`:\n\n```ts\nimport { resolvePackageJSON } from 'pkg-types'\n\nconst packageJsonPath = await resolvePackageJSON()\n```\n\n## `empathic`\n\n[`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards.\n\nIt can be combined with `node:fs` to read `package.json` files:\n\n```ts\nimport fs from 'node:fs/promises' // [!code ++]\nimport * as pkg from 'empathic' // [!code ++]\nimport { readPackageUp } from 'read-package-up' // [!code --]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJsonPath = pkg.up() // [!code ++]\nconst packageJson = packageJsonPath // [!code ++]\n ? JSON.parse(await readFile(packageJsonPath, 'utf8')) // [!code ++]\n : undefined // [!code ++]\n```\n\n> [!NOTE]\n> This is of course a more manual way to read the `package.json` file, so one of the other options may be more attractive.\n",
|
|
101
|
+
"sqlite3.md": "---\ndescription: Modern alternatives to the sqlite3 package for working with SQLite in Node.js\n---\n\n# Replacements for `sqlite3`\n\n## `node:sqlite` (native, since Node.js 22.13.0)\n\nNode.js ships a built-in SQLite module, [`node:sqlite`](https://nodejs.org/api/sqlite.html), which is the preferred option when you can target a recent Node runtime.\n\nExample:\n\n```ts\nimport sqlite3 from 'sqlite3' // [!code --]\nimport { DatabaseSync } from 'node:sqlite' // [!code ++]\n\nconst db = new sqlite3.Database('app.db') // [!code --]\nconst db = new DatabaseSync('app.db') // [!code ++]\n\ndb.all('SELECT * FROM users', (err, rows) => {}) // [!code --]\nconst rows = db.prepare('SELECT * FROM users').all() // [!code ++]\n```\n\n## `better-sqlite3`\n\n[`better-sqlite3`](https://github.com/WiseLibs/better-sqlite3) is a popular and actively maintained SQLite library for Node.js.\n\nExample:\n\n```ts\nimport sqlite3 from 'sqlite3' // [!code --]\nimport Database from 'better-sqlite3' // [!code ++]\n\nconst db = new sqlite3.Database('app.db') // [!code --]\nconst db = new Database('app.db') // [!code ++]\n\ndb.all('SELECT * FROM users', (err, rows) => {}) // [!code --]\nconst rows = db.prepare('SELECT * FROM users').all() // [!code ++]\n```\n",
|
|
102
|
+
"utf8.md": "---\ndescription: Modern alternatives to the utf8 package for UTF-8 encoding and decoding\n---\n\n# Replacements for `utf8`\n\nModern Node and browsers provide native UTF-8 APIs, so this dependency is rarely needed.\n\n## TextEncoder/TextDecoder (native)\n\nThe built-in [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) and [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) APIs provide a native way to handle UTF-8 encoding and decoding.\n\n```ts\nconst text = '€'\nconst encoder = new TextEncoder()\nconst utf8Bytes = encoder.encode(text) // Uint8Array of UTF-8 bytes\n\n// and to decode:\n\nconst decoder = new TextDecoder('utf-8', { fatal: true })\nconst decodedText = decoder.decode(utf8Bytes) // \"€\"\n```\n\n## Buffer (native)\n\nNode's built-in [`Buffer`](https://nodejs.org/api/buffer.html) provides both `Buffer.from(str, 'utf8')` and `buf.toString('utf8')` methods for UTF-8 encoding and decoding.\n\n```ts\nimport { Buffer } from 'node:buffer'\n\nconst text = '€'\nconst utf8Buffer = Buffer.from(text, 'utf8') // Buffer of UTF-8 bytes\n```\n",
|
|
104
103
|
"slice-ansi.md": "---\ndescription: Modern alternatives for the slice-ansi package for slicing terminal strings\n---\n\n# Replacements for `slice-ansi`\n\n## `fast-slice-ansi`\n\n[`fast-slice-ansi`](https://github.com/43081j/fast-slice-ansi) is a faster and smaller alternative to `slice-ansi` for slicing strings with ANSI escape codes.\n\n```ts\nimport sliceAnsi from 'slice-ansi' // [!code --]\nimport { sliceAnsi } from 'fast-slice-ansi' // [!code ++]\nimport { styleText } from 'node:util'\n\nconst value = `The quick ${styleText('red', 'brown fox')} jumped over the lazy dog`\n\nconsole.log(sliceAnsi(value, 10, 25))\n```\n",
|
|
105
|
-
"buffer-equal.md": "---\ndescription: Native Node.js alternatives to the buffer-equal package for buffer equality checks\n---\n\n# Replacements for `buffer-equal`\n\n## `Buffer#equals` (native)\n\nBuffers have an [`equals`](https://nodejs.org/api/buffer.html#bufequalsotherbuffer) method since Node v0.12.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufferEqual from 'buffer-equal' // [!code --]\n\nconst buf1 = Buffer.from('303')\nconst buf2 = Buffer.from('303')\n\nbufferEqual(buf1, buf2) // [!code --]\nbuf1.equals(buf2) // [!code ++]\n```\n",
|
|
106
|
-
"moment.md": "---\ndescription: Modern alternatives to moment.js for date manipulation and formatting\n---\n\n# Replacements for `Moment.js`\n\n## `day.js`\n\n[Day.js](https://github.com/iamkun/dayjs/) provides a similar API to Moment.js with a much smaller footprint.\n\nExample:\n\n```ts\nimport moment from 'moment' // [!code --]\nimport dayjs from 'dayjs' // [!code ++]\n\nconst now = moment() // [!code --]\nconst now = dayjs() // [!code ++]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = dayjs().format('YYYY-MM-DD') // [!code ++]\n```\n\n## `date-fns`\n\n[date-fns](https://github.com/date-fns/date-fns) offers tree-shakable functions for working with native JavaScript dates.\n\nExample:\n\n```ts\nimport moment from 'moment' // [!code --]\nimport { addDays, format, subWeeks } from 'date-fns' // [!code ++]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = format(new Date(), 'yyyy-MM-dd') // [!code ++]\n\nconst tomorrow = moment().add(1, 'day') // [!code --]\nconst tomorrow = addDays(new Date(), 1) // [!code ++]\n\nconst lastWeek = moment().subtract(1, 'week') // [!code --]\nconst lastWeek = subWeeks(new Date(), 1) // [!code ++]\n```\n\n## `luxon`\n\n[Luxon](https://github.com/moment/luxon) is created by a Moment.js maintainer and offers powerful internationalization support.\n\nExample:\n\n```ts\nimport moment from 'moment' // [!code --]\nimport { DateTime } from 'luxon' // [!code ++]\n\nconst now = moment() // [!code --]\nconst now = DateTime.now() // [!code ++]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = DateTime.now().toFormat('yyyy-MM-dd') // [!code ++]\n\nconst tomorrow = moment().add(1, 'day') // [!code --]\nconst tomorrow = DateTime.now().plus({ days: 1 }) // [!code ++]\n```\n\n## `Date` (native)\n\nFor simple use cases, native JavaScript [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) and [`Intl`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) APIs may be sufficient:\n\n<!-- prettier-ignore -->\n```ts\nimport moment from 'moment' // [!code --]\n\nconst formatted = moment().format('YYYY-MM-DD') // [!code --]\nconst formatted = new Date().toISOString().split('T')[0] // [!code ++]\n\nconst localized = moment().format('MMMM Do YYYY') // [!code --]\nconst localized = new Intl.DateTimeFormat('en-US', { // [!code ++]\n year: 'numeric', // [!code ++]\n month: 'long', // [!code ++]\n day: 'numeric' // [!code ++]\n}).format(new Date()) // [!code ++]\n```\n",
|
|
107
|
-
"read-pkg.md": "---\ndescription: Native Node.js alternatives to the read-pkg package for reading package.json files\n---\n\n# Replacements for `read-pkg`\n\n## `pkg-types`\n\n[`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types.\n\nFor example:\n\n```ts\nimport { readPackageJSON } from 'pkg-types' // [!code ++]\nimport { readPackage } from 'read-pkg' // [!code --]\n\nconst packageJson = await readPackage() // [!code --]\nconst packageJson = await readPackageJSON() // [!code ++]\n```\n\nYou may also specify a `cwd`:\n\n```ts\nimport { readPackageJSON } from 'pkg-types'\n\nconst packageJson = await readPackageJson({ cwd })\n```\n\n## Native `node:fs`\n\nYou can use `node:fs` to read a known `package.json`:\n\n```ts\nimport fs from 'node:fs/promises' // [!code ++]\nimport { readPackage } from 'read-pkg' // [!code --]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJson = JSON.parse(await readFile('./package.json', 'utf8')) // [!code ++]\n```\n\n> [!NOTE]\n> Using this approach, you will have to handle errors yourself (e.g. failure to read the file).\n",
|
|
108
|
-
"fast-glob.md": "---\ndescription: Modern alternatives to the fast-glob package for fast file system pattern matching\n---\n\n# Replacements for `fast-glob`\n\n## `tinyglobby`\n\n[`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) is a modern, lightweight alternative that provides similar functionality with better performance.\n\nExample:\n\n<!-- eslint-skip -->\n\n```ts\nimport fg from 'fast-glob' // [!code --]\nimport { glob } from 'tinyglobby' // [!code ++]\n\nconst files = await fg('**/*.ts', { // [!code --]\nconst files = await glob('**/*.ts', { // [!code ++]\n cwd: process.cwd(),\n ignore: ['**/node_modules/**'],\n expandDirectories: false // [!code ++]\n})\n```\n\nMost options from `fast-glob` have direct equivalents in `tinyglobby`. Check the [tinyglobby documentation](https://superchupu.dev/tinyglobby/migration) for the complete list of supported options.\n",
|
|
109
|
-
"builtin-modules.md": "---\ndescription: Native Node.js alternatives to the builtin-modules package for listing built-in modules\n---\n\n# Replacements for `builtin-modules`\n\n## `builtinModules` (native, since Node.js 6.x)\n\nFor getting the list of built-in modules, you can use [`builtinModules`](https://nodejs.org/api/module.html#modulebuiltinmodules):\n\n```ts\nimport builtinModulesList from 'builtin-modules' // [!code --]\nimport { builtinModules } from 'node:module' // [!code ++]\n\nbuiltinModulesList.includes('fs') // true [!code --]\nbuiltinModules.includes('fs') // true [!code ++]\n```\n",
|
|
110
|
-
"collection-map.md": "---\ndescription: Native alternatives to the collection-map package\n---\n\n# Replacements for `collection-map`\n\n## Objects\n\n<!-- prettier-ignore -->\n```js\nconst map = require('collection-map') // [!code --]\nconst data = { a: 'foo', b: 'bar', c: 'baz' }\n\n// Mapping values\nconst res = map(data, (item) => item) // [!code --]\nconst res = Object.values(data).map((item) => item) // [!code ++]\n\n// Mapping keys\nconst res = map(data, (item, key) => key) // [!code --]\nconst res = Object.keys(data).map((key) => key) // [!code ++]\n\n// Mapping keys and values\nconst res = map(data, (item, key) => fn(item, key)) // [!code --]\nconst res = Object.fromEntries( // [!code ++]\n Object.entries(data).map(([key, value]) => fn(value, key)) // [!code ++]\n) // [!code ++]\n```\n\n## Arrays\n\n```js\nconst map = require('collection-map') // [!code --]\nconst data = ['foo', 'bar', 'baz']\n\n// Mapping items\nconst res = map(data, (item) => item) // [!code --]\nconst res = data.map((item) => item) // [!code ++]\n\n// Mapping indices\nconst res = map(data, (item, index) => index) // [!code --]\nconst res = data.map((_, index) => index) // [!code ++]\n\n// Mapping items indices\nconst res = map(data, (item, index) => fn(item, index)) // [!code --]\nconst res = data.map((item, index) => fn(item, index)) // [!code ++]\n```\n\n## Property Strings\n\nWhen passing a string to extract a specific property, use a standard map with property access.\n\n```js\nconst map = require('collection-map') // [!code --]\n\nconst obj = {\n a: { aaa: 'one', bbb: 'four', ccc: 'seven' },\n b: { aaa: 'two', bbb: 'five', ccc: 'eight' },\n c: { aaa: 'three', bbb: 'six', ccc: 'nine' }\n}\n\n// Objects: Map values to property\nmap(obj, 'aaa') // [!code --]\nObject.values(obj).map((item) => item.aaa) // [!code ++]\n\n// Arrays: Map items to property\nconst array = [obj.a, obj.b, obj.c]\nmap(array, 'bbb') // [!code --]\narray.map((item) => item.bbb) // [!code ++]\n```\n\n## `thisArg` (Context)\n\nNative `.map()` supports a second argument for `thisArg`.\n\n<!-- prettier-ignore -->\n```js\nconst map = require('collection-map') // [!code --]\n\nconst array = ['a', 'b', 'c']\nconst ctx = { a: 'aaa', b: 'bbb', c: 'ccc' }\n\nconst res = map(array, function(item) { // [!code --]\nconst res = array.map(function(item) { // [!code ++]\n return this[item]\n}, ctx)\n```\n",
|
|
111
|
-
"graphviz.md": "---\ndescription: Modern alternatives to the graphviz package\n---\n\n# Replacements for `graphviz`\n\n## `ts-graphviz`\n\n[`ts-graphviz`](https://github.com/ts-graphviz/ts-graphviz) is an actively maintained graphviz implementation in pure TypeScript.\n\nExample:\n\n```ts\nimport {\n attribute as _,\n Digraph,\n Subgraph,\n Node,\n Edge,\n toDot\n} from 'ts-graphviz'\n\nconst G = new Digraph()\nconst A = new Subgraph('A')\nconst node1 = new Node('node1', {\n [_.color]: 'red'\n})\nconst node2 = new Node('node2', {\n [_.color]: 'blue'\n})\nconst edge = new Edge([node1, node2], {\n [_.label]: 'Edge Label',\n [_.color]: 'pink'\n})\nG.addSubgraph(A)\nA.addNode(node1)\nA.addNode(node2)\nA.addEdge(edge)\nconst dot = toDot(G)\n// digraph {\n// subgraph \"A\" {\n// \"node1\" [\n// color = \"red\",\n// ]\n// \"node2\" [\n// color = \"blue\",\n// ]\n// \"node1\" -> \"node2\" [\n// label = \"Edge Label\",\n// color = \"pink\",\n// ]\n// }\n// }\n```\n",
|
|
112
|
-
"http-proxy.md": "---\ndescription: Modern alternatives to the http-proxy package for HTTP and WebSocket proxying in Node.js\n---\n\n# Replacements for `http-proxy`\n\n[`http-proxy`](https://github.com/http-party/node-http-proxy) has not been maintained since 2020 and has known crashes, memory leaks, and socket issues on modern Node.js versions.\n\n## `httpxy`\n\n[`httpxy`](https://github.com/unjs/httpxy) is a maintained fork of `http-proxy` with critical upstream bug fixes, zero dependencies, and additional helpers such as `proxyFetch` and `proxyUpgrade`.\n\nExample:\n\n```ts\nimport httpProxy from 'http-proxy' // [!code --]\nimport { createProxyServer } from 'httpxy' // [!code ++]\nimport { createServer } from 'node:http'\n\nconst proxy = httpProxy.createProxyServer({}) // [!code --]\nconst proxy = createProxyServer({}) // [!code ++]\n\nconst server = createServer((req, res) => {\n proxy.web(req, res, { target: 'http://localhost:8080' }) // [!code --]\n proxy.web(req, res, { target: 'http://localhost:8080' }) // [!code ++]\n})\n\nserver.on('upgrade', (req, socket, head) => {\n proxy.ws(req, socket, head, { target: 'http://localhost:8080' }) // [!code --]\n proxy.ws(req, socket, { target: 'http://localhost:8080' }, head) // [!code ++]\n})\n```\n\n## `http-proxy-3`\n\n[`http-proxy-3`](https://github.com/sagemathinc/http-proxy-3) is a TypeScript rewrite with API compatibility, HTTP/2 support, and production use in Vite, JupyterHub, and CoCalc.\n\nExample:\n\n```ts\nimport httpProxy from 'http-proxy' // [!code --]\nimport { createProxyServer } from 'http-proxy-3' // [!code ++]\nimport { createServer } from 'node:http'\n\nconst proxy = httpProxy.createProxyServer({}) // [!code --]\nconst proxy = createProxyServer({}) // [!code ++]\n\nconst server = createServer((req, res) => {\n proxy.web(req, res, { target: 'http://localhost:8080' })\n})\n\nserver.on('upgrade', (req, socket, head) => {\n proxy.ws(req, socket, head, { target: 'http://localhost:8080' }) // [!code --]\n proxy.ws(req, socket, { target: 'http://localhost:8080' }, head) // [!code ++]\n})\n```\n",
|
|
113
|
-
"buffer-equal-constant-time.md": "---\ndescription: Native Node.js alternatives to the buffer-equal-constant-time package for safe buffer equality checks\n---\n\n# Replacements for `buffer-equal-constant-time`\n\n## `crypto.timingSafeEqual` (native)\n\nYou can use the [`timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b) function from the `node:crypto` module.\n\nExample:\n\n```ts\nimport { Buffer } from 'node:buffer'\nimport bufferEqual from 'buffer-equal-constant-time' // [!code --]\nimport * as crypto from 'node:crypto' // [!code ++]\n\nconst bufUser = Buffer.from('303')\nconst bufSecret = Buffer.from('303')\n\nbufferEqual(bufUser, bufSecret) // [!code --]\nbufUser.length === bufSecret.length // [!code ++]\n ? crypto.timingSafeEqual(bufUser, bufSecret) // [!code ++]\n : !crypto.timingSafeEqual(bufUser, bufUser) // [!code ++]\n```\n",
|
|
114
|
-
"portfinder.md": "---\ndescription: Modern alternatives to the portfinder package for finding an available port\n---\n\n# Replacements for `portfinder`\n\n## `get-port`\n\n[`get-port`](https://github.com/sindresorhus/get-port) is a lighter and more modern package for finding an available port.\n\nExample:\n\n```ts\nimport portfinder from 'portfinder' // [!code --]\nimport getPort from 'get-port' // [!code ++]\n\nconst port = await portfinder.getPortPromise() // [!code --]\nconst port = await getPort() // [!code ++]\n```\n",
|
|
115
|
-
"is-builtin-module.md": "---\ndescription: Native Node.js alternatives to the is-builtin-module package for checking built-in modules\n---\n\n# Replacements for `is-builtin-module`\n\n## `isBuiltin` (native, since Node.js 16.x)\n\nFor determining if a module is built-in or not, you can use [isBuiltin](https://nodejs.org/api/module.html#moduleisbuiltinmodulename):\n\n```ts\nimport { isBuiltin } from 'node:module' // [!code ++]\nimport isBuiltinModule from 'is-builtin-module' // [!code --]\n\nisBuiltin('fs') // true [!code ++]\nisBuiltinModule('fs') // true [!code --]\n```\n\n## `builtInModules` (native, since Node.js 6.x and 15.x)\n\nBefore Node.js 16.x, `isBuiltin` was not available, so you need to implement your own check using [builtinModules](https://nodejs.org/api/module.html#modulebuiltinmodules):\n\n<!-- prettier-ignore -->\n```ts\nimport { builtinModules } from 'node:module' // [!code ++]\nimport isBuiltinModule from 'is-builtin-module' // [!code --]\n\nfunction isBuiltin(moduleName) { // [!code ++]\n const name = moduleName.startsWith('node:') // [!code ++]\n ? moduleName.slice(5) // [!code ++]\n : moduleName // [!code ++]\n return builtinModules.includes(name) // [!code ++]\n} // [!code ++]\n\nisBuiltin('fs') // true [!code ++]\nisBuiltinModule('fs') // true [!code --]\n```\n",
|
|
116
|
-
"cpx.md": "---\ndescription: Modern alternatives to the cpx package for copying file globs with watch mode\n---\n\n# Replacements for `cpx`\n\n## `cpx2`\n\n[`cpx`](https://github.com/mysticatea/cpx) is unmaintained. [`cpx2`](https://github.com/bcomnes/cpx2) is an actively maintained fork that keeps the same CLI bin name (`cpx`), so it works as a drop-in replacement for CLI usage. For the Node API, switch your import to `cpx2`.\n\n```sh\nnpm i -D cpx # [!code --]\nnpm i -D cpx2 # [!code ++]\n\n# CLI stays the same (bin name is still \"cpx\")\ncpx \"src/**/*.{html,png,jpg}\" app --watch\n```\n\nNode API replacement:\n\n<!-- eslint-skip -->\n\n```ts\nconst cpx = require('cpx') // [!code --]\nconst cpx = require('cpx2') // [!code ++]\n\ncpx.copy('src/**/*.js', 'dist', (err) => {\n if (err) throw err\n})\n```\n",
|
|
117
104
|
"dotenv.md": "---\ndescription: Native Node.js alternatives to the dotenv package for loading and managing .env files in Node.js\n---\n\n# Replacements for `dotenv`\n\n## `--env-file` / `--env-file-if-exists` (native, Node.js)\n\n[`--env-file`](https://nodejs.org/dist/latest-v20.x/docs/api/cli.html#--env-fileconfig) (Node.js v20.6.0+) and [`--env-file-if-exists`](https://nodejs.org/docs/latest-v22.x/api/cli.html#--env-file-if-existsfile) (Node.js v22.9.0+) can be passed as command-line flags to load environment variables from a specified file.\n\n`--env-file` throws if the file is missing. If the file may be absent, use `--env-file-if-exists`.\n\n```bash\nnode --env-file=.env index.js\n```\n\nAlso supported by:\n\n- [tsx](https://github.com/privatenumber/tsx)\n- [Bun](https://bun.sh/docs/runtime/env#manually-specifying-env-files)\n- [Deno](https://docs.deno.com/runtime/reference/env_variables/#.env-file)\n\nRemove dotenv preload:\n\n```ts\nimport 'dotenv/config' // [!code --]\n// No import needed when using --env-file\n```\n\nRemove explicit dotenv config:\n\n```ts\nimport dotenv from 'dotenv' // [!code --]\n\ndotenv.config({ path: '.env' }) // [!code --]\n// No runtime configuration needed\n```\n\nIn package.json scripts:\n\n```json\n{\n \"scripts\": {\n \"start\": \"node index.js\", // [!code --]\n \"start\": \"node --env-file=.env index.js\" // [!code ++]\n }\n}\n```\n\n## Node.js `parseEnv`\n\n[`parseEnv`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilparseenvcontent) (Node.js v20.12.0+) can be used to parse a `.env` string into an object without loading it into `process.env`.\n\n```ts\nimport { parse } from 'dotenv' // [!code --]\nimport { parseEnv } from 'node:util' // [!code ++]\n\nconst envContent = '...'\n\nconst env = parse(envContent) // [!code --]\nconst env = parseEnv(envContent) // [!code ++]\n```\n\nIf the `.env` is a Node.js Buffer, convert it to a string first with `.toString()`.\n",
|
|
118
|
-
"
|
|
119
|
-
"
|
|
105
|
+
"source-map-explorer.md": "---\ndescription: Modern alternatives to the source-map-explorer package for exploring bundle sourcemaps\n---\n\n# Replacements for `source-map-explorer`\n\n## `rollup-plugin-visualizer`\n\n[`rollup-plugin-visualizer`](https://github.com/btd/rollup-plugin-visualizer) allows you to visualize rollup, rolldown, and vite bundles\n\n### Rollup (`rollup.config.js`)\n\n```js\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default {\n plugins: [\n // Keep it last.\n visualizer()\n ]\n}\n```\n\n### Rolldown (`rolldown.config.ts`)\n\n```js\nimport { defineConfig, type RolldownPlugin } from 'rolldown'\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default defineConfig({\n plugins: [visualizer() as RolldownPlugin]\n})\n```\n\n### Vite (`vite.config.js`)\n\n```js\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default {\n plugins: [visualizer()]\n}\n```\n\n### Vite + TypeScript (`vite.config.ts`)\n\n```ts\nimport { defineConfig, type PluginOption } from 'vite'\nimport { visualizer } from 'rollup-plugin-visualizer'\n\nexport default defineConfig({\n plugins: [visualizer() as PluginOption]\n})\n```\n\n## `sonda`\n\n[`sonda`](https://github.com/filipsobol/sonda) allows you to visualize vite, rollup, rolldown, esbuild, webpack, and rspack bundles\n\nExample:\n\n```js\nimport { defineConfig } from 'vite'\nimport Sonda from 'sonda/vite'\n\nexport default defineConfig({\n build: {\n sourcemap: true\n },\n plugins: [Sonda()]\n})\n```\n\nFor full docs check their [website](https://sonda.dev/getting-started).\n\n## `webpack-bundle-analyzer`\n\n[`webpack-bundle-analyzer`](https://github.com/webpack/webpack-bundle-analyzer) allows you to visualize webpack bundles\n\nExample:\n\n```js\nimport { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'\n\nmodule.exports = {\n plugins: [new BundleAnalyzerPlugin()]\n}\n```\n",
|
|
106
|
+
"readable-stream.md": "---\ndescription: Modern alternatives to the readable-stream package for working with streaming data in Node.js\n---\n\n# Replacements for `readable-stream`\n\n[`readable-stream`](https://github.com/nodejs/readable-stream) mirrors Node’s core streams and works in browsers. In most cases, prefer native options.\n\n## `node:stream` (native, since Node.js v0.9.4)\n\nUse the built-in `stream` module ([Node Streams docs](https://nodejs.org/api/stream.html)).\n\n```ts\nimport { Duplex, Readable, Transform, Writable } from 'readable-stream' // [!code --]\nimport { Duplex, Readable, Transform, Writable } from 'node:stream' // [!code ++]\n```\n\n## Web Streams (native, browsers and Node.js 16.5.0+)\n\nUse the [Web Streams API (MDN)](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) in browsers and modern Node. It’s global in Node 18+ ([Node Web Streams docs](https://nodejs.org/api/webstreams.html)); on 16.5–17.x import from `stream/web` ([details](https://nodejs.org/api/webstreams.html#streamweb-the-web-streams-api)). Interop with Node streams is available via [Readable.toWeb](https://nodejs.org/api/stream.html#streamreadabletowebstreamreadable-options) and [Writable.fromWeb](https://nodejs.org/api/stream.html#streamwritablefromwebwritablestream-options).\n\nExample: convert a Web ReadableStream (from fetch) to a Node stream and pipe it to a file.\n\n```ts\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { createWriteStream } from 'node:fs'\n\nconst res = await fetch('https://example.com/data.txt') // Web ReadableStream\nconst nodeReadable = Readable.fromWeb(res.body)\nawait pipeline(nodeReadable, createWriteStream('data.txt'))\n```\n",
|
|
107
|
+
"graphviz.md": "---\ndescription: Modern alternatives to the graphviz package\n---\n\n# Replacements for `graphviz`\n\n## `ts-graphviz`\n\n[`ts-graphviz`](https://github.com/ts-graphviz/ts-graphviz) is an actively maintained graphviz implementation in pure TypeScript.\n\nExample:\n\n```ts\nimport {\n attribute as _,\n Digraph,\n Subgraph,\n Node,\n Edge,\n toDot\n} from 'ts-graphviz'\n\nconst G = new Digraph()\nconst A = new Subgraph('A')\nconst node1 = new Node('node1', {\n [_.color]: 'red'\n})\nconst node2 = new Node('node2', {\n [_.color]: 'blue'\n})\nconst edge = new Edge([node1, node2], {\n [_.label]: 'Edge Label',\n [_.color]: 'pink'\n})\nG.addSubgraph(A)\nA.addNode(node1)\nA.addNode(node2)\nA.addEdge(edge)\nconst dot = toDot(G)\n// digraph {\n// subgraph \"A\" {\n// \"node1\" [\n// color = \"red\",\n// ]\n// \"node2\" [\n// color = \"blue\",\n// ]\n// \"node1\" -> \"node2\" [\n// label = \"Edge Label\",\n// color = \"pink\",\n// ]\n// }\n// }\n```\n",
|
|
108
|
+
"react-helmet.md": "---\ndescription: Modern alternatives to the react-helmet package\n---\n\n# Replacements for `react-helmet`\n\n## Support for Document Metadata (native, since React 19)\n\n[Support for Document Metadata](https://react.dev/blog/2024/12/05/react-19#support-for-metadata-tags) is available since React 19\n\nExample:\n\n```jsx\nfunction BlogPost({ post }) {\n return (\n <article>\n <h1>{post.title}</h1>\n <title>{post.title}</title>\n <meta name=\"keywords\" content={post.keywords} />\n <p>Eee equals em-see-squared...</p>\n </article>\n )\n}\n```\n\n## `react-helmet-async`\n\n[`react-helmet-async`](https://github.com/staylor/react-helmet-async) is a fork of `react-helmet`.\n\nExample:\n\n<!-- prettier-ignore -->\n```jsx\nimport { Helmet } from 'react-helmet' // [!code --]\nimport { Helmet, HelmetProvider } from 'react-helmet-async' // [!code ++]\n\nconst app = (\n <HelmetProvider> // [!code ++]\n <App>\n <Helmet>\n <title>Hello World</title>\n <link rel=\"canonical\" href=\"https://e18e.dev/\" />\n </Helmet>\n <h1>Hello World</h1>\n </App>\n </HelmetProvider> // [!code ++]\n)\n```\n",
|
|
109
|
+
"parseargs.md": "---\ndescription: Modern alternatives to CLI argument parsing packages using Node.js built-in util.parseArgs\n---\n\n# Replacements for argument parsers\n\n## `util.parseArgs` (native, since Node.js 16.x)\n\n[`util.parseArgs`](https://nodejs.org/api/util.html#utilparseargsconfig) is built into Node.js (since 18.3.0 and 16.17.0) and can replace many common CLI options parsing libraries.\n\nExample:\n\n```ts\nimport { parseArgs } from 'node:util'\n\nconst { values, positionals } = parseArgs({\n args: process.argv.slice(2),\n options: {\n force: { type: 'boolean', short: 'f' },\n output: { type: 'string', short: 'o' }\n },\n allowPositionals: true\n})\n```\n\n> [!NOTE]\n> `parseArgs` only supports `string` and `boolean` types. If you'd like to support stronger types, one of the other options may be a better fit.\n\n## `mri`\n\n[`mri`](https://github.com/lukeed/mri) is a minimalistic argument parser that supports both short and long options, as well as positional arguments.\n\nExample:\n\n```ts\nimport mri from 'mri'\n\nconst options = mri(process.argv.slice(2), {\n alias: {\n f: 'force',\n o: 'output'\n },\n boolean: ['force']\n})\n```\n\n## CLI builders\n\nIf you need a CLI builder, check the the [CLI builders page](https://e18e.dev/docs/replacements/cli-builders).\n",
|
|
110
|
+
"fast-glob.md": "---\ndescription: Modern alternatives to the fast-glob package for fast file system pattern matching\n---\n\n# Replacements for `fast-glob`\n\n## `tinyglobby`\n\n[`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) is a modern, lightweight alternative that provides similar functionality with better performance.\n\nExample:\n\n<!-- eslint-skip -->\n\n```ts\nimport fg from 'fast-glob' // [!code --]\nimport { glob } from 'tinyglobby' // [!code ++]\n\nconst files = await fg('**/*.ts', { // [!code --]\nconst files = await glob('**/*.ts', { // [!code ++]\n cwd: process.cwd(),\n ignore: ['**/node_modules/**'],\n expandDirectories: false // [!code ++]\n})\n```\n\nMost options from `fast-glob` have direct equivalents in `tinyglobby`. Check the [tinyglobby documentation](https://superchupu.dev/tinyglobby/migration) for the complete list of supported options.\n",
|
|
111
|
+
"invariant.md": "---\ndescription: Modern alternatives to the invariant package for runtime assertions\n---\n\n# Replacements for `invariant`\n\n## `tiny-invariant`\n\n[`tiny-invariant`](https://github.com/alexreardon/tiny-invariant) provides a similar API with zero dependencies.\n\nFor example:\n\n```ts\nimport invariant from 'invariant' // [!code --]\nimport invariant from 'tiny-invariant' // [!code ++]\n\ninvariant(ok, 'Hello %s, code %d', name, code) // [!code --]\ninvariant(ok, `Hello ${name}, code ${code}`) // [!code ++]\n```\n\nSimilarly, you can lazily compute messages to avoid unnecessary work:\n\n```ts\nimport invariant from 'invariant' // [!code --]\nimport invariant from 'tiny-invariant' // [!code ++]\n\ninvariant(value, getExpensiveMessage()) // [!code --]\ninvariant(value, () => getExpensiveMessage()) // [!code ++]\n```\n",
|
|
112
|
+
"eslint-plugin-eslint-comments.md": "---\ndescription: Modern alternatives to the eslint-plugin-eslint-comments package for ESLint comment linting\n---\n\n# Replacements for `eslint-plugin-eslint-comments`\n\n## `@eslint-community/eslint-plugin-eslint-comments`\n\n[`@eslint-community/eslint-plugin-eslint-comments`](https://github.com/eslint-community/eslint-plugin-eslint-comments) is the actively maintained successor with updated dependencies, flat config support, and continued development.\n\n```ts\nimport eslintComments from 'eslint-plugin-eslint-comments' // [!code --]\nimport commentsCommunity from '@eslint-community/eslint-plugin-eslint-comments/configs' // [!code ++]\n\nexport default [\n commentsCommunity.recommended, // [!code ++]\n {\n plugins: {\n 'eslint-comments': eslintComments // [!code --]\n },\n rules: {\n 'eslint-comments/no-unused-disable': 'error', // [!code --]\n '@eslint-community/eslint-comments/no-unused-disable': 'error' // [!code ++]\n }\n }\n]\n```\n\nIf you're using a legacy config format:\n\n```ts\nmodule.exports = {\n extends: [\n 'eslint:recommended',\n 'plugin:eslint-comments/recommended', // [!code --]\n 'plugin:@eslint-community/eslint-comments/recommended' // [!code ++]\n ],\n rules: {\n 'eslint-comments/no-unused-disable': 'error', // [!code --]\n '@eslint-community/eslint-comments/no-unused-disable': 'error' // [!code ++]\n }\n}\n```\n",
|
|
113
|
+
"depcheck.md": "---\ndescription: Modern alternatives to depcheck for analyzing project dependencies and unused code\n---\n\n# Replacements for `depcheck`\n\n## `knip`\n\n[knip](https://github.com/webpro-nl/knip) is a more actively maintained and feature-rich alternative to [`depcheck`](https://github.com/depcheck/depcheck). In most cases, knip works out of the box without any configuration - just run `npx knip`. For projects that need customization, you can create a configuration file.\n\nExample:\n\n```json\n{\n \"$schema\": \"https://unpkg.com/knip@5/schema.json\",\n \"ignoreDependencies\": [\"@types/*\", \"eslint-*\"]\n}\n```\n",
|
|
114
|
+
"tar-fs.md": "---\ndescription: Lighter alternative to the tar-fs package for packing and extracting tar archives on the filesystem\n---\n\n# Replacements for `tar-fs`\n\n## `modern-tar`\n\n[`tar-fs`](https://github.com/mafintosh/tar-fs) provides filesystem bindings on top of [`tar-stream`](https://github.com/mafintosh/tar-stream). [`modern-tar`](https://github.com/ayuhito/modern-tar) covers the same workflows through [`modern-tar/fs`](https://github.com/ayuhito/modern-tar), with zero dependencies and built-in TypeScript types.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport tar from 'tar-fs' // [!code --]\nimport { createReadStream, createWriteStream } from 'node:fs' // [!code ++]\nimport { packTar, unpackTar } from 'modern-tar/fs' // [!code ++]\nimport { pipeline } from 'node:stream/promises' // [!code ++]\n\ntar.pack('./my-directory').pipe(createWriteStream('my-tarball.tar')) // [!code --]\nawait pipeline(packTar('./my-directory'), createWriteStream('my-tarball.tar')) // [!code ++]\n\ncreateReadStream('my-other-tarball.tar').pipe( // [!code --]\n tar.extract('./my-other-directory') // [!code --]\n) // [!code --]\nawait pipeline( // [!code ++]\n createReadStream('my-other-tarball.tar'), // [!code ++]\n unpackTar('./my-other-directory') // [!code ++]\n) // [!code ++]\n```\n",
|
|
115
|
+
"split.md": "---\ndescription: Native Node.js alternatives to the split package for splitting stream by lines\n---\n\n# Replacements for `split`\n\n## `readline.createInterface` (native, since Node.js v6.6.0)\n\nThe [`readline.createInterface`](https://nodejs.org/api/readline.html#readlinecreateinterfaceoptions)\nmethod can be used to read a stream line by line, effectively replacing the functionality of the `split` package.\n\nExample:\n\n<!-- prettier-ignore -->\n```js\nimport split from 'split' // [!code --]\nimport { createInterface } from 'node:readline' // [!code ++]\nimport * as fs from 'node:fs'\n\nconst input = fs.createReadStream('file.txt')\n\nconst stream = input.pipe(split()) // [!code --]\nstream.on('data', (line) => { // [!code --]\n fn(line) // [!code --]\n}) // [!code --]\n\nconst lines = createInterface({ input, crlfDelay: Infinity }) // [!code ++]\n\nfor await (const line of lines) { // [!code ++]\n fn(line) // [!code ++]\n} // [!code ++]\n```\n",
|
|
116
|
+
"read-pkg.md": "---\ndescription: Native Node.js alternatives to the read-pkg package for reading package.json files\n---\n\n# Replacements for `read-pkg`\n\n## `pkg-types`\n\n[`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types.\n\nFor example:\n\n```ts\nimport { readPackageJSON } from 'pkg-types' // [!code ++]\nimport { readPackage } from 'read-pkg' // [!code --]\n\nconst packageJson = await readPackage() // [!code --]\nconst packageJson = await readPackageJSON() // [!code ++]\n```\n\nYou may also specify a `cwd`:\n\n```ts\nimport { readPackageJSON } from 'pkg-types'\n\nconst packageJson = await readPackageJson({ cwd })\n```\n\n## Native `node:fs`\n\nYou can use `node:fs` to read a known `package.json`:\n\n```ts\nimport fs from 'node:fs/promises' // [!code ++]\nimport { readPackage } from 'read-pkg' // [!code --]\n\nconst packageJson = await readPackageUp() // [!code --]\nconst packageJson = JSON.parse(await readFile('./package.json', 'utf8')) // [!code ++]\n```\n\n> [!NOTE]\n> Using this approach, you will have to handle errors yourself (e.g. failure to read the file).\n",
|
|
117
|
+
"extend.md": "---\ndescription: Native alternatives to the extend package for deep cloning and merging objects\n---\n\n# Replacements for `extend`\n\n## `structuredClone` (native)\n\nIf you only need to deep clone an object, you can use [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone):\n\n```ts\nimport extend from 'extend' // [!code --]\n\nextend(true, {}, config) // true [!code --]\nstructuredClone(config) // true [!code ++]\n```\n\n## Spread syntax\n\nIf you need to merge two shallow objects, you can use [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals):\n\n```ts\nconst obj1 = { foo: 'bar', x: 42 }\nconst obj2 = { bar: 'baz', y: 13 }\n\nconst mergedObj = { ...obj1, ...obj2 }\n```\n\n## `defu`\n\nIf you need to deep merge two objects, you can use [`defu`](https://github.com/unjs/defu):\n\n```ts\nimport { defu } from 'defu'\n\nconst options = defu(object, ...defaults)\n```\n",
|
|
118
|
+
"mkdirp.md": "---\ndescription: Modern alternatives to the mkdirp and make-dir packages for recursively creating directories in Node.js\n---\n\n# Replacements for `mkdirp` / `make-dir`\n\n## Recursive `fs.mkdir` (native, since Node.js v10.12.0)\n\nNode.js v10.12.0 and up supports the `recursive` option in the [`fs.mkdir`](https://nodejs.org/api/fs.html#fsmkdirpath-options-callback) function, which allows parent directories to be created automatically.\n\nExample migration from [`mkdirp`](https://github.com/isaacs/node-mkdirp):\n\n```ts\nimport { mkdirp } from 'mkdirp' // [!code --]\nimport { mkdir, mkdirSync } from 'node:fs' // [!code ++]\nimport { mkdir as mkdirAsync } from 'node:fs/promises' // [!code ++]\n\n// Async\nawait mkdirp('/tmp/foo/bar/baz') // [!code --]\nawait mkdirAsync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n\n// Sync\nmkdirp.sync('/tmp/foo/bar/baz') // [!code --]\nmkdirSync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n```\n\nExample migration from [`make-dir`](https://github.com/sindresorhus/make-dir):\n\n```ts\nimport { makeDirectory, makeDirectorySync } from 'make-dir' // [!code --]\nimport { mkdir, mkdirSync } from 'node:fs' // [!code ++]\nimport { mkdir as mkdirAsync } from 'node:fs/promises' // [!code ++]\n\n// Async\nawait makeDirectory('/tmp/foo/bar/baz') // [!code --]\nawait mkdirAsync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n\n// Sync\nmakeDirectorySync('/tmp/foo/bar/baz') // [!code --]\nmkdirSync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++]\n```\n"
|
|
120
119
|
}
|