feat(theme-check-vscode): surface orphaned files on startup#1218
feat(theme-check-vscode): surface orphaned files on startup#1218ryandiginomad wants to merge 2 commits into
Conversation
On activation, check the theme for orphaned (dead) files and show a single dismissable notification with "Review" (opens the existing dead-code picker) and "Don't show again" actions, instead of requiring the user to run the dead-code command manually. - Gated by a new `themeCheck.checkOrphanedFilesOnBoot` setting (default on), mirroring the existing `themeCheck.preloadOnBoot` pattern - Reuses the whole-theme dead-code detection already exposed via ThemeGraphDeadCodeRequest - Extract fetchDeadCode + showDeadCodePicker from makeDeadCode so the startup check and the command share logic (no behavior change; covered by tests) - Wired into both node and browser activation, fire-and-forget so it never blocks or fails activation Closes Shopify#970
|
Quick check-in — this PR has been ready for review for a week. CLA signed, CI green. Ready whenever the theme-tools team has a window, and happy to address anything that comes up. |
aswamy
left a comment
There was a problem hiding this comment.
Thanks for the PR @ryandiginomad . Please ensure your PR description follows the PR template here. This ensures that you have run the code and have tested it out manually before submitting.
| const enabled = workspace.getConfiguration().get(CHECK_ORPHANED_ON_BOOT_SETTING, true); | ||
| if (!enabled) return; | ||
|
|
||
| const configFiles = await workspace.findFiles('**/.theme-check.yml', '**/node_modules/**'); |
There was a problem hiding this comment.
Startup check misses supported theme roots. This only scans **/.theme-check.yml, but the existing root detector also supports shopify.extension.toml roots and configless themes inferred from assets + snippets (see find-root.ts (line 7)). Those workspaces can activate the extension but will never get this new orphaned-file prompt.
There was a problem hiding this comment.
Good catch — fixed in 2d33a1f. The startup scan now globs every root signal findRoot recognises ({.theme-check.yml,shopify.extension.toml,snippets/*}) instead of just .theme-check.yml, and each match is resolved to its root via the server's themeGraph/rootUri request, so theme app extensions and configless themes get the prompt too.
|
|
||
| const configFiles = await workspace.findFiles('**/.theme-check.yml', '**/node_modules/**'); | ||
|
|
||
| let total = 0; |
There was a problem hiding this comment.
This aggregates total across all config files, but line 42 opens the picker only for firstHit. In a workspace with multiple themes, the notification may say “Found 12 orphaned files” while Review shows only the first theme’s subset.
There was a problem hiding this comment.
Fixed in 2d33a1f. The check now dedupes the resolved roots and prompts once per theme that has orphaned files, so each notification's count matches the files its own "Review" picker opens — no more cross-theme aggregation. Your two-theme workspace would now get one notification per theme. Added unit tests for the multi-theme and dedupe cases.
|
Done — reworked the description to follow the PR template, including a Tophatting section with screenshots: tested in a real extension host against a fresh Dawn clone (boot notification → Review opens the dead-code picker → Don't show again writes the setting → no notification after reload). Happy to adjust anything else. |
|
@ryandiginomad Please also complete the comments i wrote above |
… boot Addresses review feedback on the orphaned-files startup check: - The startup scan only globbed `**/.theme-check.yml`, so theme app extensions (`shopify.extension.toml`) and configless themes (inferred from a `snippets` directory) never got the prompt even though they activate the extension. The glob now matches every root signal that `findRoot` recognises, and the server resolves each anchor to its root. - The notification aggregated the orphaned-file count across all themes but "Review" only opened the first theme's files. It now dedupes by the server-resolved root and prompts once per theme, so each count matches the files its own picker opens.
|
Thanks for the detailed review and the two-theme screenshot — both inline points are addressed in 2d33a1f (replied in each thread):
Both behaviors are covered by new unit tests (multi-theme prompting, root dedupe, the wider glob, per-root counts): |

What are you adding in this PR?
Closes #970.
theme-graph already knows which files are orphaned (dead code), and there's a
Liquid Theme Check: Find dead codecommand to list them — but it's easy to miss because you have to know to run it. This surfaces it proactively: on activation, if the theme has orphaned files, the extension shows a single dismissable notification.themeCheck.checkOrphanedFilesOnBootsetting (defaulttrue), mirroring the existingthemeCheck.preloadOnBootpatternImplementation notes:
ThemeGraphDeadCodeRequest(ThemeGraphManager.deadCode(rootUri)) — no server changes.workspace.findFiles('**/.theme-check.yml')(there's no active editor at boot), aggregates orphaned files across roots, and prompts once.makeDeadCodeto extractfetchDeadCode+showDeadCodePickerso the command and the startup check share logic —makeDeadCode's behavior is unchanged and covered by a characterization test.nodeandbrowseractivation, fire-and-forget so it never blocks or fails activation.Unit tests: new
orphanedFilesOnBoot.spec.tscovers disabled setting / no orphans / orphans → notification / "Don't show again" → setting update / "Review" → picker, plus characterization tests guarding themakeDeadCoderefactor. Fulltheme-check-vscodevitest suite green (23 tests),tsc --noEmitclean, prettier clean.🤖 AI assistance
Drafted with Claude Code. I reviewed every change, ran the tests, and tophatted the flows below in a real extension host. The orphaned-files detection this builds on is existing Shopify code; this PR adds the startup surfacing plus a shared refactor.
What's next? Any followup issues?
None required. A few knobs I'm happy to adjust in this PR if you have preferences:
true(matches the issue's "prompt on start-up" intent) vs opt-infalsefor less startup noise.minor(new feature + setting); can drop topatchgiven the fixed version group.What did you learn?
workspace.findFiles('**/.theme-check.yml')instead.assets/component-progress-bar.css,snippets/quick-order-product-row.liquid), so the notification surfaces real signal even on a vanilla theme.Tophatting
Tested manually against a fresh Dawn clone — which has 2 orphaned files out of the box — plus one intentionally orphaned snippet (3 total), using the web extension host (this also exercises the
browseractivation path):Boot with orphans → one dismissable notification:
Review → opens the existing dead-code quick pick with all 3 files:
Don't show again → writes the setting to user settings:
Reload with the setting off → no notification on boot.
Before you deploy
changeset