feat: support ESM configuration files#306
Merged
Merged
Conversation
Load .versionrc.mjs (and ESM-syntax .versionrc.js) via Node's require(esm), unwrapping the module-namespace wrapper to its default export. getConfiguration stays synchronous. Requires Node >= 22.12, where require(esm) is unflagged. Previously an ESM config loaded without error on Node >= 22.12 but was silently ignored, because the namespace wrapper passed the object check while the user's settings sat unread under `.default`. Tests spawn bin/cli.js in a child process: vitest's module runner intercepts createRequire and rejects ESM sources with a Babel SyntaxError, so in-process tests cannot observe real require(esm) behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for ES module configuration files:
.versionrc.mjs, and.versionrc.jswritten withexport default(object or function). CommonJS configs behave exactly as before.Background
On Node >= 22.12,
require()of an ES module succeeds (unflaggedrequire(esm)) and returns a module-namespace wrapper ({ __esModule: true, default: {...} }).getConfigurationnever unwrapped it, so an ESM.versionrc.jsloaded without any error while the user's configuration was silently ignored — verified with the real CLI, where an ESM config'stagPrefixwas not applied while the identical CommonJS config's was.Changes
lib/configuration.js: add.versionrc.mjsto the config-file list, route.mjsthrough the JS loading branch, and unwrap the module-namespace wrapper (detected via__esModule/Symbol.toStringTag === 'Module') to itsdefaultexport before the existing function-vs-object handling.getConfigurationremains synchronous — noimport(), no API change. The unwrap also covers Babel/TS-transpiled configs, which set__esModulethemselves.test/esm-config.integration-test.js(new): four tests — ESM object in.versionrc.js, ESM object in.versionrc.mjs, ESM default-exported function, and a CommonJS control. These spawnbin/cli.js --dry-runin a child process because vitest's module runner interceptscreateRequireand throws a Babel SyntaxError on ESM sources, a failure mode that doesn't exist in production; only a child process observes realrequire(esm)behavior.README.md: document the new formats and the Node >= 22.12 floor for ESM configs.Notes
enginesis>=22, butrequire(esm)was unflagged in 22.12 — on Node 22.0–22.11 an ESM config fails with Node's ownERR_REQUIRE_ESM. Documented in the README rather than adding a catch-and-rethrow; happy to add a friendlier error if preferred.Test plan
npm test— 142 tests passing, plus eslint and prettier checks.mjs/ CJS control🤖 Generated with Claude Code