├── .gitignore ├── .editorconfig ├── src ├── manifests-dir-cjs.cts ├── manifests-dir.ts ├── main.ts └── types.ts ├── .prettierrc.json ├── docs ├── templates │ └── module.md └── modules │ ├── buffer-equal.md │ ├── find-cache-dir.md │ ├── buffer-equals.md │ ├── core-util-is.md │ ├── find-cache-directory.md │ ├── faker.md │ ├── builtin-modules.md │ ├── md5.md │ ├── bluebird-q.md │ ├── buf-compare.md │ ├── find-pkg.md │ ├── depcheck.md │ ├── lodash-underscore.md │ ├── jquery.md │ ├── find-file-up.md │ ├── pkg-dir.md │ ├── materialize-css.md │ ├── traverse.md │ ├── xmldom.md │ ├── cpx.md │ ├── invariant.md │ ├── body-parser.md │ ├── fast-glob.md │ ├── lint-staged.md │ ├── jsx-ast-utils.md │ ├── ez-spawn.md │ ├── eslint-plugin-vitest.md │ ├── deep-equal.md │ ├── utf8.md │ ├── string-width.md │ ├── read-pkg.md │ ├── eslint-plugin-node.md │ ├── is-builtin-module.md │ ├── eslint-plugin-react.md │ ├── ora.md │ ├── path-exists.md │ ├── crypto-js.md │ ├── execa.md │ ├── eslint-plugin-eslint-comments.md │ ├── dotenv.md │ ├── js-yaml.md │ ├── read-pkg-up.md │ ├── read-package-up.md │ ├── mkdirp.md │ ├── globby.md │ ├── axios.md │ ├── shortid.md │ ├── emoji-regex.md │ ├── dot-prop.md │ ├── eslint-plugin-es.md │ ├── readable-stream.md │ ├── rimraf.md │ ├── npm-run-all.md │ ├── graphemer.md │ ├── tempy.md │ ├── glob.md │ ├── object-hash.md │ ├── eslint-plugin-import.md │ ├── uri-js.md │ ├── sort-object.md │ ├── strip-ansi.md │ ├── find-up.md │ ├── moment.md │ ├── README.md │ ├── qs.md │ ├── chalk.md │ └── fs-extra.md ├── scripts ├── validate-modules.js ├── update-manifests-dist-path.js ├── generate-schema.js ├── sort-manifests.js ├── validate-manifests.js ├── validate-module-list.js └── check-manifest-problems.js ├── tsconfig.json ├── .github └── workflows │ ├── main.yml │ └── publish.yml ├── LICENSE ├── package.json ├── README.md ├── manifest-schema.json └── manifests ├── micro-utilities.json └── native.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.tshy 3 | /dist 4 | /main.js 5 | *.swp 6 | /.idea 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_size = 2 6 | indent_style = space 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /src/manifests-dir-cjs.cts: -------------------------------------------------------------------------------- 1 | import * as path from 'node:path'; 2 | 3 | const currentDir = __dirname; 4 | export const manifestsDir = path.resolve(currentDir, '../manifests'); 5 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "printWidth": 80, 4 | "semi": true, 5 | "singleQuote": true, 6 | "tabWidth": 2, 7 | "trailingComma": "none", 8 | "useTabs": false, 9 | "arrowParens": "always" 10 | } 11 | -------------------------------------------------------------------------------- /docs/templates/module.md: -------------------------------------------------------------------------------- 1 | # {moduleName} 2 | 3 | {Optional description} 4 | 5 | ## Alternatives 6 | 7 | ### {Alternative package name} 8 | 9 | {Description of alternative package} 10 | 11 | [Project Page](https://github.com) 12 | 13 | [npm](https://npmjs.com) 14 | -------------------------------------------------------------------------------- /src/manifests-dir.ts: -------------------------------------------------------------------------------- 1 | import {fileURLToPath} from 'node:url'; 2 | import * as path from 'node:path'; 3 | 4 | // @ts-ignore filthy cjs/esm polyfill hacks so we can have import.meta 5 | const currentDir = fileURLToPath(new URL('.', import.meta.url)); 6 | export const manifestsDir = path.resolve(currentDir, '../manifests'); 7 | -------------------------------------------------------------------------------- /scripts/validate-modules.js: -------------------------------------------------------------------------------- 1 | import {validateModuleList} from './validate-module-list.js'; 2 | import {validateManifests} from './validate-manifests.js'; 3 | import {checkManifestsForProblems} from './check-manifest-problems.js'; 4 | 5 | await validateManifests(); 6 | await validateModuleList(); 7 | await checkManifestsForProblems(); 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "nodenext", 5 | "moduleResolution": "nodenext", 6 | "types": ["node"], 7 | "declaration": true, 8 | "isolatedModules": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "strict": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true 13 | }, 14 | "include": [ 15 | "src/**/*.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /docs/modules/buffer-equal.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the buffer-equal package for buffer equality checks 3 | --- 4 | 5 | # Replacements for `buffer-equal` 6 | 7 | ## `Buffer#equals` (native) 8 | 9 | Buffers have an `equals` method since Node 0.12. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { Buffer } from 'node:buffer' 15 | import bufferEqual from 'buffer-equal' // [!code --] 16 | 17 | const buf1 = Buffer.from('303') 18 | const buf2 = Buffer.from('303') 19 | 20 | bufferEqual(buf1, buf2) // [!code --] 21 | buf1.equals(buf2) // [!code ++] 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/modules/find-cache-dir.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the find-cache-dir package for locating cache directories 3 | --- 4 | 5 | # Replacements for `find-cache-dir` 6 | 7 | ## `empathic` 8 | 9 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 10 | 11 | Example: 12 | 13 | ```ts 14 | import * as pkg from 'empathic' // [!code ++] 15 | import findCacheDirectory from 'find-cache-dir' // [!code --] 16 | 17 | findCacheDirectory({ name: 'foo' }) // [!code --] 18 | pkg.cache('foo') // [!code ++] 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/modules/buffer-equals.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the buffer-equals package for buffer equality checks 3 | --- 4 | 5 | # Replacements for `buffer-equals` 6 | 7 | ## `Buffer#equals` (native) 8 | 9 | Buffers have an `equals` method since Node 0.12. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { Buffer } from 'node:buffer' 15 | import bufferEquals from 'buffer-equals' // [!code --] 16 | 17 | const buf1 = Buffer.from('303') 18 | const buf2 = Buffer.from('303') 19 | 20 | bufferEquals(buf1, buf2) // [!code --] 21 | buf1.equals(buf2) // [!code ++] 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/modules/core-util-is.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the core-util-is package 3 | --- 4 | 5 | # Replacements for `core-util-is` 6 | 7 | ## Node.js util 8 | 9 | [`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.) 10 | 11 | Example: 12 | 13 | ```ts 14 | import * as cui from 'core-util-is' // [!code --] 15 | import { types } from 'node:util' // [!code ++] 16 | 17 | const isDate = cui.isDate(value) // [!code --] 18 | const isDate = types.isDate(value) // [!code ++] 19 | ``` -------------------------------------------------------------------------------- /docs/modules/find-cache-directory.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the find-cache-directory package for locating cache directories 3 | --- 4 | 5 | # Replacements for `find-cache-directory` 6 | 7 | ## `empathic` 8 | 9 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 10 | 11 | Example: 12 | 13 | ```ts 14 | import * as pkg from 'empathic' // [!code ++] 15 | import findCacheDirectory from 'find-cache-directory' // [!code --] 16 | 17 | findCacheDirectory({ name: 'foo' }) // [!code --] 18 | pkg.cache('foo') // [!code ++] 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/modules/faker.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern replacements for the unmaintained faker package generating massive amounts of fake (but realistic) data 3 | --- 4 | 5 | # Replacements for `faker` 6 | 7 | ## `@faker-js/faker` 8 | 9 | [`@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. 10 | 11 | ```ts 12 | const faker = require('faker') // [!code --] 13 | const { faker } = require('@faker-js/faker') // [!code ++] 14 | 15 | faker.datatype.boolean() 16 | 17 | faker.image.avatar() 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/modules/builtin-modules.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the builtin-modules package for listing built-in modules 3 | --- 4 | 5 | # Replacements for `builtin-modules` 6 | 7 | ## Node.js (since 6.x) 8 | 9 | For getting the list of built-in modules, you can use [builtinModules](https://nodejs.org/api/module.html#modulebuiltinmodules): 10 | 11 | ```ts 12 | import builtinModulesList from 'builtin-modules' // [!code --] 13 | import { builtinModules } from 'node:module' // [!code ++] 14 | 15 | builtinModulesList.includes('fs') // true [!code --] 16 | builtinModules.includes('fs') // true [!code ++] 17 | ``` 18 | -------------------------------------------------------------------------------- /scripts/update-manifests-dist-path.js: -------------------------------------------------------------------------------- 1 | import {readFile, writeFile} from 'node:fs/promises'; 2 | import {fileURLToPath} from 'node:url'; 3 | import * as path from 'node:path'; 4 | 5 | const scriptDir = fileURLToPath(new URL('.', import.meta.url)); 6 | const distPath = path.resolve(scriptDir, '../dist'); 7 | const flavours = ['esm', 'commonjs']; 8 | 9 | for (const flavour of flavours) { 10 | const flavourPath = `${distPath}/${flavour}/manifests-dir.js`; 11 | const contents = await readFile(flavourPath, 'utf8'); 12 | await writeFile( 13 | flavourPath, 14 | contents.replaceAll('../manifests', '../../manifests') 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /docs/modules/md5.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the md5 package for MD5 hash generation 3 | --- 4 | 5 | # Replacements for `md5` 6 | 7 | ## `crypto` (native) 8 | 9 | If you're using the [`md5`](https://github.com/pvorb/node-md5) package, consider using a stronger algorithm where possible. If you must keep MD5 for compatibility, Node.js provides a native alternative via the `crypto` module. 10 | 11 | ```ts 12 | import crypto from 'node:crypto' // [!code ++] 13 | import md5 from 'md5' // [!code --] 14 | 15 | md5('message') // [!code --] 16 | crypto.createHash('md5').update('message').digest('hex') // [!code ++] 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/modules/bluebird-q.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the Bluebird and Q Promise libraries for async control flow in JavaScript 3 | --- 4 | 5 | # Replacements for `bluebird` / `q` 6 | 7 | ## `Promise` (native) 8 | 9 | [`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. 10 | 11 | ## NativeBird 12 | 13 | [`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. 14 | -------------------------------------------------------------------------------- /docs/modules/buf-compare.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the buf-compare package for buffer comparison 3 | --- 4 | 5 | # Replacements for `buf-compare` 6 | 7 | ## `Buffer.compare` (native) 8 | 9 | `Buffer.compare` is a native method which achieves the same result as `buf-compare`, available since Node v0.11.13. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { Buffer } from 'node:buffer' 15 | import bufCompare from 'buf-compare' // [!code --] 16 | 17 | const buf1 = Buffer.from('303') 18 | const buf2 = Buffer.from('808') 19 | 20 | bufCompare(buf1, buf2) // [!code --] 21 | Buffer.compare(buf1, buf2) // [!code ++] 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/modules/find-pkg.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the find-pkg package for finding package.json files 3 | --- 4 | 5 | # Replacements for `find-pkg` 6 | 7 | ## `empathic` 8 | 9 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 10 | 11 | The main difference is that `empathic` is _synchronous_, so you should no longer `await` the result. 12 | 13 | Example: 14 | 15 | ```ts 16 | import * as pkg from 'empathic/package' // [!code ++] 17 | import findPkg from 'find-pkg' // [!code --] 18 | 19 | await findPkg(path) // [!code --] 20 | pkg.up(path) // [!code ++] 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/modules/depcheck.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to depcheck for analyzing project dependencies and unused code 3 | --- 4 | 5 | # Replacements for `depcheck` 6 | 7 | ## `knip` 8 | 9 | [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. 10 | 11 | Example: 12 | 13 | ```json 14 | { 15 | "$schema": "https://unpkg.com/knip@5/schema.json", 16 | "ignoreDependencies": ["@types/*", "eslint-*"] 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/modules/lodash-underscore.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives for Lodash for array/object manipulation and common programming tasks 3 | --- 4 | 5 | # `lodash` / `underscore` 6 | 7 | ## You don’t (may not) need Lodash/Underscore 8 | 9 | Here you could read how to replace Lodash or Underscore in your project. 10 | 11 | [Website](https://you-dont-need.github.io/You-Dont-Need-Lodash-Underscore) 12 | 13 | ## es-toolkit 14 | 15 | [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. 16 | -------------------------------------------------------------------------------- /docs/modules/jquery.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the jQuery library for DOM traversal, events, and AJAX 3 | --- 4 | 5 | # Replacements for `jQuery` 6 | 7 | ## You might not need jQuery 8 | 9 | [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. 10 | 11 | ## You (Might) Don't Need jQuery 12 | 13 | [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. 14 | -------------------------------------------------------------------------------- /docs/modules/find-file-up.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the find-file-up package for finding files by walking up parent directories 3 | --- 4 | 5 | # Replacements for `find-file-up` 6 | 7 | ## `empathic` 8 | 9 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 10 | 11 | The main difference is that `empathic` is _synchronous_, so you should no longer `await` the result. 12 | 13 | Example: 14 | 15 | ```ts 16 | import * as find from 'empathic/find' // [!code ++] 17 | import findUp from 'find-file-up' // [!code --] 18 | 19 | await findUp('package.json', cwd) // [!code --] 20 | find.file('package.json', { cwd }) // [!code ++] 21 | ``` 22 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build & Test 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | node-version: [18.x, 20.x, 21.x] 14 | fail-fast: false 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | - name: Use Node v${{ matrix.node-version }} 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | - name: Install Dependencies 23 | run: npm ci 24 | - name: Build 25 | run: npm run build 26 | - name: Validate Files 27 | run: npm run test:validate 28 | -------------------------------------------------------------------------------- /docs/modules/pkg-dir.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the pkg-dir package for finding package root directories 3 | --- 4 | 5 | # Replacements for `pkg-dir` 6 | 7 | ## `empathic` 8 | 9 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 10 | 11 | The main difference is that `empathic` is _synchronous_, so you should no longer `await` the result. 12 | 13 | Example: 14 | 15 | ```ts 16 | import { dirname } from 'node:path' // [!code ++] 17 | import * as pkg from 'empathic/package' // [!code ++] 18 | import { packageDirectory } from 'pkg-dir' // [!code --] 19 | 20 | const dir = await packageDirectory() // [!code --] 21 | const dir = dirname(pkg.up()) // [!code ++] 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/modules/materialize-css.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to materialize-css (Materialize) and modern Material Design UI libraries 3 | --- 4 | 5 | # Replacements for `materialize-css` 6 | 7 | ## `@materializecss/materialize` 8 | 9 | [`@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. 10 | 11 | ## `@material/web` 12 | 13 | > [!NOTE] 14 | > The project is currently in maintenance mode pending new maintainers. 15 | 16 | Modern Web Components implementing Material Design 3. 17 | 18 | [Project Page](https://github.com/material-components/material-web) 19 | -------------------------------------------------------------------------------- /scripts/generate-schema.js: -------------------------------------------------------------------------------- 1 | import tsj from 'ts-json-schema-generator'; 2 | import {writeFile} from 'node:fs/promises'; 3 | import {fileURLToPath} from 'node:url'; 4 | import * as path from 'node:path'; 5 | 6 | const scriptDir = fileURLToPath(new URL('.', import.meta.url)); 7 | const schemaPath = path.resolve(scriptDir, '../manifest-schema.json'); 8 | const tsconfigPath = path.resolve(scriptDir, '../tsconfig.json'); 9 | const typesPath = path.resolve(scriptDir, '../src/types.ts'); 10 | 11 | const generator = tsj.createGenerator({ 12 | path: typesPath, 13 | tsconfig: tsconfigPath, 14 | type: 'ManifestModule', 15 | topRef: false 16 | }); 17 | 18 | const schema = generator.createSchema(); 19 | 20 | await writeFile(schemaPath, JSON.stringify(schema, null, 2)); 21 | -------------------------------------------------------------------------------- /docs/modules/traverse.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternative to the traverse package to traverse and transform objects by visiting every node on a recursive walk 3 | --- 4 | 5 | # Replacements for `traverse` 6 | 7 | ## `neotraverse` 8 | 9 | [`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. 10 | 11 | ```ts 12 | import traverse from 'traverse' // [!code --] 13 | import traverse from 'neotraverse' // [!code ++] 14 | 15 | const obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }] 16 | 17 | traverse(obj).forEach(function (x) { 18 | if (x < 0) this.update(x + 128) 19 | }) 20 | 21 | console.log(obj) 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/modules/xmldom.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the xmldom package for XML DOM parsing and serialization 3 | --- 4 | 5 | # Replacements for `xmldom` 6 | 7 | ## `@xmldom/xmldom` 8 | 9 | [`@xmldom/xmldom`](https://github.com/xmldom/xmldom) is the maintained fork of the original `xmldom`. 10 | 11 | For example: 12 | 13 | ```ts 14 | import { DOMParser, XMLSerializer } from 'xmldom' // [!code --] 15 | import { DOMParser, XMLSerializer } from '@xmldom/xmldom' // [!code ++] 16 | 17 | const doc = new DOMParser().parseFromString(source, 'text/xml') 18 | const xml = new XMLSerializer().serializeToString(doc) 19 | ``` 20 | 21 | CommonJS: 22 | 23 | ```ts 24 | const { DOMParser, XMLSerializer } = require('xmldom') // [!code --] 25 | const { DOMParser, XMLSerializer } = require('@xmldom/xmldom') // [!code ++] 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/modules/cpx.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the cpx package for copying file globs with watch mode 3 | --- 4 | 5 | # Replacements for `cpx` 6 | 7 | ## `cpx2` 8 | 9 | [`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`. 10 | 11 | ```sh 12 | npm i -D cpx # [!code --] 13 | npm i -D cpx2 # [!code ++] 14 | 15 | # CLI stays the same (bin name is still "cpx") 16 | cpx "src/**/*.{html,png,jpg}" app --watch 17 | ``` 18 | 19 | Node API replacement: 20 | 21 | 22 | ```ts 23 | const cpx = require('cpx') // [!code --] 24 | const cpx = require('cpx2') // [!code ++] 25 | 26 | cpx.copy("src/**/*.js", "dist", err => { 27 | if (err) throw err 28 | }) 29 | ``` 30 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {readFileSync} from 'node:fs'; 2 | import {ManifestModule} from './types.js'; 3 | import {manifestsDir} from './manifests-dir.js'; 4 | 5 | const nativeReplacements = JSON.parse( 6 | readFileSync(`${manifestsDir}/native.json`, 'utf8') 7 | ) as ManifestModule; 8 | const microUtilsReplacements = JSON.parse( 9 | readFileSync(`${manifestsDir}/micro-utilities.json`, 'utf8') 10 | ) as ManifestModule; 11 | const preferredReplacements = JSON.parse( 12 | readFileSync(`${manifestsDir}/preferred.json`, 'utf8') 13 | ) as ManifestModule; 14 | 15 | export * from './types.js'; 16 | 17 | export {nativeReplacements, microUtilsReplacements, preferredReplacements}; 18 | 19 | export const all: ManifestModule = { 20 | moduleReplacements: [ 21 | ...nativeReplacements.moduleReplacements, 22 | ...microUtilsReplacements.moduleReplacements, 23 | ...preferredReplacements.moduleReplacements 24 | ] 25 | }; 26 | -------------------------------------------------------------------------------- /scripts/sort-manifests.js: -------------------------------------------------------------------------------- 1 | import {readdir, readFile, writeFile} from 'node:fs/promises'; 2 | import {fileURLToPath} from 'node:url'; 3 | import * as path from 'node:path'; 4 | 5 | const scriptDir = fileURLToPath(new URL('.', import.meta.url)); 6 | const manifestsDir = path.resolve(scriptDir, '../manifests'); 7 | const manifests = await readdir(manifestsDir); 8 | 9 | for (const manifestName of manifests) { 10 | if (!manifestName.endsWith('.json')) { 11 | continue; 12 | } 13 | 14 | const manifestPath = path.join(manifestsDir, manifestName); 15 | const manifest = JSON.parse(await readFile(manifestPath, {encoding: 'utf8'})); 16 | manifest.moduleReplacements.sort((a, b) => { 17 | if (a.moduleName === b.moduleName) { 18 | return 0; 19 | } 20 | return a.moduleName > b.moduleName ? 1 : -1; 21 | }); 22 | 23 | await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8'); 24 | } 25 | -------------------------------------------------------------------------------- /docs/modules/invariant.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the invariant package for runtime assertions 3 | --- 4 | 5 | # Replacements for `invariant` 6 | 7 | ## `tiny-invariant` 8 | 9 | [`tiny-invariant`](https://github.com/alexreardon/tiny-invariant) provides a similar API with zero dependencies. 10 | 11 | For example: 12 | 13 | ```ts 14 | import invariant from 'invariant' // [!code --] 15 | import invariant from 'tiny-invariant' // [!code ++] 16 | 17 | invariant(ok, 'Hello %s, code %d', name, code) // [!code --] 18 | invariant(ok, `Hello ${name}, code ${code}`) // [!code ++] 19 | ``` 20 | 21 | Similarly, you can lazily compute messages to avoid unnecessary work: 22 | 23 | ```ts 24 | import invariant from 'invariant' // [!code --] 25 | import invariant from 'tiny-invariant' // [!code ++] 26 | 27 | invariant(value, getExpensiveMessage()) // [!code --] 28 | invariant(value, () => getExpensiveMessage()) // [!code ++] 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/modules/body-parser.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the body-parser package for parsing HTTP request bodies in Node.js servers 3 | --- 4 | 5 | # Replacements for `body-parser` 6 | 7 | ## `milliparsec` 8 | 9 | [`milliparsec`](https://github.com/tinyhttp/milliparsec) is a lightweight alternative to [`body-parser`](https://github.com/expressjs/body-parser) with a smaller footprint. 10 | 11 | Example: 12 | 13 | ```ts 14 | import bodyParser from 'body-parser' // [!code --] 15 | import { json, urlencoded } from 'milliparsec' // [!code ++] 16 | import express from 'express' 17 | 18 | const app = express() 19 | 20 | app.use(bodyParser.json()) // [!code --] 21 | app.use(bodyParser.urlencoded({ extended: true })) // [!code --] 22 | 23 | app.use(json()) // [!code ++] 24 | app.use(urlencoded()) // [!code ++] 25 | ``` 26 | 27 | For API differences and feature comparison, see the [migration.md](https://github.com/tinyhttp/milliparsec/blob/master/migration.md). 28 | -------------------------------------------------------------------------------- /docs/modules/fast-glob.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the fast-glob package for fast file system pattern matching 3 | --- 4 | 5 | # Replacements for `fast-glob` 6 | 7 | ## `tinyglobby` 8 | 9 | [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) is a modern, lightweight alternative that provides similar functionality with better performance. 10 | 11 | Example: 12 | 13 | 14 | ```ts 15 | import fg from 'fast-glob' // [!code --] 16 | import { glob } from 'tinyglobby' // [!code ++] 17 | 18 | const files = await fg('**/*.ts', { // [!code --] 19 | const files = await glob('**/*.ts', { // [!code ++] 20 | cwd: process.cwd(), 21 | ignore: ['**/node_modules/**'], 22 | expandDirectories: false // [!code ++] 23 | }) 24 | ``` 25 | 26 | Most 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. 27 | -------------------------------------------------------------------------------- /docs/modules/lint-staged.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to lint-staged for running commands on staged Git files 3 | --- 4 | 5 | # Replacements for `lint-staged` 6 | 7 | ## `nano-staged` 8 | 9 | [`nano-staged`](https://www.npmjs.com/package/nano-staged) is a tiny pre-commit runner for staged (and more) files; much smaller and faster than `lint-staged`, with a simple config. 10 | 11 | package.json config: 12 | 13 | 14 | ```json 15 | { 16 | "lint-staged": { // [!code --] 17 | "nano-staged": { // [!code ++] 18 | "*.{js,ts}": ["prettier --write"] 19 | }, 20 | } 21 | ``` 22 | 23 | > [!NOTE] 24 | > Differences to be aware of: 25 | > - `lint-staged` has advanced features like backup stashing, partial-staging handling, per-directory configs in monorepos, and detailed concurrency controls. 26 | > - `nano-staged` focuses on simplicity and speed. If you rely on `lint-staged`’s stash/partial-staging features, keep using `lint-staged`. 27 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | interface ModuleReplacementLike { 2 | type: string; 3 | moduleName: string; 4 | category?: string; 5 | } 6 | 7 | export interface DocumentedModuleReplacement extends ModuleReplacementLike { 8 | type: 'documented'; 9 | docPath: string; 10 | } 11 | 12 | export interface NativeModuleReplacement extends ModuleReplacementLike { 13 | type: 'native'; 14 | mdnPath: string; 15 | nodeVersion: string; 16 | replacement: string; 17 | } 18 | 19 | export interface SimpleModuleReplacement extends ModuleReplacementLike { 20 | type: 'simple'; 21 | replacement: string; 22 | } 23 | 24 | export interface NoModuleReplacement extends ModuleReplacementLike { 25 | type: 'none'; 26 | } 27 | 28 | export type ModuleReplacement = 29 | | DocumentedModuleReplacement 30 | | NativeModuleReplacement 31 | | SimpleModuleReplacement 32 | | NoModuleReplacement; 33 | 34 | export interface ManifestModule { 35 | moduleReplacements: ModuleReplacement[]; 36 | } 37 | -------------------------------------------------------------------------------- /docs/modules/jsx-ast-utils.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the jsx-ast-utils package for statically analyzing JSX ASTs 3 | --- 4 | 5 | # Replacements for `jsx-ast-utils` 6 | 7 | ## `jsx-ast-utils-x` 8 | 9 | [`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. 10 | 11 | ```ts 12 | import { hasProp } from 'jsx-ast-utils' // [!code --] 13 | import { hasProp } from 'jsx-ast-utils-x' // [!code ++] 14 | 15 | import hasProp from 'jsx-ast-utils/hasProp' // [!code --] 16 | import hasProp from 'jsx-ast-utils-x/hasProp' // [!code ++] 17 | 18 | module.exports = context => ({ 19 | JSXOpeningElement: (node) => { 20 | const onChange = hasProp(node.attributes, 'onChange') 21 | if (onChange) { 22 | context.report({ node, message: 'No onChange!' }) 23 | } 24 | }, 25 | }) 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/modules/ez-spawn.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the ez-spawn package for spawning child processes 3 | --- 4 | 5 | # Replacements for `@jsdevtools/ez-spawn` 6 | 7 | ## `tinyexec` 8 | 9 | `ez-spawn` accepts shell-like command strings, which `tinyexec` does not. 10 | 11 | For example: 12 | 13 | ```ts 14 | import ezSpawn from '@jsdevtools/ez-spawn' // [!code --] 15 | import { x } from 'tinyexec' // [!code ++] 16 | 17 | await ezSpawn.async('ls -l') // [!code --] 18 | await x('ls', ['-l']) // [!code ++] 19 | ``` 20 | 21 | Alternatively, you can use [`args-tokenizer`](https://github.com/TrySound/args-tokenizer/) to convert a shell string to a command and arguments: 22 | 23 | ```ts 24 | import ezSpawn from '@jsdevtools/ez-spawn' // [!code --] 25 | import { tokenizeArgs } from 'args-tokenizer' // [!code ++] 26 | import { x } from 'tinyexec' // [!code ++] 27 | 28 | const [command, ...args] = tokenizeArgs('ls -l') // [!code ++] 29 | await ezSpawn.async('ls -l') // [!code --] 30 | await x(command, args) // [!code ++] 31 | ``` 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 James Garbutt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/modules/eslint-plugin-vitest.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the eslint-plugin-vitest package for Vitest-specific linting rules 3 | --- 4 | 5 | # Replacements for `eslint-plugin-vitest` 6 | 7 | ## `@vitest/eslint-plugin` 8 | 9 | [`@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). 10 | 11 | ```ts 12 | import vitest from '@vitest/eslint-plugin' // [!code ++] 13 | import vitest from 'eslint-plugin-vitest' // [!code --] 14 | 15 | export default [ 16 | { 17 | files: ['tests/**'], // or any other pattern 18 | plugins: { 19 | vitest, 20 | }, 21 | rules: { 22 | ...vitest.configs.recommended.rules, // you can also use vitest.configs.all.rules to enable all rules 23 | 'vitest/max-nested-describe': ['error', { max: 3 }], // you can also modify rules' behavior using option like this 24 | }, 25 | }, 26 | ] 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/modules/deep-equal.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the deep-equal package for deep object comparison 3 | --- 4 | 5 | # Replacements for `deep-equal` 6 | 7 | ## `dequal` 8 | 9 | [`dequal`](https://www.npmjs.com/package/dequal) has the same simple API as deep equal. 10 | 11 | Example: 12 | 13 | ```ts 14 | import equal from 'deep-equal' // [!code --] 15 | import dequal from 'dequal' // [!code ++] 16 | 17 | const a = { foo: 'bar' } 18 | const b = { foo: 'bar' } 19 | 20 | equal(a, b) // true [!code --] 21 | dequal(a, b) // true [!code ++] 22 | ``` 23 | 24 | ## `fast-deep-equal` 25 | 26 | [`fast-deep-equal`](https://www.npmjs.com/package/fast-deep-equal) again has the same API shape. 27 | 28 | Example: 29 | 30 | ```ts 31 | import deepEqual from 'deep-equal' // [!code --] 32 | import fastDeepEqual from 'fast-deep-equal' // [!code ++] 33 | 34 | const a = { foo: 'bar' } 35 | const b = { foo: 'bar' } 36 | 37 | deepEqual(a, b) // true [!code --] 38 | fastDeepEqual(a, b) // true [!code ++] 39 | ``` 40 | 41 | > [!NOTE] 42 | > This library has a separate entrypoint for supporting Maps, Sets, etc. You can use `fast-deep-equal/es6` to support those types. 43 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish (npm) 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: 22 15 | - run: npm ci 16 | - run: npm run build 17 | - run: npm run test:validate 18 | 19 | publish-npm: 20 | needs: build 21 | runs-on: ubuntu-latest 22 | permissions: 23 | id-token: write 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: 22.x 29 | registry-url: 'https://registry.npmjs.org' 30 | cache: 'npm' 31 | - run: npm i -g npm@latest 32 | - run: npm ci 33 | - run: npm version ${TAG_NAME} --git-tag-version=false 34 | env: 35 | TAG_NAME: ${{ github.ref_name }} 36 | - run: npm publish --provenance --access public --tag next 37 | if: "github.event.release.prerelease" 38 | - run: npm publish --provenance --access public 39 | if: "!github.event.release.prerelease" 40 | -------------------------------------------------------------------------------- /docs/modules/utf8.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the utf8 package for UTF-8 encoding and decoding 3 | --- 4 | 5 | # Replacements for `utf8` 6 | 7 | Modern Node and browsers provide native UTF-8 APIs, so this dependency is rarely needed. 8 | 9 | ## TextEncoder/TextDecoder (built-in) 10 | 11 | The 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. 12 | 13 | ```ts 14 | const text = "€"; 15 | const encoder = new TextEncoder(); 16 | const utf8Bytes = encoder.encode(text); // Uint8Array of UTF-8 bytes 17 | 18 | // and to decode: 19 | 20 | const decoder = new TextDecoder('utf-8', { fatal: true }); 21 | const decodedText = decoder.decode(utf8Bytes); // "€" 22 | ``` 23 | 24 | ## Buffer (Node.js) 25 | 26 | Node'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. 27 | 28 | ```ts 29 | const text = "€"; 30 | const utf8Buffer = Buffer.from(text, 'utf8'); // Buffer of UTF-8 bytes 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/modules/string-width.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the string-width package for measuring the visual width of a string 3 | --- 4 | 5 | # Replacements for `string-width` 6 | 7 | ## `fast-string-width` 8 | 9 | [`fast-string-width`](https://github.com/fabiospampinato/fast-string-width) is a drop‑in replacement for `string-width` that’s faster and smaller. 10 | 11 | ```ts 12 | import stringWidth from 'string-width' // [!code --] 13 | import stringWidth from 'fast-string-width' // [!code ++] 14 | 15 | console.log(stringWidth('abc')) // 3 16 | console.log(stringWidth('👩‍👩‍👧‍👦')) // 1 17 | console.log(stringWidth('\u001B[31mhello\u001B[39m')) // 5 18 | ``` 19 | 20 | ## Bun API (native) 21 | 22 | If you’re on Bun ≥ 1.0.29, you can use the built‑in [`stringWidth`](https://bun.com/reference/bun/stringWidth): 23 | 24 | ```ts 25 | import stringWidth from 'string-width' // [!code --] 26 | import { stringWidth } from 'bun' // [!code ++] 27 | 28 | console.log(stringWidth('abc')) // 3 29 | console.log(stringWidth('👩‍👩‍👧‍👦')) // 1 30 | console.log(stringWidth('\u001B[31mhello\u001B[39m')) // 5 31 | console.log( 32 | stringWidth('\u001B[31mhello\u001B[39m', { countAnsiEscapeCodes: false }) 33 | ) // 5 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/modules/read-pkg.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the read-pkg package for reading package.json files 3 | --- 4 | 5 | # Replacements for `read-pkg` 6 | 7 | ## `pkg-types` 8 | 9 | [`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types. 10 | 11 | For example: 12 | 13 | ```ts 14 | import { readPackageJSON } from 'pkg-types' // [!code ++] 15 | import { readPackage } from 'read-pkg' // [!code --] 16 | 17 | const packageJson = await readPackage() // [!code --] 18 | const packageJson = await readPackageJSON() // [!code ++] 19 | ``` 20 | 21 | You may also specify a `cwd`: 22 | 23 | ```ts 24 | import { readPackageJSON } from 'pkg-types' 25 | 26 | const packageJson = await readPackageJson({ cwd }) 27 | ``` 28 | 29 | ## Native `node:fs` 30 | 31 | You can use `node:fs` to read a known `package.json`: 32 | 33 | ```ts 34 | import fs from 'node:fs/promises' // [!code ++] 35 | import { readPackage } from 'read-pkg' // [!code --] 36 | 37 | const packageJson = await readPackageUp() // [!code --] 38 | const packageJson = JSON.parse(await readFile('./package.json', 'utf8')) // [!code ++] 39 | ``` 40 | 41 | > [!NOTE] 42 | > Using this approach, you will have to handle errors yourself (e.g. failure to read the file). 43 | -------------------------------------------------------------------------------- /scripts/validate-manifests.js: -------------------------------------------------------------------------------- 1 | import ajv from 'ajv'; 2 | import {readdir, readFile} from 'node:fs/promises'; 3 | import {fileURLToPath} from 'node:url'; 4 | import * as path from 'node:path'; 5 | 6 | const validator = new ajv(); 7 | const scriptDir = fileURLToPath(new URL('.', import.meta.url)); 8 | const manifestsDir = path.resolve(scriptDir, '../manifests'); 9 | const schemaPath = path.resolve(scriptDir, '../manifest-schema.json'); 10 | 11 | export async function validateManifests() { 12 | console.log('Validating manifests against JSON schema...'); 13 | const manifests = await readdir(manifestsDir); 14 | const schema = JSON.parse(await readFile(schemaPath, {encoding: 'utf8'})); 15 | const validate = validator.compile(schema); 16 | 17 | for (const manifestName of manifests) { 18 | if (!manifestName.endsWith('.json')) { 19 | continue; 20 | } 21 | 22 | const manifestPath = path.join(manifestsDir, manifestName); 23 | const manifest = JSON.parse( 24 | await readFile(manifestPath, {encoding: 'utf8'}) 25 | ); 26 | const isValid = validate(manifest); 27 | if (!isValid) { 28 | console.log(validate.errors); 29 | throw new Error(`Validation for ${manifestPath} failed!`); 30 | } 31 | } 32 | console.log('OK'); 33 | } 34 | -------------------------------------------------------------------------------- /docs/modules/eslint-plugin-node.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the eslint-plugin-node package for Node.js-specific linting rules 3 | --- 4 | 5 | # Replacements for `eslint-plugin-node` 6 | 7 | ## `eslint-plugin-n` 8 | 9 | [`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. 10 | 11 | ```ts 12 | import nPlugin from 'eslint-plugin-n' // [!code ++] 13 | import nodePlugin from 'eslint-plugin-node' // [!code --] 14 | 15 | export default [ 16 | { 17 | files: ['**/*.js'], // or any other pattern 18 | plugins: { 19 | node: nodePlugin, // [!code --] 20 | n: nPlugin, // [!code ++] 21 | }, 22 | rules: { 23 | ...nodePlugin.configs['recommended-script'].rules, // [!code --] 24 | ...nPlugin.configs['recommended-script'].rules, // [!code ++] 25 | 'node/exports-style': ['error', 'module.exports'], // [!code --] 26 | 'n/exports-style': ['error', 'module.exports'], // [!code ++] 27 | }, 28 | }, 29 | ] 30 | ``` 31 | 32 | If you're using a legacy config format: 33 | 34 | ```ts 35 | module.exports = { 36 | extends: [ 37 | 'eslint:recommended', 38 | 'plugin:node/recommended', // [!code --] 39 | 'plugin:n/recommended', // [!code ++] 40 | ], 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/modules/is-builtin-module.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the is-builtin-module package for checking built-in modules 3 | --- 4 | 5 | # Replacements for `is-builtin-module` 6 | 7 | ## Node.js (since 16.x) 8 | 9 | For determining if a module is built-in or not, you can use [isBuiltin](https://nodejs.org/api/module.html#moduleisbuiltinmodulename): 10 | 11 | ```ts 12 | import { isBuiltin } from 'node:module' // [!code ++] 13 | import isBuiltinModule from 'is-builtin-module' // [!code --] 14 | 15 | isBuiltin('fs') // true [!code ++] 16 | isBuiltinModule('fs') // true [!code --] 17 | ``` 18 | 19 | ## Node.js 6.x to 15.x 20 | 21 | Before 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): 22 | 23 | ```ts 24 | import { builtinModules } from 'node:module' // [!code ++] 25 | import isBuiltinModule from 'is-builtin-module' // [!code --] 26 | 27 | function isBuiltin(moduleName) { // [!code ++] 28 | const name = moduleName.startsWith('node:') // [!code ++] 29 | ? moduleName.slice(5) // [!code ++] 30 | : moduleName // [!code ++] 31 | 32 | return builtinModules.includes(name) // [!code ++] 33 | } // [!code ++] 34 | 35 | isBuiltin('fs') // true [!code ++] 36 | isBuiltinModule('fs') // true [!code --] 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/modules/eslint-plugin-react.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the eslint-plugin-react package for React/JSX-specific linting rules 3 | --- 4 | 5 | # Replacements for `eslint-plugin-react` 6 | 7 | ## `@eslint-react/eslint-plugin` 8 | 9 | [`@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. 10 | 11 | Flat config example: 12 | 13 | ```ts 14 | import eslintReact from '@eslint-react/eslint-plugin' // [!code ++] 15 | import reactPlugin from 'eslint-plugin-react' // [!code --] 16 | 17 | export default [ 18 | { 19 | files: ['**/*.{jsx,tsx}'], 20 | plugins: { 21 | 'react': reactPlugin, // [!code --] 22 | '@eslint-react': eslintReact, // [!code ++] 23 | }, 24 | rules: { 25 | ...reactPlugin.configs.recommended.rules, // [!code --] 26 | ...eslintReact.configs.recommended.rules, // [!code ++] 27 | 28 | 'react/no-unknown-property': 'error', // [!code --] 29 | '@eslint-react/dom/no-unknown-property': 'error', // [!code ++] 30 | }, 31 | }, 32 | ] 33 | ``` 34 | 35 | > [!NOTE] 36 | > `@eslint-react/eslint-plugin` is not a drop‑in replacement. Use [their migration guide](https://eslint-react.xyz/docs/migration) to map rules/options and automate changes where possible. 37 | -------------------------------------------------------------------------------- /docs/modules/ora.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the ora package for displaying elegant terminal spinners with status indicators 3 | --- 4 | 5 | # Replacements for `ora` 6 | 7 | ## `nanospinner` 8 | 9 | [`nanospinner`](https://github.com/usmanyunusov/nanospinner) provides simple start/success/error/warning methods with one dependency (`picocolors`). 10 | 11 | ```ts 12 | import ora from 'ora' // [!code --] 13 | import { createSpinner } from 'nanospinner' // [!code ++] 14 | 15 | const spinner = ora('Loading...').start() // [!code --] 16 | const spinner = createSpinner('Loading...').start() // [!code ++] 17 | 18 | spinner.succeed('Done!') // [!code --] 19 | spinner.success('Done!') // [!code ++] 20 | 21 | spinner.fail('Error!') // [!code --] 22 | spinner.error('Error!') // [!code ++] 23 | ``` 24 | 25 | ## `picospinner` 26 | 27 | [`picospinner`](https://github.com/tinylibs/picospinner) has zero dependencies with support for custom symbols, frames, and colors through Node.js built-in styling. 28 | 29 | ```ts 30 | import ora from 'ora' // [!code --] 31 | import { Spinner } from 'picospinner' // [!code ++] 32 | 33 | const spinner = ora('Loading...').start() // [!code --] 34 | const spinner = new Spinner('Loading...') // [!code ++] 35 | spinner.start() // [!code ++] 36 | ``` 37 | 38 | If you want to customize the color of the spinner, you can specify this when creating an instance: 39 | 40 | ```ts 41 | const spinner = new Spinner('Loading...', { colors: { spinner: 'yellow' } }) 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/modules/path-exists.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the path-exists package for checking if a path exists 3 | --- 4 | 5 | # Replacements for `path-exists` 6 | 7 | ## Node.js (async) 8 | 9 | Use [`fs/promises.access`](https://nodejs.org/docs/latest/api/fs.html#fspromisesaccesspath-mode) and return a boolean. 10 | 11 | ```ts 12 | import pathExists from 'path-exists' // [!code --] 13 | import { access } from 'node:fs/promises' // [!code ++] 14 | 15 | const exists = await pathExists('/etc/passwd') // [!code --] 16 | const exists = await access('/etc/passwd').then(() => true, () => false) // [!code ++] 17 | ``` 18 | 19 | ## Node.js (sync) 20 | 21 | Added in v0.1.21: synchronous path/file existence check via [`fs.existsSync`](https://nodejs.org/docs/latest/api/fs.html#fsexistssyncpath). 22 | 23 | ```ts 24 | import pathExists from 'path-exists' // [!code --] 25 | import { existsSync } from 'node:fs' // [!code ++] 26 | 27 | if (await pathExists('/etc/passwd')) // [!code --] 28 | if (existsSync('/etc/passwd')) // [!code ++] 29 | console.log('The path exists.') 30 | ``` 31 | 32 | ## Bun 33 | 34 | [`Bun.file()`](https://bun.sh/reference/bun/BunFile) returns a BunFile with an `.exists()` method. 35 | 36 | ```ts 37 | import pathExists from 'path-exists' // [!code --] 38 | 39 | const path = '/path/to/package.json' 40 | const exists = await pathExists(path) // [!code --] 41 | const file = Bun.file(path) // [!code ++] 42 | const exists = await file.exists() // boolean [!code ++] 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/modules/crypto-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the `crypto-js` package for cryptographic operations 3 | --- 4 | 5 | # Replacements for `crypto-js` 6 | 7 | `crypto-js` is no longer actively maintained and has been discontinued since engines now come with this functionality built-in. 8 | 9 | ## Node `node:crypto` (built-in) 10 | 11 | Node provides a [`node:crypto`](https://nodejs.org/api/crypto.html) module as part of its standard library. 12 | 13 | This supports hashes/HMAC, AES-GCM, PBKDF2/scrypt, RSA/ECDSA/Ed25519, and secure RNG. 14 | 15 | ```ts 16 | import sha256 from 'crypto-js/sha256'; // [!code --] 17 | import { createHash } from 'node:crypto'; // [!code ++] 18 | 19 | const secret = 'abcdefg'; 20 | const hash = sha256(secret).toString(); // [!code --] 21 | const hash = createHash('sha256') // [!code ++] 22 | .update(secret) // [!code ++] 23 | .digest('hex'); // [!code ++] 24 | ``` 25 | 26 | ## Web Crypto API (native) 27 | 28 | The [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. 29 | 30 | > [!NOTE] 31 | > A few legacy algorithms are intentionally omitted for security reasons (e.g. MD5). 32 | 33 | ## Bun (built-in) 34 | 35 | Bun supports the Web Crypto API natively, and also provides support for streaming hashing via [`Bun.CryptoHasher`](https://bun.sh/docs/api/hashing). 36 | 37 | As with the Web Crypto API, many legacy algorithms are intentionally omitted for security reasons (e.g. MD5). 38 | -------------------------------------------------------------------------------- /docs/modules/execa.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the execa package for running child processes 3 | --- 4 | 5 | # Replacements for `execa` 6 | 7 | ## `tinyexec` 8 | 9 | [`tinyexec`](https://github.com/tinylibs/tinyexec) is a minimal process execution library. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { execa } from 'execa' // [!code --] 15 | import { x } from 'tinyexec' // [!code ++] 16 | 17 | const { stdout } = await execa('ls', ['-l']) // [!code --] 18 | const { stdout } = await x('ls', ['-l'], { throwOnError: true }) // [!code ++] 19 | ``` 20 | 21 | ## `nanoexec` 22 | 23 | If 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. 24 | 25 | Example: 26 | 27 | ```ts 28 | import { execa } from 'execa' // [!code --] 29 | import exec from 'nanoexec' // [!code ++] 30 | 31 | const { stdout } = await execa('echo', ['example']) // [!code --] 32 | const res = await exec('echo', ['example']) // [!code ++] 33 | const stdout = res.stdout.toString('utf8') // [!code ++] 34 | ``` 35 | 36 | ## Bun 37 | 38 | If you’re on Bun, its built-in [`$`](https://bun.com/reference/bun/$) template tag can replace `execa`’s script-style usage: 39 | 40 | Example: 41 | 42 | ```ts 43 | import { $ } from 'execa' // [!code --] 44 | import { $ } from 'bun' // [!code ++] 45 | 46 | const { stdout } = await $`echo "Hello"` // [!code --] 47 | const stdout = await $`echo "Hello"`.text() // [!code ++] 48 | ``` -------------------------------------------------------------------------------- /docs/modules/eslint-plugin-eslint-comments.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the eslint-plugin-eslint-comments package for ESLint comment linting 3 | --- 4 | 5 | # Replacements for `eslint-plugin-eslint-comments` 6 | 7 | ## `@eslint-community/eslint-plugin-eslint-comments` 8 | 9 | [`@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. 10 | 11 | ```ts 12 | import eslintComments from 'eslint-plugin-eslint-comments' // [!code --] 13 | import commentsCommunity from '@eslint-community/eslint-plugin-eslint-comments/configs' // [!code ++] 14 | 15 | export default [ 16 | commentsCommunity.recommended, // [!code ++] 17 | { 18 | plugins: { 19 | 'eslint-comments': eslintComments, // [!code --] 20 | }, 21 | rules: { 22 | 'eslint-comments/no-unused-disable': 'error', // [!code --] 23 | '@eslint-community/eslint-comments/no-unused-disable': 'error', // [!code ++] 24 | } 25 | } 26 | ] 27 | ``` 28 | 29 | If you're using a legacy config format: 30 | 31 | ```ts 32 | module.exports = { 33 | extends: [ 34 | 'eslint:recommended', 35 | 'plugin:eslint-comments/recommended', // [!code --] 36 | 'plugin:@eslint-community/eslint-comments/recommended' // [!code ++] 37 | ], 38 | rules: { 39 | 'eslint-comments/no-unused-disable': 'error', // [!code --] 40 | '@eslint-community/eslint-comments/no-unused-disable': 'error' // [!code ++] 41 | } 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/modules/dotenv.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the dotenv package for loading and managing .env files in Node.js 3 | --- 4 | 5 | # Replacements for `dotenv` 6 | 7 | Although dotenv is reliable, it may not be necessary or may lack certain features. 8 | 9 | ## Node.js --env-file / --env-file-if-exists 10 | 11 | Built into Node.js (v20.6.0+; v22.9.0 for `--env-file-if-exists`). Zero dependencies—perfect for most apps that just need to load a `.env` at startup. 12 | 13 | [`--env-file`](https://nodejs.org/dist/latest-v20.x/docs/api/cli.html#--env-fileconfig) throws if the file is missing. If the file may be absent, use [`--env-file-if-exists`](https://nodejs.org/docs/latest-v22.x/api/cli.html#--env-file-if-existsconfig). 14 | 15 | ```bash 16 | node --env-file=.env index.js 17 | ``` 18 | 19 | Also supported by: 20 | 21 | - [tsx](https://www.npmjs.com/package/tsx) 22 | - [Bun](https://bun.sh/docs/runtime/env#manually-specifying-env-files) 23 | - [Deno](https://docs.deno.com/runtime/reference/env_variables/#.env-file) 24 | 25 | Remove dotenv preload: 26 | 27 | ```ts 28 | import 'dotenv/config' // [!code --] 29 | // No import needed when using --env-file 30 | ``` 31 | 32 | Remove explicit dotenv config: 33 | 34 | ```ts 35 | import dotenv from 'dotenv' // [!code --] 36 | 37 | dotenv.config({ path: '.env' }) // [!code --] 38 | // No runtime configuration needed 39 | ``` 40 | 41 | In package.json scripts: 42 | 43 | ```json 44 | { 45 | "scripts": { 46 | "start": "node index.js", // [!code --] 47 | "start": "node --env-file=.env index.js" // [!code ++] 48 | } 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/modules/js-yaml.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to js-yaml for YAML parsing and stringifying 3 | --- 4 | 5 | # Replacements for `js-yaml` 6 | 7 | `js-yaml` appears to be unmaintained and has known spec-compliance issues. 8 | 9 | ## `yaml` 10 | 11 | [`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. 12 | 13 | Parse (load): 14 | 15 | ```ts 16 | import yaml from 'js-yaml' // [!code --] 17 | import { parse } from 'yaml' // [!code ++] 18 | 19 | const obj = yaml.load(src) // [!code --] 20 | const obj = parse(src) // [!code ++] 21 | ``` 22 | 23 | Stringify (dump): 24 | 25 | ```ts 26 | import yaml from 'js-yaml' // [!code --] 27 | import { stringify } from 'yaml' // [!code ++] 28 | 29 | const text = yaml.dump(obj) // [!code --] 30 | const text = stringify(obj) // [!code ++] 31 | ``` 32 | 33 | Multi-document: 34 | 35 | ```ts 36 | import yaml from 'js-yaml' // [!code --] 37 | import { parseAllDocuments } from 'yaml' // [!code ++] 38 | 39 | const out: any[] = [] // [!code --] 40 | yaml.loadAll(src, d => out.push(d)) // [!code --] 41 | const out = parseAllDocuments(src).map(d => d.toJSON()) // [!code ++] 42 | ``` 43 | 44 | ## Bun `YAML` API 45 | 46 | [Native YAML parsing](https://bun.com/blog/release-notes/bun-v1.2.21#native-yaml-support) is supported in Bun since v1.2.21. 47 | 48 | Example: 49 | 50 | ```ts 51 | import yaml from 'js-yaml' // [!code --] 52 | import { YAML } from 'bun' // [!code ++] 53 | 54 | yaml.load(src) // [!code --] 55 | YAML.parse(src) // [!code ++] 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/modules/read-pkg-up.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the read-pkg-up package for reading package.json files up the directory tree 3 | --- 4 | 5 | # Replacements for `read-pkg-up` 6 | 7 | ## `pkg-types` 8 | 9 | [`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types. 10 | 11 | For example: 12 | 13 | ```ts 14 | import { readPackageUp } from 'read-pkg-up' // [!code --] 15 | import { readPackageJSON } from 'pkg-types' // [!code ++] 16 | 17 | const packageJson = await readPackageJSON() // [!code ++] 18 | const packageJson = await readPackageUp() // [!code --] 19 | ``` 20 | 21 | Similarly, you can get hold of the path via `resolvePackageJSON`: 22 | 23 | ```ts 24 | import { resolvePackageJSON } from 'pkg-types' 25 | 26 | const packageJsonPath = await resolvePackageJSON() 27 | ``` 28 | 29 | ## `empathic` 30 | 31 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 32 | 33 | It can be combined with `node:fs` to read `package.json` files: 34 | 35 | ```ts 36 | import { readPackageUp } from 'read-pkg-up' // [!code --] 37 | import fs from 'node:fs/promises' // [!code ++] 38 | import * as pkg from 'empathic' // [!code ++] 39 | 40 | const packageJson = await readPackageUp() // [!code --] 41 | const packageJsonPath = pkg.up() // [!code ++] 42 | const packageJson = packageJsonPath ? JSON.parse(await readFile(packageJsonPath, 'utf8')) : undefined // [!code ++] 43 | ``` 44 | 45 | > [!NOTE] 46 | > This is of course a more manual way to read the `package.json` file, so one of the other options may be more attractive. 47 | -------------------------------------------------------------------------------- /docs/modules/read-package-up.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the read-package-up package for reading package.json files up the directory tree 3 | --- 4 | 5 | # Replacements for `read-package-up` 6 | 7 | ## `pkg-types` 8 | 9 | [`pkg-types`](https://github.com/unjs/pkg-types) provides a similar API and strong types. 10 | 11 | For example: 12 | 13 | ```ts 14 | import { readPackageJSON } from 'pkg-types' // [!code ++] 15 | import { readPackageUp } from 'read-package-up' // [!code --] 16 | 17 | const packageJson = await readPackageUp() // [!code --] 18 | const packageJson = await readPackageJSON() // [!code ++] 19 | ``` 20 | 21 | Similarly, you can get hold of the path via `resolvePackageJSON`: 22 | 23 | ```ts 24 | import { resolvePackageJSON } from 'pkg-types' 25 | 26 | const packageJsonPath = await resolvePackageJSON() 27 | ``` 28 | 29 | ## `empathic` 30 | 31 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 32 | 33 | It can be combined with `node:fs` to read `package.json` files: 34 | 35 | ```ts 36 | import fs from 'node:fs/promises' // [!code ++] 37 | import * as pkg from 'empathic' // [!code ++] 38 | import { readPackageUp } from 'read-package-up' // [!code --] 39 | 40 | const packageJson = await readPackageUp() // [!code --] 41 | const packageJsonPath = pkg.up() // [!code ++] 42 | const packageJson = packageJsonPath ? JSON.parse(await readFile(packageJsonPath, 'utf8')) : undefined // [!code ++] 43 | ``` 44 | 45 | > [!NOTE] 46 | > This is of course a more manual way to read the `package.json` file, so one of the other options may be more attractive. 47 | -------------------------------------------------------------------------------- /docs/modules/mkdirp.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the mkdirp and make-dir packages for recursively creating directories in Node.js 3 | --- 4 | 5 | # Replacements for `mkdirp` / `make-dir` 6 | 7 | ## Node.js (since v10.12.0) 8 | 9 | Node.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. 10 | 11 | Example migration from [`mkdirp`](https://github.com/isaacs/node-mkdirp): 12 | 13 | ```ts 14 | import { mkdirp } from 'mkdirp' // [!code --] 15 | import { mkdir, mkdirSync } from 'node:fs' // [!code ++] 16 | import { mkdir as mkdirAsync } from 'node:fs/promises' // [!code ++] 17 | 18 | // Async 19 | await mkdirp('/tmp/foo/bar/baz') // [!code --] 20 | await mkdirAsync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++] 21 | 22 | // Sync 23 | mkdirp.sync('/tmp/foo/bar/baz') // [!code --] 24 | mkdirSync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++] 25 | ``` 26 | 27 | Example migration from [`make-dir`](https://github.com/sindresorhus/make-dir): 28 | 29 | ```ts 30 | import { makeDirectory, makeDirectorySync } from 'make-dir' // [!code --] 31 | import { mkdir, mkdirSync } from 'node:fs' // [!code ++] 32 | import { mkdir as mkdirAsync } from 'node:fs/promises' // [!code ++] 33 | 34 | // Async 35 | await makeDirectory('/tmp/foo/bar/baz') // [!code --] 36 | await mkdirAsync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++] 37 | 38 | // Sync 39 | makeDirectorySync('/tmp/foo/bar/baz') // [!code --] 40 | mkdirSync('/tmp/foo/bar/baz', { recursive: true }) // [!code ++] 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/modules/globby.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the globby package for globbing and .gitignore support 3 | --- 4 | 5 | # Replacements for `globby` 6 | 7 | ## `tinyglobby` 8 | 9 | [`globby`](https://github.com/sindresorhus/globby) is a convenience wrapper around [`fast-glob`](https://github.com/mrmlnc/fast-glob). 10 | 11 | You 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. 12 | 13 | If 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: 14 | 15 | ```ts 16 | import { execSync } from 'node:child_process'; 17 | import { glob, escapePath } from 'tinyglobby'; 18 | 19 | async function globWithGitignore(patterns, options = {}) { 20 | const { cwd = process.cwd(), ...restOptions } = options; 21 | 22 | try { 23 | const gitIgnored = execSync( 24 | 'git ls-files --others --ignored --exclude-standard --directory', 25 | { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] } 26 | ) 27 | .split('\n') 28 | .filter(Boolean) 29 | .map(p => escapePath(p)); 30 | 31 | return glob(patterns, { 32 | ...restOptions, 33 | cwd, 34 | ignore: [...(restOptions.ignore || []), ...gitIgnored] 35 | }); 36 | } catch { 37 | return glob(patterns, options); 38 | } 39 | } 40 | 41 | const paths = await globWithGitignore(['**/*'], {cwd}) 42 | ``` -------------------------------------------------------------------------------- /docs/modules/axios.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the axios package for making HTTP requests in browsers and Node.js 3 | --- 4 | 5 | # Replacements for `axios` 6 | 7 | ## Native `fetch` API 8 | 9 | The 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 most HTTP requests, it can replace `axios` without extra dependencies. 10 | 11 | Example: 12 | 13 | ```ts 14 | // GET 15 | const res = await fetch('https://api.example.com/data') 16 | const data = await res.json() 17 | 18 | // POST 19 | await fetch('https://api.example.com/data', { 20 | method: 'POST', 21 | headers: { 'Content-Type': 'application/json' }, 22 | body: JSON.stringify({ key: 'value' }) 23 | }) 24 | ``` 25 | 26 | ## `ky` 27 | 28 | [`ky`](https://github.com/sindresorhus/ky) is a lightweight HTTP client based on the Fetch API with timeout support, hooks (interceptors) and other helpers. 29 | 30 | Example: 31 | 32 | ```ts 33 | import ky from 'ky' 34 | 35 | const api = ky.create({ 36 | prefixUrl: 'https://api.example.com', 37 | timeout: 5000, // ms 38 | }) 39 | 40 | const data = await api.get('users').json() 41 | ``` 42 | 43 | ## `ofetch` 44 | 45 | [`ofetch`](https://github.com/unjs/ofetch) s a fetch wrapper with automatic JSON parsing, request/response interceptors, and retries. 46 | 47 | Example: 48 | 49 | ```ts 50 | import { ofetch } from 'ofetch' 51 | 52 | const api = ofetch.create({ 53 | baseURL: 'https://api.example.com', 54 | }) 55 | 56 | const data = await api('/user', { query: { id: 123 } }) 57 | const created = await api('/items', { method: 'POST', body: { name: 'A' } }) 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/modules/shortid.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern, secure alternatives to the shortid package for generating URL‑friendly unique IDs 3 | --- 4 | 5 | # Replacements for `shortid` 6 | 7 | ## `nanoid` 8 | 9 | [`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). 10 | 11 | :::info Good to know before migration 12 | - `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}$/`. 13 | 14 | - `shortid.seed()`/`shortid.worker()`: not needed and not provided by `nanoid` (it uses a secure random source). Avoid seeded/deterministic IDs for security. 15 | ::: 16 | 17 | ### Basic migration 18 | 19 | ```ts 20 | import shortid from 'shortid' // [!code --] 21 | import { nanoid } from 'nanoid' // [!code ++] 22 | 23 | const id = shortid.generate() // [!code --] 24 | const id = nanoid() // [!code ++] => "V1StGXR8_Z5jdHi6B-myT" 25 | ``` 26 | 27 | ### Control length 28 | 29 | ```ts 30 | // shortid produced ~7-14 chars; with nanoid you pick the size explicitly: 31 | nanoid(10) // e.g., "NG3oYbq9qE" 32 | ``` 33 | 34 | ### Custom alphabet (replacement for `shortid.characters`) 35 | 36 | 37 | ```ts 38 | shortid.characters('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$@') // [!code --] 39 | import { customAlphabet } from 'nanoid' // [!code ++] 40 | 41 | const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$@' // [!code ++] 42 | const makeId = customAlphabet(alphabet, 12) // [!code ++] 43 | const id = makeId() // [!code ++] 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/modules/emoji-regex.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the emoji-regex package for emoji detection and matching 3 | --- 4 | 5 | # Replacements for `emoji-regex` 6 | 7 | ## `emoji-regex-xs` 8 | 9 | [`emoji-regex-xs`](https://github.com/slevithan/emoji-regex-xs) offers the same API and features whilst being 98% smaller. 10 | 11 | ```ts 12 | import emojiRegex from 'emoji-regex' // [!code --] 13 | import emojiRegex from 'emoji-regex-xs' // [!code ++] 14 | 15 | const text = ` 16 | \u{231A}: ⌚ default emoji presentation character (Emoji_Presentation) 17 | \u{2194}\u{FE0F}: ↔️ default text presentation character rendered as emoji 18 | \u{1F469}: 👩 emoji modifier base (Emoji_Modifier_Base) 19 | \u{1F469}\u{1F3FF}: 👩🏿 emoji modifier base followed by a modifier 20 | ` 21 | 22 | const regex = emojiRegex() 23 | for (const match of text.matchAll(regex)) { 24 | const emoji = match[0] 25 | console.log(`Matched sequence ${emoji} — code points: ${[...emoji].length}`) 26 | } 27 | ``` 28 | 29 | ## Unicode RegExp (native) 30 | 31 | If 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. 32 | 33 | ```ts 34 | import emojiRegex from 'emoji-regex' // [!code --] 35 | 36 | const regex = emojiRegex() // [!code --] 37 | const regex = /\p{RGI_Emoji}/gv // [!code ++] 38 | 39 | for (const match of text.matchAll(regex)) { 40 | const emoji = match[0] 41 | console.log(`Matched sequence ${emoji} — code points: ${[...emoji].length}`) 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/modules/dot-prop.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the dot-prop package for getting, setting, and deleting nested object properties using dot notation 3 | --- 4 | 5 | # Replacements for `dot-prop` 6 | 7 | ## `dlv` + `dset` 8 | 9 | [`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. 10 | 11 | ```ts 12 | import { getProperty, setProperty } from 'dot-prop' // [!code --] 13 | import delve from 'dlv' // [!code ++] 14 | import { dset } from 'dset' // [!code ++] 15 | 16 | const value = getProperty(obj, 'foo.bar.baz') // [!code --] 17 | const value = delve(obj, 'foo.bar.baz') // [!code ++] 18 | 19 | setProperty(obj, 'foo.bar.baz', 'value') // [!code --] 20 | dset(obj, 'foo.bar.baz', 'value') // [!code ++] 21 | ``` 22 | 23 | ## `object-path` 24 | 25 | [`object-path`](https://github.com/mariocasciaro/object-path) provides get/set/has/delete operations plus array methods like push, insert, and empty. 26 | 27 | ```ts 28 | import { deleteProperty, getProperty, hasProperty, setProperty } from 'dot-prop' // [!code --] 29 | import objectPath from 'object-path' // [!code ++] 30 | 31 | const value = getProperty(obj, 'foo.bar.baz') // [!code --] 32 | const value = objectPath.get(obj, 'foo.bar.baz') // [!code ++] 33 | 34 | setProperty(obj, 'foo.bar.baz', 'value') // [!code --] 35 | objectPath.set(obj, 'foo.bar.baz', 'value') // [!code ++] 36 | 37 | const exists = hasProperty(obj, 'foo.bar.baz') // [!code --] 38 | const exists = objectPath.has(obj, 'foo.bar.baz') // [!code ++] 39 | 40 | deleteProperty(obj, 'foo.bar.baz') // [!code --] 41 | objectPath.del(obj, 'foo.bar.baz') // [!code ++] 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/modules/eslint-plugin-es.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the eslint-plugin-es package for ECMAScript feature linting 3 | --- 4 | 5 | # Replacements for `eslint-plugin-es` 6 | 7 | ## `eslint-plugin-es-x` 8 | 9 | [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. 10 | 11 | ```ts 12 | import { FlatCompat } from '@eslint/eslintrc' // [!code --] 13 | import pluginES from 'eslint-plugin-es' // [!code --] 14 | import pluginESx from 'eslint-plugin-es-x' // [!code ++] 15 | 16 | const compat = new FlatCompat() // [!code --] 17 | 18 | export default [ 19 | { 20 | files: ['**/*.js'], 21 | languageOptions: { 22 | ecmaVersion: 2020, 23 | }, 24 | plugins: { 25 | 'es': pluginES, // [!code --] 26 | 'es-x': pluginESx, // [!code ++] 27 | }, 28 | rules: { 29 | 'es/no-regexp-lookbehind-assertions': 'error', // [!code --] 30 | 'es-x/no-regexp-lookbehind-assertions': 'error' // [!code ++] 31 | }, 32 | }, 33 | 34 | ...compat.extends('plugin:es/restrict-to-es2018'), // [!code --] 35 | pluginESx.configs['flat/restrict-to-es2018'], // [!code ++] 36 | ] 37 | ``` 38 | 39 | If you're using a legacy config format: 40 | 41 | ```ts 42 | module.exports = { 43 | extends: [ 44 | 'eslint:recommended', 45 | 'plugin:es/restrict-to-es2018', // [!code --] 46 | 'plugin:es-x/restrict-to-es2018', // [!code ++] 47 | ], 48 | plugins: [ 49 | 'es', // [!code --] 50 | 'es-x' // [!code ++] 51 | ], 52 | rules: { 53 | 'es/no-regexp-lookbehind-assertions': 'error', // [!code --] 54 | 'es-x/no-regexp-lookbehind-assertions': 'error', // [!code ++] 55 | } 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/modules/readable-stream.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the readable-stream package for working with streaming data in Node.js 3 | --- 4 | 5 | # Replacements for `readable-stream` 6 | 7 | [`readable-stream`](https://www.npmjs.com/package/readable-stream) mirrors Node’s core streams and works in browsers. In most cases, prefer native options. 8 | 9 | ## Node.js (since v0.9.4) 10 | 11 | Use the built-in `stream` module ([Node Streams docs](https://nodejs.org/api/stream.html)). 12 | 13 | ```ts 14 | import { Duplex, Readable, Transform, Writable } from 'readable-stream' // [!code --] 15 | import { Duplex, Readable, Transform, Writable } from 'node:stream' // [!code ++] 16 | ``` 17 | 18 | ## Streams API (Browsers and Node.js 16.5.0+) 19 | 20 | Use 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). 21 | 22 | Example: convert a Web ReadableStream (from fetch) to a Node stream and pipe it to a file. 23 | 24 | ```ts 25 | import { Readable } from 'node:stream' 26 | import { pipeline } from 'node:stream/promises' 27 | import { createWriteStream } from 'node:fs' 28 | 29 | const res = await fetch('https://example.com/data.txt') // Web ReadableStream 30 | const nodeReadable = Readable.fromWeb(res.body) 31 | await pipeline(nodeReadable, createWriteStream('data.txt')) 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/modules/rimraf.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the rimraf package for recursive directory removal 3 | --- 4 | 5 | # Replacements for `rimraf` 6 | 7 | ## Node.js 8 | 9 | Node.js v14.14.0 and above provide a native alternative: [`fs.rm`](https://nodejs.org/api/fs.html#fspromisesrmpath-options). It supports recursive deletion and works as a direct replacement. 10 | 11 | ```ts 12 | import rimraf from 'rimraf' // [!code --] 13 | import { rm } from 'node:fs/promises' // [!code ++] 14 | 15 | await rimraf('./dist') // [!code --] 16 | await rm('./dist', { recursive: true, force: true }) // [!code ++] 17 | ``` 18 | 19 | ## Node.js (before v14.14.0) 20 | 21 | If 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. 22 | 23 | ```ts 24 | import rimraf from 'rimraf' // [!code --] 25 | import { rmdir } from 'node:fs/promises' // [!code ++] 26 | 27 | await rimraf('./dist') // [!code --] 28 | await rmdir('./dist', { recursive: true }) // [!code ++] 29 | ``` 30 | 31 | ## CLI usage 32 | 33 | To replace `rimraf` inside npm scripts, you can run Node directly in eval mode: 34 | 35 | ```sh 36 | node -e "require('fs').rmSync('./dist', { recursive: true, force: true, maxRetries: process.platform === 'win32' ? 10 : 0 })" 37 | ``` 38 | 39 | ## `premove` 40 | 41 | If 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. 42 | 43 | ```json 44 | { 45 | "scripts": { 46 | "clean": "rimraf lib", // [!code --] 47 | "clean": "premove lib" // [!code ++] 48 | } 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/modules/npm-run-all.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the npm-run-all package for running multiple npm scripts 3 | --- 4 | 5 | # Replacements for `npm-run-all` 6 | 7 | ## `npm-run-all2` 8 | 9 | [npm-run-all2](https://github.com/bcomnes/npm-run-all2) is an actively maintained fork with important fixes, dependency updates. 10 | 11 | ```json 12 | { 13 | "scripts": { 14 | "build": "npm-run-all clean lint compile" 15 | } 16 | } 17 | ``` 18 | 19 | The commands remain the same: `npm-run-all`, `run-s`, and `run-p`. 20 | 21 | ## `concurrently` 22 | 23 | Another 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. 24 | 25 | ```json 26 | { 27 | "scripts": { 28 | "dev": "npm-run-all --parallel \"watch-*\" start", // [!code --] 29 | "dev": "concurrently \"npm:watch-*\" \"npm:start\"" // [!code ++] 30 | } 31 | } 32 | ``` 33 | 34 | ## `Wireit` 35 | 36 | For 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. 37 | 38 | ```json 39 | { 40 | "scripts": { 41 | "build": "wireit", 42 | "compile": "wireit", 43 | "bundle": "wireit" 44 | }, 45 | "wireit": { 46 | "build": { 47 | "dependencies": ["compile", "bundle"] 48 | }, 49 | "compile": { 50 | "command": "tsc", 51 | "files": ["src/**/*.ts"], 52 | "output": ["lib/**"] 53 | }, 54 | "bundle": { 55 | "command": "rollup -c", 56 | "dependencies": ["compile"], 57 | "files": ["rollup.config.js"], 58 | "output": ["dist/**"] 59 | } 60 | } 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /docs/modules/graphemer.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the grapheme-splitter and graphemer packages for splitting strings into Unicode grapheme clusters 3 | --- 4 | 5 | # Replacements for `grapheme-splitter` / `graphemer` 6 | 7 | ## `Intl.Segmenter` (native) 8 | 9 | [`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+. 10 | 11 | ```ts 12 | import GraphemeSplitter from 'grapheme-splitter' // [!code --] 13 | 14 | const splitter = new GraphemeSplitter() // [!code --] 15 | const segmenter = new Intl.Segmenter() // [!code ++] 16 | 17 | const graphemes = splitter.splitGraphemes(text) // [!code --] 18 | const graphemes = [...segmenter.segment(text)].map(s => s.segment) // [!code ++] 19 | 20 | const count = splitter.countGraphemes(text) // [!code --] 21 | const count = [...segmenter.segment(text)].length // [!code ++] 22 | ``` 23 | 24 | ## `unicode-segmenter` 25 | 26 | [`unicode-segmenter`](https://github.com/cometkim/unicode-segmenter) is a lightweight, fast alternative with zero dependencies and excellent browser compatibility. 27 | 28 | ```ts 29 | import GraphemeSplitter from 'grapheme-splitter' // [!code --] 30 | import { countGraphemes, splitGraphemes } from 'unicode-segmenter/grapheme' // [!code ++] 31 | 32 | const splitter = new GraphemeSplitter() // [!code --] 33 | 34 | const graphemes = splitter.splitGraphemes(text) // [!code --] 35 | const graphemes = [...splitGraphemes(text)] // [!code ++] 36 | 37 | const count = splitter.countGraphemes(text) // [!code --] 38 | const count = countGraphemes(text) // [!code ++] 39 | ``` 40 | 41 | You can also use it as an `Intl.Segmenter` polyfill: 42 | 43 | ```ts 44 | import 'unicode-segmenter/intl-polyfill' 45 | 46 | const segmenter = new Intl.Segmenter() 47 | const graphemes = [...segmenter.segment(text)].map(s => s.segment) 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/modules/tempy.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the tempy package for creating temporary files and directories 3 | --- 4 | 5 | # Replacements for `tempy` 6 | 7 | ## Node.js (since v14.x) 8 | 9 | Node.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), available in v14.14.0 and up. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { temporaryDirectory } from 'tempy' // [!code --] 15 | import { mkdtemp, realpath } from 'node:fs/promises' // [!code ++] 16 | import { join } from 'node:path' // [!code ++] 17 | import { tmpdir } from 'node:os' // [!code ++] 18 | 19 | const tempDir = temporaryDirectory() // [!code --] 20 | const tempDir = await mkdtemp(join(await realpath(tmpdir()), 'foo-')) // [!code ++] 21 | ``` 22 | 23 | ## Deno 24 | 25 | Deno 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`. 26 | 27 | ```ts 28 | import { temporaryDirectory } from 'tempy' // [!code --] 29 | 30 | const tempDir = temporaryDirectory({ prefix: 'foo-' }) // [!code --] 31 | const tempDir = await Deno.makeTempDir({ prefix: 'foo-' }) // [!code ++] 32 | ``` 33 | 34 | ```ts 35 | import { temporaryFile } from 'tempy' // [!code --] 36 | 37 | const tempFile = temporaryFile({ extension: 'txt' }) // [!code --] 38 | const tempFile = await Deno.makeTempFile({ suffix: '.txt' }) // [!code ++] 39 | ``` 40 | 41 | > [!NOTE] 42 | > See also: secure tempfiles in Node.js without dependencies (Advanced Web Machinery): https://advancedweb.hu/secure-tempfiles-in-nodejs-without-dependencies/ 43 | -------------------------------------------------------------------------------- /scripts/validate-module-list.js: -------------------------------------------------------------------------------- 1 | import {fileURLToPath} from 'node:url'; 2 | import * as path from 'node:path'; 3 | import {readFile, readdir} from 'node:fs/promises'; 4 | 5 | const scriptDir = fileURLToPath(new URL('.', import.meta.url)); 6 | const moduleListDir = path.resolve(scriptDir, '..', 'docs', 'modules'); 7 | const moduleListReadmePath = path.resolve(moduleListDir, 'README.md'); 8 | const manifestsDir = path.resolve(scriptDir, '../manifests'); 9 | 10 | export async function validateModuleList() { 11 | console.log('Validating README contains all documented modules...'); 12 | const moduleListReadme = await readFile(moduleListReadmePath, { 13 | encoding: 'utf8' 14 | }); 15 | const listOfDocumentedModules = 16 | moduleListReadme.split('## List of modules')[1]; 17 | const allDocPaths = []; 18 | 19 | const manifests = await readdir(manifestsDir); 20 | 21 | for (const manifestName of manifests) { 22 | const manifestPath = path.join(manifestsDir, manifestName); 23 | const manifestObj = JSON.parse( 24 | await readFile(manifestPath, {encoding: 'utf8'}) 25 | ); 26 | 27 | for (const mod of manifestObj.moduleReplacements) { 28 | if (mod.type === 'documented') { 29 | allDocPaths.push(mod.docPath); 30 | } 31 | } 32 | } 33 | 34 | const files = await readdir(moduleListDir); 35 | for (const file of files) { 36 | if (!file.endsWith('.md') || file === 'README.md') { 37 | continue; 38 | } 39 | 40 | const docName = file.slice(0, -3); 41 | 42 | if (!listOfDocumentedModules.includes(file)) { 43 | throw new Error( 44 | `Module ${file} is not listed in the README.md but was found in modules documentation. 45 | Please add 46 | - [\`${docName}\`](./${file}) 47 | to ./docs/modules/README.md` 48 | ); 49 | } 50 | 51 | if (!allDocPaths.includes(docName)) { 52 | throw new Error( 53 | `Module ${docName} has documentation but does not exist in any manifest` 54 | ); 55 | } 56 | } 57 | console.log('OK'); 58 | } 59 | -------------------------------------------------------------------------------- /docs/modules/glob.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the glob package for file pattern matching and globbing 3 | --- 4 | 5 | # Replacements for `glob` 6 | 7 | ## `tinyglobby` 8 | 9 | [`tinyglobby`](https://github.com/SuperchupuDev/tinyglobby) provides a similar API. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { glob } from 'glob' // [!code --] 15 | import { glob } from 'tinyglobby' // [!code ++] 16 | 17 | const files = await glob('**/*.ts') 18 | ``` 19 | 20 | Most options available to `glob` are available in `tinyglobby`, read more at the [tinyglobby documentation](https://superchupu.dev/tinyglobby/documentation). 21 | 22 | ## `fs.glob` (native, since Node 22.x) 23 | 24 | [`fs.glob`](https://nodejs.org/api/fs.html#fspromisesglobpattern-options) is built into modern versions of Node. 25 | 26 | Example: 27 | 28 | 29 | ```ts 30 | import { glob } from 'glob' // [!code --] 31 | import { glob } from 'node:fs/promises' // [!code ++] 32 | 33 | const files = await glob('src/**/*.ts', { // [!code --] 34 | const files = await Array.fromAsync(glob('src/**/*.ts', { // [!code ++] 35 | cwd, 36 | }) // [!code --] 37 | })) // [!code ++] 38 | ``` 39 | 40 | You can also iterate over the results asynchronously: 41 | 42 | ```ts 43 | for await (const result of glob('src/**/*.ts', { cwd })) { 44 | // result is an individual path 45 | console.log(result) 46 | } 47 | ``` 48 | 49 | ## `fdir` 50 | 51 | [`fdir`](https://github.com/thecodrr/fdir/) offers similar functionality but through a different API (and `tinyglobby` is actually built on top of it). 52 | 53 | Example: 54 | 55 | 56 | ```ts 57 | import { fdir } from 'fdir' // [!code ++] 58 | import { glob } from 'glob' // [!code --] 59 | 60 | const files = new fdir() // [!code ++] 61 | .withBasePath() // [!code ++] 62 | .glob('src/**/*.ts') // [!code ++] 63 | .crawl(cwd) // [!code ++] 64 | .withPromise() // [!code ++] 65 | const files = await glob('src/**/*.ts', { // [!code --] 66 | cwd, // [!code --] 67 | maxDepth: 6 // [!code --] 68 | }) // [!code --] 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/modules/object-hash.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to object-hash for hashing objects and values 3 | --- 4 | 5 | # Replacements for `object-hash` 6 | 7 | ## `ohash` 8 | 9 | [`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`. 10 | 11 | Example: 12 | 13 | ```ts 14 | import objectHash from 'object-hash' // [!code --] 15 | import { hash } from 'ohash' // [!code ++] 16 | 17 | const h = objectHash(obj) // [!code --] 18 | const h = hash(obj) // [!code ++] 19 | ``` 20 | 21 | ## Web Crypto 22 | 23 | Use the standard `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. 24 | 25 | Example: 26 | 27 | ```ts 28 | import objectHash from 'object-hash' // [!code --] 29 | import stringify from 'safe-stable-stringify' // [!code ++] 30 | 31 | const h = objectHash(obj, { algorithm: 'sha256' }) // [!code --] 32 | const data = new TextEncoder().encode(stringify(obj)) // [!code ++] 33 | const buf = await crypto.subtle.digest('SHA-256', data) // [!code ++] 34 | const h = Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('') // [!code ++] 35 | ``` 36 | 37 | ## Bun `CryptoHasher` 38 | 39 | Bun 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). 40 | 41 | Docs: https://bun.com/reference/bun/CryptoHasher 42 | 43 | Example: 44 | 45 | ```ts 46 | import objectHash from 'object-hash' // [!code --] 47 | import stringify from 'safe-stable-stringify' // [!code ++] 48 | 49 | const h = objectHash(obj, { algorithm: 'sha256' }) // [!code --] 50 | const hasher = new CryptoHasher('sha256') // [!code ++] 51 | hasher.update(stringify(obj)) // [!code ++] 52 | const h = hasher.digest('hex') // [!code ++] 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/modules/eslint-plugin-import.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternative to eslint-plugin-import, which helps with linting of ES6+ import/export syntax 3 | --- 4 | 5 | # Replacements for `eslint-plugin-import` 6 | 7 | ## `eslint-plugin-import-x` 8 | 9 | [`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 faster module resolution via a Rust-based resolver, a smaller dependency footprint 10 | 11 | ### Flat config 12 | 13 | ```ts 14 | import importPlugin from 'eslint-plugin-import' // [!code --] 15 | import { createNodeResolver, importX } from 'eslint-plugin-import-x' // [!code ++] 16 | import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript' // [!code ++] 17 | 18 | export default [ 19 | importPlugin.flatConfigs.recommended, // [!code --] 20 | importX.flatConfigs.recommended, // [!code ++] 21 | { 22 | settings: { 23 | 'import/resolver': { typescript: true }, // [!code --] 24 | 'import-x/resolver-next': [createTypeScriptImportResolver(), createNodeResolver()], // [!code ++] 25 | }, 26 | rules: { 27 | 'import/no-unresolved': 'error', // [!code --] 28 | 'import-x/no-unresolved': 'error', // [!code ++] 29 | 'import/no-nodejs-modules': 'warn', // [!code --] 30 | 'import-x/no-nodejs-modules': 'warn', // [!code ++] 31 | } 32 | } 33 | ] 34 | ``` 35 | 36 | ### Legacy config 37 | 38 | ```ts 39 | module.exports = { 40 | extends: [ 41 | 'eslint:recommended', 42 | 'plugin:import/recommended', // [!code --] 43 | 'plugin:import-x/recommended', // [!code ++] 44 | 'plugin:import/typescript', // [!code --] 45 | 'plugin:import-x/typescript' // [!code ++] 46 | ], 47 | plugins: [ 48 | 'import', // [!code --] 49 | 'import-x' // [!code ++] 50 | ], 51 | settings: { 52 | 'import/resolver': { typescript: true }, // [!code --] 53 | 'import-x/resolver': { typescript: true } // [!code ++] 54 | }, 55 | rules: { 56 | 'import/no-unresolved': 'error', // [!code --] 57 | 'import-x/no-unresolved': 'error' // [!code ++] 58 | } 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/modules/uri-js.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to uri-js for RFC 3986 URI parsing, resolving, and normalization 3 | --- 4 | 5 | # Replacements for `uri-js` 6 | 7 | [`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)). 8 | 9 | ## Native `URL` 10 | 11 | Good for standard web URLs (http/https/ws/wss/file/mailto, etc.). 12 | 13 | - MDN URL: https://developer.mozilla.org/en-US/docs/Web/API/URL 14 | - Node.js URL: https://nodejs.org/api/url.html#class-url 15 | 16 | Example: 17 | 18 | ```ts 19 | import * as URI from 'uri-js' // [!code --] 20 | 21 | URI.resolve('https://a/b/c/d?q', '../../g') // [!code --] 22 | new URL('../../g', 'https://a/b/c/d?q').href // [!code ++] 23 | ``` 24 | 25 | > [!NOTE] 26 | > [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. 27 | 28 | ## `uri-js-replace` 29 | 30 | [`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. 31 | 32 | ```ts 33 | import * as URI from 'uri-js' // [!code --] 34 | import * as URI from 'uri-js-replace' // [!code ++] 35 | 36 | const parsed = URI.parse('uri://user:pass@example.com:123/one/two?q=a#f') 37 | const out = URI.serialize({ scheme: 'http', host: 'example.com', fragment: 'footer' }) 38 | const norm = URI.normalize('URI://www.example.org/red%09ros\xE9#red') 39 | ``` 40 | 41 | ## `fast-uri` 42 | 43 | [`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`. 44 | 45 | ```ts 46 | import * as uri from 'uri-js' // [!code --] 47 | import * as uri from 'fast-uri' // [!code ++] 48 | 49 | uri.parse('uri://user:pass@example.com:123/one/two.three?q1=a1#a') 50 | uri.serialize({ scheme: 'http', host: 'example.com', fragment: 'footer' }) 51 | uri.resolve('uri://a/b/c/d?q', '../../g') 52 | uri.equal('example://a/b/%7Bfoo%7D', 'eXAMPLE://a/./b/../b/%63/%7bfoo%7d') 53 | ``` 54 | -------------------------------------------------------------------------------- /scripts/check-manifest-problems.js: -------------------------------------------------------------------------------- 1 | import {readdir, readFile} from 'node:fs/promises'; 2 | import {fileURLToPath} from 'node:url'; 3 | import * as path from 'node:path'; 4 | 5 | const scriptDir = fileURLToPath(new URL('.', import.meta.url)); 6 | const manifestsDir = path.resolve(scriptDir, '../manifests'); 7 | const seenModules = new Set(); 8 | 9 | async function checkManifestForDuplicates(name, manifest) { 10 | const seenInThisManifest = new Set(); 11 | 12 | for (const mod of manifest.moduleReplacements) { 13 | if (seenInThisManifest.has(mod.moduleName)) { 14 | throw new Error( 15 | `Module ${mod.moduleName} was found multiple times in ${name}` 16 | ); 17 | } 18 | if (seenModules.has(mod.moduleName)) { 19 | throw new Error( 20 | `Module ${mod.moduleName} was found in multiple manifests` 21 | ); 22 | } 23 | seenInThisManifest.add(mod.moduleName); 24 | seenModules.add(mod.moduleName); 25 | } 26 | } 27 | 28 | function checkManifestIsSorted(name, manifest) { 29 | const sorted = [...manifest.moduleReplacements].sort((a, b) => { 30 | if (a.moduleName === b.moduleName) { 31 | return 0; 32 | } 33 | return a.moduleName > b.moduleName ? 1 : -1; 34 | }); 35 | 36 | for (let i = 0; i < sorted.length; i++) { 37 | const mod = sorted[i]; 38 | const unsortedMod = manifest.moduleReplacements[i]; 39 | 40 | if (mod !== unsortedMod) { 41 | throw new Error(`Manifest ${name} should be sorted by module name (a-z)`); 42 | } 43 | } 44 | } 45 | 46 | export async function checkManifestsForProblems() { 47 | console.log('Checking for problems in manifests...'); 48 | const manifests = await readdir(manifestsDir); 49 | seenModules.clear(); 50 | 51 | for (const manifestName of manifests) { 52 | if (!manifestName.endsWith('.json')) { 53 | continue; 54 | } 55 | 56 | const manifestPath = path.join(manifestsDir, manifestName); 57 | const manifest = JSON.parse( 58 | await readFile(manifestPath, {encoding: 'utf8'}) 59 | ); 60 | 61 | await checkManifestForDuplicates(manifestName, manifest); 62 | checkManifestIsSorted(manifestName, manifest); 63 | } 64 | console.log('OK'); 65 | } 66 | -------------------------------------------------------------------------------- /docs/modules/sort-object.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the sort-object package for sorting object keys 3 | --- 4 | 5 | # Replacements for `sort-object` 6 | 7 | ## JavaScript APIs (`Object.keys` + `Array.sort`) 8 | 9 | For simple cases: 10 | 11 | ```ts 12 | import sortObj from 'sort-object' // [!code --] 13 | 14 | const sorted = sortObj(object) // [!code --] 15 | 16 | // Ascending A→Z 17 | const sorted = Object.fromEntries( // [!code ++] 18 | Object.entries(object).sort((a, b) => a[0].localeCompare(b[0])) // [!code ++] 19 | ) // [!code ++] 20 | ``` 21 | 22 | Replicating `sortBy` (function returns an ordered key list): 23 | 24 | ```ts 25 | import sortObj from 'sort-object' // [!code --] 26 | 27 | const sorted = sortObj(object, { sortBy: (obj) => { // [!code --] 28 | const arr = [] // [!code --] 29 | Object.keys(obj).forEach((k) => { // [!code --] 30 | if (obj[k].startsWith('a')) // [!code --] 31 | arr.push(k) // [!code --] 32 | }) // [!code --] 33 | return arr.reverse() // [!code --] 34 | } }) // [!code --] 35 | 36 | const sortBy = obj => Object.keys(obj).filter(k => obj[k].startsWith('a')).reverse() // [!code ++] 37 | const sorted = Object.fromEntries( // [!code ++] 38 | sortBy(object).map(k => [k, object[k]]) // [!code ++] 39 | ) // [!code ++] 40 | ``` 41 | 42 | ## `sort-object-keys` 43 | 44 | [`sort-object-keys`](https://www.npmjs.com/package/sort-object-keys) is zero‑dependency and matches common `sort-object` use cases (custom order array or comparator). 45 | 46 | ```ts 47 | import sortObj from 'sort-object' // [!code --] 48 | import sortObjectKeys from 'sort-object-keys' // [!code ++] 49 | 50 | // Default A→Z 51 | const sorted = sortObj(object) // [!code --] 52 | const sorted = sortObjectKeys(object) // [!code ++] 53 | 54 | // With comparator 55 | const sortedByCmp = sortObj(object, { sort: (a, b) => a.localeCompare(b) }) // [!code --] 56 | const sortedByCmp = sortObjectKeys(object, (a, b) => a.localeCompare(b)) // [!code ++] 57 | ``` 58 | 59 | ## `sortobject` 60 | 61 | [`sortobject`](https://www.npmjs.com/package/sortobject) is zero‑dependency and deeply sorts nested objects. 62 | 63 | ```ts 64 | import sortObj from 'sort-object' // [!code --] 65 | import sortobject from 'sortobject' // [!code ++] 66 | 67 | const sorted = sortObj(object) // [!code --] 68 | const sorted = sortobject(object) // [!code ++] 69 | ``` 70 | -------------------------------------------------------------------------------- /docs/modules/strip-ansi.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Native Node.js alternatives to the strip-ansi package for removing ANSI escape codes from strings 3 | --- 4 | 5 | # Replacements for `strip-ansi` 6 | 7 | ## Node.js 8 | 9 | Added in v16.11.0, [util.stripVTControlCharacters](https://nodejs.org/api/util.html#utilstripvtcontrolcharactersstr) can be used to strip ANSI escape codes from a string. 10 | 11 | ```ts 12 | import stripAnsi from 'strip-ansi' // [!code --] 13 | import { stripVTControlCharacters } from 'node:util' // [!code ++] 14 | 15 | console.log(stripAnsi('\u001B[4me18e\u001B[0m')) // [!code --] 16 | console.log(stripVTControlCharacters('\u001B[4me18e\u001B[0m')) // [!code ++] 17 | ``` 18 | 19 | > [!NOTE] 20 | > 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. 21 | 22 | ## Deno 23 | 24 | Deno implements the Node `util` API, and also provides [`util.stripVTControlCharacters`](https://docs.deno.com/api/node/util/~/stripVTControlCharacters). The usage is identical: 25 | 26 | ```ts 27 | import stripAnsi from 'strip-ansi' // [!code --] 28 | import { stripVTControlCharacters } from 'node:util' // [!code ++] 29 | 30 | console.log(stripAnsi('\u001B[4me18e\u001B[0m')) // [!code --] 31 | console.log(stripVTControlCharacters('\u001B[4me18e\u001B[0m')) // [!code ++] 32 | ``` 33 | 34 | ## Bun 35 | 36 | ### Using Node‑compatible API 37 | 38 | Bun also implements Node’s [`util.stripVTControlCharacters`](https://bun.sh/reference/node/util/stripVTControlCharacters) through its Node compat layer: 39 | 40 | ```ts 41 | import stripAnsi from 'strip-ansi' // [!code --] 42 | import { stripVTControlCharacters } from 'node:util' // [!code ++] 43 | 44 | console.log(stripAnsi('\u001B[1mHello\u001B[0m')) // [!code --] 45 | console.log(stripVTControlCharacters('\u001B[1mHello\u001B[0m')) // [!code ++] 46 | ``` 47 | 48 | ### Using Bun's native API (>=1.2.21) 49 | 50 | Since 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. 51 | 52 | ```ts 53 | import stripAnsi from 'strip-ansi' // [!code --] 54 | import { stripANSI } from 'bun' // [!code ++] 55 | 56 | console.log(stripAnsi('\u001B[31mHello World\u001B[0m')) // [!code --] 57 | console.log(Bun.stripANSI('\u001B[31mHello World\u001B[0m')) // [!code ++] 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/modules/find-up.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the find-up package for finding files by walking up parent directories 3 | --- 4 | 5 | # Replacements for `find-up` 6 | 7 | ## `empathic` 8 | 9 | [`empathic`](https://github.com/lukeed/empathic) provides a more generic way to find files and directories upwards. 10 | 11 | The main difference is that `empathic` is _synchronous_, so you should no longer `await` the result. 12 | 13 | Example: 14 | 15 | ```ts 16 | import * as find from 'empathic/find' // [!code ++] 17 | import { findUp } from 'find-up' // [!code --] 18 | 19 | await findUp('package.json') // [!code --] 20 | find.up('package.json') // [!code ++] 21 | ``` 22 | 23 | ### `findUpMultiple` 24 | 25 | When finding multiple files, you can use `find.any`: 26 | 27 | ```ts 28 | import * as find from 'empathic/find' // [!code ++] 29 | import { findUpMultiple } from 'find-up' // [!code --] 30 | 31 | const files = await findUpMultiple(['package.json', 'tsconfig.json']) // [!code --] 32 | const files = find.any(['package.json', 'tsconfig.json']) // [!code ++] 33 | ``` 34 | 35 | ### Options 36 | 37 | #### `type` 38 | 39 | The `type` option can be replaced by using the equivalent function. 40 | 41 | For example, finding a file: 42 | 43 | ```ts 44 | import * as find from 'empathic/find' // [!code ++] 45 | import { findUp } from 'find-up' // [!code --] 46 | 47 | await findUp('package.json', { type: 'file' }) // [!code --] 48 | find.file('package.json') // [!code ++] 49 | ``` 50 | 51 | #### `cwd` 52 | 53 | This option is supported just the same: 54 | 55 | ```ts 56 | find.file('package.json', { cwd }) 57 | ``` 58 | 59 | #### `stopAt` 60 | 61 | This option is replaced by `last`: 62 | 63 | 64 | ```ts 65 | import { findUp } from 'find-up' // [!code --] 66 | import * as find from 'empathic/find' // [!code ++] 67 | 68 | await findUp( // [!code --] 69 | find.file( // [!code ++] 70 | 'package.json', 71 | { stopAt: '/some/dir' }, // [!code --] 72 | { last: '/some/dir' }, // [!code ++] 73 | ) 74 | ``` 75 | 76 | ## `pkg-types` 77 | 78 | [`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. 79 | 80 | ```ts 81 | import { findUp } from 'find-up' // [!code --] 82 | import { readPackageJSON } from 'pkg-types' // [!code ++] 83 | 84 | const packagePath = await findUp('package.json') // [!code --] 85 | const packageJson = await readPackageJSON() // [!code ++] 86 | ``` 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "module-replacements", 3 | "description": "This package provides a set of manifests which each define a mapping of JS modules to their suggested replacements.", 4 | "version": "1.0.0", 5 | "main": "./dist/commonjs/main.js", 6 | "scripts": { 7 | "build": "npm run clean && npm run build:types", 8 | "build:types": "tsc --noEmit", 9 | "build:update-manifest-paths": "node scripts/update-manifests-dist-path.js", 10 | "clean": "node -e \"fs.rmSync('./dist', {force: true, recursive: true})\"", 11 | "format": "prettier --write \"./src/**/*.ts\" \"./manifests/**/*.json\"", 12 | "generate-schema": "node scripts/generate-schema.js", 13 | "prepare": "tshy && npm run build:update-manifest-paths", 14 | "test:validate": "node scripts/validate-modules.js", 15 | "sort-manifests": "node scripts/sort-manifests.js" 16 | }, 17 | "tshy": { 18 | "exports": { 19 | ".": "./src/main.ts", 20 | "./package.json": "./package.json", 21 | "./manifests/micro-utilities.json": "./manifests/micro-utilities.json", 22 | "./manifests/native.json": "./manifests/native.json", 23 | "./manifests/preferred.json": "./manifests/preferred.json" 24 | } 25 | }, 26 | "files": [ 27 | "dist", 28 | "manifests" 29 | ], 30 | "repository": { 31 | "type": "git", 32 | "url": "git+https://github.com/es-tooling/module-replacements.git" 33 | }, 34 | "author": "James Garbutt (https://github.com/43081j)", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/es-tooling/module-replacements/issues" 38 | }, 39 | "homepage": "https://github.com/es-tooling/module-replacements#readme", 40 | "devDependencies": { 41 | "@types/node": "^20.14.9", 42 | "ajv": "^8.16.0", 43 | "prettier": "^3.2.4", 44 | "ts-json-schema-generator": "^2.3.0", 45 | "tshy": "^1.11.0", 46 | "typescript": "^5.3.3" 47 | }, 48 | "exports": { 49 | ".": { 50 | "import": { 51 | "types": "./dist/esm/main.d.ts", 52 | "default": "./dist/esm/main.js" 53 | }, 54 | "require": { 55 | "types": "./dist/commonjs/main.d.ts", 56 | "default": "./dist/commonjs/main.js" 57 | } 58 | }, 59 | "./package.json": "./package.json", 60 | "./manifests/micro-utilities.json": "./manifests/micro-utilities.json", 61 | "./manifests/native.json": "./manifests/native.json", 62 | "./manifests/preferred.json": "./manifests/preferred.json" 63 | }, 64 | "types": "./dist/commonjs/main.d.ts", 65 | "type": "module" 66 | } 67 | -------------------------------------------------------------------------------- /docs/modules/moment.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to moment.js for date manipulation and formatting 3 | --- 4 | 5 | # Replacements for `Moment.js` 6 | 7 | ## `Day.js` 8 | 9 | [Day.js](https://github.com/iamkun/dayjs/) provides a similar API to Moment.js with a much smaller footprint. 10 | 11 | Example: 12 | 13 | ```ts 14 | import moment from 'moment' // [!code --] 15 | import dayjs from 'dayjs' // [!code ++] 16 | 17 | const now = moment() // [!code --] 18 | const now = dayjs() // [!code ++] 19 | 20 | const formatted = moment().format('YYYY-MM-DD') // [!code --] 21 | const formatted = dayjs().format('YYYY-MM-DD') // [!code ++] 22 | ``` 23 | 24 | ## `date-fns` 25 | 26 | [date-fns](https://github.com/date-fns/date-fns) offers tree-shakable functions for working with native JavaScript dates. 27 | 28 | Example: 29 | 30 | ```ts 31 | import moment from 'moment' // [!code --] 32 | import { addDays, format, subWeeks } from 'date-fns' // [!code ++] 33 | 34 | const formatted = moment().format('YYYY-MM-DD') // [!code --] 35 | const formatted = format(new Date(), 'yyyy-MM-dd') // [!code ++] 36 | 37 | const tomorrow = moment().add(1, 'day') // [!code --] 38 | const tomorrow = addDays(new Date(), 1) // [!code ++] 39 | 40 | const lastWeek = moment().subtract(1, 'week') // [!code --] 41 | const lastWeek = subWeeks(new Date(), 1) // [!code ++] 42 | ``` 43 | 44 | ## `Luxon` 45 | 46 | [Luxon](https://github.com/moment/luxon) is created by a Moment.js maintainer and offers powerful internationalization support. 47 | 48 | Example: 49 | 50 | ```ts 51 | import moment from 'moment' // [!code --] 52 | import { DateTime } from 'luxon' // [!code ++] 53 | 54 | const now = moment() // [!code --] 55 | const now = DateTime.now() // [!code ++] 56 | 57 | const formatted = moment().format('YYYY-MM-DD') // [!code --] 58 | const formatted = DateTime.now().toFormat('yyyy-MM-dd') // [!code ++] 59 | 60 | const tomorrow = moment().add(1, 'day') // [!code --] 61 | const tomorrow = DateTime.now().plus({ days: 1 }) // [!code ++] 62 | ``` 63 | 64 | ## Native JavaScript `Date` 65 | 66 | For 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: 67 | 68 | ```ts 69 | import moment from 'moment' // [!code --] 70 | 71 | const formatted = moment().format('YYYY-MM-DD') // [!code --] 72 | const formatted = new Date().toISOString().split('T')[0] // [!code ++] 73 | 74 | const localized = moment().format('MMMM Do YYYY') // [!code --] 75 | const localized = new Intl.DateTimeFormat('en-US', { // [!code ++] 76 | year: 'numeric', // [!code ++] 77 | month: 'long', // [!code ++] 78 | day: 'numeric' // [!code ++] 79 | }).format(new Date()) // [!code ++] 80 | ``` 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # module-replacements 2 | 3 | As part of the community [e18e](https://e18e.dev) effort, this project 4 | provides a collection of module replacements (i.e. possible alternative 5 | packages). 6 | 7 | We provide two things: 8 | - Manifests (mappings of modules to their possible replacements) 9 | - Documentation for more complex replacements 10 | 11 | ## List of replacements 12 | 13 | You can find a list of replacements in the 14 | [modules readme](./docs/modules/README.md). 15 | 16 | ## Tools 17 | 18 | Some tools consume the lists of modules in this repository: 19 | 20 | | Name | Description | 21 | | -- | -- | 22 | | [eslint-plugin-depend](https://github.com/es-tooling/eslint-plugin-depend) | ESLint plugin to detect possible replacements | 23 | 24 | 25 | ## Manifests 26 | 27 | The manifests can be used via the `module-replacements` npm package. 28 | 29 | We provide three manifests: 30 | 31 | - All (includes every manifest) 32 | - Native replacements 33 | - Micro utility replacements 34 | - Preferred replacements 35 | 36 | ### Usage 37 | 38 | You can install this package via npm: 39 | 40 | ```sh 41 | npm i -S module-replacements 42 | ``` 43 | 44 | You can then import the manifest of your choice: 45 | 46 | ```ts 47 | import {nativeReplacements} from 'module-replacements'; 48 | ``` 49 | 50 | The manifests are also available directly in the `manifests/` directory 51 | of the package (e.g. `node_modules/module-replacements/manifests/native.json`). 52 | 53 | ### Native replacements (`nativeReplacements`, `native.json`) 54 | 55 | These are modules which can now be replaced by native functionality. 56 | 57 | For example, pseudo-polyfills which provide functionality of widely available 58 | platform features can be replaced by their platform equivalents. 59 | 60 | Similarly, features which did not exist at the time but have now existed in 61 | the platform for many years, so no longer need a dependency. 62 | 63 | ### Micro utility replacements (`microUtilsReplacements`, `micro-utilities.json`) 64 | 65 | This is a more opinionated list of modules considered to be 'micro utilities' - 66 | very small utilities which could possibly be replaced with native equivalents 67 | or removed entirely. 68 | 69 | ### Preferred replacements (`preferredReplacements`, `preferred.json`) 70 | 71 | This is a very opinionated list of modules with preferred replacements. Often 72 | these replacements are much lighter or more modern than the modules they are 73 | replacing. 74 | 75 | Sometimes these may also be actively maintained forks of older, unmaintained 76 | source packages. 77 | 78 | # Contributing 79 | 80 | If you would like to add a replacement mapping to one of the manifests, please 81 | open an issue where this can be discussed. 82 | 83 | Keep in mind, very newly available native features are unlikely to join the 84 | list since they are not widely available yet. 85 | -------------------------------------------------------------------------------- /docs/modules/README.md: -------------------------------------------------------------------------------- 1 | # Module replacements 2 | 3 | This is a list of all modules we suggest replacing, along with documentation 4 | to suggest alternatives. 5 | 6 | ## ESLint plugin 7 | 8 | You can set your project up to automatically warn on usage of these modules 9 | by using the 10 | [`eslint-plugin-depend`](https://github.com/es-tooling/eslint-plugin-depend) 11 | ESLint plugin. 12 | 13 | ## List of modules 14 | 15 | - [`@jsdevtools/ezspawn`](./ez-spawn.md) 16 | - [`axios`](./axios.md) 17 | - [`bluebird`](./bluebird-q.md) 18 | - [`body-parser`](./body-parser.md) 19 | - [`buf-compare`](./buf-compare.md) 20 | - [`buffer-equal`](./buffer-equal.md) 21 | - [`buffer-equals`](./buffer-equals.md) 22 | - [`builtin-modules`](./builtin-modules.md) 23 | - [`chalk`](./chalk.md) 24 | - [`core-util-is`](./core-util-is.md) 25 | - [`cpx`](./cpx.md) 26 | - [`crypto-js`](./crypto-js.md) 27 | - [`deep-equal`](./deep-equal.md) 28 | - [`depcheck`](./depcheck.md) 29 | - [`dot-prop`](./dot-prop.md) 30 | - [`dotenv`](./dotenv.md) 31 | - [`emoji-regex`](./emoji-regex.md) 32 | - [`eslint-plugin-es`](./eslint-plugin-es.md) 33 | - [`eslint-plugin-eslint-comments`](./eslint-plugin-eslint-comments.md) 34 | - [`eslint-plugin-import`](./eslint-plugin-import.md) 35 | - [`eslint-plugin-node`](./eslint-plugin-node.md) 36 | - [`eslint-plugin-react`](./eslint-plugin-react.md) 37 | - [`eslint-plugin-vitest`](./eslint-plugin-vitest.md) 38 | - [`execa`](./execa.md) 39 | - [`ezspawn`](./ez-spawn.md) 40 | - [`faker`](./faker.md) 41 | - [`fast-glob`](./fast-glob.md) 42 | - [`find-cache-dir`](./find-cache-dir.md) 43 | - [`find-cache-directory`](./find-cache-directory.md) 44 | - [`find-file-up`](./find-file-up.md) 45 | - [`find-pkg`](./find-pkg.md) 46 | - [`find-up`](./find-up.md) 47 | - [`fs-extra`](./fs-extra.md) 48 | - [`glob`](./glob.md) 49 | - [`globby`](./globby.md) 50 | - [`graphemer`](./graphemer.md) 51 | - [`invariant`](./invariant.md) 52 | - [`is-builtin-module`](./is-builtin-module.md) 53 | - [`jQuery`](./jquery.md) 54 | - [`js-yaml`](./js-yaml.md) 55 | - [`jsx-ast-utils`](./jsx-ast-utils.md) 56 | - [`lint-staged`](./lint-staged.md) 57 | - [`lodash`, `underscore` and related](./lodash-underscore.md) 58 | - [`materialize-css`](./materialize-css.md) 59 | - [`md5`](./md5.md) 60 | - [`mkdirp`](./mkdirp.md) 61 | - [`moment.js`](./moment.md) 62 | - [`npm-run-all`](./npm-run-all.md) 63 | - [`object-hash`](./object-hash.md) 64 | - [`ora`](./ora.md) 65 | - [`path-exists`](./path-exists.md) 66 | - [`pkg-dir`](./pkg-dir.md) 67 | - [`qs`](./qs.md) 68 | - [`read-pkg`](./read-pkg.md) 69 | - [`read-pkg-up`](./read-pkg-up.md) 70 | - [`read-package-up`](./read-package-up.md) 71 | - [`readable-stream`](./readable-stream.md) 72 | - [`rimraf`](./rimraf.md) 73 | - [`shortid`](./shortid.md) 74 | - [`sort-object`](./sort-object.md) 75 | - [`string-width`](./string-width.md) 76 | - [`strip-ansi`](./strip-ansi.md) 77 | - [`tempy`](./tempy.md) 78 | - [`traverse`](./traverse.md) 79 | - [`uri-js`](./uri-js.md) 80 | - [`utf8`](./utf8.md) 81 | - [`xmldom`](./xmldom.md) 82 | -------------------------------------------------------------------------------- /docs/modules/qs.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the qs package for parsing and serializing query strings 3 | --- 4 | 5 | # Replacements for `qs` 6 | 7 | ## `URLSearchParams` 8 | 9 | [`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. 10 | 11 | Example: 12 | 13 | ```ts 14 | import qs from 'qs' // [!code --] 15 | 16 | const query = 'a=1&a=2&b=3' 17 | 18 | const obj = qs.parse(query) // [!code --] 19 | const sp = new URLSearchParams(query) // [!code ++] 20 | const obj = Object.fromEntries(sp) // [!code ++] 21 | const a = sp.getAll('a') // [!code ++] 22 | ``` 23 | 24 | ## `fast-querystring` 25 | 26 | [`fast-querystring`](https://www.npmjs.com/package/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. 27 | 28 | Example: 29 | 30 | ```ts 31 | import qs from 'qs' // [!code --] 32 | import fqs from 'fast-querystring' // [!code ++] 33 | 34 | const obj = qs.parse('tag=a&tag=b') // [!code --] 35 | const obj = fqs.parse('tag=a&tag=b') // [!code ++] 36 | 37 | const str = qs.stringify({ tag: ['a', 'b'], q: 'x y' }) // [!code --] 38 | const str = fqs.stringify({ tag: ['a', 'b'], q: 'x y' }) // [!code ++] 39 | ``` 40 | 41 | ## `picoquery` 42 | 43 | [`picoquery`](https://www.npmjs.com/package/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. 44 | 45 | Example: 46 | 47 | ```ts 48 | import qs from 'qs' // [!code --] 49 | import { parse, stringify } from 'picoquery' // [!code ++] 50 | 51 | const opts = { // [!code ++] 52 | nestingSyntax: 'js', // [!code ++] 53 | arrayRepeat: true, // [!code ++] 54 | arrayRepeatSyntax: 'bracket' // [!code ++] 55 | } // [!code ++] 56 | 57 | const obj = qs.parse('user[name]=foo&tags[]=bar&tags[]=baz') // [!code --] 58 | const obj = parse('user[name]=foo&tags[]=bar&tags[]=baz', opts) // [!code ++] 59 | 60 | const str = qs.stringify({ user: { name: 'foo' }, tags: ['bar', 'baz'] }, { arrayFormat: 'brackets' }) // [!code --] 61 | const str = stringify({ user: { name: 'foo' }, tags: ['bar', 'baz'] }, opts) // [!code ++] 62 | ``` 63 | 64 | ## `neoqs` 65 | 66 | [`neoqs`](https://www.npmjs.com/package/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. 67 | 68 | Example: 69 | 70 | ```ts 71 | import qs from 'qs' // [!code --] 72 | import * as qs from 'neoqs' // [!code ++] 73 | 74 | const obj = qs.parse('a[b][c]=1&arr[]=2&arr[]=3') 75 | const str = qs.stringify(obj, { arrayFormat: 'brackets' }) 76 | ``` 77 | -------------------------------------------------------------------------------- /manifest-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "type": "object", 4 | "properties": { 5 | "moduleReplacements": { 6 | "type": "array", 7 | "items": { 8 | "anyOf": [ 9 | { 10 | "type": "object", 11 | "properties": { 12 | "type": { 13 | "type": "string", 14 | "const": "documented" 15 | }, 16 | "moduleName": { 17 | "type": "string" 18 | }, 19 | "category": { 20 | "type": "string" 21 | }, 22 | "docPath": { 23 | "type": "string" 24 | } 25 | }, 26 | "required": [ 27 | "docPath", 28 | "moduleName", 29 | "type" 30 | ], 31 | "additionalProperties": false 32 | }, 33 | { 34 | "type": "object", 35 | "properties": { 36 | "type": { 37 | "type": "string", 38 | "const": "native" 39 | }, 40 | "moduleName": { 41 | "type": "string" 42 | }, 43 | "category": { 44 | "type": "string" 45 | }, 46 | "mdnPath": { 47 | "type": "string" 48 | }, 49 | "nodeVersion": { 50 | "type": "string" 51 | }, 52 | "replacement": { 53 | "type": "string" 54 | } 55 | }, 56 | "required": [ 57 | "mdnPath", 58 | "moduleName", 59 | "nodeVersion", 60 | "replacement", 61 | "type" 62 | ], 63 | "additionalProperties": false 64 | }, 65 | { 66 | "type": "object", 67 | "properties": { 68 | "type": { 69 | "type": "string", 70 | "const": "simple" 71 | }, 72 | "moduleName": { 73 | "type": "string" 74 | }, 75 | "category": { 76 | "type": "string" 77 | }, 78 | "replacement": { 79 | "type": "string" 80 | } 81 | }, 82 | "required": [ 83 | "moduleName", 84 | "replacement", 85 | "type" 86 | ], 87 | "additionalProperties": false 88 | }, 89 | { 90 | "type": "object", 91 | "properties": { 92 | "type": { 93 | "type": "string", 94 | "const": "none" 95 | }, 96 | "moduleName": { 97 | "type": "string" 98 | }, 99 | "category": { 100 | "type": "string" 101 | } 102 | }, 103 | "required": [ 104 | "moduleName", 105 | "type" 106 | ], 107 | "additionalProperties": false 108 | } 109 | ] 110 | } 111 | } 112 | }, 113 | "required": [ 114 | "moduleReplacements" 115 | ], 116 | "additionalProperties": false, 117 | "definitions": {} 118 | } -------------------------------------------------------------------------------- /docs/modules/chalk.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the chalk package for terminal string styling and colors, with notes on browser console support 3 | --- 4 | 5 | # Replacements for `chalk` 6 | 7 | ## `styleText` (native) 8 | 9 | Since 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. 10 | 11 | Example: 12 | 13 | ```ts 14 | import { styleText } from 'node:util' // [!code ++] 15 | import chalk from 'chalk' // [!code --] 16 | 17 | console.log(`Hello ${chalk.blue('blue')} world!`) // [!code --] 18 | console.log(`Hello ${styleText('blue', 'blue')} world!`) // [!code ++] 19 | ``` 20 | 21 | When using multiple styles, you can pass an array to `styleText`: 22 | 23 | ```ts 24 | console.log(`I am ${chalk.blue.bgRed('blue on red')}!`) // [!code --] 25 | console.log(`I am ${styleText(['blue', 'bgRed'], 'blue on red')}!`) // [!code ++] 26 | ``` 27 | 28 | > [!NOTE] 29 | > `styleText` does not support RGB and hex colors (e.g. `#EFEFEF` or `255, 239, 235`). You can view the available styles in the [Node documentation](https://nodejs.org/api/util.html#modifiers). 30 | 31 | ## `picocolors` 32 | 33 | [`picocolors`](https://github.com/alexeyraspopov/picocolors) follows a similar API but without chaining: 34 | 35 | ```ts 36 | import chalk from 'chalk' // [!code --] 37 | import picocolors from 'picocolors' // [!code ++] 38 | 39 | console.log(`Hello ${chalk.blue('blue')} world!`) // [!code --] 40 | console.log(`Hello ${picocolors.blue('blue')} world!`) // [!code ++] 41 | 42 | // A chained example 43 | console.log(chalk.blue.bgRed('blue on red')) // [!code --] 44 | console.log(picocolors.blue(picocolors.bgRed('blue on red'))) // [!code ++] 45 | ``` 46 | 47 | > [!NOTE] 48 | > `picocolors` currently does not support RGB and hex colors (e.g. `#EFEFEF` or `255, 239, 235`). 49 | 50 | ## `ansis` 51 | 52 | [`ansis`](https://github.com/webdiscus/ansis/) supports a chaining syntax similar to chalk and supports both RGB, and hex colors. 53 | 54 | Example: 55 | 56 | ```ts 57 | import ansis from 'ansis' // [!code ++] 58 | import chalk from 'chalk' // [!code --] 59 | 60 | console.log(`Hello ${chalk.blue('blue')} world!`) // [!code --] 61 | console.log(`Hello ${ansis.blue('blue')} world!`) // [!code ++] 62 | ``` 63 | 64 | When using multiple styles, you can chain them just like in chalk: 65 | 66 | ```ts 67 | console.log(chalk.blue.bgRed('blue on red')) // [!code --] 68 | console.log(ansis.blue.bgRed('blue on red')) // [!code ++] 69 | ``` 70 | 71 | Similarly, you can use RGB and hex colors: 72 | 73 | ```ts 74 | console.log(chalk.rgb(239, 239, 239)('Hello world!')) // [!code --] 75 | console.log(ansis.rgb(239, 239, 239)('Hello world!')) // [!code ++] 76 | ``` 77 | 78 | ## Browser support 79 | 80 | While these libraries are primarily designed for terminal output, some projects may need colored output in browser environments. 81 | 82 | Following [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output), the native approach is `%c` directive in `console.log`: 83 | 84 | ```ts 85 | console.log( 86 | 'Hello %ce%c1%c8%ce', 87 | 'color: #ec8f5e;', 88 | 'color: #f2ca60;', 89 | 'color: #bece57;', 90 | 'color: #7bb560;', 91 | 'Ecosystem Performance' 92 | ) 93 | ``` 94 | 95 | Library support: 96 | - [`ansis`](https://github.com/webdiscus/ansis#browser-compatibility-for-ansi-codes) - colors are supported in _Chromium_ browsers 97 | - `picocolors` - strips colors in browser environments 98 | - `node:util` - is not available in browsers 99 | -------------------------------------------------------------------------------- /manifests/micro-utilities.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleReplacements": [ 3 | { 4 | "type": "simple", 5 | "moduleName": "arr-diff", 6 | "replacement": "Use a.filter((item) => !b.includes(item))", 7 | "category": "micro-utilities" 8 | }, 9 | { 10 | "type": "simple", 11 | "moduleName": "array-last", 12 | "replacement": "Use arr.at(-1) or arr[arr.length - 1]", 13 | "category": "micro-utilities" 14 | }, 15 | { 16 | "type": "simple", 17 | "moduleName": "array-union", 18 | "replacement": "Use [...new Set([...a, ...b])]", 19 | "category": "micro-utilities" 20 | }, 21 | { 22 | "type": "simple", 23 | "moduleName": "array-uniq", 24 | "replacement": "Use [...new Set(arr)]", 25 | "category": "micro-utilities" 26 | }, 27 | { 28 | "type": "simple", 29 | "moduleName": "array-unique", 30 | "replacement": "Use [...new Set(arr)]", 31 | "category": "micro-utilities" 32 | }, 33 | { 34 | "type": "simple", 35 | "moduleName": "arrify", 36 | "replacement": "Use (v == null ? [] : Array.isArray(v) ? v : [v])", 37 | "category": "micro-utilities" 38 | }, 39 | { 40 | "type": "simple", 41 | "moduleName": "call-bind", 42 | "replacement": "Use Function.call.bind(v)", 43 | "category": "micro-utilities" 44 | }, 45 | { 46 | "type": "simple", 47 | "moduleName": "clone-regexp", 48 | "replacement": "Use new RegExp(regexpToCopy)", 49 | "category": "micro-utilities" 50 | }, 51 | { 52 | "type": "simple", 53 | "moduleName": "es-get-iterator", 54 | "replacement": "Use v[Symbol.iterator]?.()", 55 | "category": "micro-utilities" 56 | }, 57 | { 58 | "type": "simple", 59 | "moduleName": "es-set-tostringtag", 60 | "replacement": "Use Object.defineProperty(target, Symbol.toStringTag, { value, configurable: true })", 61 | "category": "micro-utilities" 62 | }, 63 | { 64 | "type": "simple", 65 | "moduleName": "filter-obj", 66 | "replacement": "Use Object.fromEntries(Object.entries(obj).filter(fn))", 67 | "category": "micro-utilities" 68 | }, 69 | { 70 | "type": "simple", 71 | "moduleName": "has-flag", 72 | "replacement": "Use process.argv.includes('--flag')", 73 | "category": "micro-utilities" 74 | }, 75 | { 76 | "type": "simple", 77 | "moduleName": "is-array-buffer", 78 | "replacement": "Use v instanceof ArrayBuffer, or if cross-realm, use Object.prototype.toString.call(v) === \"[object ArrayBuffer]\"", 79 | "category": "micro-utilities" 80 | }, 81 | { 82 | "type": "simple", 83 | "moduleName": "is-boolean-object", 84 | "replacement": "Use Object.prototype.toString.call(v) === \"[object Boolean]\"", 85 | "category": "micro-utilities" 86 | }, 87 | { 88 | "type": "simple", 89 | "moduleName": "is-ci", 90 | "replacement": "Use Boolean(process.env.CI)", 91 | "category": "micro-utilities" 92 | }, 93 | { 94 | "type": "simple", 95 | "moduleName": "is-date-object", 96 | "replacement": "Use v instanceof Date, or if cross-realm, use Object.prototype.toString.call(v) === \"[object Date]\"", 97 | "category": "micro-utilities" 98 | }, 99 | { 100 | "type": "simple", 101 | "moduleName": "is-even", 102 | "replacement": "Use (n % 2) === 0", 103 | "category": "micro-utilities" 104 | }, 105 | { 106 | "type": "simple", 107 | "moduleName": "is-finite", 108 | "replacement": "Use Number.isFinite(v)", 109 | "category": "micro-utilities" 110 | }, 111 | { 112 | "type": "simple", 113 | "moduleName": "is-negative", 114 | "replacement": "Use (n) => n < 0", 115 | "category": "micro-utilities" 116 | }, 117 | { 118 | "type": "simple", 119 | "moduleName": "is-negative-zero", 120 | "replacement": "Use Object.is(v, -0)", 121 | "category": "micro-utilities" 122 | }, 123 | { 124 | "type": "simple", 125 | "moduleName": "is-npm", 126 | "replacement": "Use process.env.npm_config_user_agent?.startsWith(\"npm\")", 127 | "category": "micro-utilities" 128 | }, 129 | { 130 | "type": "simple", 131 | "moduleName": "is-number", 132 | "replacement": "Use typeof v === \"number\" || (typeof v === \"string\" && Number.isFinite(+v))", 133 | "category": "micro-utilities" 134 | }, 135 | { 136 | "type": "simple", 137 | "moduleName": "is-number-object", 138 | "replacement": "Use Object.prototype.toString.call(v) === \"[object Number]\"", 139 | "category": "micro-utilities" 140 | }, 141 | { 142 | "type": "simple", 143 | "moduleName": "is-odd", 144 | "replacement": "Use (n % 2) === 1", 145 | "category": "micro-utilities" 146 | }, 147 | { 148 | "type": "simple", 149 | "moduleName": "is-plain-object", 150 | "replacement": "Use v && typeof v === \"object\" && (Object.getPrototypeOf(v) === null || Object.getPrototypeOf(v) === Object.prototype)", 151 | "category": "micro-utilities" 152 | }, 153 | { 154 | "type": "simple", 155 | "moduleName": "is-primitive", 156 | "replacement": "Use v === null || (typeof v !== \"function\" && typeof v !== \"object\")", 157 | "category": "micro-utilities" 158 | }, 159 | { 160 | "type": "simple", 161 | "moduleName": "is-regexp", 162 | "replacement": "Use v instanceof RegExp, or if cross-realm, use Object.prototype.toString.call(v) === \"[object RegExp]\"", 163 | "category": "micro-utilities" 164 | }, 165 | { 166 | "type": "simple", 167 | "moduleName": "is-string", 168 | "replacement": "Use typeof str === \"string\"", 169 | "category": "micro-utilities" 170 | }, 171 | { 172 | "type": "simple", 173 | "moduleName": "is-travis", 174 | "replacement": "Use (\"TRAVIS\" in process.env)", 175 | "category": "micro-utilities" 176 | }, 177 | { 178 | "type": "simple", 179 | "moduleName": "is-whitespace", 180 | "replacement": "Use str.trim() === \"\" or /^\\s*$/.test(str)", 181 | "category": "micro-utilities" 182 | }, 183 | { 184 | "type": "simple", 185 | "moduleName": "is-windows", 186 | "replacement": "Use process.platform === \"win32\"", 187 | "category": "micro-utilities" 188 | }, 189 | { 190 | "type": "simple", 191 | "moduleName": "kind-of", 192 | "replacement": "Use typeof v, or Object.prototype.toString.call(v) to get the internal [[Class]]", 193 | "category": "micro-utilities" 194 | }, 195 | { 196 | "type": "simple", 197 | "moduleName": "lower-case", 198 | "replacement": "Use str.toLocaleLowerCase() or str.toLowerCase()", 199 | "category": "micro-utilities" 200 | }, 201 | { 202 | "type": "simple", 203 | "moduleName": "repeat-string", 204 | "replacement": "Use str.repeat(n)", 205 | "category": "micro-utilities" 206 | }, 207 | { 208 | "type": "simple", 209 | "moduleName": "slash", 210 | "replacement": "Use path.startsWith('\\\\?\\') ? path : path.replace(/\\/g, '/')", 211 | "category": "micro-utilities" 212 | }, 213 | { 214 | "type": "simple", 215 | "moduleName": "split-lines", 216 | "replacement": "Use str.split(/\\r?\\n/)", 217 | "category": "micro-utilities" 218 | }, 219 | { 220 | "type": "simple", 221 | "moduleName": "uniq", 222 | "replacement": "Use [...new Set(arr)]", 223 | "category": "micro-utilities" 224 | }, 225 | { 226 | "type": "simple", 227 | "moduleName": "upper-case", 228 | "replacement": "Use str.toLocaleUpperCase() or str.toUpperCase()", 229 | "category": "micro-utilities" 230 | } 231 | ] 232 | } 233 | -------------------------------------------------------------------------------- /docs/modules/fs-extra.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Modern alternatives to the fs-extra package for working with the file system 3 | --- 4 | 5 | # Replacements for `fs-extra` 6 | 7 | ## Node.js 8 | 9 | Modern Node.js includes built-in fs and fs/promises APIs that cover what [`fs-extra`](https://github.com/jprichardson/node-fs-extra) historically provided. The table below maps `fs-extra` methods to Node.js APIs and highlights significant differences 10 | 11 | | fs-extra | node:fs | Notes | 12 | | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | 13 | | [`copy(src, dest[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/copy.md) | [`fsPromises.cp(src, dest[, options])`](https://nodejs.org/api/fs.html#fspromisescpsrc-dest-options) | If src is a file and dest is an existing directory, `fs-extra` throws; `fs.cp` copies into the directory. filter must be sync. | 14 | | [`copySync(src, dest[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/copy-sync.md) | [`fs.cpSync(src, dest[, options])`](https://nodejs.org/api/fs.html#fscpsyncsrc-dest-options) | | 15 | | [`remove(path[, callback])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/remove.md) | [`fsPromises.rm(path[, options])`](https://nodejs.org/api/fs.html#fspromisesrmpath-options) | Use `force: true` to match fs-extra’s "silently ignore missing path". Consider `maxRetries`/`retryDelay`. | 16 | | [`removeSync(path)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/remove-sync.md) | [`fs.rmSync(path[, options])`](https://nodejs.org/api/fs.html#fsrmsyncpath-options) | | 17 | | [`mkdirs(dir[, options][, callback])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md), [`mkdirp(...)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md), [`ensureDir(...)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md) | [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) | Use `{ recursive: true }`. | 18 | | [`mkdirsSync(dir[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir-sync.md), [`mkdirpSync(...)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir-sync.md), [`ensureDirSync(...)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir-sync.md) | [`fs.mkdirSync(path[, options])`](https://nodejs.org/api/fs.html#fsmkdirsyncpath-options) | Use `{ recursive: true }`. | 19 | | [`pathExists(path)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/pathExists.md) | [`fsPromises.access(path[, mode])`](https://nodejs.org/api/fs.html#fspromisesaccesspath-mode) | Return `boolean` (wrap resolve/reject). | 20 | | [`pathExistsSync(path)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/pathExists-sync.md) | [`fs.existsSync(path)`](https://nodejs.org/api/fs.html#fsexistssyncpath) | | 21 | | [`outputFile(file, data[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/outputFile.md) | [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) + [`fsPromises.writeFile(file, data[, options])`](https://nodejs.org/api/fs.html#fspromiseswritefilefile-data-options) | Ensure parent directory. | 22 | | [`outputFileSync(file, data[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/outputFile-sync.md) | [`fs.mkdirSync(path[, options])`](https://nodejs.org/api/fs.html#fsmkdirsyncpath-options) + [`fs.writeFileSync(file, data[, options])`](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options) | | 23 | | [`readJson(file[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/readJson.md) | [`fsPromises.readFile(path[, options])`](https://nodejs.org/api/fs.html#fspromisesreadfilepath-options) | Use `JSON.parse`; ensure 'utf8'. fs-extra’s `throws:false` is not built-in. | 24 | | [`writeJson(file, obj[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/writeJson.md) | [`fsPromises.writeFile(file, data[, options])`](https://nodejs.org/api/fs.html#fspromiseswritefilefile-data-options) | Use `JSON.stringify`; EOL option not built-in. | 25 | | [`outputJson(file, obj[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/outputJson.md) | [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) + [`fsPromises.writeFile(file, data[, options])`](https://nodejs.org/api/fs.html#fspromiseswritefilefile-data-options) | Ensure parent directory; EOL not built-in. | 26 | | [`ensureFile(file)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureFile.md) / [`createFile(file)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureFile.md) | [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) + [`fsPromises.writeFile(file, data[, options])`](https://nodejs.org/api/fs.html#fspromiseswritefilefile-data-options) | Non-truncating create (e.g., `{ flag: 'a' }`). | 27 | | [`ensureFileSync(file)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureFile-sync.md) / [`createFileSync(file)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureFile-sync.md) | [`fs.mkdirSync(path[, options])`](https://nodejs.org/api/fs.html#fsmkdirsyncpath-options) + [`fs.writeFileSync(file, data[, options])`](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options) | | 28 | | [`ensureLink(src, dst)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureLink.md) / [`createLink(src, dst)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureLink.md) | [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) + [`fsPromises.link(existingPath, newPath)`](https://nodejs.org/api/fs.html#fspromiseslinkexistingpath-newpath) | Same device only. | 29 | | [`ensureLinkSync(src, dst)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureLink-sync.md) / [`createLinkSync(src, dst)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureLink-sync.md) | [`fs.mkdirSync(path[, options])`](https://nodejs.org/api/fs.html#fsmkdirsyncpath-options) + [`fs.linkSync(existingPath, newPath)`](https://nodejs.org/api/fs.html#fslinksyncexistingpath-newpath) | | 30 | | [`ensureSymlink(src, dst[, type])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureSymlink.md) / [`createSymlink(...)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureSymlink.md) | [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) + [`fsPromises.symlink(target, path[, type])`](https://nodejs.org/api/fs.html#fspromisessymlinktarget-path-type) | | 31 | | [`ensureSymlinkSync(src, dst[, type])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureSymlink-sync.md) / [`createSymlinkSync(...)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureSymlink-sync.md) | [`fs.mkdirSync(path[, options])`](https://nodejs.org/api/fs.html#fsmkdirsyncpath-options) + [`fs.symlinkSync(target, path[, type])`](https://nodejs.org/api/fs.html#fssymlinksynctarget-path-type) | | 32 | | [`emptyDir(dir)`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/emptyDir.md) / `emptydir(dir)` | [`fsPromises.rm(path[, options])`](https://nodejs.org/api/fs.html#fspromisesrmpath-options) + [`fsPromises.mkdir(path[, options])`](https://nodejs.org/api/fs.html#fspromisesmkdirpath-options) | Preserves dir inode vs `rm`+`mkdir` (inode changes). | 33 | | [`move(src, dest[, options])`](https://github.com/jprichardson/node-fs-extra/blob/master/docs/move.md) | [`fsPromises.rename(oldPath, newPath)`](https://nodejs.org/api/fs.html#fspromisesrenameoldpath-newpath) | Not cross-device; add `cp` + `rm` fallback. No overwrite option - handle existing dest. | 34 | -------------------------------------------------------------------------------- /manifests/native.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleReplacements": [ 3 | { 4 | "type": "native", 5 | "moduleName": "array-buffer-byte-length", 6 | "nodeVersion": "0.10.0", 7 | "replacement": "ArrayBuffer.prototype.byteLength", 8 | "mdnPath": "Global_Objects/ArrayBuffer/byteLength", 9 | "category": "native" 10 | }, 11 | { 12 | "type": "native", 13 | "moduleName": "array-every", 14 | "nodeVersion": "0.10.0", 15 | "replacement": "Array.prototype.every", 16 | "mdnPath": "Global_Objects/Array/every", 17 | "category": "native" 18 | }, 19 | { 20 | "type": "native", 21 | "moduleName": "array-includes", 22 | "nodeVersion": "6.0.0", 23 | "replacement": "Array.prototype.includes", 24 | "mdnPath": "Global_Objects/Array/includes", 25 | "category": "native" 26 | }, 27 | { 28 | "type": "native", 29 | "moduleName": "array-map", 30 | "nodeVersion": "0.10.0", 31 | "replacement": "Array.prototype.map", 32 | "mdnPath": "Global_Objects/Array/map", 33 | "category": "native" 34 | }, 35 | { 36 | "type": "native", 37 | "moduleName": "array.from", 38 | "nodeVersion": "4.0.0", 39 | "replacement": "Array.from", 40 | "mdnPath": "Global_Objects/Array/from", 41 | "category": "native" 42 | }, 43 | { 44 | "type": "native", 45 | "moduleName": "array.of", 46 | "nodeVersion": "4.0.0", 47 | "replacement": "Array.of", 48 | "mdnPath": "Global_Objects/Array/of", 49 | "category": "native" 50 | }, 51 | { 52 | "type": "native", 53 | "moduleName": "array.prototype.at", 54 | "nodeVersion": "16.6.0", 55 | "replacement": "Array.prototype.at", 56 | "mdnPath": "Global_Objects/Array/at", 57 | "category": "native" 58 | }, 59 | { 60 | "type": "native", 61 | "moduleName": "array.prototype.concat", 62 | "nodeVersion": "0.10.0", 63 | "replacement": "Array.prototype.concat", 64 | "mdnPath": "Global_Objects/Array/concat", 65 | "category": "native" 66 | }, 67 | { 68 | "type": "native", 69 | "moduleName": "array.prototype.copywithin", 70 | "nodeVersion": "4.0.0", 71 | "replacement": "Array.prototype.copyWithin", 72 | "mdnPath": "Global_Objects/Array/copyWithin", 73 | "category": "native" 74 | }, 75 | { 76 | "type": "native", 77 | "moduleName": "array.prototype.entries", 78 | "nodeVersion": "0.12.0", 79 | "replacement": "Array.prototype.entries", 80 | "mdnPath": "Global_Objects/Array/entries", 81 | "category": "native" 82 | }, 83 | { 84 | "type": "native", 85 | "moduleName": "array.prototype.every", 86 | "nodeVersion": "0.10.0", 87 | "replacement": "Array.prototype.every", 88 | "mdnPath": "Global_Objects/Array/every", 89 | "category": "native" 90 | }, 91 | { 92 | "type": "native", 93 | "moduleName": "array.prototype.filter", 94 | "nodeVersion": "0.10.0", 95 | "replacement": "Array.prototype.filter", 96 | "mdnPath": "Global_Objects/Array/filter", 97 | "category": "native" 98 | }, 99 | { 100 | "type": "native", 101 | "moduleName": "array.prototype.find", 102 | "nodeVersion": "4.0.0", 103 | "replacement": "Array.prototype.find", 104 | "mdnPath": "Global_Objects/Array/find", 105 | "category": "native" 106 | }, 107 | { 108 | "type": "native", 109 | "moduleName": "array.prototype.findindex", 110 | "nodeVersion": "4.0.0", 111 | "replacement": "Array.prototype.findIndex", 112 | "mdnPath": "Global_Objects/Array/findIndex", 113 | "category": "native" 114 | }, 115 | { 116 | "type": "native", 117 | "moduleName": "array.prototype.flat", 118 | "nodeVersion": "11.0.0", 119 | "replacement": "Array.prototype.flat", 120 | "mdnPath": "Global_Objects/Array/flat", 121 | "category": "native" 122 | }, 123 | { 124 | "type": "native", 125 | "moduleName": "array.prototype.flatmap", 126 | "nodeVersion": "11.0.0", 127 | "replacement": "Array.prototype.flatMap", 128 | "mdnPath": "Global_Objects/Array/flatMap", 129 | "category": "native" 130 | }, 131 | { 132 | "type": "native", 133 | "moduleName": "array.prototype.foreach", 134 | "nodeVersion": "0.10.0", 135 | "replacement": "Array.prototype.forEach", 136 | "mdnPath": "Global_Objects/Array/forEach", 137 | "category": "native" 138 | }, 139 | { 140 | "type": "native", 141 | "moduleName": "array.prototype.indexof", 142 | "nodeVersion": "0.10.0", 143 | "replacement": "Array.prototype.indexOf", 144 | "mdnPath": "Global_Objects/Array/indexOf", 145 | "category": "native" 146 | }, 147 | { 148 | "type": "native", 149 | "moduleName": "array.prototype.join", 150 | "nodeVersion": "0.10.0", 151 | "replacement": "Array.prototype.join", 152 | "mdnPath": "Global_Objects/Array/join", 153 | "category": "native" 154 | }, 155 | { 156 | "type": "native", 157 | "moduleName": "array.prototype.keys", 158 | "nodeVersion": "0.12.0", 159 | "replacement": "Array.prototype.keys", 160 | "mdnPath": "Global_Objects/Array/keys", 161 | "category": "native" 162 | }, 163 | { 164 | "type": "native", 165 | "moduleName": "array.prototype.lastindexof", 166 | "nodeVersion": "0.10.0", 167 | "replacement": "Array.prototype.lastIndexOf", 168 | "mdnPath": "Global_Objects/Array/lastIndexOf", 169 | "category": "native" 170 | }, 171 | { 172 | "type": "native", 173 | "moduleName": "array.prototype.map", 174 | "nodeVersion": "0.10.0", 175 | "replacement": "Array.prototype.map", 176 | "mdnPath": "Global_Objects/Array/map", 177 | "category": "native" 178 | }, 179 | { 180 | "type": "native", 181 | "moduleName": "array.prototype.push", 182 | "nodeVersion": "0.10.0", 183 | "replacement": "Array.prototype.push", 184 | "mdnPath": "Global_Objects/Array/push", 185 | "category": "native" 186 | }, 187 | { 188 | "type": "native", 189 | "moduleName": "array.prototype.reduce", 190 | "nodeVersion": "0.10.0", 191 | "replacement": "Array.prototype.reduce", 192 | "mdnPath": "Global_Objects/Array/reduce", 193 | "category": "native" 194 | }, 195 | { 196 | "type": "native", 197 | "moduleName": "array.prototype.reduceright", 198 | "nodeVersion": "0.10.0", 199 | "replacement": "Array.prototype.reduceRight", 200 | "mdnPath": "Global_Objects/Array/reduceRight", 201 | "category": "native" 202 | }, 203 | { 204 | "type": "native", 205 | "moduleName": "array.prototype.slice", 206 | "nodeVersion": "0.10.0", 207 | "replacement": "Array.prototype.slice", 208 | "mdnPath": "Global_Objects/Array/slice", 209 | "category": "native" 210 | }, 211 | { 212 | "type": "native", 213 | "moduleName": "array.prototype.some", 214 | "nodeVersion": "0.10.0", 215 | "replacement": "Array.prototype.some", 216 | "mdnPath": "Global_Objects/Array/some", 217 | "category": "native" 218 | }, 219 | { 220 | "type": "native", 221 | "moduleName": "array.prototype.splice", 222 | "nodeVersion": "0.10.0", 223 | "replacement": "Array.prototype.splice", 224 | "mdnPath": "Global_Objects/Array/splice", 225 | "category": "native" 226 | }, 227 | { 228 | "type": "native", 229 | "moduleName": "array.prototype.unshift", 230 | "nodeVersion": "0.10.0", 231 | "replacement": "Array.prototype.unshift", 232 | "mdnPath": "Global_Objects/Array/unshift", 233 | "category": "native" 234 | }, 235 | { 236 | "type": "native", 237 | "moduleName": "array.prototype.values", 238 | "nodeVersion": "10.9.0", 239 | "replacement": "Array.prototype.values", 240 | "mdnPath": "Global_Objects/Array/values", 241 | "category": "native" 242 | }, 243 | { 244 | "type": "native", 245 | "moduleName": "arraybuffer.prototype.slice", 246 | "nodeVersion": "0.12.0", 247 | "replacement": "ArrayBuffer.prototype.slice", 248 | "mdnPath": "Global_Objects/ArrayBuffer/slice", 249 | "category": "native" 250 | }, 251 | { 252 | "type": "native", 253 | "moduleName": "concat-map", 254 | "nodeVersion": "11.0.0", 255 | "replacement": "Array.prototype.flatMap", 256 | "mdnPath": "Global_Objects/Array/flatMap", 257 | "category": "native" 258 | }, 259 | { 260 | "type": "native", 261 | "moduleName": "data-view-buffer", 262 | "nodeVersion": "0.10.0", 263 | "replacement": "DataView.prototype.buffer", 264 | "mdnPath": "Global_Objects/DataView/buffer", 265 | "category": "native" 266 | }, 267 | { 268 | "type": "native", 269 | "moduleName": "data-view-byte-length", 270 | "nodeVersion": "0.10.0", 271 | "replacement": "DataView.prototype.byteLength", 272 | "mdnPath": "Global_Objects/DataView/byteLength", 273 | "category": "native" 274 | }, 275 | { 276 | "type": "native", 277 | "moduleName": "data-view-byte-offset", 278 | "nodeVersion": "0.10.0", 279 | "replacement": "DataView.prototype.byteOffset", 280 | "mdnPath": "Global_Objects/DataView/byteOffset", 281 | "category": "native" 282 | }, 283 | { 284 | "type": "native", 285 | "moduleName": "date", 286 | "nodeVersion": "0.10.0", 287 | "replacement": "Date", 288 | "mdnPath": "Global_Objects/Date", 289 | "category": "native" 290 | }, 291 | { 292 | "type": "native", 293 | "moduleName": "defaults", 294 | "nodeVersion": "4.0.0", 295 | "replacement": "Object.assign, or if deep clones are needed, use structuredClone", 296 | "mdnPath": "Global_Objects/Object/assign", 297 | "category": "native" 298 | }, 299 | { 300 | "type": "native", 301 | "moduleName": "define-accessor-property", 302 | "nodeVersion": "0.10.0", 303 | "replacement": "Object.defineProperty", 304 | "mdnPath": "Global_Objects/Object/defineProperty", 305 | "category": "native" 306 | }, 307 | { 308 | "type": "native", 309 | "moduleName": "define-data-property", 310 | "nodeVersion": "0.10.0", 311 | "replacement": "Object.defineProperty", 312 | "mdnPath": "Global_Objects/Object/defineProperty", 313 | "category": "native" 314 | }, 315 | { 316 | "type": "native", 317 | "moduleName": "define-properties", 318 | "nodeVersion": "0.10.0", 319 | "replacement": "Object.defineProperties", 320 | "mdnPath": "Global_Objects/Object/defineProperties", 321 | "category": "native" 322 | }, 323 | { 324 | "type": "native", 325 | "moduleName": "error-cause", 326 | "nodeVersion": "16.9.0", 327 | "replacement": "Use errors `.cause` property and second `Error` constructors argument to define it", 328 | "mdnPath": "Global_Objects/Error/cause", 329 | "category": "native" 330 | }, 331 | { 332 | "type": "native", 333 | "moduleName": "es-aggregate-error", 334 | "nodeVersion": "15.0.0", 335 | "replacement": "AggregateError", 336 | "mdnPath": "Global_Objects/AggregateError", 337 | "category": "native" 338 | }, 339 | { 340 | "type": "native", 341 | "moduleName": "es-create-array-iterator", 342 | "nodeVersion": "0.12.0", 343 | "replacement": "Array.prototype.{ entries, keys, values, [Symbol.iterator] }", 344 | "mdnPath": "Global_Objects/Array/entries", 345 | "category": "native" 346 | }, 347 | { 348 | "type": "native", 349 | "moduleName": "es-define-property", 350 | "nodeVersion": "0.10.0", 351 | "replacement": "Object.defineProperty", 352 | "mdnPath": "Global_Objects/Object/defineProperty", 353 | "category": "native" 354 | }, 355 | { 356 | "type": "native", 357 | "moduleName": "es-errors", 358 | "nodeVersion": "0.10.0", 359 | "replacement": "Error / EvalError / RangeError / ReferenceError / SyntaxError / TypeError / URIError", 360 | "mdnPath": "Global_Objects/Error", 361 | "category": "native" 362 | }, 363 | { 364 | "type": "native", 365 | "moduleName": "es-shim-unscopables", 366 | "nodeVersion": "0.12.0", 367 | "replacement": "Array.prototype[Symbol.unscopables]", 368 | "mdnPath": "Global_Objects/Array/@@unscopables", 369 | "category": "native" 370 | }, 371 | { 372 | "type": "native", 373 | "moduleName": "es-string-html-methods", 374 | "nodeVersion": "0.10.0", 375 | "replacement": "String.prototype.{ anchor, big, blink, bold, fixed, fontcolor, fontsize, italics, link, small, strike, sub, sup }", 376 | "mdnPath": "Global_Objects/String#html_wrapper_methods", 377 | "category": "native" 378 | }, 379 | { 380 | "type": "native", 381 | "moduleName": "extend-shallow", 382 | "nodeVersion": "4.0.0", 383 | "replacement": "Object.assign, or if deep clones are needed, use structuredClone", 384 | "mdnPath": "Global_Objects/Object/assign", 385 | "category": "native" 386 | }, 387 | { 388 | "type": "native", 389 | "moduleName": "filter-array", 390 | "nodeVersion": "0.10.0", 391 | "replacement": "Array.prototype.filter", 392 | "mdnPath": "Global_Objects/Array/filter", 393 | "category": "native" 394 | }, 395 | { 396 | "type": "native", 397 | "moduleName": "for-each", 398 | "nodeVersion": "0.12.0", 399 | "replacement": "for...of (using \"Object.entries\" if dealing with objects)", 400 | "mdnPath": "Statements/for...of", 401 | "category": "native" 402 | }, 403 | { 404 | "type": "native", 405 | "moduleName": "function-bind", 406 | "nodeVersion": "0.10.0", 407 | "replacement": "Function.prototype.bind", 408 | "mdnPath": "Global_Objects/Function/bind", 409 | "category": "native" 410 | }, 411 | { 412 | "type": "native", 413 | "moduleName": "function.prototype.name", 414 | "nodeVersion": "0.10.0", 415 | "replacement": "Use functions `.name` property", 416 | "mdnPath": "Global_Objects/Function/name", 417 | "category": "native" 418 | }, 419 | { 420 | "type": "native", 421 | "moduleName": "functions-have-names", 422 | "nodeVersion": "0.10.0", 423 | "replacement": "Always `true`", 424 | "mdnPath": "Global_Objects/Function/name", 425 | "category": "native" 426 | }, 427 | { 428 | "type": "native", 429 | "moduleName": "get-symbol-description", 430 | "nodeVersion": "11.0.0", 431 | "replacement": "Symbol.prototype.description", 432 | "mdnPath": "Global_Objects/Symbol/description", 433 | "category": "native" 434 | }, 435 | { 436 | "type": "native", 437 | "moduleName": "global", 438 | "nodeVersion": "12.0.0", 439 | "replacement": "globalThis", 440 | "mdnPath": "Global_Objects/globalThis", 441 | "category": "native" 442 | }, 443 | { 444 | "type": "native", 445 | "moduleName": "globalthis", 446 | "nodeVersion": "12.0.0", 447 | "replacement": "globalThis", 448 | "mdnPath": "Global_Objects/globalThis", 449 | "category": "native" 450 | }, 451 | { 452 | "type": "native", 453 | "moduleName": "gopd", 454 | "nodeVersion": "0.10.0", 455 | "replacement": "Object.getOwnPropertyDescriptor", 456 | "mdnPath": "Global_Objects/Object/getOwnPropertyDescriptor", 457 | "category": "native" 458 | }, 459 | { 460 | "type": "native", 461 | "moduleName": "has", 462 | "nodeVersion": "0.10.0", 463 | "replacement": "Object.prototype.hasOwnProperty.call(obj, prop) (or in later versions of node, \"Object.hasOwn(obj, prop)\")", 464 | "mdnPath": "Global_Objects/Object/hasOwnProperty", 465 | "category": "native" 466 | }, 467 | { 468 | "type": "native", 469 | "moduleName": "has-own-prop", 470 | "nodeVersion": "0.10.0", 471 | "replacement": "Object.prototype.hasOwnProperty.call(obj, prop) (or in later versions of node, \"Object.hasOwn(obj, prop)\")", 472 | "mdnPath": "Global_Objects/Object/hasOwnProperty", 473 | "category": "native" 474 | }, 475 | { 476 | "type": "native", 477 | "moduleName": "has-proto", 478 | "nodeVersion": "0.10.0", 479 | "replacement": "Always `true`", 480 | "mdnPath": "Operators/Object_initializer#prototype_setter", 481 | "category": "native" 482 | }, 483 | { 484 | "type": "native", 485 | "moduleName": "has-symbols", 486 | "nodeVersion": "0.12.0", 487 | "replacement": "Always `true`", 488 | "mdnPath": "Global_Objects/Symbol", 489 | "category": "native" 490 | }, 491 | { 492 | "type": "native", 493 | "moduleName": "has-tostringtag", 494 | "nodeVersion": "6.0.0", 495 | "replacement": "Always `true`", 496 | "mdnPath": "Global_Objects/Symbol/toStringTag", 497 | "category": "native" 498 | }, 499 | { 500 | "type": "native", 501 | "moduleName": "hasown", 502 | "nodeVersion": "0.10.0", 503 | "replacement": "Object.prototype.hasOwnProperty.call(obj, prop) (or in later versions of node, \"Object.hasOwn(obj, prop)\")", 504 | "mdnPath": "Global_Objects/Object/hasOwnProperty", 505 | "category": "native" 506 | }, 507 | { 508 | "type": "native", 509 | "moduleName": "index-of", 510 | "nodeVersion": "0.10.0", 511 | "replacement": "Array.prototype.indexOf", 512 | "mdnPath": "Global_Objects/Array/indexOf", 513 | "category": "native" 514 | }, 515 | { 516 | "type": "native", 517 | "moduleName": "inherits", 518 | "nodeVersion": "6.0.0", 519 | "replacement": "Use native class syntax", 520 | "mdnPath": "Classes/extends", 521 | "category": "native" 522 | }, 523 | { 524 | "type": "native", 525 | "moduleName": "is-nan", 526 | "nodeVersion": "0.10.0", 527 | "replacement": "Number.isNaN", 528 | "mdnPath": "Global_Objects/Number/isNaN", 529 | "category": "native" 530 | }, 531 | { 532 | "type": "native", 533 | "moduleName": "iterate-iterator", 534 | "nodeVersion": "0.12.0", 535 | "replacement": "for...of", 536 | "mdnPath": "Statements/for...of", 537 | "category": "native" 538 | }, 539 | { 540 | "type": "native", 541 | "moduleName": "iterate-value", 542 | "nodeVersion": "0.12.0", 543 | "replacement": "for...of", 544 | "mdnPath": "Statements/for...of", 545 | "category": "native" 546 | }, 547 | { 548 | "type": "native", 549 | "moduleName": "last-index-of", 550 | "nodeVersion": "0.10.0", 551 | "replacement": "Array.prototype.lastIndexOf", 552 | "mdnPath": "Global_Objects/Array/lastIndexOf", 553 | "category": "native" 554 | }, 555 | { 556 | "type": "native", 557 | "moduleName": "left-pad", 558 | "nodeVersion": "8.0.0", 559 | "replacement": "String.prototype.padStart", 560 | "mdnPath": "Global_Objects/String/padStart", 561 | "category": "native" 562 | }, 563 | { 564 | "type": "native", 565 | "moduleName": "math.acosh", 566 | "nodeVersion": "0.10.0", 567 | "replacement": "Math.acosh", 568 | "mdnPath": "Global_Objects/Math/acosh", 569 | "category": "native" 570 | }, 571 | { 572 | "type": "native", 573 | "moduleName": "math.atanh", 574 | "nodeVersion": "0.10.0", 575 | "replacement": "Math.atanh", 576 | "mdnPath": "Global_Objects/Math/atanh", 577 | "category": "native" 578 | }, 579 | { 580 | "type": "native", 581 | "moduleName": "math.cbrt", 582 | "nodeVersion": "0.10.0", 583 | "replacement": "Math.cbrt", 584 | "mdnPath": "Global_Objects/Math/cbrt", 585 | "category": "native" 586 | }, 587 | { 588 | "type": "native", 589 | "moduleName": "math.clz32", 590 | "nodeVersion": "0.10.0", 591 | "replacement": "Math.clz32", 592 | "mdnPath": "Global_Objects/Math/clz32", 593 | "category": "native" 594 | }, 595 | { 596 | "type": "native", 597 | "moduleName": "math.f16round", 598 | "nodeVersion": "0.10.0", 599 | "replacement": "Math.f16round", 600 | "mdnPath": "Global_Objects/Math/f16round", 601 | "category": "native" 602 | }, 603 | { 604 | "type": "native", 605 | "moduleName": "math.fround", 606 | "nodeVersion": "0.10.0", 607 | "replacement": "Math.fround", 608 | "mdnPath": "Global_Objects/Math/fround", 609 | "category": "native" 610 | }, 611 | { 612 | "type": "native", 613 | "moduleName": "math.imul", 614 | "nodeVersion": "0.10.0", 615 | "replacement": "Math.imul", 616 | "mdnPath": "Global_Objects/Math/imul", 617 | "category": "native" 618 | }, 619 | { 620 | "type": "native", 621 | "moduleName": "math.log10", 622 | "nodeVersion": "0.10.0", 623 | "replacement": "Math.log10", 624 | "mdnPath": "Global_Objects/Math/log10", 625 | "category": "native" 626 | }, 627 | { 628 | "type": "native", 629 | "moduleName": "math.log1p", 630 | "nodeVersion": "0.10.0", 631 | "replacement": "Math.log1p", 632 | "mdnPath": "Global_Objects/Math/log1p", 633 | "category": "native" 634 | }, 635 | { 636 | "type": "native", 637 | "moduleName": "math.sign", 638 | "nodeVersion": "0.10.0", 639 | "replacement": "Math.sign", 640 | "mdnPath": "Global_Objects/Math/sign", 641 | "category": "native" 642 | }, 643 | { 644 | "type": "native", 645 | "moduleName": "node.extend", 646 | "nodeVersion": "4.0.0", 647 | "replacement": "Object.assign, or if deep clones are needed, use structuredClone", 648 | "mdnPath": "Global_Objects/Object/assign", 649 | "category": "native" 650 | }, 651 | { 652 | "type": "native", 653 | "moduleName": "number.isfinite", 654 | "nodeVersion": "0.10.0", 655 | "replacement": "Number.isFinite", 656 | "mdnPath": "Global_Objects/Number/isFinite", 657 | "category": "native" 658 | }, 659 | { 660 | "type": "native", 661 | "moduleName": "number.isinteger", 662 | "nodeVersion": "0.10.0", 663 | "replacement": "Number.isInteger", 664 | "mdnPath": "Global_Objects/Number/isInteger", 665 | "category": "native" 666 | }, 667 | { 668 | "type": "native", 669 | "moduleName": "number.isnan", 670 | "nodeVersion": "0.10.0", 671 | "replacement": "Number.isNaN", 672 | "mdnPath": "Global_Objects/Number/isNaN", 673 | "category": "native" 674 | }, 675 | { 676 | "type": "native", 677 | "moduleName": "number.issafeinteger", 678 | "nodeVersion": "0.10.0", 679 | "replacement": "Number.isSafeInteger", 680 | "mdnPath": "Global_Objects/Number/isSafeInteger", 681 | "category": "native" 682 | }, 683 | { 684 | "type": "native", 685 | "moduleName": "number.parsefloat", 686 | "nodeVersion": "0.10.0", 687 | "replacement": "Number.parseFloat", 688 | "mdnPath": "Global_Objects/Number/parseFloat", 689 | "category": "native" 690 | }, 691 | { 692 | "type": "native", 693 | "moduleName": "number.parseint", 694 | "nodeVersion": "0.10.0", 695 | "replacement": "Number.parseInt", 696 | "mdnPath": "Global_Objects/Number/parseInt", 697 | "category": "native" 698 | }, 699 | { 700 | "type": "native", 701 | "moduleName": "number.prototype.toexponential", 702 | "nodeVersion": "0.10.0", 703 | "replacement": "Number.prototype.toExponential", 704 | "mdnPath": "Global_Objects/Number/toExponential", 705 | "category": "native" 706 | }, 707 | { 708 | "type": "native", 709 | "moduleName": "object-assign", 710 | "nodeVersion": "4.0.0", 711 | "replacement": "Object.assign", 712 | "mdnPath": "Global_Objects/Object/assign", 713 | "category": "native" 714 | }, 715 | { 716 | "type": "native", 717 | "moduleName": "object-is", 718 | "nodeVersion": "0.10.0", 719 | "replacement": "Object.is", 720 | "mdnPath": "Global_Objects/Object/is", 721 | "category": "native" 722 | }, 723 | { 724 | "type": "native", 725 | "moduleName": "object-keys", 726 | "nodeVersion": "0.10.0", 727 | "replacement": "Object.keys(obj)", 728 | "mdnPath": "Global_Objects/Object/keys", 729 | "category": "native" 730 | }, 731 | { 732 | "type": "native", 733 | "moduleName": "object.assign", 734 | "nodeVersion": "4.0.0", 735 | "replacement": "Object.assign", 736 | "mdnPath": "Global_Objects/Object/assign", 737 | "category": "native" 738 | }, 739 | { 740 | "type": "native", 741 | "moduleName": "object.defineproperties", 742 | "nodeVersion": "0.10.0", 743 | "replacement": "Object.defineProperties", 744 | "mdnPath": "Global_Objects/Object/defineProperties", 745 | "category": "native" 746 | }, 747 | { 748 | "type": "native", 749 | "moduleName": "object.entries", 750 | "nodeVersion": "7.0.0", 751 | "replacement": "Object.entries", 752 | "mdnPath": "Global_Objects/Object/entries", 753 | "category": "native" 754 | }, 755 | { 756 | "type": "native", 757 | "moduleName": "object.fromentries", 758 | "nodeVersion": "12.0.0", 759 | "replacement": "Object.fromEntries", 760 | "mdnPath": "Global_Objects/Object/fromEntries", 761 | "category": "native" 762 | }, 763 | { 764 | "type": "native", 765 | "moduleName": "object.getownpropertydescriptors", 766 | "nodeVersion": "7.0.0", 767 | "replacement": "Object.getOwnPropertyDescriptors", 768 | "mdnPath": "Global_Objects/Object/getOwnPropertyDescriptors", 769 | "category": "native" 770 | }, 771 | { 772 | "type": "native", 773 | "moduleName": "object.getprototypeof", 774 | "nodeVersion": "0.10.0", 775 | "replacement": "Object.getPrototypeOf", 776 | "mdnPath": "Global_Objects/Object/getPrototypeOf", 777 | "category": "native" 778 | }, 779 | { 780 | "type": "native", 781 | "moduleName": "object.hasown", 782 | "nodeVersion": "16.9.0", 783 | "replacement": "Object.hasOwn", 784 | "mdnPath": "Global_Objects/Object/hasOwn", 785 | "category": "native" 786 | }, 787 | { 788 | "type": "native", 789 | "moduleName": "object.keys", 790 | "nodeVersion": "0.10.0", 791 | "replacement": "Object.keys(obj)", 792 | "mdnPath": "Global_Objects/Object/keys", 793 | "category": "native" 794 | }, 795 | { 796 | "type": "native", 797 | "moduleName": "object.values", 798 | "nodeVersion": "7.0.0", 799 | "replacement": "Object.values", 800 | "mdnPath": "Global_Objects/Object/values", 801 | "category": "native" 802 | }, 803 | { 804 | "type": "native", 805 | "moduleName": "pad-left", 806 | "nodeVersion": "8.0.0", 807 | "replacement": "String.prototype.padStart", 808 | "mdnPath": "Global_Objects/String/padStart", 809 | "category": "native" 810 | }, 811 | { 812 | "type": "native", 813 | "moduleName": "parseint", 814 | "nodeVersion": "0.10.0", 815 | "replacement": "parseInt", 816 | "mdnPath": "Global_Objects/parseInt", 817 | "category": "native" 818 | }, 819 | { 820 | "type": "native", 821 | "moduleName": "promise.allsettled", 822 | "nodeVersion": "12.9.0", 823 | "replacement": "Promise.allSettled", 824 | "mdnPath": "Global_Objects/Promise/allSettled", 825 | "category": "native" 826 | }, 827 | { 828 | "type": "native", 829 | "moduleName": "promise.any", 830 | "nodeVersion": "15.0.0", 831 | "replacement": "Promise.any", 832 | "mdnPath": "Global_Objects/Promise/any", 833 | "category": "native" 834 | }, 835 | { 836 | "type": "native", 837 | "moduleName": "promise.prototype.finally", 838 | "nodeVersion": "10.0.0", 839 | "replacement": "Promise.prototype.finally", 840 | "mdnPath": "Global_Objects/Promise/finally", 841 | "category": "native" 842 | }, 843 | { 844 | "type": "native", 845 | "moduleName": "reflect.getprototypeof", 846 | "nodeVersion": "6.0.0", 847 | "replacement": "Reflect.getPrototypeOf", 848 | "mdnPath": "Global_Objects/Reflect/getPrototypeOf", 849 | "category": "native" 850 | }, 851 | { 852 | "type": "native", 853 | "moduleName": "reflect.ownkeys", 854 | "nodeVersion": "6.0.0", 855 | "replacement": "Reflect.ownKeys", 856 | "mdnPath": "Global_Objects/Reflect/ownKeys", 857 | "category": "native" 858 | }, 859 | { 860 | "type": "native", 861 | "moduleName": "regexp.prototype.flags", 862 | "nodeVersion": "6.0.0", 863 | "replacement": "RegExp.prototype.flags (e.g. \"/foo/g.flags\")", 864 | "mdnPath": "Global_Objects/RegExp/flags", 865 | "category": "native" 866 | }, 867 | { 868 | "type": "native", 869 | "moduleName": "string.prototype.at", 870 | "nodeVersion": "16.6.0", 871 | "replacement": "String.prototype.at", 872 | "mdnPath": "Global_Objects/String/at", 873 | "category": "native" 874 | }, 875 | { 876 | "type": "native", 877 | "moduleName": "string.prototype.lastindexof", 878 | "nodeVersion": "0.10.0", 879 | "replacement": "String.prototype.lastIndexOf", 880 | "mdnPath": "Global_Objects/String/lastIndexOf", 881 | "category": "native" 882 | }, 883 | { 884 | "type": "native", 885 | "moduleName": "string.prototype.matchall", 886 | "nodeVersion": "12.0.0", 887 | "replacement": "String.prototype.matchAll", 888 | "mdnPath": "Global_Objects/String/matchAll", 889 | "category": "native" 890 | }, 891 | { 892 | "type": "native", 893 | "moduleName": "string.prototype.padend", 894 | "nodeVersion": "8.0.0", 895 | "replacement": "String.prototype.padEnd", 896 | "mdnPath": "Global_Objects/String/padEnd", 897 | "category": "native" 898 | }, 899 | { 900 | "type": "native", 901 | "moduleName": "string.prototype.padleft", 902 | "nodeVersion": "8.0.0", 903 | "replacement": "String.prototype.padStart", 904 | "mdnPath": "Global_Objects/String/padStart", 905 | "category": "native" 906 | }, 907 | { 908 | "type": "native", 909 | "moduleName": "string.prototype.padright", 910 | "nodeVersion": "8.0.0", 911 | "replacement": "String.prototype.padEnd", 912 | "mdnPath": "Global_Objects/String/padEnd", 913 | "category": "native" 914 | }, 915 | { 916 | "type": "native", 917 | "moduleName": "string.prototype.padstart", 918 | "nodeVersion": "8.0.0", 919 | "replacement": "String.prototype.padStart", 920 | "mdnPath": "Global_Objects/String/padStart", 921 | "category": "native" 922 | }, 923 | { 924 | "type": "native", 925 | "moduleName": "string.prototype.replaceall", 926 | "nodeVersion": "15.0.0", 927 | "replacement": "String.prototype.replaceAll", 928 | "mdnPath": "Global_Objects/String/replaceAll", 929 | "category": "native" 930 | }, 931 | { 932 | "type": "native", 933 | "moduleName": "string.prototype.split", 934 | "nodeVersion": "0.10.0", 935 | "replacement": "String.prototype.split", 936 | "mdnPath": "Global_Objects/String/split", 937 | "category": "native" 938 | }, 939 | { 940 | "type": "native", 941 | "moduleName": "string.prototype.substr", 942 | "nodeVersion": "0.10.0", 943 | "replacement": "String.prototype.substr", 944 | "mdnPath": "Global_Objects/String/substr", 945 | "category": "native" 946 | }, 947 | { 948 | "type": "native", 949 | "moduleName": "string.prototype.trim", 950 | "nodeVersion": "0.10.0", 951 | "replacement": "String.prototype.trim", 952 | "mdnPath": "Global_Objects/String/trim", 953 | "category": "native" 954 | }, 955 | { 956 | "type": "native", 957 | "moduleName": "string.prototype.trimend", 958 | "nodeVersion": "10.0.0", 959 | "replacement": "String.prototype.trimEnd", 960 | "mdnPath": "Global_Objects/String/trimEnd", 961 | "category": "native" 962 | }, 963 | { 964 | "type": "native", 965 | "moduleName": "string.prototype.trimleft", 966 | "nodeVersion": "10.0.0", 967 | "replacement": "String.prototype.trimLeft", 968 | "mdnPath": "Global_Objects/String/trimLeft", 969 | "category": "native" 970 | }, 971 | { 972 | "type": "native", 973 | "moduleName": "string.prototype.trimright", 974 | "nodeVersion": "10.0.0", 975 | "replacement": "String.prototype.trimRight", 976 | "mdnPath": "Global_Objects/String/trimRight", 977 | "category": "native" 978 | }, 979 | { 980 | "type": "native", 981 | "moduleName": "string.prototype.trimstart", 982 | "nodeVersion": "10.0.0", 983 | "replacement": "String.prototype.trimStart", 984 | "mdnPath": "Global_Objects/String/trimStart", 985 | "category": "native" 986 | }, 987 | { 988 | "type": "native", 989 | "moduleName": "string.raw", 990 | "nodeVersion": "4.0.0", 991 | "replacement": "String.raw", 992 | "mdnPath": "Global_Objects/String/raw", 993 | "category": "native" 994 | }, 995 | { 996 | "type": "native", 997 | "moduleName": "symbol.prototype.description", 998 | "nodeVersion": "11.0.0", 999 | "replacement": "Symbol.prototype.description", 1000 | "mdnPath": "Global_Objects/Symbol/description", 1001 | "category": "native" 1002 | }, 1003 | { 1004 | "type": "native", 1005 | "moduleName": "typed-array-buffer", 1006 | "nodeVersion": "0.10.0", 1007 | "replacement": "%TypedArray%.prototype.buffer", 1008 | "mdnPath": "Global_Objects/TypedArray/buffer", 1009 | "category": "native" 1010 | }, 1011 | { 1012 | "type": "native", 1013 | "moduleName": "typed-array-byte-length", 1014 | "nodeVersion": "0.10.0", 1015 | "replacement": "%TypedArray%.prototype.byteLength", 1016 | "mdnPath": "Global_Objects/TypedArray/byteLength", 1017 | "category": "native" 1018 | }, 1019 | { 1020 | "type": "native", 1021 | "moduleName": "typed-array-byte-offset", 1022 | "nodeVersion": "0.10.0", 1023 | "replacement": "%TypedArray%.prototype.byteOffset", 1024 | "mdnPath": "Global_Objects/TypedArray/byteOffset", 1025 | "category": "native" 1026 | }, 1027 | { 1028 | "type": "native", 1029 | "moduleName": "typed-array-length", 1030 | "nodeVersion": "0.10.0", 1031 | "replacement": "%TypedArray%.prototype.length", 1032 | "mdnPath": "Global_Objects/TypedArray/length", 1033 | "category": "native" 1034 | }, 1035 | { 1036 | "type": "native", 1037 | "moduleName": "typedarray.prototype.slice", 1038 | "nodeVersion": "4.0.0", 1039 | "replacement": "%TypedArray%.prototype.slice", 1040 | "mdnPath": "Global_Objects/TypedArray/slice", 1041 | "category": "native" 1042 | }, 1043 | { 1044 | "type": "native", 1045 | "moduleName": "xtend", 1046 | "nodeVersion": "4.0.0", 1047 | "replacement": "Object.assign, or if deep clones are needed, use structuredClone", 1048 | "mdnPath": "Global_Objects/Object/assign", 1049 | "category": "native" 1050 | } 1051 | ] 1052 | } 1053 | --------------------------------------------------------------------------------