node-sarif-builder
Advanced tools
Comparing version 0.1.2-alpha202201101046.0 to 0.1.2-alpha202201101920.0
@@ -1,2 +0,5 @@ | ||
import { SarifBuilder, SarifResultBuilder, SarifRunBuilder } from './lib/sarif-builder'; | ||
export { SarifBuilder, SarifRunBuilder, SarifResultBuilder }; | ||
import { SarifBuilder } from './lib/sarif-builder'; | ||
import { SarifResultBuilder } from './lib/sarif-result-builder'; | ||
import { SarifRuleBuilder } from './lib/sarif-rule-builder'; | ||
import { SarifRunBuilder } from './lib/sarif-run-builder'; | ||
export { SarifBuilder, SarifRunBuilder, SarifRuleBuilder, SarifResultBuilder }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SarifResultBuilder = exports.SarifRunBuilder = exports.SarifBuilder = void 0; | ||
exports.SarifResultBuilder = exports.SarifRuleBuilder = exports.SarifRunBuilder = exports.SarifBuilder = void 0; | ||
const sarif_builder_1 = require("./lib/sarif-builder"); | ||
Object.defineProperty(exports, "SarifBuilder", { enumerable: true, get: function () { return sarif_builder_1.SarifBuilder; } }); | ||
Object.defineProperty(exports, "SarifResultBuilder", { enumerable: true, get: function () { return sarif_builder_1.SarifResultBuilder; } }); | ||
Object.defineProperty(exports, "SarifRunBuilder", { enumerable: true, get: function () { return sarif_builder_1.SarifRunBuilder; } }); | ||
const sarif_result_builder_1 = require("./lib/sarif-result-builder"); | ||
Object.defineProperty(exports, "SarifResultBuilder", { enumerable: true, get: function () { return sarif_result_builder_1.SarifResultBuilder; } }); | ||
const sarif_rule_builder_1 = require("./lib/sarif-rule-builder"); | ||
Object.defineProperty(exports, "SarifRuleBuilder", { enumerable: true, get: function () { return sarif_rule_builder_1.SarifRuleBuilder; } }); | ||
const sarif_run_builder_1 = require("./lib/sarif-run-builder"); | ||
Object.defineProperty(exports, "SarifRunBuilder", { enumerable: true, get: function () { return sarif_run_builder_1.SarifRunBuilder; } }); |
@@ -1,3 +0,4 @@ | ||
import { ArtifactLocation, Log, Region, Result, Run } from 'sarif'; | ||
import { LogOptions, SarifResultOptions, SarifRunOptions } from '../types/node-sarif-builder'; | ||
import { Log, Run } from 'sarif'; | ||
import { LogOptions } from '../types/node-sarif-builder'; | ||
import { SarifRunBuilder } from './sarif-run-builder'; | ||
export declare class SarifBuilder { | ||
@@ -9,35 +10,7 @@ log: Log; | ||
generateSarifFile(file: string): Promise<void>; | ||
buildSarifOutput(): Log; | ||
buildSarifJsonString(options?: { | ||
indent: boolean; | ||
}): string; | ||
completeRunFields(run: Run): Run; | ||
} | ||
export declare class SarifRunBuilder { | ||
run: Run; | ||
constructor(options?: SarifRunOptions); | ||
initSimple(options: { | ||
toolName: string; | ||
}): void; | ||
addResult(sarifResultBuilder: SarifResultBuilder): void; | ||
setToolName(name: string): void; | ||
} | ||
export declare class SarifResultBuilder { | ||
result: Result; | ||
constructor(options?: SarifResultOptions); | ||
initSimple(options: { | ||
level: Result.level; | ||
messageText: string; | ||
ruleId: string; | ||
fileUri?: string; | ||
startLine?: number; | ||
startColumn?: number; | ||
endLine?: number; | ||
endColumn?: number; | ||
}): void; | ||
setLevel(level: Result.level): void; | ||
setMessageText(message: string): void; | ||
setRuleId(ruleId: string): void; | ||
setLocationRegion(region: Region): void; | ||
setLocationArtifactUri(artifactLocation: ArtifactLocation): void; | ||
private manageInitLocation; | ||
private manageInitPhysicalLocation; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SarifResultBuilder = exports.SarifRunBuilder = exports.SarifBuilder = void 0; | ||
exports.SarifBuilder = void 0; | ||
const fs = require("fs-extra"); | ||
const utils_1 = require("./utils"); | ||
// SARIF Builder | ||
@@ -15,3 +16,3 @@ class SarifBuilder { | ||
}; | ||
setOptionValues(options, this.log); | ||
(0, utils_1.setOptionValues)(options, this.log); | ||
} | ||
@@ -29,3 +30,10 @@ addRun(sarifRunBuilder) { | ||
} | ||
buildSarifOutput() { | ||
// Complete runs | ||
this.log.runs = this.log.runs.map(run => this.completeRunFields(run)); | ||
return this.log; | ||
} | ||
// Build final sarif json, complete when possible | ||
buildSarifJsonString(options = { indent: false }) { | ||
this.buildSarifOutput(); | ||
const sarifJson = options.indent | ||
@@ -39,104 +47,46 @@ ? JSON.stringify(this.log, null, 2) | ||
} | ||
} | ||
exports.SarifBuilder = SarifBuilder; | ||
// SARIF Run builder | ||
class SarifRunBuilder { | ||
// Initialize SARIF Run builder | ||
constructor(options = {}) { | ||
// Default run value | ||
this.run = { | ||
tool: { | ||
driver: { | ||
name: process.env.npm_package_name || | ||
'SARIF_BUILDER_INVALID: Please send the tool name in SarifRunBuilder tool property, or call setToolName(name)', | ||
}, | ||
}, | ||
results: [], | ||
}; | ||
setOptionValues(options, this.run); | ||
} | ||
initSimple(options) { | ||
if (options.toolName) { | ||
this.setToolName(options.toolName); | ||
completeRunFields(run) { | ||
var _a, _b, _c, _d; | ||
// Collect all missing artifacts from results | ||
run.artifacts = run.artifacts || []; | ||
for (const result of run.results) { | ||
for (const location of result.locations || []) { | ||
if (((_b = (_a = location === null || location === void 0 ? void 0 : location.physicalLocation) === null || _a === void 0 ? void 0 : _a.artifactLocation) === null || _b === void 0 ? void 0 : _b.uri) && | ||
run.artifacts.filter(artifact => { var _a; return ((_a = artifact === null || artifact === void 0 ? void 0 : artifact.location) === null || _a === void 0 ? void 0 : _a.uri) === location.physicalLocation.artifactLocation.uri; }).length === 0) { | ||
// Add result to driver artifact only if not existing | ||
run.artifacts.push(location.physicalLocation.artifactLocation); | ||
} | ||
} | ||
} | ||
// Build artifacts indexes | ||
const artifactIndexes = Object.fromEntries(run.artifacts.map((artifact, index) => { | ||
var _a; | ||
return [(_a = artifact === null || artifact === void 0 ? void 0 : artifact.location) === null || _a === void 0 ? void 0 : _a.uri, index]; | ||
})); | ||
// Build rules indexes | ||
const rulesIndexes = Object.fromEntries((((_d = (_c = run === null || run === void 0 ? void 0 : run.tool) === null || _c === void 0 ? void 0 : _c.driver) === null || _d === void 0 ? void 0 : _d.rules) || []).map((rule, index) => { | ||
return [rule.id, index]; | ||
})); | ||
// Update index in results with computed values | ||
run.results = run.results.map(result => { | ||
// Set rule index in results | ||
if (rulesIndexes[result.ruleId]) { | ||
result.ruleIndex = rulesIndexes[result.ruleId]; | ||
} | ||
// Set artifact index in results | ||
if (result.locations) { | ||
result.locations = result.locations.map(location => { | ||
var _a, _b; | ||
const uri = (_b = (_a = location === null || location === void 0 ? void 0 : location.physicalLocation) === null || _a === void 0 ? void 0 : _a.artifactLocation) === null || _b === void 0 ? void 0 : _b.uri; | ||
if (uri && artifactIndexes[uri] !== undefined && artifactIndexes[uri] !== null) { | ||
location.physicalLocation.artifactLocation.index = artifactIndexes[uri]; | ||
} | ||
return location; | ||
}); | ||
} | ||
return result; | ||
}); | ||
return run; | ||
} | ||
addResult(sarifResultBuilder) { | ||
this.run.results.push(sarifResultBuilder.result); | ||
} | ||
setToolName(name) { | ||
this.run.tool.driver.name = name; | ||
} | ||
} | ||
exports.SarifRunBuilder = SarifRunBuilder; | ||
class SarifResultBuilder { | ||
// Initialize SARIF Result builder | ||
constructor(options = {}) { | ||
// Default result value | ||
this.result = { | ||
level: 'error', | ||
message: {}, | ||
ruleId: 'SARIF_BUILDER_INVALID: Please send the ruleId name in SarifResultBuilder tool property, or call setRuleId(ruleId)', | ||
}; | ||
setOptionValues(options, this.result); | ||
} | ||
initSimple(options) { | ||
this.setLevel(options.level); | ||
this.setMessageText(options.messageText); | ||
this.setRuleId(options.ruleId); | ||
if (options.fileUri) { | ||
this.setLocationArtifactUri({ uri: options.fileUri }); | ||
} | ||
if (options.startLine !== null) { | ||
// Initialize Region with default values with necessary | ||
const region = { | ||
startLine: options.startLine, | ||
startColumn: options.startColumn || 1, | ||
endLine: options.endLine || options.startLine, | ||
endColumn: options.endColumn || 1, | ||
}; | ||
this.setLocationRegion(region); | ||
} | ||
} | ||
setLevel(level) { | ||
this.result.level = level; | ||
} | ||
setMessageText(message) { | ||
this.result.message.text = message; | ||
} | ||
setRuleId(ruleId) { | ||
this.result.ruleId = ruleId; | ||
} | ||
setLocationRegion(region) { | ||
this.manageInitPhysicalLocation(); | ||
this.result.locations[0].physicalLocation.region = region; | ||
} | ||
setLocationArtifactUri(artifactLocation) { | ||
this.manageInitPhysicalLocation(); | ||
this.result.locations[0].physicalLocation.artifactLocation = | ||
artifactLocation; | ||
} | ||
manageInitLocation() { | ||
var _a, _b; | ||
if ((_b = (_a = this.result) === null || _a === void 0 ? void 0 : _a.locations) === null || _b === void 0 ? void 0 : _b.length) { | ||
return; | ||
} | ||
this.result.locations = [{}]; | ||
} | ||
manageInitPhysicalLocation() { | ||
var _a; | ||
this.manageInitLocation(); | ||
if ((_a = this.result) === null || _a === void 0 ? void 0 : _a.locations[0].physicalLocation) { | ||
return; | ||
} | ||
this.result.locations[0].physicalLocation = {}; | ||
} | ||
} | ||
exports.SarifResultBuilder = SarifResultBuilder; | ||
function setOptionValues(options, object) { | ||
for (const key of Object.keys(object)) { | ||
if (options[key] !== undefined) { | ||
object[key] = options[key]; | ||
} | ||
} | ||
return object; | ||
} | ||
exports.SarifBuilder = SarifBuilder; |
@@ -8,2 +8,5 @@ "use strict"; | ||
const sarif_builder_1 = require("./sarif-builder"); | ||
const sarif_result_builder_1 = require("./sarif-result-builder"); | ||
const sarif_rule_builder_1 = require("./sarif-rule-builder"); | ||
const sarif_run_builder_1 = require("./sarif-run-builder"); | ||
(0, ava_1.default)('Create SarifBuilder', (t) => { | ||
@@ -20,3 +23,3 @@ const sarifBuilder = new sarif_builder_1.SarifBuilder(); | ||
(0, ava_1.default)('Create SarifRunBuilder', (t) => { | ||
const sarifBuilder = new sarif_builder_1.SarifRunBuilder(); | ||
const sarifBuilder = new sarif_run_builder_1.SarifRunBuilder(); | ||
t.assert(sarifBuilder != null, 'SarifRunBuilder has been created'); | ||
@@ -30,7 +33,7 @@ }); | ||
(0, ava_1.default)('Create SarifResultBuilder', (t) => { | ||
const sarifResultBuilder = new sarif_builder_1.SarifResultBuilder(); | ||
const sarifResultBuilder = new sarif_result_builder_1.SarifResultBuilder(); | ||
t.assert(sarifResultBuilder != null, 'SarifResultBuilder has been created'); | ||
}); | ||
(0, ava_1.default)('Create SarifResultBuilder and set message', (t) => { | ||
const sarifResultBuilder = new sarif_builder_1.SarifResultBuilder(); | ||
const sarifResultBuilder = new sarif_result_builder_1.SarifResultBuilder(); | ||
sarifResultBuilder.setMessageText('MegaLinter message'); | ||
@@ -43,4 +46,4 @@ t.assert(sarifResultBuilder != null, 'SarifResultBuilder has been created'); | ||
t.assert(sarifResultBuilder != null, 'SarifResultBuilder has been created'); | ||
t.is(sarifResultBuilder.result.message.text, 'This is not cool !'); | ||
t.is(sarifResultBuilder.result.ruleId, 'Wow !'); | ||
t.is(sarifResultBuilder.result.message.text, 'An assignment operator (=) was used in a conditional test. This is usually a typo, and the comparison operator (==) was intended.'); | ||
t.is(sarifResultBuilder.result.ruleId, 'AssignmentInConditional'); | ||
t.is(sarifResultBuilder.result.locations[0].physicalLocation.artifactLocation | ||
@@ -54,5 +57,6 @@ .uri, 'src/urf/wesh.js'); | ||
(0, ava_1.default)('Create SarifResultBuilder and generate file', (t) => { | ||
var _a, _b; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
const sarifBuilder = new sarif_builder_1.SarifBuilder(); | ||
const sarifRunBuilder = createInitSarifRunBuilder(); | ||
sarifRunBuilder.addRule(createInitSarifRuleBuilder()); | ||
const sarifResultBuilder = createInitSarifResultBuilder(); | ||
@@ -66,15 +70,29 @@ sarifRunBuilder.addResult(sarifResultBuilder); | ||
t.assert(((_a = outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs) === null || _a === void 0 ? void 0 : _a.length) > 0, 'No runs found in generated SARIF log'); | ||
t.assert(((_b = outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs[0].results) === null || _b === void 0 ? void 0 : _b.length) > 0, 'No results found in generated SARIF log'); | ||
t.assert(((_d = (_c = (_b = outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs[0].tool) === null || _b === void 0 ? void 0 : _b.driver) === null || _c === void 0 ? void 0 : _c.rules) === null || _d === void 0 ? void 0 : _d.length) > 0, 'No rules found in generated SARIF log'); | ||
t.assert((outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs[0].artifacts.length) > 0, 'No artifacts found in generated SARIF log'); | ||
t.assert(((_e = outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs[0].results) === null || _e === void 0 ? void 0 : _e.length) > 0, 'No results found in generated SARIF log'); | ||
t.assert((outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs[0].results[0].ruleIndex) !== null, 'Result rule index should be set'); | ||
t.assert(((_j = (_h = (_g = (_f = outputSarifObj === null || outputSarifObj === void 0 ? void 0 : outputSarifObj.runs[0].results[0]) === null || _f === void 0 ? void 0 : _f.locations[0]) === null || _g === void 0 ? void 0 : _g.physicalLocation) === null || _h === void 0 ? void 0 : _h.artifactLocation) === null || _j === void 0 ? void 0 : _j.index) !== null, 'Result artifact index should be set'); | ||
}); | ||
(0, ava_1.default)('Create SarifResultBuilder with error', (t) => { | ||
let error = false; | ||
try { | ||
createInitSarifWrongResultBuilder(); | ||
} | ||
catch (e) { | ||
error = true; | ||
} | ||
t.assert(error === true, 'Error should have been triggered'); | ||
}); | ||
function createInitSarifRunBuilder() { | ||
const sarifRunBuilder = new sarif_builder_1.SarifRunBuilder(); | ||
sarifRunBuilder.initSimple({ toolName: 'MegaLinter' }); | ||
const sarifRunBuilder = new sarif_run_builder_1.SarifRunBuilder(); | ||
sarifRunBuilder.initSimple({ name: 'MegaLinter' }); | ||
return sarifRunBuilder; | ||
} | ||
function createInitSarifResultBuilder() { | ||
const sarifResultBuilder = new sarif_builder_1.SarifResultBuilder(); | ||
const sarifResultBuilder = new sarif_result_builder_1.SarifResultBuilder(); | ||
sarifResultBuilder.initSimple({ | ||
level: 'warning', | ||
messageText: 'This is not cool !', | ||
ruleId: 'Wow !', | ||
messageText: 'An assignment operator (=) was used in a conditional test. This is usually a typo, and the comparison operator (==) was intended.', | ||
ruleId: 'AssignmentInConditional', | ||
fileUri: 'src/urf/wesh.js', | ||
@@ -85,1 +103,22 @@ startLine: 8, | ||
} | ||
function createInitSarifWrongResultBuilder() { | ||
const sarifResultBuilder = new sarif_result_builder_1.SarifResultBuilder(); | ||
sarifResultBuilder.initSimple({ | ||
level: 'warning', | ||
messageText: 'some code used = , you may should have used ==', | ||
ruleId: 'AssignmentInConditional', | ||
fileUri: 'src/urf/wesh.js', | ||
startLine: 0, | ||
}); | ||
return sarifResultBuilder; | ||
} | ||
function createInitSarifRuleBuilder() { | ||
const sarifRuleBuilder = new sarif_rule_builder_1.SarifRuleBuilder(); | ||
sarifRuleBuilder.initSimple({ | ||
ruleId: 'AssignmentInConditional', | ||
shortDescriptionText: 'This is wrong, that should not happenAn assignment operator (=) was used in a conditional test. This is usually a typo, and the comparison operator (==) was intended.', | ||
fullDescriptionText: 'Change something in your code and this rule will not be triggered !', | ||
helpUri: 'https://codenarc.org/codenarc-rules-basic.html#AssignmentInConditional' | ||
}); | ||
return sarifRuleBuilder; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Address, Artifact, ArtifactLocation, Attachment, CodeFlow, Conversion, ExternalProperties, ExternalPropertyFileReferences, Fix, Graph, GraphTraversal, Invocation, Location, Log, LogicalLocation, Message, PropertyBag, ReportingDescriptorReference, Result, ResultProvenance, Run, RunAutomationDetails, SpecialLocations, Stack, Suppression, ThreadFlowLocation, Tool, ToolComponent, VersionControlDetails, WebRequest, WebResponse } from 'sarif'; | ||
import { Address, Artifact, ArtifactLocation, Attachment, CodeFlow, Conversion, ExternalProperties, ExternalPropertyFileReferences, Fix, Graph, GraphTraversal, Invocation, Location, Log, LogicalLocation, Message, MultiformatMessageString, PropertyBag, ReportingConfiguration, ReportingDescriptorReference, ReportingDescriptorRelationship, Result, ResultProvenance, Run, RunAutomationDetails, SpecialLocations, Stack, Suppression, ThreadFlowLocation, Tool, ToolComponent, VersionControlDetails, WebRequest, WebResponse } from 'sarif'; | ||
export interface LogOptions { | ||
@@ -155,2 +155,68 @@ /** | ||
} | ||
export interface SarifRuleOptions { | ||
/** | ||
* Default reporting configuration information. | ||
*/ | ||
defaultConfiguration?: ReportingConfiguration | undefined; | ||
/** | ||
* An array of unique identifies in the form of a GUID by which this report was known in some previous version of | ||
* the analysis tool. | ||
*/ | ||
deprecatedGuids?: string[] | undefined; | ||
/** | ||
* An array of stable, opaque identifiers by which this report was known in some previous version of the analysis | ||
* tool. | ||
*/ | ||
deprecatedIds?: string[] | undefined; | ||
/** | ||
* An array of readable identifiers by which this report was known in some previous version of the analysis tool. | ||
*/ | ||
deprecatedNames?: string[] | undefined; | ||
/** | ||
* A description of the report. Should, as far as possible, provide details sufficient to enable resolution of any | ||
* problem indicated by the result. | ||
*/ | ||
fullDescription?: MultiformatMessageString | undefined; | ||
/** | ||
* A unique identifer for the reporting descriptor in the form of a GUID. | ||
*/ | ||
guid?: string | undefined; | ||
/** | ||
* Provides the primary documentation for the report, useful when there is no online documentation. | ||
*/ | ||
help?: MultiformatMessageString | undefined; | ||
/** | ||
* A URI where the primary documentation for the report can be found. | ||
*/ | ||
helpUri?: string | undefined; | ||
/** | ||
* A stable, opaque identifier for the report. | ||
*/ | ||
id?: string; | ||
/** | ||
* A set of name/value pairs with arbitrary names. Each value is a multiformatMessageString object, which holds | ||
* message strings in plain text and (optionally) Markdown format. The strings can include placeholders, which can | ||
* be used to construct a message in combination with an arbitrary number of additional string arguments. | ||
*/ | ||
messageStrings?: { | ||
[key: string]: MultiformatMessageString; | ||
} | undefined; | ||
/** | ||
* A report identifier that is understandable to an end user. | ||
*/ | ||
name?: string | undefined; | ||
/** | ||
* An array of objects that describe relationships between this reporting descriptor and others. | ||
*/ | ||
relationships?: ReportingDescriptorRelationship[] | undefined; | ||
/** | ||
* A concise description of the report. Should be a single sentence that is understandable when visible space is | ||
* limited to a single line of text. | ||
*/ | ||
shortDescription?: MultiformatMessageString | undefined; | ||
/** | ||
* Key/value pairs that provide additional information about the report. | ||
*/ | ||
properties?: PropertyBag | undefined; | ||
} | ||
export interface SarifResultOptions { | ||
@@ -157,0 +223,0 @@ /** |
{ | ||
"name": "node-sarif-builder", | ||
"version": "0.1.2-alpha202201101046.0", | ||
"version": "0.1.2-alpha202201101920.0", | ||
"description": "Module to help building SARIF log files", | ||
@@ -19,2 +19,3 @@ "main": "dist/index.js", | ||
"test:unit": "nyc --silent ava", | ||
"pretest": "tsc", | ||
"diff-integration-tests": "mkdir -p diff && rm -rf diff/test && cp -r test diff/test && rm -rf diff/test/test-*/.git && cd diff && git init --quiet && git add -A && git commit --quiet --no-verify --allow-empty -m 'WIP' && echo '\\n\\nCommitted most recent integration test output in the \"diff\" directory. Review the changes with \"cd diff && git diff HEAD\" or your preferred git diff viewer.'", | ||
@@ -21,0 +22,0 @@ "watch:build": "tsc -p tsconfig.json -w", |
@@ -1,7 +0,6 @@ | ||
import { | ||
SarifBuilder, | ||
SarifResultBuilder, | ||
SarifRunBuilder, | ||
} from './lib/sarif-builder'; | ||
import { SarifBuilder } from './lib/sarif-builder'; | ||
import { SarifResultBuilder } from './lib/sarif-result-builder'; | ||
import { SarifRuleBuilder } from './lib/sarif-rule-builder'; | ||
import { SarifRunBuilder } from './lib/sarif-run-builder'; | ||
export { SarifBuilder, SarifRunBuilder, SarifResultBuilder }; | ||
export { SarifBuilder, SarifRunBuilder, SarifRuleBuilder, SarifResultBuilder }; |
@@ -8,7 +8,6 @@ import * as os from 'os'; | ||
import { | ||
SarifBuilder, | ||
SarifResultBuilder, | ||
SarifRunBuilder, | ||
} from './sarif-builder'; | ||
import { SarifBuilder, } from './sarif-builder'; | ||
import { SarifResultBuilder } from './sarif-result-builder'; | ||
import { SarifRuleBuilder } from './sarif-rule-builder'; | ||
import { SarifRunBuilder } from './sarif-run-builder'; | ||
@@ -56,4 +55,4 @@ test('Create SarifBuilder', (t) => { | ||
t.assert(sarifResultBuilder != null, 'SarifResultBuilder has been created'); | ||
t.is(sarifResultBuilder.result.message.text, 'This is not cool !'); | ||
t.is(sarifResultBuilder.result.ruleId, 'Wow !'); | ||
t.is(sarifResultBuilder.result.message.text, 'An assignment operator (=) was used in a conditional test. This is usually a typo, and the comparison operator (==) was intended.'); | ||
t.is(sarifResultBuilder.result.ruleId, 'AssignmentInConditional'); | ||
t.is( | ||
@@ -85,2 +84,3 @@ sarifResultBuilder.result.locations[0].physicalLocation.artifactLocation | ||
const sarifRunBuilder = createInitSarifRunBuilder(); | ||
sarifRunBuilder.addRule(createInitSarifRuleBuilder()); | ||
const sarifResultBuilder = createInitSarifResultBuilder(); | ||
@@ -101,10 +101,39 @@ sarifRunBuilder.addResult(sarifResultBuilder); | ||
t.assert( | ||
outputSarifObj?.runs[0].tool?.driver?.rules?.length > 0, | ||
'No rules found in generated SARIF log' | ||
); | ||
t.assert( | ||
outputSarifObj?.runs[0].artifacts.length > 0, | ||
'No artifacts found in generated SARIF log' | ||
); | ||
t.assert( | ||
outputSarifObj?.runs[0].results?.length > 0, | ||
'No results found in generated SARIF log' | ||
); | ||
t.assert( | ||
outputSarifObj?.runs[0].results[0].ruleIndex !== null, | ||
'Result rule index should be set' | ||
); | ||
t.assert( | ||
outputSarifObj?.runs[0].results[0]?.locations[0]?.physicalLocation?.artifactLocation?.index !== null, | ||
'Result artifact index should be set' | ||
); | ||
}); | ||
test('Create SarifResultBuilder with error', (t) => { | ||
let error = false; | ||
try { | ||
createInitSarifWrongResultBuilder(); | ||
} catch (e) { | ||
error = true; | ||
} | ||
t.assert( | ||
error === true, | ||
'Error should have been triggered' | ||
); | ||
}); | ||
function createInitSarifRunBuilder() { | ||
const sarifRunBuilder = new SarifRunBuilder(); | ||
sarifRunBuilder.initSimple({ toolName: 'MegaLinter' }); | ||
sarifRunBuilder.initSimple({ name: 'MegaLinter' }); | ||
return sarifRunBuilder; | ||
@@ -117,4 +146,4 @@ } | ||
level: 'warning', | ||
messageText: 'This is not cool !', | ||
ruleId: 'Wow !', | ||
messageText: 'An assignment operator (=) was used in a conditional test. This is usually a typo, and the comparison operator (==) was intended.', | ||
ruleId: 'AssignmentInConditional', | ||
fileUri: 'src/urf/wesh.js', | ||
@@ -125,1 +154,24 @@ startLine: 8, | ||
} | ||
function createInitSarifWrongResultBuilder() { | ||
const sarifResultBuilder = new SarifResultBuilder(); | ||
sarifResultBuilder.initSimple({ | ||
level: 'warning', | ||
messageText: 'some code used = , you may should have used ==', | ||
ruleId: 'AssignmentInConditional', | ||
fileUri: 'src/urf/wesh.js', | ||
startLine: 0, | ||
}); | ||
return sarifResultBuilder; | ||
} | ||
function createInitSarifRuleBuilder() { | ||
const sarifRuleBuilder = new SarifRuleBuilder(); | ||
sarifRuleBuilder.initSimple({ | ||
ruleId: 'AssignmentInConditional', | ||
shortDescriptionText: 'This is wrong, that should not happenAn assignment operator (=) was used in a conditional test. This is usually a typo, and the comparison operator (==) was intended.', | ||
fullDescriptionText: 'Change something in your code and this rule will not be triggered !', | ||
helpUri: 'https://codenarc.org/codenarc-rules-basic.html#AssignmentInConditional' | ||
}); | ||
return sarifRuleBuilder; | ||
} |
import * as fs from 'fs-extra'; | ||
import { ArtifactLocation, Log, Region, Result, Run } from 'sarif'; | ||
import { Log, Run } from 'sarif'; | ||
import { | ||
LogOptions, | ||
SarifResultOptions, | ||
SarifRunOptions, | ||
} from '../types/node-sarif-builder'; | ||
import { LogOptions } from '../types/node-sarif-builder'; | ||
import { SarifRunBuilder } from './sarif-run-builder'; | ||
import { setOptionValues } from './utils'; | ||
// SARIF Builder | ||
@@ -38,3 +37,11 @@ export class SarifBuilder { | ||
buildSarifOutput() { | ||
// Complete runs | ||
this.log.runs = this.log.runs.map(run => this.completeRunFields(run)); | ||
return this.log; | ||
} | ||
// Build final sarif json, complete when possible | ||
buildSarifJsonString(options = { indent: false }) { | ||
this.buildSarifOutput(); | ||
const sarifJson = options.indent | ||
@@ -50,126 +57,49 @@ ? JSON.stringify(this.log, null, 2) | ||
} | ||
} | ||
// SARIF Run builder | ||
export class SarifRunBuilder { | ||
// Default run value | ||
run: Run = { | ||
tool: { | ||
driver: { | ||
name: | ||
process.env.npm_package_name || | ||
'SARIF_BUILDER_INVALID: Please send the tool name in SarifRunBuilder tool property, or call setToolName(name)', | ||
}, | ||
}, | ||
results: [], | ||
}; | ||
// Initialize SARIF Run builder | ||
constructor(options: SarifRunOptions = {}) { | ||
setOptionValues(options, this.run); | ||
} | ||
initSimple(options: { toolName: string }) { | ||
if (options.toolName) { | ||
this.setToolName(options.toolName); | ||
completeRunFields(run: Run): Run { | ||
// Collect all missing artifacts from results | ||
run.artifacts = run.artifacts || []; | ||
for (const result of run.results) { | ||
for (const location of result.locations || []) { | ||
if (location?.physicalLocation?.artifactLocation?.uri && | ||
run.artifacts.filter(artifact => artifact?.location?.uri === location.physicalLocation.artifactLocation.uri).length === 0) { | ||
// Add result to driver artifact only if not existing | ||
run.artifacts.push(location.physicalLocation.artifactLocation); | ||
} | ||
} | ||
} | ||
} | ||
// Build artifacts indexes | ||
const artifactIndexes = Object.fromEntries(run.artifacts.map((artifact, index) => { | ||
return [artifact?.location?.uri, index]; | ||
})); | ||
// Build rules indexes | ||
const rulesIndexes = Object.fromEntries((run?.tool?.driver?.rules || []).map((rule, index) => { | ||
return [rule.id, index]; | ||
})); | ||
addResult(sarifResultBuilder: SarifResultBuilder) { | ||
this.run.results.push(sarifResultBuilder.result); | ||
} | ||
// Update index in results with computed values | ||
run.results = run.results.map(result => { | ||
// Set rule index in results | ||
if (rulesIndexes[result.ruleId]) { | ||
result.ruleIndex = rulesIndexes[result.ruleId] | ||
} | ||
// Set artifact index in results | ||
if (result.locations) { | ||
result.locations = result.locations.map(location => { | ||
const uri = location?.physicalLocation?.artifactLocation?.uri; | ||
if (uri && artifactIndexes[uri] !== undefined && artifactIndexes[uri] !== null) { | ||
location.physicalLocation.artifactLocation.index = artifactIndexes[uri]; | ||
} | ||
return location; | ||
}); | ||
} | ||
return result; | ||
}) | ||
setToolName(name: string) { | ||
this.run.tool.driver.name = name; | ||
return run; | ||
} | ||
} | ||
export class SarifResultBuilder { | ||
// Default result value | ||
result: Result = { | ||
level: 'error', | ||
message: {}, | ||
ruleId: | ||
'SARIF_BUILDER_INVALID: Please send the ruleId name in SarifResultBuilder tool property, or call setRuleId(ruleId)', | ||
}; | ||
// Initialize SARIF Result builder | ||
constructor(options: SarifResultOptions = {}) { | ||
setOptionValues(options, this.result); | ||
} | ||
initSimple(options: { | ||
level: Result.level; | ||
messageText: string; | ||
ruleId: string; | ||
fileUri?: string; | ||
startLine?: number; | ||
startColumn?: number; | ||
endLine?: number; | ||
endColumn?: number; | ||
}) { | ||
this.setLevel(options.level); | ||
this.setMessageText(options.messageText); | ||
this.setRuleId(options.ruleId); | ||
if (options.fileUri) { | ||
this.setLocationArtifactUri({ uri: options.fileUri }); | ||
} | ||
if (options.startLine !== null) { | ||
// Initialize Region with default values with necessary | ||
const region: Region = { | ||
startLine: options.startLine, | ||
startColumn: options.startColumn || 1, | ||
endLine: options.endLine || options.startLine, | ||
endColumn: options.endColumn || 1, | ||
}; | ||
this.setLocationRegion(region); | ||
} | ||
} | ||
setLevel(level: Result.level) { | ||
this.result.level = level; | ||
} | ||
setMessageText(message: string) { | ||
this.result.message.text = message; | ||
} | ||
setRuleId(ruleId: string) { | ||
this.result.ruleId = ruleId; | ||
} | ||
setLocationRegion(region: Region) { | ||
this.manageInitPhysicalLocation(); | ||
this.result.locations[0].physicalLocation.region = region; | ||
} | ||
setLocationArtifactUri(artifactLocation: ArtifactLocation) { | ||
this.manageInitPhysicalLocation(); | ||
this.result.locations[0].physicalLocation.artifactLocation = | ||
artifactLocation; | ||
} | ||
private manageInitLocation() { | ||
if (this.result?.locations?.length) { | ||
return; | ||
} | ||
this.result.locations = [{}]; | ||
} | ||
private manageInitPhysicalLocation() { | ||
this.manageInitLocation(); | ||
if (this.result?.locations[0].physicalLocation) { | ||
return; | ||
} | ||
this.result.locations[0].physicalLocation = {}; | ||
} | ||
} | ||
function setOptionValues(options, object: any) { | ||
for (const key of Object.keys(object)) { | ||
if (options[key] !== undefined) { | ||
object[key] = options[key]; | ||
} | ||
} | ||
return object; | ||
} |
@@ -18,4 +18,7 @@ import { | ||
Message, | ||
MultiformatMessageString, | ||
PropertyBag, | ||
ReportingConfiguration, | ||
ReportingDescriptorReference, | ||
ReportingDescriptorRelationship, | ||
Result, | ||
@@ -220,2 +223,81 @@ ResultProvenance, | ||
export interface SarifRuleOptions { | ||
/** | ||
* Default reporting configuration information. | ||
*/ | ||
defaultConfiguration?: ReportingConfiguration | undefined; | ||
/** | ||
* An array of unique identifies in the form of a GUID by which this report was known in some previous version of | ||
* the analysis tool. | ||
*/ | ||
deprecatedGuids?: string[] | undefined; | ||
/** | ||
* An array of stable, opaque identifiers by which this report was known in some previous version of the analysis | ||
* tool. | ||
*/ | ||
deprecatedIds?: string[] | undefined; | ||
/** | ||
* An array of readable identifiers by which this report was known in some previous version of the analysis tool. | ||
*/ | ||
deprecatedNames?: string[] | undefined; | ||
/** | ||
* A description of the report. Should, as far as possible, provide details sufficient to enable resolution of any | ||
* problem indicated by the result. | ||
*/ | ||
fullDescription?: MultiformatMessageString | undefined; | ||
/** | ||
* A unique identifer for the reporting descriptor in the form of a GUID. | ||
*/ | ||
guid?: string | undefined; | ||
/** | ||
* Provides the primary documentation for the report, useful when there is no online documentation. | ||
*/ | ||
help?: MultiformatMessageString | undefined; | ||
/** | ||
* A URI where the primary documentation for the report can be found. | ||
*/ | ||
helpUri?: string | undefined; | ||
/** | ||
* A stable, opaque identifier for the report. | ||
*/ | ||
id?: string; | ||
/** | ||
* A set of name/value pairs with arbitrary names. Each value is a multiformatMessageString object, which holds | ||
* message strings in plain text and (optionally) Markdown format. The strings can include placeholders, which can | ||
* be used to construct a message in combination with an arbitrary number of additional string arguments. | ||
*/ | ||
messageStrings?: { [key: string]: MultiformatMessageString } | undefined; | ||
/** | ||
* A report identifier that is understandable to an end user. | ||
*/ | ||
name?: string | undefined; | ||
/** | ||
* An array of objects that describe relationships between this reporting descriptor and others. | ||
*/ | ||
relationships?: ReportingDescriptorRelationship[] | undefined; | ||
/** | ||
* A concise description of the report. Should be a single sentence that is understandable when visible space is | ||
* limited to a single line of text. | ||
*/ | ||
shortDescription?: MultiformatMessageString | undefined; | ||
/** | ||
* Key/value pairs that provide additional information about the report. | ||
*/ | ||
properties?: PropertyBag | undefined; | ||
} | ||
export interface SarifResultOptions { | ||
@@ -222,0 +304,0 @@ /** |
272787
46
1775