feat: add peekToLinkedOnly mode (#127)#160
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a cssPeek.peekToLinkedOnly setting so definition lookup can be restricted to stylesheets directly referenced by the current document.
Changes:
- Registers and passes through the new
peekToLinkedOnlyconfiguration. - Adds linked stylesheet parsing and URI filtering in definition lookup.
- Adds fixtures and tests for linked-only behavior and parser coverage.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
package.json |
Adds the new extension setting. |
client/src/extension.ts |
Reads and forwards the setting to language server initialization. |
server/src/server.ts |
Applies linked-only filtering during definition requests. |
server/src/core/findDefinition.ts |
Adds optional URI allow-list filtering. |
server/src/utils/linkedStylesheets.ts |
Implements stylesheet reference detection and URI resolution. |
tests/src/linkedOnly.test.ts |
Adds tests for linked-only filtering and parser behavior. |
tests/fixture/linked.html, linked.css, unlinked.css |
Adds test fixture files for linked-only lookup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const importRe = | ||
| /\bimport\b[^'";]*?["']([^"']+\.(?:css|scss|sass|less))["']/gi; |
There was a problem hiding this comment.
Fixed in c5bb2d3. Tightened the import regex with a negative lookahead \bimport\b(?!\s*\() (and excluded (/) from the inter-token char class) so dynamic import('./foo.css') calls are no longer matched. Added a unit test ("ignores dynamic import() expressions") that confirms import('./theme.css') and await import("./other.scss") are skipped while a sibling import './static.css' is still included.
| try { | ||
| return new URL(ref, baseUri).toString(); |
There was a problem hiding this comment.
Fixed in c5bb2d3. resolveStylesheetUri now strips ?query and #fragment from the local ref before constructing the URI (ref.replace(/[?#].*$/, "")), so cache-busted and fragment-qualified references resolve to the same file URI the stylesheet map is keyed by. The import / @import regexes were also widened to tolerate a trailing ?…/#… after the extension so the suffix doesn't prevent matching in the first place. Added a unit test ("strips query strings and fragments from local refs") covering both ./app.css?v=1 and ./themed.scss#dark.
Add a new `cssPeek.peekToLinkedOnly` setting (default false) that, when enabled, restricts peek targets to stylesheets explicitly referenced from the current source file. Supported reference syntaxes: - HTML: <link rel="stylesheet" href="..."> - JS/TS/JSX/TSX/Svelte/Vue: import './foo.css' / import x from './foo.scss' - CSS/SCSS/LESS: @import 'foo.css' / @import url('foo.css') When the setting is on, `findDefinition` is called with an `allowedUris` set derived by parsing the current document, so only matching stylesheet URIs are searched. Existing behaviour is unchanged when the setting is off. Closes #127 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t refs
Tightens the JS import regex with a negative lookahead so dynamic
`import('./foo.css')` calls are no longer included in linked-only
results, matching the documented behavior.
Strips `?query` and `#fragment` from local stylesheet refs before
resolving so cache-busted (`./app.css?v=1`) and fragment-qualified
references resolve to the underlying file URI used to key the
stylesheet map.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
c5bb2d3 to
1efadb8
Compare
Closes #127
What
Adds a new
cssPeek.peekToLinkedOnlysetting (boolean, defaultfalse). When enabled, CSS Peek's definition search is restricted to stylesheets explicitly referenced from the current source file, rather than the entire workspace.This is useful in large monorepos where many unrelated stylesheets define the same class name and only the linked ones are relevant.
How
package.json: registers the new setting.client/src/extension.ts: reads the setting and passes it throughinitializationOptions(the server also picks it up viaworkspace/configuration, which is the path actually used per request).server/src/server.ts: inonDefinition, when the setting is on, parses the current document for stylesheet references and passes the resolved URIs as anallowedUris: Set<string>tofindDefinition.server/src/core/findDefinition.ts:findSymbols/findDefinitionaccept an optionalallowedUrisparameter and skip stylesheet URIs not in the set.server/src/utils/linkedStylesheets.ts: new helper that scans the source text for stylesheet references and resolves them against the document's URI.Supported reference syntaxes
<link rel="stylesheet" href="...">(attribute order agnostic).import './foo.css',import x from './foo.scss'.@import './foo.css',@import url('./foo.css').Relative (
./,../) and absolute (/,http://...) paths are resolved against the document URI. Bare specifiers (e.g.import 'normalize.css') are ignored because we don't resolve throughnode_modules.Known limitations
Documented as part of the change because the feature is intentionally a simple string-based heuristic:
styled-components,emotion,vanilla-extract, etc.).@use/@forward(@importonly).import('./foo.css')).@/styles/foo.css, TS path mappings).node_modulesresolution.@imports — only stylesheets directly referenced by the current source are searched. Selectors defined in a transitively@imported file will not be found.<style src="...">(Vue SFC sugar).When the setting is
false(the default), behaviour is unchanged.Tests
Adds
tests/src/linkedOnly.test.tswith:linked.htmllinkslinked.css;unlinked.cssexists but is not linked). Verifies that with the setting off both files match, and with the linked-only filter on onlylinked.cssis searched.@import, and<link>tags withoutrel="stylesheet".Verification
yarn build— clean.yarn test— 31 passing (24 prior + 7 new).yarn lint— clean.yarn prettier— clean for all files touched by this PR (pre-existing warnings in unrelated files are not addressed here).🤖 Generated with Claude Code