Refactor interpreted-data interface in preparation for other interpretations than SARIF
This commit is contained in:
committed by
Andrew Eisenberg
parent
a2b5ad07ff
commit
d9a04ea895
@@ -674,20 +674,13 @@ export class CodeQLCliServer implements Disposable {
|
|||||||
return await this.runJsonCodeQlCliCommand<DecodedBqrsChunk>(['bqrs', 'decode'], subcommandArgs, 'Reading bqrs data');
|
return await this.runJsonCodeQlCliCommand<DecodedBqrsChunk>(['bqrs', 'decode'], subcommandArgs, 'Reading bqrs data');
|
||||||
}
|
}
|
||||||
|
|
||||||
async runInterpretCommand(format: string, metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo) {
|
async runInterpretCommand(format: string, additonalArgs: string[], metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo) {
|
||||||
const args = [
|
const args = [
|
||||||
'--output', interpretedResultsPath,
|
'--output', interpretedResultsPath,
|
||||||
'--format', format,
|
'--format', format,
|
||||||
// Forward all of the query metadata.
|
// Forward all of the query metadata.
|
||||||
...Object.entries(metadata).map(([key, value]) => `-t=${key}=${value}`)
|
...Object.entries(metadata).map(([key, value]) => `-t=${key}=${value}`)
|
||||||
];
|
].concat(additonalArgs);
|
||||||
if (format == SARIF_FORMAT) {
|
|
||||||
// TODO: This flag means that we don't group interpreted results
|
|
||||||
// by primary location. We may want to revisit whether we call
|
|
||||||
// interpretation with and without this flag, or do some
|
|
||||||
// grouping client-side.
|
|
||||||
args.push('--no-group-results');
|
|
||||||
}
|
|
||||||
if (sourceInfo !== undefined) {
|
if (sourceInfo !== undefined) {
|
||||||
args.push(
|
args.push(
|
||||||
'--source-archive', sourceInfo.sourceArchive,
|
'--source-archive', sourceInfo.sourceArchive,
|
||||||
@@ -710,12 +703,20 @@ export class CodeQLCliServer implements Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async interpretBqrs(metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo): Promise<sarif.Log> {
|
async interpretBqrs(metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo): Promise<sarif.Log> {
|
||||||
await this.runInterpretCommand(SARIF_FORMAT, metadata, resultsPath, interpretedResultsPath, sourceInfo);
|
const additionalArgs = [
|
||||||
|
// TODO: This flag means that we don't group interpreted results
|
||||||
|
// by primary location. We may want to revisit whether we call
|
||||||
|
// interpretation with and without this flag, or do some
|
||||||
|
// grouping client-side.
|
||||||
|
'--no-group-results'
|
||||||
|
];
|
||||||
|
|
||||||
|
await this.runInterpretCommand(SARIF_FORMAT, additionalArgs, metadata, resultsPath, interpretedResultsPath, sourceInfo);
|
||||||
return await sarifParser(interpretedResultsPath);
|
return await sarifParser(interpretedResultsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateResultsCsv(metadata: QueryMetadata, resultsPath: string, csvPath: string, sourceInfo?: SourceInfo): Promise<void> {
|
async generateResultsCsv(metadata: QueryMetadata, resultsPath: string, csvPath: string, sourceInfo?: SourceInfo): Promise<void> {
|
||||||
await this.runInterpretCommand(CSV_FORMAT, metadata, resultsPath, csvPath, sourceInfo);
|
await this.runInterpretCommand(CSV_FORMAT, [], metadata, resultsPath, csvPath, sourceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
async sortBqrs(resultsPath: string, sortedResultsPath: string, resultSet: string, sortKeys: number[], sortDirections: SortDirection[]): Promise<void> {
|
async sortBqrs(resultsPath: string, sortedResultsPath: string, resultSet: string, sortKeys: number[], sortDirections: SortDirection[]): Promise<void> {
|
||||||
@@ -1039,11 +1040,11 @@ class SplitBuffer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A version of startsWith that isn't overriden by a broken version of ms-python.
|
* A version of startsWith that isn't overriden by a broken version of ms-python.
|
||||||
*
|
*
|
||||||
* The definition comes from
|
* The definition comes from
|
||||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
||||||
* which is CC0/public domain
|
* which is CC0/public domain
|
||||||
*
|
*
|
||||||
* See https://github.com/github/vscode-codeql/issues/802 for more context as to why we need it.
|
* See https://github.com/github/vscode-codeql/issues/802 for more context as to why we need it.
|
||||||
*/
|
*/
|
||||||
private static startsWith(s: string, searchString: string, position: number): boolean {
|
private static startsWith(s: string, searchString: string, position: number): boolean {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
import { Logger } from './logging';
|
import { Logger } from './logging';
|
||||||
import * as messages from './pure/messages';
|
import * as messages from './pure/messages';
|
||||||
import { commandRunner } from './commandRunner';
|
import { commandRunner } from './commandRunner';
|
||||||
import { CompletedQueryInfo, interpretResults } from './query-results';
|
import { CompletedQueryInfo, interpretResultsSarif } from './query-results';
|
||||||
import { QueryEvaluationInfo, tmpDir } from './run-queries';
|
import { QueryEvaluationInfo, tmpDir } from './run-queries';
|
||||||
import { parseSarifLocation, parseSarifPlainTextMessage } from './pure/sarif-utils';
|
import { parseSarifLocation, parseSarifPlainTextMessage } from './pure/sarif-utils';
|
||||||
import {
|
import {
|
||||||
@@ -93,7 +93,7 @@ function numPagesOfResultSet(resultSet: RawResultSet): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function numInterpretedPages(interpretation: Interpretation | undefined): number {
|
function numInterpretedPages(interpretation: Interpretation | undefined): number {
|
||||||
return Math.ceil((interpretation?.sarif.runs[0].results?.length || 0) / PAGE_SIZE.getValue<number>());
|
return Math.ceil((interpretation?.data.runs[0].results?.length || 0) / PAGE_SIZE.getValue<number>());
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InterfaceManager extends DisposableObject {
|
export class InterfaceManager extends DisposableObject {
|
||||||
@@ -140,9 +140,9 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
this._diagnosticCollection.clear();
|
this._diagnosticCollection.clear();
|
||||||
if (this.isShowingPanel()) {
|
if (this.isShowingPanel()) {
|
||||||
void this.postMessage({
|
void this.postMessage({
|
||||||
t: 'untoggleShowProblems'
|
t: 'untoggleShowProblems'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -474,7 +474,7 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
if (this._interpretation === undefined) {
|
if (this._interpretation === undefined) {
|
||||||
throw new Error('Trying to show interpreted results but interpretation was undefined');
|
throw new Error('Trying to show interpreted results but interpretation was undefined');
|
||||||
}
|
}
|
||||||
if (this._interpretation.sarif.runs[0].results === undefined) {
|
if (this._interpretation.data.t === 'SarifInterpretationData' && this._interpretation.data.runs[0].results === undefined) {
|
||||||
throw new Error('Trying to show interpreted results but results were undefined');
|
throw new Error('Trying to show interpreted results but results were undefined');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +592,7 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sarif = await interpretResults(
|
const sarif = await interpretResultsSarif(
|
||||||
this.cliServer,
|
this.cliServer,
|
||||||
metadata,
|
metadata,
|
||||||
resultsPaths,
|
resultsPaths,
|
||||||
@@ -608,7 +608,7 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
const numTotalResults = sarif.runs[0]?.results?.length || 0;
|
const numTotalResults = sarif.runs[0]?.results?.length || 0;
|
||||||
|
|
||||||
const interpretation: Interpretation = {
|
const interpretation: Interpretation = {
|
||||||
sarif,
|
data: sarif,
|
||||||
sourceLocationPrefix,
|
sourceLocationPrefix,
|
||||||
numTruncatedResults: 0,
|
numTruncatedResults: 0,
|
||||||
numTotalResults,
|
numTotalResults,
|
||||||
@@ -621,7 +621,6 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
private getPageOfInterpretedResults(
|
private getPageOfInterpretedResults(
|
||||||
pageNumber: number
|
pageNumber: number
|
||||||
): Interpretation {
|
): Interpretation {
|
||||||
|
|
||||||
function getPageOfRun(run: Sarif.Run): Sarif.Run {
|
function getPageOfRun(run: Sarif.Run): Sarif.Run {
|
||||||
return {
|
return {
|
||||||
...run, results: run.results?.slice(
|
...run, results: run.results?.slice(
|
||||||
@@ -631,16 +630,21 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._interpretation === undefined) {
|
const interp = this._interpretation;
|
||||||
|
if (interp === undefined) {
|
||||||
throw new Error('Tried to get interpreted results before interpretation finished');
|
throw new Error('Tried to get interpreted results before interpretation finished');
|
||||||
}
|
}
|
||||||
if (this._interpretation.sarif.runs.length !== 1) {
|
|
||||||
void this.logger.log(`Warning: SARIF file had ${this._interpretation.sarif.runs.length} runs, expected 1`);
|
if (interp.data.t !== 'SarifInterpretationData')
|
||||||
|
return interp;
|
||||||
|
|
||||||
|
if (interp.data.runs.length !== 1) {
|
||||||
|
void this.logger.log(`Warning: SARIF file had ${interp.data.runs.length} runs, expected 1`);
|
||||||
}
|
}
|
||||||
const interp = this._interpretation;
|
|
||||||
return {
|
return {
|
||||||
...interp,
|
...interp,
|
||||||
sarif: { ...interp.sarif, runs: [getPageOfRun(interp.sarif.runs[0])] },
|
data: { ...interp.data, runs: [getPageOfRun(interp.data.runs[0])] },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -730,9 +734,12 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
interpretation: Interpretation,
|
interpretation: Interpretation,
|
||||||
databaseItem: DatabaseItem
|
databaseItem: DatabaseItem
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { sarif, sourceLocationPrefix } = interpretation;
|
const { data, sourceLocationPrefix } = interpretation;
|
||||||
|
|
||||||
if (!sarif.runs || !sarif.runs[0].results) {
|
if (data.t !== 'SarifInterpretationData')
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!data.runs || !data.runs[0].results) {
|
||||||
void this.logger.log(
|
void this.logger.log(
|
||||||
'Didn\'t find a run in the sarif results. Error processing sarif?'
|
'Didn\'t find a run in the sarif results. Error processing sarif?'
|
||||||
);
|
);
|
||||||
@@ -741,7 +748,7 @@ export class InterfaceManager extends DisposableObject {
|
|||||||
|
|
||||||
const diagnostics: [Uri, ReadonlyArray<Diagnostic>][] = [];
|
const diagnostics: [Uri, ReadonlyArray<Diagnostic>][] = [];
|
||||||
|
|
||||||
for (const result of sarif.runs[0].results) {
|
for (const result of data.runs[0].results) {
|
||||||
const message = result.message.text;
|
const message = result.message.text;
|
||||||
if (message === undefined) {
|
if (message === undefined) {
|
||||||
void this.logger.log('Sarif had result without plaintext message');
|
void this.logger.log('Sarif had result without plaintext message');
|
||||||
|
|||||||
@@ -12,13 +12,14 @@ export const SELECT_TABLE_NAME = '#select';
|
|||||||
export const ALERTS_TABLE_NAME = 'alerts';
|
export const ALERTS_TABLE_NAME = 'alerts';
|
||||||
|
|
||||||
export type RawTableResultSet = { t: 'RawResultSet' } & RawResultSet;
|
export type RawTableResultSet = { t: 'RawResultSet' } & RawResultSet;
|
||||||
export type PathTableResultSet = {
|
export type InterpretedResultSet<T> = {
|
||||||
t: 'SarifResultSet';
|
t: 'InterpretedResultSet';
|
||||||
readonly schema: ResultSetSchema;
|
readonly schema: ResultSetSchema;
|
||||||
name: string;
|
name: string;
|
||||||
} & Interpretation;
|
interpretation: InterpretationT<T>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ResultSet = RawTableResultSet | PathTableResultSet;
|
export type ResultSet = RawTableResultSet | InterpretedResultSet<InterpretationData>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only ever show this many rows in a raw result table.
|
* Only ever show this many rows in a raw result table.
|
||||||
@@ -46,7 +47,14 @@ export interface PreviousExecution {
|
|||||||
durationSeconds: number;
|
durationSeconds: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Interpretation {
|
export type SarifInterpretationData = {
|
||||||
|
t: 'SarifInterpretationData';
|
||||||
|
} & sarif.Log;
|
||||||
|
|
||||||
|
// Add more interpretation data kinds when needed (e.g., graph data)
|
||||||
|
export type InterpretationData = SarifInterpretationData;
|
||||||
|
|
||||||
|
export interface InterpretationT<T> {
|
||||||
sourceLocationPrefix: string;
|
sourceLocationPrefix: string;
|
||||||
numTruncatedResults: number;
|
numTruncatedResults: number;
|
||||||
numTotalResults: number;
|
numTotalResults: number;
|
||||||
@@ -55,9 +63,11 @@ export interface Interpretation {
|
|||||||
* they appear in the sarif file.
|
* they appear in the sarif file.
|
||||||
*/
|
*/
|
||||||
sortState?: InterpretedResultsSortState;
|
sortState?: InterpretedResultsSortState;
|
||||||
sarif: sarif.Log;
|
data: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Interpretation = InterpretationT<InterpretationData>;
|
||||||
|
|
||||||
export interface ResultsPaths {
|
export interface ResultsPaths {
|
||||||
resultsPath: string;
|
resultsPath: string;
|
||||||
interpretedResultsPath: string;
|
interpretedResultsPath: string;
|
||||||
@@ -358,7 +368,7 @@ export function getDefaultResultSetName(
|
|||||||
return [
|
return [
|
||||||
ALERTS_TABLE_NAME,
|
ALERTS_TABLE_NAME,
|
||||||
SELECT_TABLE_NAME,
|
SELECT_TABLE_NAME,
|
||||||
resultSetNames[0],
|
resultSetNames[0]
|
||||||
].filter((resultSetName) => resultSetNames.includes(resultSetName))[0];
|
].filter((resultSetName) => resultSetNames.includes(resultSetName))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { CancellationTokenSource, env } from 'vscode';
|
|||||||
import { QueryWithResults, QueryEvaluationInfo } from './run-queries';
|
import { QueryWithResults, QueryEvaluationInfo } from './run-queries';
|
||||||
import * as messages from './pure/messages';
|
import * as messages from './pure/messages';
|
||||||
import * as cli from './cli';
|
import * as cli from './cli';
|
||||||
import * as sarif from 'sarif';
|
|
||||||
import * as fs from 'fs-extra';
|
import * as fs from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {
|
import {
|
||||||
@@ -11,7 +10,8 @@ import {
|
|||||||
SortedResultSetInfo,
|
SortedResultSetInfo,
|
||||||
QueryMetadata,
|
QueryMetadata,
|
||||||
InterpretedResultsSortState,
|
InterpretedResultsSortState,
|
||||||
ResultsPaths
|
ResultsPaths,
|
||||||
|
SarifInterpretationData
|
||||||
} from './pure/interface-types';
|
} from './pure/interface-types';
|
||||||
import { QueryHistoryConfig } from './config';
|
import { QueryHistoryConfig } from './config';
|
||||||
import { DatabaseInfo } from './pure/interface-types';
|
import { DatabaseInfo } from './pure/interface-types';
|
||||||
@@ -148,19 +148,20 @@ export class CompletedQueryInfo implements QueryWithResults {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call cli command to interpret results.
|
* Call cli command to interpret SARIF results.
|
||||||
*/
|
*/
|
||||||
export async function interpretResults(
|
export async function interpretResultsSarif(
|
||||||
server: cli.CodeQLCliServer,
|
cli: cli.CodeQLCliServer,
|
||||||
metadata: QueryMetadata | undefined,
|
metadata: QueryMetadata | undefined,
|
||||||
resultsPaths: ResultsPaths,
|
resultsPaths: ResultsPaths,
|
||||||
sourceInfo?: cli.SourceInfo
|
sourceInfo?: cli.SourceInfo
|
||||||
): Promise<sarif.Log> {
|
): Promise<SarifInterpretationData> {
|
||||||
const { resultsPath, interpretedResultsPath } = resultsPaths;
|
const { resultsPath, interpretedResultsPath } = resultsPaths;
|
||||||
if (await fs.pathExists(interpretedResultsPath)) {
|
if (await fs.pathExists(interpretedResultsPath)) {
|
||||||
return JSON.parse(await fs.readFile(interpretedResultsPath, 'utf8'));
|
return { ...JSON.parse(await fs.readFile(interpretedResultsPath, 'utf8')), t: 'SarifInterpretationData' };
|
||||||
}
|
}
|
||||||
return await server.interpretBqrs(ensureMetadataIsComplete(metadata), resultsPath, interpretedResultsPath, sourceInfo);
|
const res = await cli.interpretBqrsSarif(ensureMetadataIsComplete(metadata), resultsPath, interpretedResultsPath, sourceInfo);
|
||||||
|
return { ...res, t: 'SarifInterpretationData' };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureMetadataIsComplete(metadata: QueryMetadata | undefined) {
|
export function ensureMetadataIsComplete(metadata: QueryMetadata | undefined) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as Keys from '../pure/result-keys';
|
|||||||
import * as octicons from './octicons';
|
import * as octicons from './octicons';
|
||||||
import { className, renderLocation, ResultTableProps, zebraStripe, selectableZebraStripe, jumpToLocation, nextSortDirection, emptyQueryResultsMessage } from './result-table-utils';
|
import { className, renderLocation, ResultTableProps, zebraStripe, selectableZebraStripe, jumpToLocation, nextSortDirection, emptyQueryResultsMessage } from './result-table-utils';
|
||||||
import { onNavigation, NavigationEvent } from './results';
|
import { onNavigation, NavigationEvent } from './results';
|
||||||
import { PathTableResultSet } from '../pure/interface-types';
|
import { InterpretedResultSet, SarifInterpretationData } from '../pure/interface-types';
|
||||||
import {
|
import {
|
||||||
parseSarifPlainTextMessage,
|
parseSarifPlainTextMessage,
|
||||||
parseSarifLocation,
|
parseSarifLocation,
|
||||||
@@ -15,7 +15,7 @@ import { InterpretedResultsSortColumn, SortDirection, InterpretedResultsSortStat
|
|||||||
import { vscode } from './vscode-api';
|
import { vscode } from './vscode-api';
|
||||||
import { isWholeFileLoc, isLineColumnLoc } from '../pure/bqrs-utils';
|
import { isWholeFileLoc, isLineColumnLoc } from '../pure/bqrs-utils';
|
||||||
|
|
||||||
export type PathTableProps = ResultTableProps & { resultSet: PathTableResultSet };
|
export type PathTableProps = ResultTableProps & { resultSet: InterpretedResultSet<SarifInterpretationData> };
|
||||||
export interface PathTableState {
|
export interface PathTableState {
|
||||||
expanded: { [k: string]: boolean };
|
expanded: { [k: string]: boolean };
|
||||||
selectedPathNode: undefined | Keys.PathNode;
|
selectedPathNode: undefined | Keys.PathNode;
|
||||||
@@ -51,7 +51,7 @@ export class PathTable extends React.Component<PathTableProps, PathTableState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sortClass(column: InterpretedResultsSortColumn): string {
|
sortClass(column: InterpretedResultsSortColumn): string {
|
||||||
const sortState = this.props.resultSet.sortState;
|
const sortState = this.props.resultSet.interpretation.sortState;
|
||||||
if (sortState !== undefined && sortState.sortBy === column) {
|
if (sortState !== undefined && sortState.sortBy === column) {
|
||||||
return sortState.sortDirection === SortDirection.asc ? 'sort-asc' : 'sort-desc';
|
return sortState.sortDirection === SortDirection.asc ? 'sort-asc' : 'sort-desc';
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ export class PathTable extends React.Component<PathTableProps, PathTableState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNextSortState(column: InterpretedResultsSortColumn): InterpretedResultsSortState | undefined {
|
getNextSortState(column: InterpretedResultsSortColumn): InterpretedResultsSortState | undefined {
|
||||||
const oldSortState = this.props.resultSet.sortState;
|
const oldSortState = this.props.resultSet.interpretation.sortState;
|
||||||
const prevDirection = oldSortState && oldSortState.sortBy === column ? oldSortState.sortDirection : undefined;
|
const prevDirection = oldSortState && oldSortState.sortBy === column ? oldSortState.sortDirection : undefined;
|
||||||
const nextDirection = nextSortDirection(prevDirection, true);
|
const nextDirection = nextSortDirection(prevDirection, true);
|
||||||
return nextDirection === undefined ? undefined :
|
return nextDirection === undefined ? undefined :
|
||||||
@@ -94,7 +94,7 @@ export class PathTable extends React.Component<PathTableProps, PathTableState> {
|
|||||||
</thead>;
|
</thead>;
|
||||||
|
|
||||||
const rows: JSX.Element[] = [];
|
const rows: JSX.Element[] = [];
|
||||||
const { numTruncatedResults, sourceLocationPrefix } = resultSet;
|
const { numTruncatedResults, sourceLocationPrefix } = resultSet.interpretation;
|
||||||
|
|
||||||
function renderRelatedLocations(msg: string, relatedLocations: Sarif.Location[]): JSX.Element[] {
|
function renderRelatedLocations(msg: string, relatedLocations: Sarif.Location[]): JSX.Element[] {
|
||||||
const relatedLocationsById: { [k: string]: Sarif.Location } = {};
|
const relatedLocationsById: { [k: string]: Sarif.Location } = {};
|
||||||
@@ -188,13 +188,13 @@ export class PathTable extends React.Component<PathTableProps, PathTableState> {
|
|||||||
return (e) => this.toggle(e, indices);
|
return (e) => this.toggle(e, indices);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!resultSet.sarif.runs?.[0]?.results?.length) {
|
if (!resultSet.interpretation.data.runs?.[0]?.results?.length) {
|
||||||
return this.renderNoResults();
|
return this.renderNoResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
let expansionIndex = 0;
|
let expansionIndex = 0;
|
||||||
|
|
||||||
resultSet.sarif.runs[0].results.forEach((result, resultIndex) => {
|
resultSet.interpretation.data.runs[0].results.forEach((result, resultIndex) => {
|
||||||
const text = result.message.text || '[no text]';
|
const text = result.message.text || '[no text]';
|
||||||
const msg: JSX.Element[] =
|
const msg: JSX.Element[] =
|
||||||
result.relatedLocations === undefined ?
|
result.relatedLocations === undefined ?
|
||||||
@@ -307,7 +307,7 @@ export class PathTable extends React.Component<PathTableProps, PathTableState> {
|
|||||||
const { selectedPathNode } = prevState;
|
const { selectedPathNode } = prevState;
|
||||||
if (selectedPathNode === undefined) return prevState;
|
if (selectedPathNode === undefined) return prevState;
|
||||||
|
|
||||||
const path = Keys.getPath(this.props.resultSet.sarif, selectedPathNode);
|
const path = Keys.getPath(this.props.resultSet.interpretation.data, selectedPathNode);
|
||||||
if (path === undefined) return prevState;
|
if (path === undefined) return prevState;
|
||||||
|
|
||||||
const nextIndex = selectedPathNode.pathNodeIndex + event.direction;
|
const nextIndex = selectedPathNode.pathNodeIndex + event.direction;
|
||||||
@@ -318,7 +318,7 @@ export class PathTable extends React.Component<PathTableProps, PathTableState> {
|
|||||||
return prevState;
|
return prevState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loc = parseSarifLocation(sarifLoc, this.props.resultSet.sourceLocationPrefix);
|
const loc = parseSarifLocation(sarifLoc, this.props.resultSet.interpretation.sourceLocationPrefix);
|
||||||
if (isNoLocation(loc)) {
|
if (isNoLocation(loc)) {
|
||||||
return prevState;
|
return prevState;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ function getResultCount(resultSet: ResultSet): number {
|
|||||||
switch (resultSet.t) {
|
switch (resultSet.t) {
|
||||||
case 'RawResultSet':
|
case 'RawResultSet':
|
||||||
return resultSet.schema.rows;
|
return resultSet.schema.rows;
|
||||||
case 'SarifResultSet':
|
case 'InterpretedResultSet':
|
||||||
return resultSet.numTotalResults;
|
return resultSet.interpretation.numTotalResults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,27 +87,32 @@ export class ResultTables
|
|||||||
this.props.rawResultSets.map((rs) => ({ t: 'RawResultSet', ...rs }));
|
this.props.rawResultSets.map((rs) => ({ t: 'RawResultSet', ...rs }));
|
||||||
|
|
||||||
if (this.props.interpretation != undefined) {
|
if (this.props.interpretation != undefined) {
|
||||||
|
const tableName = this.getInterpretedTableName();
|
||||||
resultSets.push({
|
resultSets.push({
|
||||||
t: 'SarifResultSet',
|
t: 'InterpretedResultSet',
|
||||||
// FIXME: The values of version, columns, tupleCount are
|
// FIXME: The values of version, columns, tupleCount are
|
||||||
// unused stubs because a SarifResultSet schema isn't used the
|
// unused stubs because a InterpretedResultSet schema isn't used the
|
||||||
// same way as a RawResultSet. Probably should pull `name` field
|
// same way as a RawResultSet. Probably should pull `name` field
|
||||||
// out.
|
// out.
|
||||||
schema: {
|
schema: {
|
||||||
name: ALERTS_TABLE_NAME,
|
name: tableName,
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: []
|
columns: []
|
||||||
},
|
},
|
||||||
name: ALERTS_TABLE_NAME,
|
name: tableName,
|
||||||
...this.props.interpretation,
|
interpretation: this.props.interpretation,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return resultSets;
|
return resultSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getInterpretedTableName(): string {
|
||||||
|
return ALERTS_TABLE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
private getResultSetNames(): string[] {
|
private getResultSetNames(): string[] {
|
||||||
return this.props.interpretation
|
return this.props.interpretation
|
||||||
? this.props.parsedResultSets.resultSetNames.concat([ALERTS_TABLE_NAME])
|
? this.props.parsedResultSets.resultSetNames.concat([this.getInterpretedTableName()])
|
||||||
: this.props.parsedResultSets.resultSetNames;
|
: this.props.parsedResultSets.resultSetNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,8 +354,15 @@ class ResultTable extends React.Component<ResultTableProps, Record<string, never
|
|||||||
switch (resultSet.t) {
|
switch (resultSet.t) {
|
||||||
case 'RawResultSet': return <RawTable
|
case 'RawResultSet': return <RawTable
|
||||||
{...this.props} resultSet={resultSet} />;
|
{...this.props} resultSet={resultSet} />;
|
||||||
case 'SarifResultSet': return <PathTable
|
case 'InterpretedResultSet': {
|
||||||
{...this.props} resultSet={resultSet} />;
|
const data = resultSet.interpretation.data;
|
||||||
|
switch (data.t) {
|
||||||
|
case 'SarifInterpretationData': {
|
||||||
|
const sarifResultSet = { ...resultSet, interpretation: { ...resultSet.interpretation, data } };
|
||||||
|
return <PathTable {...this.props} resultSet={sarifResultSet} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ class App extends React.Component<Record<string, never>, ResultsViewState> {
|
|||||||
|
|
||||||
void this.loadResults();
|
void this.loadResults();
|
||||||
break;
|
break;
|
||||||
case 'showInterpretedPage':
|
case 'showInterpretedPage': {
|
||||||
|
const tableName = ALERTS_TABLE_NAME;
|
||||||
|
|
||||||
this.updateStateWithNewResultsInfo({
|
this.updateStateWithNewResultsInfo({
|
||||||
resultsPath: '', // FIXME: Not used for interpreted, refactor so this is not needed
|
resultsPath: '', // FIXME: Not used for interpreted, refactor so this is not needed
|
||||||
parsedResultSets: {
|
parsedResultSets: {
|
||||||
@@ -114,16 +116,16 @@ class App extends React.Component<Record<string, never>, ResultsViewState> {
|
|||||||
resultSetNames: msg.resultSetNames,
|
resultSetNames: msg.resultSetNames,
|
||||||
pageNumber: msg.pageNumber,
|
pageNumber: msg.pageNumber,
|
||||||
resultSet: {
|
resultSet: {
|
||||||
t: 'SarifResultSet',
|
t: 'InterpretedResultSet',
|
||||||
name: ALERTS_TABLE_NAME,
|
name: tableName,
|
||||||
schema: {
|
schema: {
|
||||||
name: ALERTS_TABLE_NAME,
|
name: tableName,
|
||||||
rows: 1,
|
rows: 1,
|
||||||
columns: []
|
columns: []
|
||||||
},
|
},
|
||||||
...msg.interpretation,
|
interpretation: msg.interpretation,
|
||||||
},
|
},
|
||||||
selectedTable: ALERTS_TABLE_NAME,
|
selectedTable: tableName,
|
||||||
},
|
},
|
||||||
origResultsPaths: undefined as any, // FIXME: Not used for interpreted, refactor so this is not needed
|
origResultsPaths: undefined as any, // FIXME: Not used for interpreted, refactor so this is not needed
|
||||||
sortedResultsMap: new Map(), // FIXME: Not used for interpreted, refactor so this is not needed
|
sortedResultsMap: new Map(), // FIXME: Not used for interpreted, refactor so this is not needed
|
||||||
@@ -136,6 +138,7 @@ class App extends React.Component<Record<string, never>, ResultsViewState> {
|
|||||||
});
|
});
|
||||||
void this.loadResults();
|
void this.loadResults();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'resultsUpdating':
|
case 'resultsUpdating':
|
||||||
this.setState({
|
this.setState({
|
||||||
isExpectingResultsUpdate: true,
|
isExpectingResultsUpdate: true,
|
||||||
@@ -191,7 +194,7 @@ class App extends React.Component<Record<string, never>, ResultsViewState> {
|
|||||||
const resultSet = parsedResultSets.resultSet;
|
const resultSet = parsedResultSets.resultSet;
|
||||||
if (!resultSet.t) {
|
if (!resultSet.t) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Missing result set type. Should be either "SarifResultSet" or "RawResultSet".'
|
'Missing result set type. Should be either "InterpretedResultSet" or "RawResultSet".'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return [resultSet];
|
return [resultSet];
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'mocha';
|
|||||||
import 'sinon-chai';
|
import 'sinon-chai';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import * as chaiAsPromised from 'chai-as-promised';
|
import * as chaiAsPromised from 'chai-as-promised';
|
||||||
import { FullQueryInfo, InitialQueryInfo, interpretResults } from '../../query-results';
|
import { FullQueryInfo, InitialQueryInfo, interpretResultsSarif } from '../../query-results';
|
||||||
import { queriesDir, QueryEvaluationInfo, QueryWithResults, tmpDir } from '../../run-queries';
|
import { queriesDir, QueryEvaluationInfo, QueryWithResults, tmpDir } from '../../run-queries';
|
||||||
import { QueryHistoryConfig } from '../../config';
|
import { QueryHistoryConfig } from '../../config';
|
||||||
import { EvaluationResult, QueryResultType } from '../../pure/messages';
|
import { EvaluationResult, QueryResultType } from '../../pure/messages';
|
||||||
@@ -183,11 +183,11 @@ describe('query-results', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should interpretResults', async () => {
|
it('should interpretResultsSarif', async () => {
|
||||||
const spy = sandbox.mock();
|
const spy = sandbox.mock();
|
||||||
spy.returns('1234');
|
spy.returns({ a: '1234' });
|
||||||
const mockServer = {
|
const mockServer = {
|
||||||
interpretBqrs: spy
|
interpretBqrsSarif: spy
|
||||||
} as unknown as CodeQLCliServer;
|
} as unknown as CodeQLCliServer;
|
||||||
|
|
||||||
const interpretedResultsPath = path.join(tmpDir.name, 'interpreted.json');
|
const interpretedResultsPath = path.join(tmpDir.name, 'interpreted.json');
|
||||||
@@ -198,7 +198,7 @@ describe('query-results', () => {
|
|||||||
id: 'my-id' as string | undefined,
|
id: 'my-id' as string | undefined,
|
||||||
scored: undefined
|
scored: undefined
|
||||||
};
|
};
|
||||||
const results1 = await interpretResults(
|
const results1 = await interpretResultsSarif(
|
||||||
mockServer,
|
mockServer,
|
||||||
metadata,
|
metadata,
|
||||||
{
|
{
|
||||||
@@ -207,7 +207,7 @@ describe('query-results', () => {
|
|||||||
sourceInfo as SourceInfo
|
sourceInfo as SourceInfo
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(results1).to.eq('1234');
|
expect(results1).to.deep.eq({ a: '1234', t: 'SarifInterpretationData' });
|
||||||
expect(spy).to.have.been.calledWith(
|
expect(spy).to.have.been.calledWith(
|
||||||
metadata,
|
metadata,
|
||||||
resultsPath, interpretedResultsPath, sourceInfo
|
resultsPath, interpretedResultsPath, sourceInfo
|
||||||
@@ -215,9 +215,9 @@ describe('query-results', () => {
|
|||||||
|
|
||||||
// Try again, but with no id
|
// Try again, but with no id
|
||||||
spy.reset();
|
spy.reset();
|
||||||
spy.returns('1234');
|
spy.returns({a: '1234'});
|
||||||
delete metadata.id;
|
delete metadata.id;
|
||||||
const results2 = await interpretResults(
|
const results2 = await interpretResultsSarif(
|
||||||
mockServer,
|
mockServer,
|
||||||
metadata,
|
metadata,
|
||||||
{
|
{
|
||||||
@@ -225,7 +225,7 @@ describe('query-results', () => {
|
|||||||
},
|
},
|
||||||
sourceInfo as SourceInfo
|
sourceInfo as SourceInfo
|
||||||
);
|
);
|
||||||
expect(results2).to.eq('1234');
|
expect(results2).to.deep.eq({ a: '1234', t: 'SarifInterpretationData' });
|
||||||
expect(spy).to.have.been.calledWith(
|
expect(spy).to.have.been.calledWith(
|
||||||
{ kind: 'my-kind', id: 'dummy-id', scored: undefined },
|
{ kind: 'my-kind', id: 'dummy-id', scored: undefined },
|
||||||
resultsPath, interpretedResultsPath, sourceInfo
|
resultsPath, interpretedResultsPath, sourceInfo
|
||||||
@@ -236,7 +236,7 @@ describe('query-results', () => {
|
|||||||
fs.writeFileSync(interpretedResultsPath, JSON.stringify({
|
fs.writeFileSync(interpretedResultsPath, JSON.stringify({
|
||||||
a: 6
|
a: 6
|
||||||
}), 'utf8');
|
}), 'utf8');
|
||||||
const results3 = await interpretResults(
|
const results3 = await interpretResultsSarif(
|
||||||
mockServer,
|
mockServer,
|
||||||
metadata,
|
metadata,
|
||||||
{
|
{
|
||||||
@@ -244,7 +244,7 @@ describe('query-results', () => {
|
|||||||
},
|
},
|
||||||
sourceInfo as SourceInfo
|
sourceInfo as SourceInfo
|
||||||
);
|
);
|
||||||
expect(results3).to.deep.eq({ a: 6 });
|
expect(results3).to.deep.eq({ a: 6, t: 'SarifInterpretationData' });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('splat and slurp', () => {
|
describe('splat and slurp', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user