Refactor interpreted-data interface in preparation for other interpretations than SARIF

This commit is contained in:
Tom Hvitved
2021-03-25 11:55:38 +01:00
committed by Andrew Eisenberg
parent a2b5ad07ff
commit d9a04ea895
8 changed files with 116 additions and 82 deletions

View File

@@ -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 {

View File

@@ -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');

View File

@@ -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];
} }

View File

@@ -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) {

View File

@@ -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;
} }

View File

@@ -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} />;
}
}
}
} }
} }
} }

View File

@@ -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];

View File

@@ -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', () => {