From a3c3ba1c47c29d7c9196bdcee41cdb4085c01817 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 23 Mar 2026 04:00:59 +0000 Subject: [PATCH 1/3] docs: add contribution guide --- CONTRIBUTING.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..753b7c7c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,110 @@ +# Contributing + +The module replacements data set is used widely across the ecosystem, so it is important we follow a consistent process when making changes to it. This especially matters when adding new replacements, as we're effectively recommending that the ecosystem mass migrates away from the old module. + +## Adding a module to be replaced + +If you want to add a new replacement, please open an issue first to discuss it. + +In the issue you create, it is important to include as much justification as you can for why it should be replaced and what the replacement should be. + +Basic information you should include in the issue: + +- The name of the module you want to replace. +- The name of the module or native API you want to replace it with. +- Which manifest you think it belongs in (see below) +- Why you think it should be replaced (e.g. security, performance, etc.) +- Availability of the replacement (e.g. is it available in all LTS versions of Node, or only newer ones?) +- A code example of how to migrate from the old module to the new one. + +When evaluating if something should be replaced, we look for things like: + +- Is it no longer maintained? +- Does it have security issues? +- Is it significantly larger or slower than the replacement? +- Is it a very small module that should be inlined? +- Does it have a native alternative that is widely supported? +- Does it have significant adoption (usually more than 10k downloads per week)? + +When evaluating the replacement, we look for things like: + +- If not native, does it have significant adoption already (usually more than 10k downloads per week)? +- If it is native, is it available in all modern engines (usually those which are LTS)? +- Does it replace all primary functionality of the old module? +- Is it maintained and does it have a good track record of security and stability? +- Is it smaller and/or faster than the old module? + +We may also take other things into consideration, so this is not an exhaustive list. + +### Choosing a manifest + +We have three types of manifest: + +- `native`: for replacements that are native APIs in all engines, or are built into the runtime (e.g. Node) +- `micro-utilities`: for replacements of modules that are overly small and should generally be inlined +- `preferred`: for replacements of modules that are more performant than the old module + +### Choosing a replacement type + +There are different types of replacements available: + +- `removal`: for removing the old module without a replacement (e.g. modules which check if a now widely supported API is available) +- `simple`: for replacing the old module with inline code +- `native`: for replacing the old module with native APIs (e.g. standard web APIs, or Node built-ins) +- `documented`: for replacing the old module with a documented alternative + +When using the `documented` type, you should generally follow these guidelines: + +- The mapping should have a `url` which points to an e18e documentation page (i.e. those in the [modules](https://github.com/es-tooling/module-replacements/tree/main/docs/modules) directory of the repo) which describes the replacement and how to migrate to it. +- The replacement does not necessarily need a `url` itself +- The replacement does not need a `description` + +When using the `native` type: + +- The mapping generally does not need a `url` +- The replacement should have a `url` to its external documentation (e.g. MDN or Node docs) +- The replacement should have a `webFeatureId` if it is a web standard (these come from the [`web-features` dataset](https://github.com/web-platform-dx/web-features/tree/main/features)) +- The replacement should have a `nodeFeatureId` if it is a Node built-in (these come from the Node documentation) + +When using the `simple` type: + +- The replacement should be of the form `snippet::{name}` where `name` is a suitable descriptive name for what the snippet does (e.g. `snippet:is-odd` for a snippet that checks if a number is odd) +- The replacement description should be a short human-readable description of what the snippet does, and how it replaces the old module +- The replacement should have an `example` which is purely code (i.e. it should be valid JS in its entirety) and should show the snippet + +When using the `removal` type: + +- There should usually be one replacement to one mapping, with the same ID (e.g. the `airbnb-js-shims` [replacement](https://github.com/es-tooling/module-replacements/blob/131e2d8bb4a4793f54b7193ab9b7433c3f2ae839/manifests/native.json#L1366-L1370) has the same ID as the [mapping](https://github.com/es-tooling/module-replacements/blob/131e2d8bb4a4793f54b7193ab9b7433c3f2ae839/manifests/native.json#L1632-L1636)) +- The replacement description should briefly explain why the module is no longer needed + +## Removing a replacement + +It is rare, but sometimes it may make sense to remove a replacement from the dataset. + +Usually, this happens if the original module has since been improved or regained maintenance, or if the replacement is no longer maintained or has security issues. + +If you want to remove a replacement, please open an issue first to discuss it. + +Explain why you think it should be removed and provide any relevant information or evidence to support your case. + +## Adding a replacement to an existing module + +If you want to add a replacement to an existing module, please open an issue first to discuss it. You should generally follow all the same guidelines as when adding a new module, but you should also explain why you think the new replacement should be added in addition to the existing ones. + +Just like when adding a new module, we will evaluate the replacement based on similar criteria, such as adoption, availability, functionality, maintenance, security, and performance. + +## Running tests + +We currently validate the data through a set of lint scripts which you can run with `npm run lint`. This will check for things like: + +- All manifests conform to the JSON schema +- Replacement keys match their `id` property +- `webFeatureId` values reference valid features and compat keys from the `web-features` dataset +- Mapping keys match their `moduleName` for module-type mappings +- Mappings only reference replacements that exist +- All documented modules (in `docs/modules/`) are listed in the modules README +- All documented modules have a corresponding entry in a manifest +- No module appears in multiple manifests +- Mappings and replacements are sorted alphabetically +- No replacement has `engines` set (these are populated automatically at publish time) +- All e18e URLs in mappings and replacements point to documentation files that exist From 365db1915bc5a06243b6fbdd55a4b53c93d4a2c3 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:56:11 +0000 Subject: [PATCH 2/3] docs: update wording --- CONTRIBUTING.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 753b7c7c..63098f76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,12 +64,12 @@ When using the `native` type: - The mapping generally does not need a `url` - The replacement should have a `url` to its external documentation (e.g. MDN or Node docs) - The replacement should have a `webFeatureId` if it is a web standard (these come from the [`web-features` dataset](https://github.com/web-platform-dx/web-features/tree/main/features)) -- The replacement should have a `nodeFeatureId` if it is a Node built-in (these come from the Node documentation) +- The replacement should have a `nodeFeatureId` if it is a Node built-in (these are of the form `{moduleName[, exportName]}`. For example, `fs` would be `{"moduleName": "fs"}`, while `fs.readFile` would be `{"moduleName": "fs", "exportName": "readFile"}`) When using the `simple` type: - The replacement should be of the form `snippet::{name}` where `name` is a suitable descriptive name for what the snippet does (e.g. `snippet:is-odd` for a snippet that checks if a number is odd) -- The replacement description should be a short human-readable description of what the snippet does, and how it replaces the old module +- The replacement description should be a short human-readable description of what the snippet does, and how it replaces the old module (e.g. "You can use arr.at(-1) to get the last element of an array") - The replacement should have an `example` which is purely code (i.e. it should be valid JS in its entirety) and should show the snippet When using the `removal` type: @@ -98,13 +98,8 @@ Just like when adding a new module, we will evaluate the replacement based on si We currently validate the data through a set of lint scripts which you can run with `npm run lint`. This will check for things like: - All manifests conform to the JSON schema -- Replacement keys match their `id` property -- `webFeatureId` values reference valid features and compat keys from the `web-features` dataset -- Mapping keys match their `moduleName` for module-type mappings -- Mappings only reference replacements that exist -- All documented modules (in `docs/modules/`) are listed in the modules README -- All documented modules have a corresponding entry in a manifest -- No module appears in multiple manifests -- Mappings and replacements are sorted alphabetically -- No replacement has `engines` set (these are populated automatically at publish time) -- All e18e URLs in mappings and replacements point to documentation files that exist +- Valid references (`webFeatureId`, `nodeFeatureId`, docs, etc.) +- No duplicate mappings or replacements +- Documentation is up to date + +These checks are not exhaustive, we will also validate other things and do some manual checks when reviewing PRs. From db832e74888a85e8450eaa46f5aa720df49317c2 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Mon, 23 Mar 2026 21:21:15 +0000 Subject: [PATCH 3/3] docs: paolo Co-authored-by: Paolo Ricciuti --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63098f76..028db64e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,7 @@ When using the `native` type: - The mapping generally does not need a `url` - The replacement should have a `url` to its external documentation (e.g. MDN or Node docs) - The replacement should have a `webFeatureId` if it is a web standard (these come from the [`web-features` dataset](https://github.com/web-platform-dx/web-features/tree/main/features)) -- The replacement should have a `nodeFeatureId` if it is a Node built-in (these are of the form `{moduleName[, exportName]}`. For example, `fs` would be `{"moduleName": "fs"}`, while `fs.readFile` would be `{"moduleName": "fs", "exportName": "readFile"}`) +- The replacement should have a `nodeFeatureId` if it is a Node built-in (these are of the form `{ moduleName: string, exportName?: string }`. For example, `fs` would be `{"moduleName": "fs"}`, while `fs.readFile` would be `{"moduleName": "fs", "exportName": "readFile"}`) When using the `simple` type: