Skip to content

Make the bun"..." interpolator use the one npm-spec parser - #17

Merged
arcaputo3 merged 3 commits into
agent/idiomatic-scalajs-mill-workflowsfrom
agent/bun-dep-interpolator
Aug 26, 2026
Merged

arcaputo3 merged 3 commits into
agent/idiomatic-scalajs-mill-workflowsfrom
agent/bun-dep-interpolator

Conversation

@arcaputo3

Copy link
Copy Markdown
Contributor

Stack 4/N. Base is agent/bun-test-lockfile (#16), not main.

The bug

BunDep.validateLiteral hand-rolled a second, weaker npm-spec parser that only inspected the package-name half. So:

override def bunDeps = Task { Seq(bun"react@") }   // compiles cleanly

…and then throws from BunToolchainModule.parseDependency when the install runs. The interpolator exists precisely to catch that at compile time, and it didn't.

It also silently skipped validation entirely for any interpolated form (bun"react@$version"), falling back to $sc.s($args*).

The fix

  • validateLiteral delegates to parseDependency. One parser, so the compile-time and task-time rules cannot diverge again. This also deletes a dead val name binding whose two branches both evaluated to dep and whose result was discarded.
  • Interpolated forms route through a new BunDep.validate, which fails when the build evaluates the dependency list rather than inside bun install. Not as good as a compile error, but the value genuinely isn't known until then.

Proof

New invalid-bun-specifier fixture. On the parent commit it compiles and app.bunDeps succeeds, returning Seq("react@"):

X BunDependencyManifestIntegrationTests.invalid bun specifier fails in build definitions

New unit test asserts the two parsers agree in both directions across valid and invalid inputs, and that the existing literal cases all still pass — the proof the shared parser didn't over-tighten.

Verification

Unit 69 passing, integration 41 passing.

🤖 Generated with Claude Code

arcaputo3 and others added 2 commits August 26, 2026 15:03
`validateLiteral` hand-rolled a second, weaker parser that only inspected the
package-name half. So `bun"react@"` compiled cleanly and then threw from
`BunToolchainModule.parseDependency` during the install -- defeating the
entire purpose of a compile-time validator.

- `validateLiteral` now delegates to `parseDependency`, so the compile-time
  and task-time rules cannot diverge again. This also removes a dead `val
  name` binding whose two branches both evaluated to `dep` and whose result
  was discarded.
- Interpolated forms like `bun"react@$version"` are not knowable at compile
  time; the macro previously skipped validation entirely for them. They now
  route through `BunDep.validate`, which fails when the build evaluates the
  dependency list rather than inside `bun install`.

New `invalid-bun-specifier` fixture covers the literal case; on the parent
commit it compiles and `app.bunDeps` succeeds, returning Seq("react@").

Unit 69 passing, integration 41 passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`BunScalaJSModule.bunInstall` merged vendored node_modules into
`dest/node_modules` unconditionally -- including after the workspace branch
had symlinked that path to the shared workspace install's Task.dest. The
merge therefore wrote into another task's output, shared by every member of
the workspace.

- `mergeFromClasspathEntry` refuses a symlinked destination root and names
  the task the directory belongs to. On its own this turns a silent
  cross-task write into a loud failure.
- The merge moved into the non-workspace branch, and workspace members with a
  vendored-runtime dependency now fail with an actionable message instead.
  Sharing one node_modules across members is the point of a workspace, so
  merging per-member was never going to be right; hoisting vendored trees to
  the workspace install is a feature, not a bug fix, and is left for later.

Only reachable with a published vendored-runtime dependency -- mergeFrom-
ClasspathEntry no-ops unless the entry carries META-INF/bun/node_modules --
which is why no fixture caught it.

Unit 70 passing, integration 41 passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@arcaputo3
arcaputo3 deleted the branch agent/idiomatic-scalajs-mill-workflows August 26, 2026 22:11
@arcaputo3 arcaputo3 closed this Aug 26, 2026
Stop vendored runtimes leaking into a workspace's shared node_modules
@arcaputo3 arcaputo3 reopened this Aug 26, 2026
@arcaputo3
arcaputo3 changed the base branch from agent/bun-test-lockfile to agent/idiomatic-scalajs-mill-workflows August 26, 2026 22:16
@arcaputo3
arcaputo3 merged commit 11e15d8 into agent/idiomatic-scalajs-mill-workflows Aug 26, 2026
@arcaputo3
arcaputo3 deleted the agent/bun-dep-interpolator branch August 26, 2026 22:16
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.

1 participant