Conversation
When running commitlint via npx or npm exec, packages are downloaded to a temporary npx cache directory (e.g., ~/.npm/_npx) instead of traditional global node_modules. This commit adds detection and resolution from the npx cache directory to support running commitlint via npx. This helps with issue #613 - enabling usage like: npx @commitlint/cli --extends @commitlint/config-conventional Part of fixing #613
- Add npx cache detection to load-plugin.ts (similar to resolve-extends) - Add LoadPluginOptions interface with searchPaths support - This enables plugins to be resolved from npx cache when running via npx/npm exec, and from extended config paths when provided This helps with issue #613 - enabling plugin resolution when using: npx @commitlint/cli --extends @commitlint/config-conventional Part of fixing #613
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||||||
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. |
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||
b9f0775 to
2a32aec
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes module resolution when running commitlint via npx, by extending config/plugin resolution to look inside the npx cache and by refactoring plugin loading to accept an options object.
Changes:
- Add npx-cache-based resolution to
@commitlint/resolve-extends(newresolveFromNpxCacheand integration intoresolveGlobalSilent). - Refactor
loadPluginto accept{ debug, searchPaths }and attempt plugin resolution via npx cache, then search paths, then default resolution. - Add/update vitest coverage for the new npx-cache resolution path and update the
loadPlugincall site.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| @commitlint/resolve-extends/src/index.ts | Adds npx cache scanning + resolution hook to improve extends/module resolution under npx. |
| @commitlint/load/src/utils/load-plugin.ts | Refactors plugin loading to support npx-cache and custom search paths via an options object. |
| @commitlint/load/src/utils/load-plugin.test.ts | Adds tests and mocks for the new npx-cache resolution behavior. |
| @commitlint/load/src/load.ts | Updates loadPlugin call to the new options-object signature. |
Comments suppressed due to low confidence (1)
@commitlint/load/src/utils/load-plugin.ts:127
- In debug mode the log prints
(from ${resolvedPath}), butresolvedPathis only set for the npx/searchPaths/require.resolve branches; ifdynamicImport(longName)succeeds, this will printundefined. Alsoversion = require(${longName}/package.json)will resolve relative to commitlint’s own module resolution, which may not match the actualresolvedPath(e.g. npx cache/searchPaths). Consider deriving both the path and package.json lookup from the same resolved location used to load the plugin (or omitfrom ...when unresolved).
// This step is costly, so skip if debug is disabled
if (debug) {
let version: string | null = null;
try {
version = require(`${longName}/package.json`).version;
} catch {
// Do nothing
}
const loadedPluginAndVersion = version
? `${longName}@${version}`
: `${longName}, version unknown`;
console.log(
pc.blue(
`Loaded plugin ${pluginName} (${loadedPluginAndVersion}) (from ${resolvedPath})`,
),
);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Extract resolveFromNpxCache utility in resolve-extends (Issue #3) - Use require.resolve with paths option for proper module resolution (Issue #1) - Iterate ALL npx cache dirs instead of most recent by mtime (Issue #2) - Add debug logging in catch blocks in load-plugin (Issue #4) - Tighten control flow for plugin assignment (Issue #5) - Change string | void to string | undefined return types (Issue #7) - Add tests for npx cache resolution in load-plugin (Issue #6)
2a32aec to
3a380ce
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Add type safety check when assigning plugin to PluginRecords - Preserve original error when resolution succeeds but import fails - Only show resolvedPath in debug output when it's defined - Add mock for resolveFromNpxCache in tests
Previously the version was resolved using the package name which could incorrectly resolve from commitlint's own node_modules instead of the actual plugin location (npx cache or searchPath). This ensures the package.json is loaded from the same path where the plugin was actually loaded from.
Add debug logging when errors occur during npx cache reading and module resolution. This improves diagnosability when DEBUG=true by providing information about what failed instead of silently ignoring the errors.
Add sanitizeErrorMessage function to remove node_modules paths from error messages. This prevents exposing internal filesystem paths like /home/user/.npm/_npx/abc123/node_modules in error output.
Add validation to ensure searchPaths are: 1. Strings 2. Absolute paths 3. Existing directories This prevents potential security issues when untrusted configuration is used to provide search paths.
Accept both boolean and options object as third parameter to maintain backward compatibility with existing callers that pass a boolean (e.g., loadPlugin(plugins, name, true)).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The debug version lookup now uses findPackageJson() which walks up the directory tree from resolvedPath to find the package root, instead of assuming package.json is adjacent to the resolved file. This fixes 'version unknown' when resolvedPath points to a nested file like dist/index.js.
Add check that searchPaths are directories, not just existing paths.
A file path would previously pass validation but cause confusing
behavior when used in require.resolve({ paths: [...] }).
…tion - Add tests for loading plugins from npx cache - Add tests for searchPaths validation (non-string, relative, nonexistent, file) - Add test for backward compatibility with boolean parameter
Add test to verify resolveFromNpxCache returns undefined when package cannot be resolved from npx cache.
User description
Fixes: #613
PR Type
Bug fix
Description
Add npx cache detection for package and plugin resolution
Support running commitlint via npx with extended configs
Refactor loadPlugin to accept options object with searchPaths
Enable plugin resolution from npx cache (for npx/npm exec usage)
Diagram Walkthrough
File Walkthrough
index.ts
Add npx cache detection for config resolution@commitlint/resolve-extends/src/index.ts
getNpxCachePath()function to detect and locate npx cachedirectory
resolveGlobalSilent()for configresolution
resolution
load-plugin.ts
Refactor plugin loading with npx cache support@commitlint/load/src/utils/load-plugin.ts
getNpxCachePath()function to detect npx cache directoryLoadPluginOptionsinterface with debug and searchPathsproperties
loadPlugin()to accept options object instead of booleandebug parameter
searchPaths, then default resolution
paths
load.ts
Update loadPlugin call signature@commitlint/load/src/load.ts
loadPlugin()call to use new options object format