11import type {
2+ EditorSelection ,
23 QueryMetadata ,
34 RawResultsSortState ,
45 ResultSet ,
@@ -7,7 +8,16 @@ import type {
78import { SortDirection } from "../../common/interface-types" ;
89import { assertNever } from "../../common/helpers-pure" ;
910import { vscode } from "../vscode-api" ;
10- import type { UrlValueResolvable } from "../../common/raw-result-types" ;
11+ import type {
12+ CellValue ,
13+ Row ,
14+ UrlValueResolvable ,
15+ } from "../../common/raw-result-types" ;
16+ import type { Result } from "sarif" ;
17+ import {
18+ getLocationsFromSarifResult ,
19+ normalizeFileUri ,
20+ } from "../../common/sarif-utils" ;
1121
1222export interface ResultTableProps {
1323 resultSet : ResultSet ;
@@ -30,6 +40,8 @@ export interface ResultTableProps {
3040 */
3141 showRawResults : ( ) => void ;
3242
43+ filteredRawRows ?: Row [ ] ;
44+ filteredSarifResults ?: Result [ ] ;
3345 selectionFilter ?: EditorSelection ;
3446}
3547
@@ -109,3 +121,110 @@ export function nextSortDirection(
109121 return assertNever ( direction ) ;
110122 }
111123}
124+
125+ /**
126+ * Extracts all resolvable locations from a raw result row.
127+ */
128+ function getLocationsFromRawRow (
129+ row : Row ,
130+ ) : Array < { uri : string ; startLine ?: number ; endLine ?: number } > {
131+ const locations : Array < {
132+ uri : string ;
133+ startLine ?: number ;
134+ endLine ?: number ;
135+ } > = [ ] ;
136+
137+ for ( const cell of row ) {
138+ const loc = getLocationFromCell ( cell ) ;
139+ if ( loc ) {
140+ locations . push ( loc ) ;
141+ }
142+ }
143+
144+ return locations ;
145+ }
146+
147+ function getLocationFromCell (
148+ cell : CellValue ,
149+ ) : { uri : string ; startLine ?: number ; endLine ?: number } | undefined {
150+ if ( cell . type !== "entity" ) {
151+ return undefined ;
152+ }
153+ const url = cell . value . url ;
154+ if ( ! url ) {
155+ return undefined ;
156+ }
157+ if ( url . type === "wholeFileLocation" ) {
158+ return { uri : url . uri } ;
159+ }
160+ if ( url . type === "lineColumnLocation" ) {
161+ return {
162+ uri : url . uri ,
163+ startLine : url . startLine ,
164+ endLine : url . endLine ,
165+ } ;
166+ }
167+ return undefined ;
168+ }
169+
170+ /**
171+ * Checks if a result location overlaps with the editor selection.
172+ * If the selection is empty (just a cursor), matches any result in the same file.
173+ */
174+ function doesLocationOverlapSelection (
175+ loc : { uri : string ; startLine ?: number ; endLine ?: number } ,
176+ selection : EditorSelection ,
177+ ) : boolean {
178+ const normalizedLocUri = normalizeFileUri ( loc . uri ) ;
179+ const normalizedSelUri = normalizeFileUri ( selection . fileUri ) ;
180+
181+ if ( normalizedLocUri !== normalizedSelUri ) {
182+ return false ;
183+ }
184+
185+ // If selection is empty (just a cursor), match the whole file
186+ if ( selection . isEmpty ) {
187+ return true ;
188+ }
189+
190+ // If the result location has no line info, it's a whole-file location — include it
191+ if ( loc . startLine === undefined ) {
192+ return true ;
193+ }
194+
195+ // Only include results whose starting line falls within the selection range
196+ return (
197+ loc . startLine >= selection . startLine && loc . startLine <= selection . endLine
198+ ) ;
199+ }
200+
201+ /**
202+ * Filters raw result rows to those with at least one location overlapping the selection.
203+ */
204+ export function filterRawRows (
205+ rows : readonly Row [ ] ,
206+ selection : EditorSelection ,
207+ ) : Row [ ] {
208+ return rows . filter ( ( row ) => {
209+ const locations = getLocationsFromRawRow ( row ) ;
210+ return locations . some ( ( loc ) =>
211+ doesLocationOverlapSelection ( loc , selection ) ,
212+ ) ;
213+ } ) ;
214+ }
215+
216+ /**
217+ * Filters SARIF results to those with at least one location overlapping the selection.
218+ */
219+ export function filterSarifResults (
220+ results : Result [ ] ,
221+ sourceLocationPrefix : string ,
222+ selection : EditorSelection ,
223+ ) : Result [ ] {
224+ return results . filter ( ( result ) => {
225+ const locations = getLocationsFromSarifResult ( result , sourceLocationPrefix ) ;
226+ return locations . some ( ( loc ) =>
227+ doesLocationOverlapSelection ( loc , selection ) ,
228+ ) ;
229+ } ) ;
230+ }
0 commit comments