Skip to content

feat: add pnpm workspace support#68

Open
thecannabisapp wants to merge 9 commits into
pgsandstrom:masterfrom
thecannabisapp:master
Open

feat: add pnpm workspace support#68
thecannabisapp wants to merge 9 commits into
pgsandstrom:masterfrom
thecannabisapp:master

Conversation

@thecannabisapp
Copy link
Copy Markdown

This PR adds support for pnpm workspaces, resolving both workspace: and catalog: protocol references so that update decorations work correctly in monorepo setups.

What it does

  • workspace:*, workspace:^, workspace:~, workspace:x.y.z — resolves the referenced package to its actual version from the local workspace package.json, then checks npm for available updates.
  • catalog:, catalog:default, catalog:<name> — resolves versions from the root pnpm-workspace.yaml catalog and catalogs sections, then checks npm for available updates.
  • Skips quick-fix/bulk updates for workspace and catalog deps (the version lives in the workspace package or catalog definition, so updating the reference directly would be incorrect).
  • Caches workspace discovery and catalog parsing for performance.

Test coverage

  • 52 unit tests covering workspace resolution, catalog resolution, glob patterns, YAML edge cases (comments, mixed quotes), and package.json parsing integration.

Closes #43
Closes #61

Resolves workspace: protocol references to actual versions from local
workspace packages. This enables the extension to show available
updates for dependencies linked via pnpm workspaces.

- Add workspace.ts module to discover and cache workspace packages
  from pnpm-workspace.yaml, supporting *, **, and literal glob patterns
- Resolve workspace:*, workspace:^, workspace:~, and workspace:x.y.z
  to the local package version or explicit specifier
- Skip quick-fix upgrades for workspace deps (version lives in workspace package)
- Add unit tests for workspace resolution and packageJson integration
Extends pnpm workspace support to resolve catalog: protocol references
using the root pnpm-workspace.yaml catalog and catalogs sections.

- Parse catalog and catalogs blocks from pnpm-workspace.yaml
- Resolve catalog:, catalog:default, and catalog:<name> to versions
  defined in the workspace root catalog configuration
- Support quoted keys (e.g. 'react-dom') in YAML parsing
- Skip quick-fix and bulk updates for catalog deps (version lives in catalog)
- Add isolated test fixtures and unit tests for catalog resolution
@thecannabisapp
Copy link
Copy Markdown
Author

Hi @pgsandstrom — whenever you have a moment, this PR is ready for your review. I've added both workspace and catalog resolution with full test coverage, and the existing vscode e2e test still passes. Happy to make any changes you'd like. Thanks for maintaining the extension!

@pgsandstrom
Copy link
Copy Markdown
Owner

Thanks for the PR.

  1. Could you merge in the latest changes from the master branch? This is on me, I actually forgot to push the latest version to github.
  2. manual yarn parsing is fragile, it is going to fail for some users.
  3. Iterate a few more times with AI. Ask it like "make a critical review of my changes". And then manually review the suggestions to see what is sensible.
  4. Go through the code manually and check what comments and abstractions that are sensible. AI does not have a good sense for what needs explanation, this needs to be done by a human unless we want code smell.

thecannabisapp and others added 6 commits April 23, 2026 12:05
Address review feedback from pgsandstrom on PR pgsandstrom#68:
- Replace hand-rolled line-by-line YAML parsers (parsePnpmWorkspaceYaml,
  parsePnpmWorkspaceCatalogs, extractBlock, extractNestedBlocks) with js-yaml.
  This fixes fragility around comments, inline arrays, flow styles, anchors,
  multi-line strings, and other valid YAML edge cases.
- Remove verbose JSDoc comments that restated the obvious from function signatures.
- Add support for pnpm-workspace.yml (in addition to .yaml).
- Extract findWorkspaceFile helper to avoid duplicating file lookup logic.
- Add js-yaml + @types/js-yaml as direct dependencies.

All 54 tests pass. Typecheck and lint clean.
… cache

Critical review follow-up for PR pgsandstrom#68:

- BUG FIX: catalog: dependencies were never fetched from npm because
  refreshPackageJsonData only resolved workspace: versions before the
  semver filter, leaving catalog: strings to be filtered out. Added
  catalog version resolution so catalog deps now show update decorations.

- Cache workspace root lookups to avoid repeated directory traversal
  when resolving multiple deps from the same package.json.

- Test hardening: wrap writeYaml/restoreYaml in try/finally so failures
  don't leave testdata in a bad state.

- New tests: pnpm-workspace.yml extension support, invalid YAML graceful
  degradation, and catalog npm resolution coverage.

All 56 tests pass. Lint and typecheck clean.
@thecannabisapp
Copy link
Copy Markdown
Author

Hi @pgsandstrom — thanks for the review! I've gone through all four points and pushed the updates. Here's what changed:

1. Merged latest master ✅
Pulled in your v3.5.1 release + the config-reading bugfix and test.

2. Replaced fragile manual YAML parsing ✅
You were absolutely right — the hand-rolled line-by-line parsers for would break on inline arrays, flow styles, anchors, multi-line strings, etc. I replaced all of it with (now a direct dependency). The ~200 lines of / / became ~40 lines of normal object property access. Also added support for as a fallback.

3. Iterated with critical AI review ✅
Did two more passes. Found a real bug during the second one:

Bug: dependencies were never fetched from npm because only resolved versions before the semver filter. A raw string fails , so it was silently dropped — meaning catalog deps showed no update decorations at all.

Fixed by adding catalog resolution in alongside workspace resolution. Also added workspace root caching to avoid repeated directory traversal, hardened tests with , and added coverage for extension and invalid YAML.

4. Cleaned up comments and abstractions ✅
Removed verbose JSDoc that restated the obvious (e.g. "Returns undefined if the version is not a workspace reference or cannot be resolved" on a function literally named returning ). Kept the meaningful ones — like the "Skip quick-fix upgrades for workspace dependencies" comments in / that explain why, not what.

Also removed the internal-only / interfaces that were artifacts of the manual parsing approach.

All 56 tests pass, lint and typecheck are clean, and the existing vscode e2e test still passes. Ready for another look whenever you have time!

@thecannabisapp
Copy link
Copy Markdown
Author

Quick follow-up — the backticks in my last comment got eaten by shell escaping. The key changes were:

  • Replaced ~200 lines of hand-rolled YAML line parsers with js-yaml (proper parser, handles all YAML edge cases)
  • Fixed a real bug: catalog: deps were never fetched from npm because refreshPackageJsonData only resolved workspace: versions before the semver filter. Added catalog resolution there too.
  • Added workspace root caching, pnpm-workspace.yml support, and try/finally in tests.
  • Removed verbose JSDoc and internal-only BlockResult / NestedBlockResult interfaces.

Full diff: thecannabisapp/package-json-upgrade@f8c6a01...ca1daae

Copy link
Copy Markdown

@michaelfaith michaelfaith left a comment

Choose a reason for hiding this comment

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

@pgsandstrom this is pretty solid 👍 . I highlighted a few minor things, and then one recommendation to use a standard glob api, rather than rolling their own. Otherwise, this seems reasonable.

Comment thread src/updateAction.ts
Comment thread src/updateAll.ts Outdated
Comment thread src/workspace.ts
Comment thread src/workspace.ts Outdated
@thecannabisapp
Copy link
Copy Markdown
Author

@michaelfaith thanks for the review — great catches.

Nits: Agreed on all three. I'll flatten the bailouts in updateAction.ts / updateAll.ts and the nested catalog lookup in workspace.ts with optional chaining / nullish coalescing. Much cleaner.

tinyglobby: Also agreed. The hand-rolled glob only handles * and **, but pnpm workspace patterns support full micromatch semantics (brace expansion, negation, extglob, etc). I'll swap resolveGlob / resolveGlobRecursive for tinyglobby — keeps the bundle small and gives us correctness.

@pgsandstrom this should address the remaining feedback. Let me know if you'd like anything else tweaked.

- Combine workspace/catalog bailout conditions in updateAction.ts and updateAll.ts
- Flatten nested catalog lookup in workspace.ts with optional chaining
- Replace hand-rolled resolveGlob/resolveGlobRecursive with tinyglobby
- Adds tinyglobby dependency for proper glob semantics (brace expansion, negation, etc)
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.

Feature Request: Support pnpm workspaces minimumReleaseAge Request: support workspaces.

3 participants