1- import { basename } from "path" ;
21import * as React from "react" ;
32import * as Sarif from "sarif" ;
43import * as Keys from "./result-keys" ;
54import { chevronDown , chevronRight , info , listUnordered } from "./octicons" ;
65import {
76 className ,
8- renderLocation ,
97 ResultTableProps ,
108 selectableZebraStripe ,
119 jumpToLocation ,
@@ -18,15 +16,12 @@ import {
1816 NavigationDirection ,
1917 SarifInterpretationData ,
2018} from "../../common/interface-types" ;
21- import {
22- parseSarifPlainTextMessage ,
23- parseSarifLocation ,
24- isNoLocation ,
25- } from "../../common/sarif-utils" ;
26- import { isWholeFileLoc , isLineColumnLoc } from "../../common/bqrs-utils" ;
19+ import { parseSarifLocation , isNoLocation } from "../../common/sarif-utils" ;
2720import { ScrollIntoViewHelper } from "./scroll-into-view-helper" ;
2821import { sendTelemetry } from "../common/telemetry" ;
2922import { AlertTableHeader } from "./alert-table-header" ;
23+ import { SarifMessageWithLocations } from "./locations/SarifMessageWithLocations" ;
24+ import { SarifLocation } from "./locations/SarifLocation" ;
3025
3126export type AlertTableProps = ResultTableProps & {
3227 resultSet : InterpretedResultSet < SarifInterpretationData > ;
@@ -100,41 +95,6 @@ export class AlertTable extends React.Component<
10095 const { numTruncatedResults, sourceLocationPrefix } =
10196 resultSet . interpretation ;
10297
103- function renderRelatedLocations (
104- msg : string ,
105- relatedLocations : Sarif . Location [ ] ,
106- resultKey : Keys . PathNode | Keys . Result | undefined ,
107- ) : JSX . Element [ ] {
108- const relatedLocationsById : { [ k : string ] : Sarif . Location } = { } ;
109- for ( const loc of relatedLocations ) {
110- relatedLocationsById [ loc . id ! ] = loc ;
111- }
112-
113- // match things like `[link-text](related-location-id)`
114- const parts = parseSarifPlainTextMessage ( msg ) ;
115-
116- return parts . map ( ( part , i ) => {
117- if ( typeof part === "string" ) {
118- return < span key = { i } > { part } </ span > ;
119- } else {
120- const renderedLocation = renderSarifLocationWithText (
121- part . text ,
122- relatedLocationsById [ part . dest ] ,
123- resultKey ,
124- ) ;
125- return < span key = { i } > { renderedLocation } </ span > ;
126- }
127- } ) ;
128- }
129-
130- function renderNonLocation (
131- msg : string | undefined ,
132- locationHint : string ,
133- ) : JSX . Element | undefined {
134- if ( msg === undefined ) return undefined ;
135- return < span title = { locationHint } > { msg } </ span > ;
136- }
137-
13898 const updateSelectionCallback = (
13999 resultKey : Keys . PathNode | Keys . Result | undefined ,
140100 ) => {
@@ -147,65 +107,6 @@ export class AlertTable extends React.Component<
147107 } ;
148108 } ;
149109
150- function renderSarifLocationWithText (
151- text : string | undefined ,
152- loc : Sarif . Location ,
153- resultKey : Keys . PathNode | Keys . Result | undefined ,
154- ) : JSX . Element | undefined {
155- const parsedLoc = parseSarifLocation ( loc , sourceLocationPrefix ) ;
156- if ( "hint" in parsedLoc ) {
157- return renderNonLocation ( text , parsedLoc . hint ) ;
158- } else if ( isWholeFileLoc ( parsedLoc ) || isLineColumnLoc ( parsedLoc ) ) {
159- return renderLocation (
160- parsedLoc ,
161- text ,
162- databaseUri ,
163- undefined ,
164- updateSelectionCallback ( resultKey ) ,
165- ) ;
166- } else {
167- return undefined ;
168- }
169- }
170-
171- /**
172- * Render sarif location as a link with the text being simply a
173- * human-readable form of the location itself.
174- */
175- function renderSarifLocation (
176- loc : Sarif . Location ,
177- pathNodeKey : Keys . PathNode | Keys . Result | undefined ,
178- ) : JSX . Element | undefined {
179- const parsedLoc = parseSarifLocation ( loc , sourceLocationPrefix ) ;
180- if ( "hint" in parsedLoc ) {
181- return renderNonLocation ( "[no location]" , parsedLoc . hint ) ;
182- } else if ( isWholeFileLoc ( parsedLoc ) ) {
183- const shortLocation = `${ basename ( parsedLoc . userVisibleFile ) } ` ;
184- const longLocation = `${ parsedLoc . userVisibleFile } ` ;
185- return renderLocation (
186- parsedLoc ,
187- shortLocation ,
188- databaseUri ,
189- longLocation ,
190- updateSelectionCallback ( pathNodeKey ) ,
191- ) ;
192- } else if ( isLineColumnLoc ( parsedLoc ) ) {
193- const shortLocation = `${ basename ( parsedLoc . userVisibleFile ) } :${
194- parsedLoc . startLine
195- } :${ parsedLoc . startColumn } `;
196- const longLocation = `${ parsedLoc . userVisibleFile } ` ;
197- return renderLocation (
198- parsedLoc ,
199- shortLocation ,
200- databaseUri ,
201- longLocation ,
202- updateSelectionCallback ( pathNodeKey ) ,
203- ) ;
204- } else {
205- return undefined ;
206- }
207- }
208-
209110 const toggler : ( keys : Keys . ResultKey [ ] ) => ( e : React . MouseEvent ) => void = (
210111 indices ,
211112 ) => {
@@ -220,19 +121,32 @@ export class AlertTable extends React.Component<
220121 ( result , resultIndex ) => {
221122 const resultKey : Keys . Result = { resultIndex } ;
222123 const text = result . message . text || "[no text]" ;
223- const msg : JSX . Element [ ] =
224- result . relatedLocations === undefined
225- ? [ < span key = "0" > { text } </ span > ]
226- : renderRelatedLocations ( text , result . relatedLocations , resultKey ) ;
124+ const msg =
125+ result . relatedLocations === undefined ? (
126+ < span key = "0" > { text } </ span >
127+ ) : (
128+ < SarifMessageWithLocations
129+ msg = { text }
130+ relatedLocations = { result . relatedLocations }
131+ sourceLocationPrefix = { sourceLocationPrefix }
132+ databaseUri = { databaseUri }
133+ onClick = { updateSelectionCallback ( resultKey ) }
134+ />
135+ ) ;
227136
228137 const currentResultExpanded = this . state . expanded . has (
229138 Keys . keyToString ( resultKey ) ,
230139 ) ;
231140 const indicator = currentResultExpanded ? chevronDown : chevronRight ;
232- const location =
233- result . locations !== undefined &&
234- result . locations . length > 0 &&
235- renderSarifLocation ( result . locations [ 0 ] , resultKey ) ;
141+ const location = result . locations !== undefined &&
142+ result . locations . length > 0 && (
143+ < SarifLocation
144+ loc = { result . locations [ 0 ] }
145+ sourceLocationPrefix = { sourceLocationPrefix }
146+ databaseUri = { databaseUri }
147+ onClick = { updateSelectionCallback ( resultKey ) }
148+ />
149+ ) ;
236150 const locationCells = (
237151 < td className = "vscode-codeql__location-cell" > { location } </ td >
238152 ) ;
@@ -342,17 +256,28 @@ export class AlertTable extends React.Component<
342256 const step = pathNodes [ pathNodeIndex ] ;
343257 const msg =
344258 step . location !== undefined &&
345- step . location . message !== undefined
346- ? renderSarifLocationWithText (
347- step . location . message . text ,
348- step . location ,
349- pathNodeKey ,
350- )
351- : "[no location]" ;
259+ step . location . message !== undefined ? (
260+ < SarifLocation
261+ text = { step . location . message . text }
262+ loc = { step . location }
263+ sourceLocationPrefix = { sourceLocationPrefix }
264+ databaseUri = { databaseUri }
265+ onClick = { updateSelectionCallback ( pathNodeKey ) }
266+ />
267+ ) : (
268+ "[no location]"
269+ ) ;
352270 const additionalMsg =
353- step . location !== undefined
354- ? renderSarifLocation ( step . location , pathNodeKey )
355- : "" ;
271+ step . location !== undefined ? (
272+ < SarifLocation
273+ loc = { step . location }
274+ sourceLocationPrefix = { sourceLocationPrefix }
275+ databaseUri = { databaseUri }
276+ onClick = { updateSelectionCallback ( pathNodeKey ) }
277+ />
278+ ) : (
279+ ""
280+ ) ;
356281 const isSelected = Keys . equalsNotUndefined (
357282 this . state . selectedItem ,
358283 pathNodeKey ,
0 commit comments