Skip to content

fix(add-repo): rewire deps in alphabetical order, cover bundleDependencies#584

Merged
cwillisf merged 5 commits into
developfrom
fix/add-repo-sort-and-bundle
May 22, 2026
Merged

fix(add-repo): rewire deps in alphabetical order, cover bundleDependencies#584
cwillisf merged 5 commits into
developfrom
fix/add-repo-sort-and-bundle

Conversation

@cwillisf
Copy link
Copy Markdown
Contributor

@cwillisf cwillisf commented May 22, 2026

Proposed Changes

Restructure step 7 (cross-workspace dep rewiring) in scripts/add-repo.sh. Two commits:

  • fix(add-repo): rewire monorepo deps in alphabetical order — replaces the per-(package × dep × kind × name) jq nest, which appended each new entry with += {key: value}, with one jq invocation per package.json. The new filter walks all four dependency-shaped object sections, rewrites matching keys to their @Scoped equivalents pinned to the local workspace version, and sorts each touched section alphabetically by key. Result: inserted entries land where npm install --save would put them, not at the bottom. A reduce over the section names with a .[$k]-truthy guard ensures missing sections stay missing (no peerDependencies: null leakage).
  • feat(add-repo): rewire monorepo names in bundleDependencies too — extends the filter with a type-aware branch: object sections are mapped per entry and sorted by key; array sections are mapped per name and uniqued (sort + dedupe). Adds bundleDependencies and the legacy bundledDependencies to the section list. Non-array, non-object values (e.g. bundleDependencies: true) fall through unchanged.

The rewrite rules are precomputed once per import as [{matchKeys, target, version}, ...]. The new package's variant includes both the bare and @-scoped forms in matchKeys so its pre-prefixed-but-stale pins (e.g. @scratch/task-herder: 12.7.1 shipped by the source repo) get repinned. Other packages keep the existing bare-name-only policy.

Reason for Changes

Reported during a trial ./scripts/add-repo.sh scratch-storage import: @scratch/scratch-storage: 13.7.4-svg landed at the bottom of scratch-vm/package.json's dependencies instead of between @scratch/scratch-render and @scratch/scratch-svg-renderer. Same in scratch-gui. Cosmetic, but it produces diff noise on every import and would compound as more workspaces are added.

bundleDependencies was a latent gap: an entry rewritten from scratch-storage to @scratch/scratch-storage in dependencies would have left a bare "scratch-storage" orphan in bundleDependencies, and at publish time npm would silently skip bundling the no-longer-existing name. None of the current workspaces use bundleDependencies, but covering it now was almost free with the restructured filter.

Test Coverage

  • Filter unit tests (5 cases, all pass): bare-only rewrite + sort; new-package case (bare + @-scoped both match, stale @-scoped repinned); section with no matching key still sorts; missing sections stay missing; bundleDependencies array gets rewrites + sort + dedupe; legacy bundledDependencies spelling; non-array bundleDependencies: true left alone; duplicate collapse via unique.
  • Live import: ran ./scripts/add-repo.sh scratch-storage end-to-end on a throwaway branch. @scratch/scratch-storage lands between @scratch/scratch-render and @scratch/scratch-svg-renderer in both scratch-vm/package.json and scratch-gui/package.json. @scratch/task-herder in the newly-imported scratch-storage/package.json lands between @babel/runtime and arraybuffer-loader (and was repinned from the upstream's 12.7.1 to the local 13.7.4-svg). Verified via has that absent sections (optionalDependencies, bundleDependencies, bundledDependencies) stayed absent.
  • shellcheck scripts/add-repo.sh is clean.

@cwillisf cwillisf requested a review from a team as a code owner May 22, 2026 13:41
@cwillisf cwillisf requested a review from Copilot May 22, 2026 13:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors scripts/add-repo.sh step 7 to perform cross-workspace dependency rewrites in a single jq pass per package.json, ensuring rewritten dependency keys are sorted alphabetically and extending rewrites to bundleDependencies / bundledDependencies.

Changes:

  • Precomputes rewrite rules once and applies them with a single jq filter per workspace package.json.
  • Sorts dependency-shaped sections by key to reduce diff noise and match typical npm insertion order.
  • Extends rewrites to bundleDependencies / bundledDependencies arrays (rewrite + sort + dedupe).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/add-repo.sh Outdated
Comment thread scripts/add-repo.sh Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

Test Results

    8 files  ±0  1 114 suites  ±0   12m 33s ⏱️ -16s
2 845 tests ±0  2 837 ✅ ±0   8 💤 ±0  0 ❌ ±0 
6 471 runs  ±0  6 432 ✅ ±0  39 💤 ±0  0 ❌ ±0 

Results for commit 4f3eb24. ± Comparison against base commit e7d24a3.

This pull request removes 2 and adds 2 tests. Note that renamed tests count towards both.
test/unit/blocks_control.js > wait ‑ Wait block ended too early: 11 < 10 - 16.666666666666668
test/unit/blocks_control.js > wait ‑ Wait block ended too late: 11 > 10 + 333.3333333333333
test/unit/blocks_control.js > wait ‑ Wait block ended too early: 10 < 10 - 16.666666666666668
test/unit/blocks_control.js > wait ‑ Wait block ended too late: 10 > 10 + 333.3333333333333

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread scripts/add-repo.sh Outdated
Comment thread scripts/add-repo.sh Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread scripts/add-repo.sh Outdated
@cwillisf cwillisf force-pushed the fix/add-repo-sort-and-bundle branch from f5fd2c1 to 140c2e2 Compare May 22, 2026 18:11
cwillisf added 5 commits May 22, 2026 12:23
Restructure the dep rewiring step from a nested `(package × dep × kind ×
name)` loop, each iteration appending the new entry via `+= {key: value}`,
to a single jq invocation per package.json that walks all four dep sections
and rewrites matching keys to their @Scoped equivalents pinned to the local
workspace version. Each touched section is sorted alphabetically by key —
matching what `npm install --save` produces — so the inserted entry lands
in its expected position rather than at the bottom of the list.

The rewrite rules are precomputed once per import as a JSON array of
`{matchKeys, target, version}` records. The new package's variant includes
both the bare name and the @Scoped form so that pre-prefixed-but-stale
pins (e.g. `@scratch/task-herder: 12.7.1` shipped by the source repo) get
repinned. Other packages keep the existing policy of matching bare names
only.

A `reduce` over the four section keys with a `has`-style guard ensures
absent sections stay absent (no `peerDependencies: null` leakage).
`bundleDependencies` (and the legacy spelling `bundledDependencies`) is
an array of bare package names that npm bundles when running `npm pack`.
If a workspace declared one of these names by its bare form, the bare
form survived the dep rewire even after the matching `dependencies` entry
got renamed to `@scratch/<name>`. At publish time npm would then look up
the (no-longer-present) bare name and silently skip bundling it.

Extend the rewrite filter with a type-aware branch: object sections are
mapped per entry and sorted by key; array sections are mapped per name
and uniqued (sort plus dedupe — useful in the corner case where both
the bare and @Scoped forms appear in the same array). Add both bundle
spellings to the reduce list.

Non-array, non-object values (e.g. `bundleDependencies: true`, npm's
shorthand for "bundle everything") fall through the `else .` branch
unchanged.
Replace the `jq ... | sponge file` idiom with a `jq_in_place FILE ...`
helper that writes the jq output to a sibling tempfile and `mv`s it
into place only on `jq` exit 0. A `jq` failure now leaves `file`
untouched and returns the non-zero status, so `set -e` aborts at the
two call sites that don't check explicitly (the new-package fix-up
and the workspaces-list insert) and the rewiring loop's `if !`
catches it as before. With `jq | sponge`, the pipeline's exit status
was sponge's, so a `jq` error would write empty or partial JSON over
the input and the script would happily march on.

The helper seeds the tempfile with `cp -p "$file" "$tmp"` so it
inherits the original's mode (and content); the subsequent `>`
truncates without touching the mode bits, and the final mv carries
them back. Without this step, mktemp's default 0600 would silently
downgrade 0644-mode package.json files.

The replacement also drops the `moreutils` (sponge) prerequisite —
once nothing in the script reads-and-writes the same file in one
pipeline, sponge's purpose is gone.
In the per-package jq filter, if rewriting an object-shaped dep
section produces two entries with the same key (e.g. the source
package.json declared both "scratch-foo" and "@scratch/scratch-foo"
in the same section), `from_entries` would keep the later of the two
under jq's stable sort. That meant a stale `@scratch/...` pin could
silently override the freshly-rewritten workspace version.

Detect the duplicate after the map step and `error()` out, naming the
section and the colliding key. `jq_in_place`'s exit-status check then
leaves the file untouched and the rewiring loop falls through to
`package_replacement_error`, so the developer sees both jq's error
and the script's standard "could not replace monorepo refs in PKG"
message and can clean up the input package.json.

The scenario isn't expected to occur in practice; loud failure on an
unexpected input is preferred over silently making a guess.

Array sections (bundleDependencies, bundledDependencies) still use
`unique` since they carry no version information — collapsing
duplicates there is correct rather than fishy.
`jq -f --arg ... <(filter)` parses correctly — jq's argparser recognizes
`--arg` as a flag rather than treating it as the filename for `-f` —
but the layout makes a reader (LLM or human) reasonably wonder. Move
the `--arg`s ahead of `-f` so the filter-file process substitution
sits immediately after `-f`. Pure cosmetic change.
@cwillisf cwillisf force-pushed the fix/add-repo-sort-and-bundle branch from 140c2e2 to 4f3eb24 Compare May 22, 2026 19:26
@cwillisf cwillisf requested a review from Copilot May 22, 2026 19:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread scripts/add-repo.sh
@cwillisf cwillisf merged commit 9839420 into develop May 22, 2026
22 checks passed
@cwillisf cwillisf deleted the fix/add-repo-sort-and-bundle branch May 22, 2026 19:59
@github-actions github-actions Bot locked and limited conversation to collaborators May 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants