Skip to content

fix(js): read the format key only when it holds formatter options - #36

Closed
romankurakin wants to merge 1 commit into
elixir-volt:masterfrom
romankurakin:fix-format-key-collision
Closed

romankurakin wants to merge 1 commit into
elixir-volt:masterfrom
romankurakin:fix-format-key-collision

Conversation

@romankurakin

Copy link
Copy Markdown
Contributor

Fixes #34.

Volt.Builder reads config :volt, :format as the bundle format, so its value is an atom such as :esm. Volt.JS.Format and Volt.JS.Helpers read the same key as formatter options and expect a keyword list.

A project that asks the bundler for ESM therefore cannot use Volt.Formatter or mix volt.js.check. Both fail before they look at a file.

The two failures

Volt.JS.Format.load_config/0 matches only nil or a list, so the atom falls through the case:

** (CaseClauseError) no case clause matching:

    :esm

    (volt 0.17.11) lib/volt/js/format.ex:30: Volt.JS.Format.load_config/0

Volt.JS.Helpers.discovery_config/1 returns the atom unchanged, and discover_files/1 then calls Keyword.get/3 on it. This is the failure behind mix volt.js.check --type-aware:

** (FunctionClauseError) no function clause matching in Keyword.get/3

    # 1
    :esm

The change

Both functions now read the key only when it holds a keyword list, and fall back to the JSON configuration for anything else.

Nothing in the public API changes: no new function, no new configuration key. Configurations that work today keep working, and a value that used to raise now falls back instead.

Tests

Two regression tests, each next to the existing tests for the function it covers.

I also ran the branch against a Phoenix project that sets format: :esm. mix volt.js.check and mix volt.js.check --type-aware both run, and Volt.Formatter works as a mix format plugin.

`Volt.Builder` reads `config :volt, :format` as the bundle format, where the
value is an atom such as `:esm`. `Volt.JS.Format` and `Volt.JS.Helpers` read
the same key as formatter options and expect a keyword list.

A project that asks the bundler for ESM therefore cannot use `Volt.Formatter`
or `mix volt.js.check`. `load_config/0` raises a `CaseClauseError`, and
`discovery_config/1` passes the atom on to `Keyword.get/3`.

Both now accept a keyword list and fall back otherwise. A configuration that
worked before still works. A value that raised before now falls back to the
JSON configuration.
Copilot AI lite review requested due to automatic review settings September 10, 2026 06:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new Helpers.discover_format_files/0 == [] regression assertion is not hermetic and can start failing if matching JS/TS files are added under default discovery roots.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR resolves a configuration key collision where config :volt, :format can be either a bundler output format atom (e.g. :esm) or a keyword list of formatter/discovery options, causing formatter and JS-check tasks to crash when the bundler format is set.

Changes:

  • Guard Volt.JS.Format.load_config/0 so it only treats :volt, :format as formatter options when it’s a keyword list; otherwise it falls back to JSON config.
  • Guard Volt.JS.Helpers discovery config so tool config is only used when it’s a keyword list, preventing crashes from non-keyword values.
  • Add regression tests covering the :esm collision case for both modules.
File summaries
File Description
lib/volt/js/helpers.ex Ensures file discovery only consumes keyword-list tool config, ignoring atom bundle formats.
lib/volt/js/format.ex Ensures formatter config only consumes keyword-list options and otherwise loads JSON config.
test/volt/js/helpers_test.exs Adds regression coverage for discovery behavior when :format is an atom.
test/volt/js/format_test.exs Adds regression coverage for load_config/0 fallback behavior when :format is an atom.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +56 to +57
assert Helpers.discover_format_files() == []
assert Helpers.discover_files(tool: :lint) == [Path.join(tmp_dir, "lint/source.ts")]
dannote pushed a commit that referenced this pull request Sep 14, 2026
Adapt Roman Kurakin’s fix from a8a82b7 to the Discovery API. Make fallback discovery deterministic and restore all fixture configuration. Addresses #34.
@dannote

dannote commented Sep 15, 2026

Copy link
Copy Markdown
Member

Thanks, Roman! Your fix landed in #37 as 5cf6fd2 and is included in Volt 0.18.0. Closing this PR as incorporated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The format option has two meanings

3 participants