diff --git a/extensions/ql-vscode/src/common/bqrs-result.ts b/extensions/ql-vscode/src/common/bqrs-result.ts index a9dc124ec..d17f0d1e1 100644 --- a/extensions/ql-vscode/src/common/bqrs-result.ts +++ b/extensions/ql-vscode/src/common/bqrs-result.ts @@ -4,8 +4,10 @@ import { ColumnKindCode, DecodedBqrsChunk, EntityValue as BqrsEntityValue, + LineColumnLocation, ResultSetSchema, UrlValue as BqrsUrlValue, + WholeFileLocation, } from "./bqrs-cli-types"; import { CellValue, @@ -13,17 +15,19 @@ import { ColumnKind, EntityValue, RawResultSet, - Tuple, + Row, UrlValue, + UrlValueResolvable, } from "./raw-result-types"; import { assertNever } from "./helpers-pure"; +import { isEmptyPath } from "./bqrs-utils"; export function bqrsToResultSet( schema: ResultSetSchema, chunk: DecodedBqrsChunk, ): RawResultSet { const name = schema.name; - const rows = schema.rows; + const totalRowCount = schema.rows; const nextPageOffset = chunk.next; const columns = schema.columns.map( @@ -33,15 +37,15 @@ export function bqrsToResultSet( }), ); - const tuples = chunk.tuples.map( - (tuple): Tuple => tuple.map((cell): CellValue => mapCellValue(cell)), + const rows = chunk.tuples.map( + (tuple): Row => tuple.map((cell): CellValue => mapCellValue(cell)), ); return { name, - rows, + totalRowCount, columns, - tuples, + rows, nextPageOffset, }; } @@ -98,15 +102,27 @@ function mapEntityValue(cellValue: BqrsEntityValue): EntityValue { }; } -function mapUrlValue(urlValue: BqrsUrlValue): UrlValue { +function mapUrlValue(urlValue: BqrsUrlValue): UrlValue | undefined { if (typeof urlValue === "string") { + const location = tryGetLocationFromString(urlValue); + if (location !== undefined) { + return location; + } + return { type: "string", value: urlValue, }; } - if (urlValue.startLine) { + if (isWholeFileLoc(urlValue)) { + return { + type: "wholeFileLocation", + uri: urlValue.uri, + }; + } + + if (isLineColumnLoc(urlValue)) { return { type: "lineColumnLocation", uri: urlValue.uri, @@ -117,8 +133,64 @@ function mapUrlValue(urlValue: BqrsUrlValue): UrlValue { }; } - return { - type: "wholeFileLocation", - uri: urlValue.uri, - }; + return undefined; +} + +function isLineColumnLoc(loc: BqrsUrlValue): loc is LineColumnLocation { + return ( + typeof loc !== "string" && + !isEmptyPath(loc.uri) && + "startLine" in loc && + "startColumn" in loc && + "endLine" in loc && + "endColumn" in loc + ); +} + +function isWholeFileLoc(loc: BqrsUrlValue): loc is WholeFileLocation { + return ( + typeof loc !== "string" && !isEmptyPath(loc.uri) && !isLineColumnLoc(loc) + ); +} + +/** + * The CodeQL filesystem libraries use this pattern in `getURL()` predicates + * to describe the location of an entire filesystem resource. + * Such locations appear as `StringLocation`s instead of `FivePartLocation`s. + * + * Folder resources also get similar URLs, but with the `folder` scheme. + * They are deliberately ignored here, since there is no suitable location to show the user. + */ +const FILE_LOCATION_REGEX = /file:\/\/(.+):([0-9]+):([0-9]+):([0-9]+):([0-9]+)/; + +function tryGetLocationFromString(loc: string): UrlValueResolvable | undefined { + const matches = FILE_LOCATION_REGEX.exec(loc); + if (matches && matches.length > 1 && matches[1]) { + if (isWholeFileMatch(matches)) { + return { + type: "wholeFileLocation", + uri: matches[1], + }; + } else { + return { + type: "lineColumnLocation", + uri: matches[1], + startLine: Number(matches[2]), + startColumn: Number(matches[3]), + endLine: Number(matches[4]), + endColumn: Number(matches[5]), + }; + } + } + + return undefined; +} + +function isWholeFileMatch(matches: RegExpExecArray): boolean { + return ( + matches[2] === "0" && + matches[3] === "0" && + matches[4] === "0" && + matches[5] === "0" + ); } diff --git a/extensions/ql-vscode/src/common/bqrs-utils.ts b/extensions/ql-vscode/src/common/bqrs-utils.ts index 9580b8740..3a5a75d31 100644 --- a/extensions/ql-vscode/src/common/bqrs-utils.ts +++ b/extensions/ql-vscode/src/common/bqrs-utils.ts @@ -1,10 +1,22 @@ +import { createRemoteFileRef } from "../common/location-link-utils"; import { + isUrlValueResolvable, UrlValue, - ResolvableLocationValue, + UrlValueResolvable, +} from "./raw-result-types"; +import { LineColumnLocation, + UrlValue as BqrsUrlValue, WholeFileLocation, } from "./bqrs-cli-types"; -import { createRemoteFileRef } from "../common/location-link-utils"; + +/** + * Checks whether the file path is empty. If so, we do not want to render this location + * as a link. + */ +export function isEmptyPath(uriStr: string) { + return !uriStr || uriStr === "file:/"; +} /** * The CodeQL filesystem libraries use this pattern in `getURL()` predicates @@ -20,13 +32,25 @@ const FILE_LOCATION_REGEX = /file:\/\/(.+):([0-9]+):([0-9]+):([0-9]+):([0-9]+)/; * @param loc The location to test. */ export function tryGetResolvableLocation( - loc: UrlValue | undefined, -): ResolvableLocationValue | undefined { - let resolvedLoc; + loc: BqrsUrlValue | undefined, +): UrlValueResolvable | undefined { + let resolvedLoc: UrlValueResolvable | undefined; if (loc === undefined) { resolvedLoc = undefined; - } else if (isWholeFileLoc(loc) || isLineColumnLoc(loc)) { - resolvedLoc = loc as ResolvableLocationValue; + } else if (isWholeFileLoc(loc)) { + resolvedLoc = { + type: "wholeFileLocation", + uri: loc.uri, + }; + } else if (isLineColumnLoc(loc)) { + resolvedLoc = { + type: "lineColumnLocation", + uri: loc.uri, + startLine: loc.startLine, + startColumn: loc.startColumn, + endLine: loc.endLine, + endColumn: loc.endColumn, + }; } else if (isStringLoc(loc)) { resolvedLoc = tryGetLocationFromString(loc); } else { @@ -38,15 +62,17 @@ export function tryGetResolvableLocation( export function tryGetLocationFromString( loc: string, -): ResolvableLocationValue | undefined { +): UrlValueResolvable | undefined { const matches = FILE_LOCATION_REGEX.exec(loc); if (matches && matches.length > 1 && matches[1]) { if (isWholeFileMatch(matches)) { return { + type: "wholeFileLocation", uri: matches[1], - } as WholeFileLocation; + }; } else { return { + type: "lineColumnLocation", uri: matches[1], startLine: Number(matches[2]), startColumn: Number(matches[3]), @@ -68,17 +94,7 @@ function isWholeFileMatch(matches: RegExpExecArray): boolean { ); } -/** - * Checks whether the file path is empty. If so, we do not want to render this location - * as a link. - * - * @param uri A file uri - */ -export function isEmptyPath(uriStr: string) { - return !uriStr || uriStr === "file:/"; -} - -export function isLineColumnLoc(loc: UrlValue): loc is LineColumnLocation { +export function isLineColumnLoc(loc: BqrsUrlValue): loc is LineColumnLocation { return ( typeof loc !== "string" && !isEmptyPath(loc.uri) && @@ -89,23 +105,36 @@ export function isLineColumnLoc(loc: UrlValue): loc is LineColumnLocation { ); } -export function isWholeFileLoc(loc: UrlValue): loc is WholeFileLocation { +export function isWholeFileLoc(loc: BqrsUrlValue): loc is WholeFileLocation { return ( typeof loc !== "string" && !isEmptyPath(loc.uri) && !isLineColumnLoc(loc) ); } -export function isStringLoc(loc: UrlValue): loc is string { +export function isStringLoc(loc: BqrsUrlValue): loc is string { return typeof loc === "string"; } +export function tryGetBqrsRemoteLocation( + loc: BqrsUrlValue | undefined, + fileLinkPrefix: string, + sourceLocationPrefix: string | undefined, +): string | undefined { + const resolvedLoc = tryGetResolvableLocation(loc); + + return tryGetRemoteLocation( + resolvedLoc, + fileLinkPrefix, + sourceLocationPrefix, + ); +} + export function tryGetRemoteLocation( loc: UrlValue | undefined, fileLinkPrefix: string, sourceLocationPrefix: string | undefined, ): string | undefined { - const resolvableLocation = tryGetResolvableLocation(loc); - if (!resolvableLocation) { + if (!loc || !isUrlValueResolvable(loc)) { return undefined; } @@ -115,22 +144,19 @@ export function tryGetRemoteLocation( // "file:${sourceLocationPrefix}/relative/path/to/file" // So we need to strip off the first part to get the relative path. if (sourceLocationPrefix) { - if (!resolvableLocation.uri.startsWith(`file:${sourceLocationPrefix}/`)) { + if (!loc.uri.startsWith(`file:${sourceLocationPrefix}/`)) { return undefined; } - trimmedLocation = resolvableLocation.uri.replace( - `file:${sourceLocationPrefix}/`, - "", - ); + trimmedLocation = loc.uri.replace(`file:${sourceLocationPrefix}/`, ""); } else { // If the source location prefix is empty (e.g. for older remote queries), we assume that the database // was created on a Linux actions runner and has the format: // "file:/home/runner/work///relative/path/to/file" // So we need to drop the first 6 parts of the path. - if (!resolvableLocation.uri.startsWith("file:/home/runner/work/")) { + if (!loc.uri.startsWith("file:/home/runner/work/")) { return undefined; } - const locationParts = resolvableLocation.uri.split("/"); + const locationParts = loc.uri.split("/"); trimmedLocation = locationParts.slice(6, locationParts.length).join("/"); } @@ -138,11 +164,16 @@ export function tryGetRemoteLocation( fileLinkPrefix, filePath: trimmedLocation, }; + + if (loc.type === "wholeFileLocation") { + return createRemoteFileRef(fileLink); + } + return createRemoteFileRef( fileLink, - resolvableLocation.startLine, - resolvableLocation.endLine, - resolvableLocation.startColumn, - resolvableLocation.endColumn, + loc.startLine, + loc.endLine, + loc.startColumn, + loc.endColumn, ); } diff --git a/extensions/ql-vscode/src/common/interface-types.ts b/extensions/ql-vscode/src/common/interface-types.ts index 928df86fb..2f5cb988d 100644 --- a/extensions/ql-vscode/src/common/interface-types.ts +++ b/extensions/ql-vscode/src/common/interface-types.ts @@ -25,6 +25,7 @@ import { } from "../model-editor/shared/view-state"; import { Mode } from "../model-editor/shared/mode"; import { QueryLanguage } from "./query-language"; +import { UrlValueResolvable } from "./raw-result-types"; /** * This module contains types and code that are shared between @@ -208,7 +209,7 @@ export type FromResultsViewMsg = */ interface ViewSourceFileMsg { t: "viewSourceFile"; - loc: ResolvableLocationValue; + loc: ResolvableLocationValue | UrlValueResolvable; databaseUri: string; } diff --git a/extensions/ql-vscode/src/common/raw-result-types.ts b/extensions/ql-vscode/src/common/raw-result-types.ts index 482a43757..d05f20709 100644 --- a/extensions/ql-vscode/src/common/raw-result-types.ts +++ b/extensions/ql-vscode/src/common/raw-result-types.ts @@ -31,11 +31,20 @@ export type UrlValueLineColumnLocation = { endColumn: number; }; -export type UrlValue = - | UrlValueString +export type UrlValueResolvable = | UrlValueWholeFileLocation | UrlValueLineColumnLocation; +export function isUrlValueResolvable( + value: UrlValue, +): value is UrlValueResolvable { + return ( + value.type === "wholeFileLocation" || value.type === "lineColumnLocation" + ); +} + +export type UrlValue = UrlValueString | UrlValueResolvable; + export type EntityValue = { url?: UrlValue; label?: string; @@ -68,14 +77,14 @@ export type CellValue = | CellValueString | CellValueBoolean; -export type Tuple = CellValue[]; +export type Row = CellValue[]; export type RawResultSet = { name: string; - rows: number; + totalRowCount: number; columns: Column[]; - tuples: Tuple[]; + rows: Row[]; nextPageOffset?: number; }; diff --git a/extensions/ql-vscode/src/databases/local-databases/locations.ts b/extensions/ql-vscode/src/databases/local-databases/locations.ts index ff9ccc3af..df809b544 100644 --- a/extensions/ql-vscode/src/databases/local-databases/locations.ts +++ b/extensions/ql-vscode/src/databases/local-databases/locations.ts @@ -10,19 +10,19 @@ import { workspace, } from "vscode"; import { - LineColumnLocation, ResolvableLocationValue, - UrlValue, - WholeFileLocation, + UrlValue as BqrsUrlValue, } from "../../common/bqrs-cli-types"; -import { - isLineColumnLoc, - tryGetResolvableLocation, -} from "../../common/bqrs-utils"; -import { getErrorMessage } from "../../common/helpers-pure"; +import { assertNever, getErrorMessage } from "../../common/helpers-pure"; import { Logger } from "../../common/logging"; import { DatabaseItem } from "./database-item"; import { DatabaseManager } from "./database-manager"; +import { tryGetResolvableLocation } from "../../common/bqrs-utils"; +import { + UrlValueLineColumnLocation, + UrlValueResolvable, + UrlValueWholeFileLocation, +} from "../../common/raw-result-types"; const findMatchBackground = new ThemeColor("editor.findMatchBackground"); const findRangeHighlightBackground = new ThemeColor( @@ -45,7 +45,7 @@ export const shownLocationLineDecoration = * @param databaseItem Database in which to resolve the file location. */ function resolveFivePartLocation( - loc: LineColumnLocation, + loc: UrlValueLineColumnLocation, databaseItem: DatabaseItem, ): Location { // `Range` is a half-open interval, and is zero-based. CodeQL locations are closed intervals, and @@ -66,7 +66,7 @@ function resolveFivePartLocation( * @param databaseItem Database in which to resolve the filesystem resource location. */ function resolveWholeFileLocation( - loc: WholeFileLocation, + loc: UrlValueWholeFileLocation, databaseItem: DatabaseItem, ): Location { // A location corresponding to the start of the file. @@ -74,6 +74,20 @@ function resolveWholeFileLocation( return new Location(databaseItem.resolveSourceFile(loc.uri), range); } +function isUrlValueResolvable( + loc: BqrsUrlValue | UrlValueResolvable | undefined, +): loc is UrlValueResolvable { + if (!loc) { + return false; + } + + if (typeof loc !== "object") { + return false; + } + + return "type" in loc; +} + /** * Try to resolve the specified CodeQL location to a URI into the source archive. If no exact location * can be resolved, returns `undefined`. @@ -81,21 +95,28 @@ function resolveWholeFileLocation( * @param databaseItem Database in which to resolve the file location. */ export function tryResolveLocation( - loc: UrlValue | undefined, + loc: BqrsUrlValue | UrlValueResolvable | undefined, databaseItem: DatabaseItem, ): Location | undefined { - const resolvableLoc = tryGetResolvableLocation(loc); - if (!resolvableLoc || typeof resolvableLoc === "string") { + const resolvableLoc = isUrlValueResolvable(loc) + ? loc + : tryGetResolvableLocation(loc); + if (!resolvableLoc) { return; - } else if (isLineColumnLoc(resolvableLoc)) { - return resolveFivePartLocation(resolvableLoc, databaseItem); - } else { - return resolveWholeFileLocation(resolvableLoc, databaseItem); + } + + switch (resolvableLoc.type) { + case "wholeFileLocation": + return resolveWholeFileLocation(resolvableLoc, databaseItem); + case "lineColumnLocation": + return resolveFivePartLocation(resolvableLoc, databaseItem); + default: + assertNever(resolvableLoc); } } export async function showResolvableLocation( - loc: ResolvableLocationValue, + loc: ResolvableLocationValue | UrlValueResolvable, databaseItem: DatabaseItem, logger: Logger, ): Promise { @@ -153,7 +174,7 @@ export async function showLocation(location?: Location) { export async function jumpToLocation( databaseUri: string, - loc: ResolvableLocationValue, + loc: ResolvableLocationValue | UrlValueResolvable, databaseManager: DatabaseManager, logger: Logger, ) { diff --git a/extensions/ql-vscode/src/stories/data/rawResults.json b/extensions/ql-vscode/src/stories/data/rawResults.json index 3aa99a328..fc8de89c8 100644 --- a/extensions/ql-vscode/src/stories/data/rawResults.json +++ b/extensions/ql-vscode/src/stories/data/rawResults.json @@ -1,24 +1,20 @@ { - "schema": { + "resultSet": { "name": "#select", - "rows": 1, + "totalRowCount": 1, "columns": [ { - "kind": "i" + "kind": "integer" } - ] - }, - "resultSet": { - "schema": { - "name": "#select", - "rows": 1, - "columns": [ + ], + "rows": [ + [ { - "kind": "i" + "type": "number", + "value": 60688 } ] - }, - "rows": [[60688]] + ] }, "fileLinkPrefix": "https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7", "sourceLocationPrefix": "/home/runner/work/bulk-builder/bulk-builder", diff --git a/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx b/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx index a54723ee5..d0e880018 100644 --- a/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx +++ b/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx @@ -18,6 +18,7 @@ const Template: StoryFn = (args) => ( export const ClickableLocation = Template.bind({}); ClickableLocation.args = { loc: { + type: "lineColumnLocation", uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java", startLine: 22, startColumn: 27, diff --git a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysis.stories.tsx b/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysis.stories.tsx index 899c38b81..566a12234 100644 --- a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysis.stories.tsx +++ b/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysis.stories.tsx @@ -14,6 +14,7 @@ import { } from "../../variant-analysis/shared/variant-analysis"; import { createMockVariantAnalysis } from "../../../test/factories/variant-analysis/shared/variant-analysis"; import { createMockRepositoryWithMetadata } from "../../../test/factories/variant-analysis/shared/repository"; +import { ColumnKind } from "../../common/raw-result-types"; export default { title: "Variant Analysis/Variant Analysis", @@ -207,26 +208,22 @@ const repoResults: VariantAnalysisScannedRepositoryResult[] = [ variantAnalysisId: 1, repositoryId: 1, rawResults: { - schema: { + resultSet: { name: "#select", - rows: 1, + totalRowCount: 1, columns: [ { - kind: "i", + kind: ColumnKind.Integer, }, ], - }, - resultSet: { - schema: { - name: "#select", - rows: 1, - columns: [ + rows: [ + [ { - kind: "i", + type: "number", + value: 60688, }, ], - }, - rows: [[60688]], + ], }, fileLinkPrefix: "https://github.com/octodemo/hello-world-1/blob/59a2a6c7d9dde7a6ecb77c2f7e8197d6925c143b", diff --git a/extensions/ql-vscode/src/variant-analysis/bqrs-processing.ts b/extensions/ql-vscode/src/variant-analysis/bqrs-processing.ts index bea5d3e37..023086c91 100644 --- a/extensions/ql-vscode/src/variant-analysis/bqrs-processing.ts +++ b/extensions/ql-vscode/src/variant-analysis/bqrs-processing.ts @@ -1,9 +1,9 @@ import { CodeQLCliServer } from "../codeql-cli/cli"; import { Logger } from "../common/logging"; -import { transformBqrsResultSet } from "../common/bqrs-cli-types"; import { AnalysisRawResults } from "./shared/analysis-result"; import { MAX_RAW_RESULTS } from "./shared/result-limits"; import { SELECT_TABLE_NAME } from "../common/interface-types"; +import { bqrsToResultSet } from "../common/bqrs-result"; export async function extractRawResults( cliServer: CodeQLCliServer, @@ -34,9 +34,9 @@ export async function extractRawResults( pageSize: MAX_RAW_RESULTS, }); - const resultSet = transformBqrsResultSet(schema, chunk); + const resultSet = bqrsToResultSet(schema, chunk); const capped = !!chunk.next; - return { schema, resultSet, fileLinkPrefix, sourceLocationPrefix, capped }; + return { resultSet, fileLinkPrefix, sourceLocationPrefix, capped }; } diff --git a/extensions/ql-vscode/src/variant-analysis/markdown-generation.ts b/extensions/ql-vscode/src/variant-analysis/markdown-generation.ts index 05ca8b9f2..76945d25f 100644 --- a/extensions/ql-vscode/src/variant-analysis/markdown-generation.ts +++ b/extensions/ql-vscode/src/variant-analysis/markdown-generation.ts @@ -1,4 +1,3 @@ -import { CellValue } from "../common/bqrs-cli-types"; import { tryGetRemoteLocation } from "../common/bqrs-utils"; import { createRemoteFileRef } from "../common/location-link-utils"; import { @@ -19,6 +18,7 @@ import type { VariantAnalysisScannedRepositoryResult, } from "./shared/variant-analysis"; import type { RepositoryWithMetadata } from "./shared/repository"; +import { CellValue } from "../common/raw-result-types"; type MarkdownLinkType = "local" | "gist"; @@ -298,9 +298,9 @@ function generateMarkdownForRawResults( analysisRawResults: AnalysisRawResults, ): string[] { const tableRows: string[] = []; - const columnCount = analysisRawResults.schema.columns.length; + const columnCount = analysisRawResults.resultSet.columns.length; // Table headers are the column names if they exist, and empty otherwise - const headers = analysisRawResults.schema.columns.map( + const headers = analysisRawResults.resultSet.columns.map( (column) => column.name || "", ); const tableHeader = `| ${headers.join(" | ")} |`; @@ -327,23 +327,25 @@ function generateMarkdownForRawTableCell( sourceLocationPrefix: string, ) { let cellValue: string; - switch (typeof value) { + switch (value.type) { case "string": case "number": case "boolean": - cellValue = `\`${convertNonPrintableChars(value.toString())}\``; + cellValue = `\`${convertNonPrintableChars(value.value.toString())}\``; break; - case "object": + case "entity": { const url = tryGetRemoteLocation( - value.url, + value.value.url, fileLinkPrefix, sourceLocationPrefix, ); if (url) { - cellValue = `[\`${convertNonPrintableChars(value.label)}\`](${url})`; + cellValue = `[\`${convertNonPrintableChars( + value.value.label, + )}\`](${url})`; } else { - cellValue = `\`${convertNonPrintableChars(value.label)}\``; + cellValue = `\`${convertNonPrintableChars(value.value.label)}\``; } } break; diff --git a/extensions/ql-vscode/src/variant-analysis/shared/analysis-result.ts b/extensions/ql-vscode/src/variant-analysis/shared/analysis-result.ts index 4b91142ae..d62566dd2 100644 --- a/extensions/ql-vscode/src/variant-analysis/shared/analysis-result.ts +++ b/extensions/ql-vscode/src/variant-analysis/shared/analysis-result.ts @@ -1,7 +1,6 @@ -import { RawResultSet, ResultSetSchema } from "../../common/bqrs-cli-types"; +import { RawResultSet } from "../../common/raw-result-types"; export interface AnalysisRawResults { - schema: ResultSetSchema; resultSet: RawResultSet; fileLinkPrefix: string; sourceLocationPrefix: string; diff --git a/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx b/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx index a0a435dd7..4c58bcda3 100644 --- a/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx +++ b/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx @@ -1,12 +1,12 @@ import * as React from "react"; import { useCallback } from "react"; -import { ResolvableLocationValue } from "../../../common/bqrs-cli-types"; import { jumpToLocation } from "../result-table-utils"; import TextButton from "../../common/TextButton"; import { styled } from "styled-components"; +import { UrlValueResolvable } from "../../../common/raw-result-types"; interface Props { - loc: ResolvableLocationValue; + loc: UrlValueResolvable; label: string; databaseUri: string; onClick?: () => void; diff --git a/extensions/ql-vscode/src/view/results/result-table-utils.ts b/extensions/ql-vscode/src/view/results/result-table-utils.ts index 90fc55810..faec62195 100644 --- a/extensions/ql-vscode/src/view/results/result-table-utils.ts +++ b/extensions/ql-vscode/src/view/results/result-table-utils.ts @@ -7,6 +7,7 @@ import { } from "../../common/interface-types"; import { assertNever } from "../../common/helpers-pure"; import { vscode } from "../vscode-api"; +import { UrlValueResolvable } from "../../common/raw-result-types"; export interface ResultTableProps { resultSet: ResultSet; @@ -40,7 +41,7 @@ const oddRowClassName = "vscode-codeql__result-table-row--odd"; export const selectedRowClassName = "vscode-codeql__result-table-row--selected"; export function jumpToLocation( - loc: ResolvableLocationValue, + loc: ResolvableLocationValue | UrlValueResolvable, databaseUri: string, ): void { vscode.postMessage({ diff --git a/extensions/ql-vscode/src/view/variant-analysis/AnalyzedRepoItemContent.tsx b/extensions/ql-vscode/src/view/variant-analysis/AnalyzedRepoItemContent.tsx index f6f15e18d..a7ecc71ec 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/AnalyzedRepoItemContent.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/AnalyzedRepoItemContent.tsx @@ -125,8 +125,7 @@ export const AnalyzedRepoItemContent = ({ {rawResults && chosenResultFormat === ResultFormat.RawResults && ( diff --git a/extensions/ql-vscode/src/view/variant-analysis/RawResultCell.tsx b/extensions/ql-vscode/src/view/variant-analysis/RawResultCell.tsx index 557b78199..b0898359a 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/RawResultCell.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/RawResultCell.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"; -import { CellValue } from "../../common/bqrs-cli-types"; +import { CellValue } from "../../common/raw-result-types"; import { sendTelemetry } from "../common/telemetry"; import { convertNonPrintableChars } from "../../common/text-utils"; import { tryGetRemoteLocation } from "../../common/bqrs-utils"; @@ -20,20 +20,20 @@ export const RawResultCell = ({ fileLinkPrefix, sourceLocationPrefix, }: CellProps) => { - switch (typeof value) { + switch (value.type) { case "boolean": - return {value.toString()}; + return {value.value.toString()}; case "number": - return ; + return ; case "string": - return {convertNonPrintableChars(value.toString())}; - case "object": { + return {convertNonPrintableChars(value.value.toString())}; + case "entity": { const url = tryGetRemoteLocation( - value.url, + value.value.url, fileLinkPrefix, sourceLocationPrefix, ); - const safeLabel = convertNonPrintableChars(value.label); + const safeLabel = convertNonPrintableChars(value.value.label); if (url) { return ( diff --git a/extensions/ql-vscode/src/view/variant-analysis/RawResultRow.tsx b/extensions/ql-vscode/src/view/variant-analysis/RawResultRow.tsx index a92e0d7bf..d52441eb2 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/RawResultRow.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/RawResultRow.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { styled } from "styled-components"; -import { CellValue } from "../../common/bqrs-cli-types"; +import { Row } from "../../common/raw-result-types"; import { RawResultCell } from "./RawResultCell"; const StyledRow = styled.div` @@ -14,7 +14,7 @@ const StyledRow = styled.div` `; type RowProps = { - row: CellValue[]; + row: Row; fileLinkPrefix: string; sourceLocationPrefix: string; }; diff --git a/extensions/ql-vscode/src/view/variant-analysis/RawResultsTable.tsx b/extensions/ql-vscode/src/view/variant-analysis/RawResultsTable.tsx index 7eea797d1..4fcfcd8ff 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/RawResultsTable.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/RawResultsTable.tsx @@ -1,9 +1,9 @@ import * as React from "react"; import { useState } from "react"; import { styled } from "styled-components"; -import { RawResultSet, ResultSetSchema } from "../../common/bqrs-cli-types"; import TextButton from "../common/TextButton"; import { useTelemetryOnChange } from "../common/telemetry"; +import { RawResultSet } from "../../common/raw-result-types"; import { RawResultRow } from "./RawResultRow"; const numOfResultsInContractedMode = 5; @@ -26,8 +26,7 @@ const TableContainer = styled.div` `; type RawResultsTableProps = { - schema: ResultSetSchema; - results: RawResultSet; + resultSet: RawResultSet; fileLinkPrefix: string; sourceLocationPrefix: string; }; @@ -35,8 +34,7 @@ type RawResultsTableProps = { const filterTableExpandedTelemetry = (v: boolean) => v; const RawResultsTable = ({ - schema, - results, + resultSet, fileLinkPrefix, sourceLocationPrefix, }: RawResultsTableProps) => { @@ -45,14 +43,14 @@ const RawResultsTable = ({ filterTelemetryOnValue: filterTableExpandedTelemetry, }); const numOfResultsToShow = tableExpanded - ? results.rows.length + ? resultSet.rows.length : numOfResultsInContractedMode; - const showButton = results.rows.length > numOfResultsInContractedMode; + const showButton = resultSet.rows.length > numOfResultsInContractedMode; return ( <> - - {results.rows.slice(0, numOfResultsToShow).map((row, rowIndex) => ( + + {resultSet.rows.slice(0, numOfResultsToShow).map((row, rowIndex) => ( { const render = (props: Partial = {}) => { @@ -64,40 +65,49 @@ describe(AnalyzedRepoItemContent.name, () => { render({ status: VariantAnalysisRepoStatus.Succeeded, rawResults: { - schema: { + resultSet: { name: "#select", - rows: 1, + totalRowCount: 2, columns: [ { - kind: "i", + kind: ColumnKind.Integer, }, { - kind: "s", + kind: ColumnKind.String, }, { - kind: "b", + kind: ColumnKind.Boolean, }, ], - }, - resultSet: { - schema: { - name: "#select", - rows: 1, - columns: [ + rows: [ + [ { - kind: "i", + type: "number", + value: 60688, }, { - kind: "s", + type: "string", + value: "foo", }, { - kind: "b", + type: "boolean", + value: true, + }, + ], + [ + { + type: "number", + value: 5, + }, + { + type: "string", + value: "bar", + }, + { + type: "boolean", + value: false, }, ], - }, - rows: [ - [60688, "foo", true], - [5, "bar", false], ], }, fileLinkPrefix: diff --git a/extensions/ql-vscode/test/unit-tests/common/location.test.ts b/extensions/ql-vscode/test/unit-tests/common/location.test.ts index c054ffa0e..3ff75a34d 100644 --- a/extensions/ql-vscode/test/unit-tests/common/location.test.ts +++ b/extensions/ql-vscode/test/unit-tests/common/location.test.ts @@ -1,24 +1,36 @@ import { + tryGetBqrsRemoteLocation, tryGetRemoteLocation, tryGetResolvableLocation, } from "../../../src/common/bqrs-utils"; +import { + UrlValue, + UrlValueResolvable, +} from "../../../src/common/raw-result-types"; -describe("processing string locations", () => { +describe("tryGetResolvableLocation", () => { it("should detect Windows whole-file locations", () => { const loc = "file://C:/path/to/file.ext:0:0:0:0"; const wholeFileLoc = tryGetResolvableLocation(loc); - expect(wholeFileLoc).toEqual({ uri: "C:/path/to/file.ext" }); + expect(wholeFileLoc).toEqual({ + type: "wholeFileLocation", + uri: "C:/path/to/file.ext", + }); }); it("should detect Unix whole-file locations", () => { const loc = "file:///path/to/file.ext:0:0:0:0"; const wholeFileLoc = tryGetResolvableLocation(loc); - expect(wholeFileLoc).toEqual({ uri: "/path/to/file.ext" }); + expect(wholeFileLoc).toEqual({ + type: "wholeFileLocation", + uri: "/path/to/file.ext", + }); }); it("should detect Unix 5-part locations", () => { const loc = "file:///path/to/file.ext:1:2:3:4"; const wholeFileLoc = tryGetResolvableLocation(loc); expect(wholeFileLoc).toEqual({ + type: "lineColumnLocation", uri: "/path/to/file.ext", startLine: 1, startColumn: 2, @@ -34,13 +46,13 @@ describe("processing string locations", () => { }); }); -describe("getting links to remote (GitHub) locations", () => { +describe("tryGetBqrsRemoteLocation", () => { it("should return undefined if resolvableLocation is undefined", () => { const loc = "not a location"; const fileLinkPrefix = ""; const sourceLocationPrefix = ""; - const link = tryGetRemoteLocation( + const link = tryGetBqrsRemoteLocation( loc, fileLinkPrefix, sourceLocationPrefix, @@ -60,7 +72,7 @@ describe("getting links to remote (GitHub) locations", () => { const fileLinkPrefix = ""; const sourceLocationPrefix = "/home/foo/bar"; - const link = tryGetRemoteLocation( + const link = tryGetBqrsRemoteLocation( loc, fileLinkPrefix, sourceLocationPrefix, @@ -80,7 +92,7 @@ describe("getting links to remote (GitHub) locations", () => { const fileLinkPrefix = "https://github.com/owner/repo/blob/sha1234"; const sourceLocationPrefix = "/home/foo/bar"; - const link = tryGetRemoteLocation( + const link = tryGetBqrsRemoteLocation( loc, fileLinkPrefix, sourceLocationPrefix, @@ -102,7 +114,7 @@ describe("getting links to remote (GitHub) locations", () => { const fileLinkPrefix = "https://github.com/owner/repo/blob/sha1234"; const sourceLocationPrefix = ""; - const link = tryGetRemoteLocation( + const link = tryGetBqrsRemoteLocation( loc, fileLinkPrefix, sourceLocationPrefix, @@ -122,6 +134,127 @@ describe("getting links to remote (GitHub) locations", () => { const fileLinkPrefix = "https://github.com/owner/repo/blob/sha1234"; const sourceLocationPrefix = ""; + const link = tryGetBqrsRemoteLocation( + loc, + fileLinkPrefix, + sourceLocationPrefix, + ); + + expect(link).toEqual( + "https://github.com/owner/repo/blob/sha1234/path/to/file.ext#L194C18-L237C1", + ); + }); +}); + +describe("tryGetRemoteLocation", () => { + it("should return undefined if resolvableLocation is undefined", () => { + const loc = undefined; + const fileLinkPrefix = ""; + const sourceLocationPrefix = ""; + + const link = tryGetRemoteLocation( + loc, + fileLinkPrefix, + sourceLocationPrefix, + ); + + expect(link).toBeUndefined(); + }); + + it("should return undefined if resolvableLocation is string", () => { + const loc: UrlValue = { + type: "string", + value: "not a location", + }; + const fileLinkPrefix = ""; + const sourceLocationPrefix = ""; + + const link = tryGetRemoteLocation( + loc, + fileLinkPrefix, + sourceLocationPrefix, + ); + + expect(link).toBeUndefined(); + }); + + it("should return undefined if resolvableLocation has the wrong format", () => { + const loc: UrlValueResolvable = { + type: "lineColumnLocation", + uri: "file:/path/to/file.ext", + startLine: 194, + startColumn: 18, + endLine: 237, + endColumn: 1, + }; + const fileLinkPrefix = ""; + const sourceLocationPrefix = "/home/foo/bar"; + + const link = tryGetRemoteLocation( + loc, + fileLinkPrefix, + sourceLocationPrefix, + ); + + expect(link).toBeUndefined(); + }); + + it("should return a remote file ref if the sourceLocationPrefix and resolvableLocation match up", () => { + const loc: UrlValueResolvable = { + type: "lineColumnLocation", + uri: "file:/home/foo/bar/path/to/file.ext", + startLine: 194, + startColumn: 18, + endLine: 237, + endColumn: 1, + }; + const fileLinkPrefix = "https://github.com/owner/repo/blob/sha1234"; + const sourceLocationPrefix = "/home/foo/bar"; + + const link = tryGetRemoteLocation( + loc, + fileLinkPrefix, + sourceLocationPrefix, + ); + + expect(link).toEqual( + "https://github.com/owner/repo/blob/sha1234/path/to/file.ext#L194C18-L237C1", + ); + }); + + it("should return undefined if the sourceLocationPrefix is missing and resolvableLocation doesn't match the default format", () => { + const loc: UrlValueResolvable = { + type: "lineColumnLocation", + uri: "file:/home/foo/bar/path/to/file.ext", + startLine: 194, + startColumn: 18, + endLine: 237, + endColumn: 1, + }; + const fileLinkPrefix = "https://github.com/owner/repo/blob/sha1234"; + const sourceLocationPrefix = ""; + + const link = tryGetRemoteLocation( + loc, + fileLinkPrefix, + sourceLocationPrefix, + ); + + expect(link).toBeUndefined(); + }); + + it("should return a remote file ref if the sourceLocationPrefix is missing, but the resolvableLocation matches the default format", () => { + const loc: UrlValueResolvable = { + type: "lineColumnLocation", + uri: "file:/home/runner/work/foo/bar/path/to/file.ext", + startLine: 194, + startColumn: 18, + endLine: 237, + endColumn: 1, + }; + const fileLinkPrefix = "https://github.com/owner/repo/blob/sha1234"; + const sourceLocationPrefix = ""; + const link = tryGetRemoteLocation( loc, fileLinkPrefix, diff --git a/extensions/ql-vscode/test/unit-tests/data/markdown-generation/raw-results/analyses-results.json b/extensions/ql-vscode/test/unit-tests/data/markdown-generation/raw-results/analyses-results.json index b328e6cbb..1ca36266e 100644 --- a/extensions/ql-vscode/test/unit-tests/data/markdown-generation/raw-results/analyses-results.json +++ b/extensions/ql-vscode/test/unit-tests/data/markdown-generation/raw-results/analyses-results.json @@ -12,319 +12,458 @@ "artifactSizeInBytes": 3567, "interpretedResults": [], "rawResults": { - "schema": { + "resultSet": { "name": "#select", - "rows": 22, + "totalRowCount": 22, "columns": [ { "name": "c", - "kind": "e" + "kind": "entity" }, { - "kind": "i" + "kind": "integer" } - ] - }, - "resultSet": { - "schema": { - "name": "#select", - "rows": 22, - "columns": [ - { - "name": "c", - "kind": "e" - }, - { - "kind": "i" - } - ] - }, + ], "rows": [ [ { - "label": "functio ... ght);\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/Expressions/examples/CompareIdenticalValues.js", - "startLine": 8, - "startColumn": 32, - "endLine": 13, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... ght);\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/Expressions/examples/CompareIdenticalValues.js", + "startLine": 8, + "startColumn": 32, + "endLine": 13, + "endColumn": 1 + } } }, - 6 + { + "type": "number", + "value": 6 + } ], [ { - "label": "functio ... i-1);\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/LanguageFeatures/examples/ArgumentsCallerCallee.js", - "startLine": 1, - "startColumn": 2, - "endLine": 5, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... i-1);\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/LanguageFeatures/examples/ArgumentsCallerCallee.js", + "startLine": 1, + "startColumn": 2, + "endLine": 5, + "endColumn": 1 + } } }, - 5 + { + "type": "number", + "value": 5 + } ], [ { - "label": "functio ... i-1);\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/LanguageFeatures/examples/ArgumentsCallerCalleeGood.js", - "startLine": 1, - "startColumn": 2, - "endLine": 5, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... i-1);\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/LanguageFeatures/examples/ArgumentsCallerCalleeGood.js", + "startLine": 1, + "startColumn": 2, + "endLine": 5, + "endColumn": 1 + } } }, - 5 + { + "type": "number", + "value": 5 + } ], [ { - "label": "functio ... n -1;\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/Statements/examples/UselessComparisonTest.js", - "startLine": 1, - "startColumn": 1, - "endLine": 12, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... n -1;\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/src/Statements/examples/UselessComparisonTest.js", + "startLine": 1, + "startColumn": 1, + "endLine": 12, + "endColumn": 1 + } } }, - 12 + { + "type": "number", + "value": 12 + } ], [ { - "label": "functio ... false\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/constants.js", - "startLine": 1, - "startColumn": 1, - "endLine": 8, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... false\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/constants.js", + "startLine": 1, + "startColumn": 1, + "endLine": 8, + "endColumn": 1 + } } }, - 8 + { + "type": "number", + "value": 8 + } ], [ { - "label": "functio ... \\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/loop.js", - "startLine": 1, - "startColumn": 1, - "endLine": 12, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... \\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/loop.js", + "startLine": 1, + "startColumn": 1, + "endLine": 12, + "endColumn": 1 + } } }, - 12 + { + "type": "number", + "value": 12 + } ], [ { - "label": "functio ... e\\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/loop.js", - "startLine": 14, - "startColumn": 1, - "endLine": 22, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... e\\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/loop.js", + "startLine": 14, + "startColumn": 1, + "endLine": 22, + "endColumn": 1 + } } }, - 9 + { + "type": "number", + "value": 9 + } ], [ { - "label": "functio ... K\\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/loop.js", - "startLine": 24, - "startColumn": 1, - "endLine": 40, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... K\\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/loop.js", + "startLine": 24, + "startColumn": 1, + "endLine": 40, + "endColumn": 1 + } } }, - 17 + { + "type": "number", + "value": 17 + } ], [ { - "label": "functio ... e\\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/plus.js", - "startLine": 1, - "startColumn": 1, - "endLine": 17, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... e\\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/plus.js", + "startLine": 1, + "startColumn": 1, + "endLine": 17, + "endColumn": 1 + } } }, - 17 + { + "type": "number", + "value": 17 + } ], [ { - "label": "functio ... alse \\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/plus.js", - "startLine": 19, - "startColumn": 1, - "endLine": 28, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... alse \\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/plus.js", + "startLine": 19, + "startColumn": 1, + "endLine": 28, + "endColumn": 1 + } } }, - 10 + { + "type": "number", + "value": 10 + } ], [ { - "label": "functio ... true\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/plus.js", - "startLine": 30, - "startColumn": 1, - "endLine": 33, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... true\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/plus.js", + "startLine": 30, + "startColumn": 1, + "endLine": 33, + "endColumn": 1 + } } }, - 4 + { + "type": "number", + "value": 4 + } ], [ { - "label": "functio ... K\\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", - "startLine": 1, - "startColumn": 1, - "endLine": 15, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... K\\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", + "startLine": 1, + "startColumn": 1, + "endLine": 15, + "endColumn": 1 + } } }, - 15 + { + "type": "number", + "value": 15 + } ], [ { - "label": "functio ... e\\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", - "startLine": 17, - "startColumn": 1, - "endLine": 31, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... e\\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", + "startLine": 17, + "startColumn": 1, + "endLine": 31, + "endColumn": 1 + } } }, - 15 + { + "type": "number", + "value": 15 + } ], [ { - "label": "functio ... false\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", - "startLine": 33, - "startColumn": 1, - "endLine": 41, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... false\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", + "startLine": 33, + "startColumn": 1, + "endLine": 41, + "endColumn": 1 + } } }, - 9 + { + "type": "number", + "value": 9 + } ], [ { - "label": "functio ... e\\n }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", - "startLine": 43, - "startColumn": 1, - "endLine": 52, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... e\\n }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/library-tests/RangeAnalysis/tst.js", + "startLine": 43, + "startColumn": 1, + "endLine": 52, + "endColumn": 1 + } } }, - 10 + { + "type": "number", + "value": 10 + } ], [ { - "label": "functio ... ght);\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Expressions/CompareIdenticalValues/tst.js", - "startLine": 8, - "startColumn": 32, - "endLine": 13, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... ght);\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Expressions/CompareIdenticalValues/tst.js", + "startLine": 8, + "startColumn": 32, + "endLine": 13, + "endColumn": 1 + } } }, - 6 + { + "type": "number", + "value": 6 + } ], [ { - "label": "functio ... i-1);\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/LanguageFeatures/ArgumentsCallerCallee/tst.js", - "startLine": 1, - "startColumn": 2, - "endLine": 5, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... i-1);\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/LanguageFeatures/ArgumentsCallerCallee/tst.js", + "startLine": 1, + "startColumn": 2, + "endLine": 5, + "endColumn": 1 + } } }, - 5 + { + "type": "number", + "value": 5 + } ], [ { - "label": "functio ... }\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Security/CWE-834/LoopBoundInjectionExitBad.js", - "startLine": 17, - "startColumn": 1, - "endLine": 29, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... }\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Security/CWE-834/LoopBoundInjectionExitBad.js", + "startLine": 17, + "startColumn": 1, + "endLine": 29, + "endColumn": 1 + } } }, - 13 + { + "type": "number", + "value": 13 + } ], [ { - "label": "functio ... true\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/constant.js", - "startLine": 1, - "startColumn": 1, - "endLine": 4, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... true\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/constant.js", + "startLine": 1, + "startColumn": 1, + "endLine": 4, + "endColumn": 1 + } } }, - 4 + { + "type": "number", + "value": 4 + } ], [ { - "label": "functio ... n -1;\\n}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/example.js", - "startLine": 1, - "startColumn": 1, - "endLine": 12, - "endColumn": 1 + "type": "entity", + "value": { + "label": "functio ... n -1;\\n}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/example.js", + "startLine": 1, + "startColumn": 1, + "endLine": 12, + "endColumn": 1 + } } }, - 12 + { + "type": "number", + "value": 12 + } ], [ { - "label": "functio ... turn; }", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/tst.js", - "startLine": 8, - "startColumn": 3, - "endLine": 8, - "endColumn": 43 + "type": "entity", + "value": { + "label": "functio ... turn; }", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/tst.js", + "startLine": 8, + "startColumn": 3, + "endLine": 8, + "endColumn": 43 + } } }, - 1 + { + "type": "number", + "value": 1 + } ], [ { - "label": "| functio ... i+1); |}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/tst.js", - "startLine": 9, - "startColumn": 3, - "endLine": 9, - "endColumn": 52 + "type": "entity", + "value": { + "label": "| functio ... i+1); |}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/javascript/ql/test/query-tests/Statements/UselessComparisonTest/tst.js", + "startLine": 9, + "startColumn": 3, + "endLine": 9, + "endColumn": 52 + } } }, - 1 + { + "type": "number", + "value": 1 + } ] ] }, @@ -345,59 +484,58 @@ "artifactSizeInBytes": 1133, "interpretedResults": [], "rawResults": { - "schema": { + "resultSet": { "name": "#select", - "rows": 2, + "totalRowCount": 2, "columns": [ { "name": "c", - "kind": "e" + "kind": "entity" }, { - "kind": "i" + "kind": "integer" } - ] - }, - "resultSet": { - "schema": { - "name": "#select", - "rows": 2, - "columns": [ - { - "name": "c", - "kind": "e" - }, - { - "kind": "i" - } - ] - }, + ], "rows": [ [ { - "label": "functio ... rn H|0}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/packages/logic-solver/minisat.js", - "startLine": 7, - "startColumn": 91430, - "endLine": 7, - "endColumn": 105027 + "type": "entity", + "value": { + "label": "functio ... rn H|0}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/packages/logic-solver/minisat.js", + "startLine": 7, + "startColumn": 91430, + "endLine": 7, + "endColumn": 105027 + } } }, - 1 + { + "type": "number", + "value": 1 + } ], [ { - "label": "functio ... ext;\\n\\t}", - "url": { - "uri": "file:/home/runner/work/bulk-builder/bulk-builder/packages/sha/sha256.js", - "startLine": 94, - "startColumn": 2, - "endLine": 124, - "endColumn": 2 + "type": "entity", + "value": { + "label": "functio ... ext;\\n\\t}", + "url": { + "type": "lineColumnLocation", + "uri": "file:/home/runner/work/bulk-builder/bulk-builder/packages/sha/sha256.js", + "startLine": 94, + "startColumn": 2, + "endLine": 124, + "endColumn": 2 + } } }, - 31 + { + "type": "number", + "value": 31 + } ] ] },