Replace resolve Dependency with In-House @stdlib/utils/resolve
Replace the external resolve npm dependency with a new stdlib-native package. This eliminates resolve and its 3 transitive dependencies (is-core-module, path-parse, supports-preserve-symlinks-flag) from the supply chain — removing 4 third-party packages total.
Background
The resolve package implements Node.js's require.resolve() algorithm with configurable basedir and paths options.
Only these features are used:
| Feature |
Used? |
resolve(id, {basedir}, cb) (async) |
✅ 5 files |
resolve.sync(id, {basedir}) |
✅ 7 files |
resolve.sync(id, {basedir, paths}) |
✅ 1 file |
All other options (packageFilter, pathFilter, extensions, moduleDirectory, etc.) |
❌ |
Proposed Changes
New Package: @stdlib/utils/resolve
Folder Structure
lib/node_modules/@stdlib/utils/resolve/
├── README.md
├── package.json
│
├── lib/
│ ├── index.js # Entry point: exports async + .sync
│ ├── main.js # Async resolve( id, opts, clbk )
│ ├── sync.js # Sync resolve( id, opts ) → string
│ ├── validate.js # Options validation
│ ├── defaults.js # Default options (basedir, extensions)
│ ├── resolve_path.js # Core sync resolution algorithm
│ ├── async_resolve_path.js # Core async resolution algorithm
│ └── is_core_module.js # Built-in module check via module.builtinModules
│
├── docs/
│ ├── repl.txt
│ └── types/
│ ├── index.d.ts
│ └── test.ts
│
├── benchmark/
│ └── benchmark.js # Performance benchmarks (sync vs async)
│
├── examples/
│ └── index.js # Usage examples
│
└── test/
├── test.js # Main export tests
├── test.sync.js # Sync API tests
├── test.async.js # Async API tests
├── test.validate.js # Options validation tests
├── test.is_core_module.js # Core module detection tests
└── fixtures/
├── node_modules/
│ └── mock-pkg/
│ ├── package.json # { "main": "./lib/index.js" }
│ └── lib/
│ └── index.js
├── index.js # Mock directory index
├── foo.js # Mock module
└── foo.json # Mock JSON module
Key Implementation Details
lib/index.js — Entry point matching the resolve package's API shape:
var resolve = require( './main.js' ); // async
var sync = require( './sync.js' ); // sync
resolve.sync = sync;
module.exports = resolve;
lib/resolve_path.js— Core Node.js resolution algorithm:
- If
id is a core module → return id
- If
id starts with ./ or ../ or / → resolve as file, then as directory
- Otherwise → walk
node_modules directories upward from basedir; if paths option given, also search those
- File resolution: try exact path →
.js → .json → .node
- Directory resolution: read
package.json main field → fallback to index.js → index.json → index.node
lib/is_core_module.js — Zero-dependency replacement for is-core-module:
var builtinModules = require( 'module' ).builtinModules;
function isCoreModule( id ) {
return builtinModules.indexOf( id ) !== -1;
}
Internal dependencies only — no third-party packages:
path (Node.js built-in)
fs (Node.js built-in)
module (Node.js built-in)
@stdlib/assert/is-string (input validation)
@stdlib/assert/is-plain-object (options validation)
@stdlib/assert/has-own-property (options checking)
@stdlib/error/tools/fmtprodmsg (error formatting)
Consumer Migration (13 files)
Each migration is a 1-line require swap. The API shape is identical.
Sync consumers (8 files) — require( 'resolve' ).sync → require( '@stdlib/utils/resolve' ).sync:
| # |
File |
| 1 |
eslint/require-file-extensions/lib/main.js |
| 2 |
modules/pkg-deps/lib/walk_file.sync.js |
| 3 |
pkgs/browser-compatible/lib/resolve.sync.js |
| 4 |
pkgs/entry-points/lib/resolve.sync.js |
| 5 |
pkgs/browser-entry-points/lib/resolve.sync.js |
| 6 |
utils/library-manifest/lib/main.js |
| 7 |
repl/help/scripts/build.js |
Async consumers (6 files) — require( 'resolve' ) → require( '@stdlib/utils/resolve' ):
| # |
File |
| 8 |
modules/pkg-deps/lib/walk_file.js |
| 9 |
modules/pkg-deps/test/test.walk_file.js (also update proxyquire mock key) |
| 10 |
pkgs/browser-compatible/lib/resolve.js |
| 11 |
pkgs/entry-points/lib/resolve.js |
| 12 |
pkgs/browser-entry-points/lib/resolve.js |
| 13 |
lint/namespace-aliases/lib/resolve.js |
Dependency Removal
Verification Plan
Automated Tests
stdlib uses make test:
- Run new package tests using stdlib's test infrastructure:
make EXAMPLES_FILTER=".*/utils/resolve/.*"" examples
make BENCHMARKS_FILTER=".*/utils/resolve/.*"" benchmark
make TESTS_FILTER=". */utils/resolve/.*"" test
- Run consumer regression tests (pkg-deps has the most extensive test suite):
make TESTS_FILTER=". */_tools/modules/pkg-deps/.*"" test
Manual Verification
{TODO}
Replace
resolveDependency with In-House@stdlib/utils/resolveReplace the external
resolvenpm dependency with a new stdlib-native package. This eliminatesresolveand its 3 transitive dependencies (is-core-module,path-parse,supports-preserve-symlinks-flag) from the supply chain — removing 4 third-party packages total.Background
The
resolvepackage implements Node.js'srequire.resolve()algorithm with configurablebasedirandpathsoptions.Only these features are used:
resolve(id, {basedir}, cb)(async)resolve.sync(id, {basedir})resolve.sync(id, {basedir, paths})packageFilter,pathFilter,extensions,moduleDirectory, etc.)Proposed Changes
New Package:
@stdlib/utils/resolveFolder Structure
Key Implementation Details
lib/index.js— Entry point matching theresolvepackage's API shape:lib/resolve_path.js— Core Node.js resolution algorithm:idis a core module → returnididstarts with./or../or/→ resolve as file, then as directorynode_modulesdirectories upward frombasedir; ifpathsoption given, also search those.js→.json→.nodepackage.jsonmainfield → fallback toindex.js→index.json→index.nodelib/is_core_module.js— Zero-dependency replacement foris-core-module:Internal dependencies only — no third-party packages:
path(Node.js built-in)fs(Node.js built-in)module(Node.js built-in)@stdlib/assert/is-string(input validation)@stdlib/assert/is-plain-object(options validation)@stdlib/assert/has-own-property(options checking)@stdlib/error/tools/fmtprodmsg(error formatting)Consumer Migration (13 files)
Each migration is a 1-line
requireswap. The API shape is identical.Sync consumers (8 files) —
require( 'resolve' ).sync→require( '@stdlib/utils/resolve' ).sync:Async consumers (6 files) —
require( 'resolve' )→require( '@stdlib/utils/resolve' ):proxyquiremock key)Dependency Removal
Verification Plan
Automated Tests
stdlib uses
make test:Manual Verification
{TODO}