From 917cd5f31b8309e33ba59b76cc605e64ca69d525 Mon Sep 17 00:00:00 2001 From: Chris Meyer Date: Thu, 7 Mar 2019 15:08:01 -0800 Subject: [PATCH 1/6] Updates for SDK v2.0.0-csd.2.beta.2019-01-24.1 --- src/ESLint.Formatter/sarif-with-rules.js | 22 +++++++++++++++------- src/ESLint.Formatter/sarif.js | 11 ++++++----- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/ESLint.Formatter/sarif-with-rules.js b/src/ESLint.Formatter/sarif-with-rules.js index 7c5430949..ae67284dd 100644 --- a/src/ESLint.Formatter/sarif-with-rules.js +++ b/src/ESLint.Formatter/sarif-with-rules.js @@ -39,9 +39,12 @@ module.exports = function (results, data) { $schema: "http://json.schemastore.org/sarif-2.0.0", runs: [ { - files: [], + artifacts: [], tool: { - name: "ESLint" + driver: { + name: "ESLint", + downloadUri: "https://eslint.org" + } } } ] @@ -151,13 +154,11 @@ module.exports = function (results, data) { } sarifResults.push(sarifResult); - }); - }); Object.keys(sarifFiles).forEach(function (path) { - sarifLog.runs[0].files.push(sarifFiles[path]); + sarifLog.runs[0].artifacts.push(sarifFiles[path]); }); if (sarifResults.length > 0) { @@ -165,9 +166,16 @@ module.exports = function (results, data) { } if (Object.keys(sarifRules).length > 0) { - sarifLog.runs[0].resources = { - rules: sarifRules + sarifLog.runs[0].tool.driver = { + ruleDescriptors: [] }; + + var ruleIndex = 0; + Object.keys(sarifRules).forEach(function (ruleId) { + var rule = sarifRules[ruleId]; + rule.ruleIndex = ruleIndex++; + sarifLog.runs[0].tool.driver.ruleDescriptors.push(rule); + }); } return JSON.stringify(sarifLog, diff --git a/src/ESLint.Formatter/sarif.js b/src/ESLint.Formatter/sarif.js index 3be21aa00..576523008 100644 --- a/src/ESLint.Formatter/sarif.js +++ b/src/ESLint.Formatter/sarif.js @@ -36,9 +36,12 @@ module.exports = function(results) { $schema: "http://json.schemastore.org/sarif-2.0.0", runs: [ { - files: [], + artifacts: [], tool: { - name: "ESLint" + driver: { + name: "ESLint", + downloadUri: "https://eslint.org" + } } } ] @@ -127,13 +130,11 @@ module.exports = function(results) { } sarifResults.push(sarifResult); - }); - }); Object.keys(sarifFiles).forEach(function (path) { - sarifLog.runs[0].files.push(sarifFiles[path]); + sarifLog.runs[0].artifacts.push(sarifFiles[path]); }); if (sarifResults.length > 0) { From c25bd99a3eeb83eada0de5db6e375b93b13fb7ab Mon Sep 17 00:00:00 2001 From: Chris Meyer Date: Thu, 7 Mar 2019 15:36:35 -0800 Subject: [PATCH 2/6] More schema updates + add eslint version --- src/ESLint.Formatter/sarif-with-rules.js | 14 +++++++++++--- src/ESLint.Formatter/sarif.js | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/ESLint.Formatter/sarif-with-rules.js b/src/ESLint.Formatter/sarif-with-rules.js index ae67284dd..1fc9a29c2 100644 --- a/src/ESLint.Formatter/sarif-with-rules.js +++ b/src/ESLint.Formatter/sarif-with-rules.js @@ -32,6 +32,13 @@ function getResultLevel(message) { //------------------------------------------------------------------------------ module.exports = function (results, data) { + let version; + + try { + const pkg = require("../../package.json"); + version = pkg.version; + } catch { } + const rulesMetdata = lodash.get(data, "rulesMetdata", null); const sarifLog = { @@ -43,7 +50,8 @@ module.exports = function (results, data) { tool: { driver: { name: "ESLint", - downloadUri: "https://eslint.org" + downloadUri: "https://eslint.org", + version: version } } } @@ -63,7 +71,7 @@ module.exports = function (results, data) { // Create a new entry in the files dictionary. sarifFiles[result.filePath] = { - fileLocation: { + location: { uri: result.filePath } }; @@ -105,7 +113,7 @@ module.exports = function (results, data) { locations: [ { physicalLocation: { - fileLocation: { + artifactLocation: { uri: result.filePath } } diff --git a/src/ESLint.Formatter/sarif.js b/src/ESLint.Formatter/sarif.js index 576523008..aadffaab3 100644 --- a/src/ESLint.Formatter/sarif.js +++ b/src/ESLint.Formatter/sarif.js @@ -30,7 +30,14 @@ function getResultLevel(message) { // Public Interface //------------------------------------------------------------------------------ -module.exports = function(results) { +module.exports = function (results) { + let version; + + try { + const pkg = require("../../package.json"); + version = pkg.version; + } catch { } + const sarifLog = { version: "2.0.0", $schema: "http://json.schemastore.org/sarif-2.0.0", @@ -40,7 +47,8 @@ module.exports = function(results) { tool: { driver: { name: "ESLint", - downloadUri: "https://eslint.org" + downloadUri: "https://eslint.org", + version: version } } } @@ -59,7 +67,7 @@ module.exports = function(results) { // Create a new entry in the files dictionary. sarifFiles[result.filePath] = { - fileLocation: { + location: { uri: result.filePath } }; @@ -101,7 +109,7 @@ module.exports = function(results) { locations: [ { physicalLocation: { - fileLocation: { + artifactLocation: { uri: result.filePath } } From bf3b60240b8a6d4376c222932e07f64e22d06bef Mon Sep 17 00:00:00 2001 From: Chris Meyer Date: Thu, 28 Mar 2019 10:56:31 -0700 Subject: [PATCH 3/6] Revert ESLint version Can't access inbox files from an npm package. --- src/ESLint.Formatter/sarif-with-rules.js | 9 +-------- src/ESLint.Formatter/sarif.js | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/ESLint.Formatter/sarif-with-rules.js b/src/ESLint.Formatter/sarif-with-rules.js index 1fc9a29c2..bf248a296 100644 --- a/src/ESLint.Formatter/sarif-with-rules.js +++ b/src/ESLint.Formatter/sarif-with-rules.js @@ -32,12 +32,6 @@ function getResultLevel(message) { //------------------------------------------------------------------------------ module.exports = function (results, data) { - let version; - - try { - const pkg = require("../../package.json"); - version = pkg.version; - } catch { } const rulesMetdata = lodash.get(data, "rulesMetdata", null); @@ -50,8 +44,7 @@ module.exports = function (results, data) { tool: { driver: { name: "ESLint", - downloadUri: "https://eslint.org", - version: version + downloadUri: "https://eslint.org" } } } diff --git a/src/ESLint.Formatter/sarif.js b/src/ESLint.Formatter/sarif.js index aadffaab3..ca66d25d6 100644 --- a/src/ESLint.Formatter/sarif.js +++ b/src/ESLint.Formatter/sarif.js @@ -31,12 +31,6 @@ function getResultLevel(message) { //------------------------------------------------------------------------------ module.exports = function (results) { - let version; - - try { - const pkg = require("../../package.json"); - version = pkg.version; - } catch { } const sarifLog = { version: "2.0.0", @@ -47,8 +41,7 @@ module.exports = function (results) { tool: { driver: { name: "ESLint", - downloadUri: "https://eslint.org", - version: version + downloadUri: "https://eslint.org" } } } From 2c66d844e31da59ebe6f8737c43868496b633c83 Mon Sep 17 00:00:00 2001 From: Chris Meyer Date: Thu, 28 Mar 2019 13:17:07 -0700 Subject: [PATCH 4/6] Update tests --- src/ESLint.Formatter/package-lock.json | 5 ++ src/ESLint.Formatter/package.json | 1 + src/ESLint.Formatter/test/sarif-with-rules.js | 66 +++++++++---------- src/ESLint.Formatter/test/sarif.js | 31 ++++----- 4 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/ESLint.Formatter/package-lock.json b/src/ESLint.Formatter/package-lock.json index d9fdd771a..34b1071e5 100644 --- a/src/ESLint.Formatter/package-lock.json +++ b/src/ESLint.Formatter/package-lock.json @@ -139,6 +139,11 @@ "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-2.1.0.tgz", "integrity": "sha512-Fuk25QlebgHnvCQvAm258+y2D8yVs1VFIFwiqXbvxG4n9vo5YZsBPZuMxnc7Gb9ElAeN8QfRDvgkkIhW4DPoPA==" }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", diff --git a/src/ESLint.Formatter/package.json b/src/ESLint.Formatter/package.json index 35e07f7fe..397f4bf2d 100644 --- a/src/ESLint.Formatter/package.json +++ b/src/ESLint.Formatter/package.json @@ -31,6 +31,7 @@ "dependencies": { "chai": "^4.2.0", "jschardet": "latest", + "lodash": "^4.17.11", "mocha": "^5.2.0", "utf8": "^3.0.0" } diff --git a/src/ESLint.Formatter/test/sarif-with-rules.js b/src/ESLint.Formatter/test/sarif-with-rules.js index 7eff5a05d..3b06a7757 100644 --- a/src/ESLint.Formatter/test/sarif-with-rules.js +++ b/src/ESLint.Formatter/test/sarif-with-rules.js @@ -5,14 +5,12 @@ "use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const assert = require("chai").assert, - formatter = require("../sarif-with-rules"); - +const assert = require("chai").assert; +const formatter = require("../sarif-with-rules"); //------------------------------------------------------------------------------ // Global Test Content @@ -67,8 +65,8 @@ describe("formatter:sarif", () => { it("should return a log with one file and no results", () => { const result = JSON.parse(formatter(code, null)); - assert.hasAllKeys(result.runs[0].files, sourceFilePath); - assert.strictEqual(result.runs[0].files[sourceFilePath].fileLocation.uri, sourceFilePath); + assert.hasAllKeys(result.runs[0].artifacts, sourceFilePath); + assert.strictEqual(result.runs[0].artifacts[sourceFilePath].artifactLocation.uri, sourceFilePath); assert.isUndefined(result.runs[0].results); }); }); @@ -88,14 +86,14 @@ describe("formatter:sarif", () => { it("should return a log with one file and one result", () => { const result = JSON.parse(formatter(code)); - assert.hasAllKeys(result.runs[0].files, sourceFilePath); - assert.strictEqual(result.runs[0].files[sourceFilePath].fileLocation.uri, sourceFilePath); + assert.hasAllKeys(result.runs[0].artifacts, sourceFilePath); + assert.strictEqual(result.runs[0].artifacts[sourceFilePath].artifactLocation.uri, sourceFilePath); assert.isDefined(result.runs[0].results); assert.lengthOf(result.runs[0].results, 1); assert.strictEqual(result.runs[0].results[0].level, "error"); assert.isDefined(result.runs[0].results[0].message); assert.strictEqual(result.runs[0].results[0].message.text, code[0].messages[0].message); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.fileLocation.uri, sourceFilePath); + assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath); }); }); }); @@ -116,11 +114,11 @@ describe("formatter:sarif", () => { const result = JSON.parse(formatter(code, rules)); const rule = rules.get(ruleid); - assert.hasAllKeys(result.runs[0].resources.rules, ruleid); - assert.strictEqual(result.runs[0].resources.rules[ruleid].id, ruleid); - assert.strictEqual(result.runs[0].resources.rules[ruleid].shortDescription.text, rule.meta.docs.description); - assert.strictEqual(result.runs[0].resources.rules[ruleid].helpUri, rule.meta.docs.url); - assert.strictEqual(result.runs[0].resources.rules[ruleid].tags.category, rule.meta.docs.category); + assert.hasAllKeys(result.runs[0].tool.driver.ruleDescriptors, ruleid); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].id, ruleid); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].shortDescription.text, rule.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].helpUri, rule.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].tags.category, rule.meta.docs.category); }); }); }); @@ -264,26 +262,26 @@ describe("formatter:sarif", () => { assert.lengthOf(result.runs[0].results, 4); - assert.hasAllKeys(result.runs[0].resources.rules, [ruleid1, ruleid2, ruleid3]); - assert.hasAllKeys(result.runs[0].files, [sourceFilePath1, sourceFilePath2]); + assert.hasAllKeys(result.runs[0].tool.driver.ruleDescriptors, [ruleid1, ruleid2, ruleid3]); + assert.hasAllKeys(result.runs[0].artifacts, [sourceFilePath1, sourceFilePath2]); - assert.strictEqual(result.runs[0].files[sourceFilePath1].fileLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].files[sourceFilePath2].fileLocation.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].files[sourceFilePath1].artifactLocation.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].files[sourceFilePath2].artifactLocation.uri, sourceFilePath2); - assert.strictEqual(result.runs[0].resources.rules[ruleid1].id, ruleid1); - assert.strictEqual(result.runs[0].resources.rules[ruleid1].shortDescription.text, rule1.meta.docs.description); - assert.strictEqual(result.runs[0].resources.rules[ruleid1].helpUri, rule1.meta.docs.url); - assert.strictEqual(result.runs[0].resources.rules[ruleid1].tags.category, rule1.meta.docs.category); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].id, ruleid1); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].shortDescription.text, rule1.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].helpUri, rule1.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].tags.category, rule1.meta.docs.category); - assert.strictEqual(result.runs[0].resources.rules[ruleid2].id, ruleid2); - assert.strictEqual(result.runs[0].resources.rules[ruleid2].shortDescription.text, rule2.meta.docs.description); - assert.strictEqual(result.runs[0].resources.rules[ruleid2].helpUri, rule2.meta.docs.url); - assert.strictEqual(result.runs[0].resources.rules[ruleid2].tags.category, rule2.meta.docs.category); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].id, ruleid2); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].shortDescription.text, rule2.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].helpUri, rule2.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].tags.category, rule2.meta.docs.category); - assert.strictEqual(result.runs[0].resources.rules[ruleid3].id, ruleid3); - assert.strictEqual(result.runs[0].resources.rules[ruleid3].shortDescription.text, rule3.meta.docs.description); - assert.strictEqual(result.runs[0].resources.rules[ruleid3].helpUri, rule3.meta.docs.url); - assert.strictEqual(result.runs[0].resources.rules[ruleid3].tags.category, rule3.meta.docs.category); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].id, ruleid3); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].shortDescription.text, rule3.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].helpUri, rule3.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].tags.category, rule3.meta.docs.category); assert.strictEqual(result.runs[0].results[0].ruleId, "the-rule"); assert.strictEqual(result.runs[0].results[1].ruleId, ruleid1); @@ -300,10 +298,10 @@ describe("formatter:sarif", () => { assert.strictEqual(result.runs[0].results[2].message.text, "Unexpected something."); assert.strictEqual(result.runs[0].results[3].message.text, "Custom error."); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.fileLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.fileLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].results[2].locations[0].physicalLocation.fileLocation.uri, sourceFilePath2); - assert.strictEqual(result.runs[0].results[3].locations[0].physicalLocation.fileLocation.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].results[2].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].results[3].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region); diff --git a/src/ESLint.Formatter/test/sarif.js b/src/ESLint.Formatter/test/sarif.js index 5cb0cc8cc..01b55b926 100644 --- a/src/ESLint.Formatter/test/sarif.js +++ b/src/ESLint.Formatter/test/sarif.js @@ -5,14 +5,12 @@ "use strict"; - //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ -const assert = require("chai").assert, - formatter = require("../sarif"); - +const assert = require("chai").assert; +const formatter = require("../sarif"); //------------------------------------------------------------------------------ // Tests @@ -28,9 +26,8 @@ describe("formatter:sarif", () => { it("should return a log with one file and no results", () => { const result = JSON.parse(formatter(code)); - - assert.hasAllKeys(result.runs[0].files, sourceFilePath); - assert.strictEqual(result.runs[0].files[sourceFilePath].fileLocation.uri, sourceFilePath); + + assert.strictEqual(result.runs[0].artifacts[0].location.uri, sourceFilePath); assert.isUndefined(result.runs[0].results); }); }); @@ -50,14 +47,13 @@ describe("formatter:sarif", () => { it("should return a log with one file and one result", () => { const result = JSON.parse(formatter(code)); - assert.hasAllKeys(result.runs[0].files, sourceFilePath); - assert.strictEqual(result.runs[0].files[sourceFilePath].fileLocation.uri, sourceFilePath); + assert.strictEqual(result.runs[0].artifacts[0].location.uri, sourceFilePath); assert.isDefined(result.runs[0].results); assert.lengthOf(result.runs[0].results, 1); assert.strictEqual(result.runs[0].results[0].level, "error"); assert.isDefined(result.runs[0].results[0].message); assert.strictEqual(result.runs[0].results[0].message.text, code[0].messages[0].message); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.fileLocation.uri, sourceFilePath); + assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath); }); }); }); @@ -178,14 +174,13 @@ describe("formatter:sarif", () => { }]; it("should return a log with two files and three results", () => { - const result = JSON.parse(formatter(code)); + const text = formatter(code); + const result = JSON.parse(text); assert.lengthOf(result.runs[0].results, 3); - - assert.hasAllKeys(result.runs[0].files, [sourceFilePath1, sourceFilePath2]); - assert.strictEqual(result.runs[0].files[sourceFilePath1].fileLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].files[sourceFilePath2].fileLocation.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].artifacts[0].location.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].artifacts[1].location.uri, sourceFilePath2); assert.strictEqual(result.runs[0].results[0].level, "error"); assert.strictEqual(result.runs[0].results[1].level, "warning"); @@ -195,9 +190,9 @@ describe("formatter:sarif", () => { assert.strictEqual(result.runs[0].results[1].message.text, "Some warning."); assert.strictEqual(result.runs[0].results[2].message.text, "Unexpected something."); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.fileLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.fileLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].results[2].locations[0].physicalLocation.fileLocation.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].results[2].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region); From 61c27c07028daed461a16576a69c3f26c017a203 Mon Sep 17 00:00:00 2001 From: Chris Meyer Date: Fri, 29 Mar 2019 19:20:47 -0700 Subject: [PATCH 5/6] Move to formatter that accepts data argument --- src/ESLint.Formatter/sarif-with-rules.js | 186 ----------- src/ESLint.Formatter/sarif.js | 39 ++- src/ESLint.Formatter/test/sarif-with-rules.js | 315 ------------------ src/ESLint.Formatter/test/sarif.js | 141 +++++++- 4 files changed, 163 insertions(+), 518 deletions(-) delete mode 100644 src/ESLint.Formatter/sarif-with-rules.js delete mode 100644 src/ESLint.Formatter/test/sarif-with-rules.js diff --git a/src/ESLint.Formatter/sarif-with-rules.js b/src/ESLint.Formatter/sarif-with-rules.js deleted file mode 100644 index bf248a296..000000000 --- a/src/ESLint.Formatter/sarif-with-rules.js +++ /dev/null @@ -1,186 +0,0 @@ -/** - * @fileoverview SARIF v2.0 formatter - * @author Microsoft - */ - -"use strict"; - -const lodash = require("lodash"); -const fs = require("fs"); -const utf8 = require("utf8"); -const jschardet = require("jschardet"); - -//------------------------------------------------------------------------------ -// Helper Functions -//------------------------------------------------------------------------------ - -/** - * Returns the severity of warning or error - * @param {Object} message message object to examine - * @returns {string} severity level - * @private - */ -function getResultLevel(message) { - if (message.fatal || message.severity === 2) { - return "error"; - } - return "warning"; -} - -//------------------------------------------------------------------------------ -// Public Interface -//------------------------------------------------------------------------------ - -module.exports = function (results, data) { - - const rulesMetdata = lodash.get(data, "rulesMetdata", null); - - const sarifLog = { - version: "2.0.0", - $schema: "http://json.schemastore.org/sarif-2.0.0", - runs: [ - { - artifacts: [], - tool: { - driver: { - name: "ESLint", - downloadUri: "https://eslint.org" - } - } - } - ] - }; - - const sarifFiles = {}; - const sarifRules = {}; - const sarifResults = []; - const embedFileContents = process.env.SARIF_ESLINT_EMBED === "true"; - - results.forEach(result => { - - if (typeof sarifFiles[result.filePath] === "undefined") { - - let contentsUtf8; - - // Create a new entry in the files dictionary. - sarifFiles[result.filePath] = { - location: { - uri: result.filePath - } - }; - - if (embedFileContents) { - try { - - // Try to get the file contents and encoding. - const contents = fs.readFileSync(result.filePath); - const encoding = jschardet.detect(contents); - - // Encoding will be null if it could not be determined. - if (encoding) { - - // Convert the content bytes to a UTF-8 string. - contentsUtf8 = utf8.encode(contents.toString(encoding.encoding)); - - sarifFiles[result.filePath].contents = { - text: contentsUtf8 - }; - sarifFiles[result.filePath].encoding = encoding.encoding; - } - } - catch (err) { - console.log(err); - } - } - } - - const messages = result.messages; - - messages.forEach(message => { - - const sarifResult = { - level: getResultLevel(message), - message: { - text: message.message - }, - locations: [ - { - physicalLocation: { - artifactLocation: { - uri: result.filePath - } - } - } - ] - }; - - if (message.ruleId) { - sarifResult.ruleId = message.ruleId; - - if (rulesMetdata && typeof sarifRules[message.ruleId] === "undefined") { - const meta = rulesMetdata[message.ruleId]; - - // An unknown ruleId will return null. This check prevents unit test failure. - if (meta) { - - // Create a new entry in the rules dictionary. - sarifRules[message.ruleId] = { - id: message.ruleId, - shortDescription: { - text: meta.docs.description - }, - helpUri: meta.docs.url, - tags: { - category: meta.docs.category - } - }; - } - } - } - - if (message.line > 0 && message.column > 0) { - sarifResult.locations[0].physicalLocation.region = { - startLine: message.line, - startColumn: message.column - }; - } - - if (message.source) { - - // Create an empty region if we don't already have one from the line / column block above. - sarifResult.locations[0].physicalLocation.region = sarifResult.locations[0].physicalLocation.region || {}; - sarifResult.locations[0].physicalLocation.region.snippet = { - text: message.source - }; - } - - sarifResults.push(sarifResult); - }); - }); - - Object.keys(sarifFiles).forEach(function (path) { - sarifLog.runs[0].artifacts.push(sarifFiles[path]); - }); - - if (sarifResults.length > 0) { - sarifLog.runs[0].results = sarifResults; - } - - if (Object.keys(sarifRules).length > 0) { - sarifLog.runs[0].tool.driver = { - ruleDescriptors: [] - }; - - var ruleIndex = 0; - Object.keys(sarifRules).forEach(function (ruleId) { - var rule = sarifRules[ruleId]; - rule.ruleIndex = ruleIndex++; - sarifLog.runs[0].tool.driver.ruleDescriptors.push(rule); - }); - } - - return JSON.stringify(sarifLog, - null, // replacer function - 2 // # of spaces for indents - ); -}; diff --git a/src/ESLint.Formatter/sarif.js b/src/ESLint.Formatter/sarif.js index ca66d25d6..bf248a296 100644 --- a/src/ESLint.Formatter/sarif.js +++ b/src/ESLint.Formatter/sarif.js @@ -5,6 +5,7 @@ "use strict"; +const lodash = require("lodash"); const fs = require("fs"); const utf8 = require("utf8"); const jschardet = require("jschardet"); @@ -30,7 +31,9 @@ function getResultLevel(message) { // Public Interface //------------------------------------------------------------------------------ -module.exports = function (results) { +module.exports = function (results, data) { + + const rulesMetdata = lodash.get(data, "rulesMetdata", null); const sarifLog = { version: "2.0.0", @@ -49,6 +52,7 @@ module.exports = function (results) { }; const sarifFiles = {}; + const sarifRules = {}; const sarifResults = []; const embedFileContents = process.env.SARIF_ESLINT_EMBED === "true"; @@ -112,6 +116,26 @@ module.exports = function (results) { if (message.ruleId) { sarifResult.ruleId = message.ruleId; + + if (rulesMetdata && typeof sarifRules[message.ruleId] === "undefined") { + const meta = rulesMetdata[message.ruleId]; + + // An unknown ruleId will return null. This check prevents unit test failure. + if (meta) { + + // Create a new entry in the rules dictionary. + sarifRules[message.ruleId] = { + id: message.ruleId, + shortDescription: { + text: meta.docs.description + }, + helpUri: meta.docs.url, + tags: { + category: meta.docs.category + } + }; + } + } } if (message.line > 0 && message.column > 0) { @@ -142,6 +166,19 @@ module.exports = function (results) { sarifLog.runs[0].results = sarifResults; } + if (Object.keys(sarifRules).length > 0) { + sarifLog.runs[0].tool.driver = { + ruleDescriptors: [] + }; + + var ruleIndex = 0; + Object.keys(sarifRules).forEach(function (ruleId) { + var rule = sarifRules[ruleId]; + rule.ruleIndex = ruleIndex++; + sarifLog.runs[0].tool.driver.ruleDescriptors.push(rule); + }); + } + return JSON.stringify(sarifLog, null, // replacer function 2 // # of spaces for indents diff --git a/src/ESLint.Formatter/test/sarif-with-rules.js b/src/ESLint.Formatter/test/sarif-with-rules.js deleted file mode 100644 index 3b06a7757..000000000 --- a/src/ESLint.Formatter/test/sarif-with-rules.js +++ /dev/null @@ -1,315 +0,0 @@ -/** - * @fileoverview Tests for SARIF format. - * @author Microsoft - */ - -"use strict"; - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -const assert = require("chai").assert; -const formatter = require("../sarif-with-rules"); - -//------------------------------------------------------------------------------ -// Global Test Content -//------------------------------------------------------------------------------ - -const rules = new Map(); - -rules.set("no-unused-vars", { - meta: { - type: "suggestion", - docs: { - description: "disallow unused variables", - category: "Variables", - recommended: true, - url: "https://eslint.org/docs/rules/no-unused-vars" - }, - fixable: "code" - } -}); -rules.set("no-extra-semi", { - meta: { - type: "suggestion", - - docs: { - description: "disallow unnecessary semicolons", - category: "Possible Errors", - recommended: true, - url: "https://eslint.org/docs/rules/no-extra-semi" - }, - - fixable: "code", - schema: [], - - messages: { - unexpected: "Unnecessary semicolon." - } - } -}); - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -describe("formatter:sarif", () => { - describe("when passed no messages", () => { - const sourceFilePath = "service.js"; - const code = [{ - filePath: sourceFilePath, - messages: [] - }]; - - it("should return a log with one file and no results", () => { - const result = JSON.parse(formatter(code, null)); - - assert.hasAllKeys(result.runs[0].artifacts, sourceFilePath); - assert.strictEqual(result.runs[0].artifacts[sourceFilePath].artifactLocation.uri, sourceFilePath); - assert.isUndefined(result.runs[0].results); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed one message", () => { - const sourceFilePath = "service.js"; - const code = [{ - filePath: sourceFilePath, - messages: [{ - message: "Unexpected value.", - severity: 2 - }] - }]; - - it("should return a log with one file and one result", () => { - const result = JSON.parse(formatter(code)); - - assert.hasAllKeys(result.runs[0].artifacts, sourceFilePath); - assert.strictEqual(result.runs[0].artifacts[sourceFilePath].artifactLocation.uri, sourceFilePath); - assert.isDefined(result.runs[0].results); - assert.lengthOf(result.runs[0].results, 1); - assert.strictEqual(result.runs[0].results[0].level, "error"); - assert.isDefined(result.runs[0].results[0].message); - assert.strictEqual(result.runs[0].results[0].message.text, code[0].messages[0].message); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed one message with a rule id", () => { - const ruleid = "no-unused-vars"; - const code = [{ - filePath: "service.js", - messages: [{ - message: "Unexpected value.", - ruleId: ruleid, - source: "getValue()" - }] - }]; - - it("should return a log with one rule", () => { - const result = JSON.parse(formatter(code, rules)); - const rule = rules.get(ruleid); - - assert.hasAllKeys(result.runs[0].tool.driver.ruleDescriptors, ruleid); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].id, ruleid); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].shortDescription.text, rule.meta.docs.description); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].helpUri, rule.meta.docs.url); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].tags.category, rule.meta.docs.category); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed one message with line but no column nor source string", () => { - const code = [{ - filePath: "service.js", - messages: [{ - message: "Unexpected value.", - line: 10 - }] - }]; - - it("should return a log with one result whose location does not contain a region", () => { - const result = JSON.parse(formatter(code)); - - assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed one message with line and column but no source string", () => { - const code = [{ - filePath: "service.js", - messages: [{ - message: "Unexpected value.", - line: 10, - column: 5 - }] - }]; - - it("should return a log with one result whose location contains a region with line and column #s", () => { - const result = JSON.parse(formatter(code)); - - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.region.startLine, code[0].messages[0].line); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.region.startColumn, code[0].messages[0].column); - assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region.snippet); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed one message with line, column, and source string", () => { - const code = [{ - filePath: "service.js", - messages: [{ - message: "Unexpected value.", - line: 10, - column: 5, - source: "getValue()" - }] - }]; - - it("should return a log with one result whose location contains a region with line and column #s", () => { - const result = JSON.parse(formatter(code)); - - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.region.startLine, code[0].messages[0].line); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.region.startColumn, code[0].messages[0].column); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.region.snippet.text, code[0].messages[0].source); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed one message with a source string but without line and column #s", () => { - const code = [{ - filePath: "service.js", - messages: [{ - message: "Unexpected value.", - severity: 2, - ruleId: "the-rule", - source: "getValue()" - }] - }]; - - it("should return a log with one result whose location contains a region with line and column #s", () => { - const result = JSON.parse(formatter(code, rules)); - - assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region.startLine); - assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region.startColumn); - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.region.snippet.text, code[0].messages[0].source); - }); - }); -}); - -describe("formatter:sarif", () => { - describe("when passed two results with two messages each", () => { - const sourceFilePath1 = "service.js"; - const sourceFilePath2 = "utils.js"; - const ruleid1 = "no-unused-vars"; - const ruleid2 = "no-extra-semi"; - const ruleid3 = "custom-rule"; - - rules.set(ruleid3, { - meta: { - type: "suggestion", - docs: { - description: "custom description", - category: "Possible Errors" - } - } - }); - const code = [{ - filePath: sourceFilePath1, - messages: [{ - message: "Unexpected value.", - severity: 2, - ruleId: "the-rule" - }, - { - ruleId: ruleid1, - message: "Some warning.", - severity: 1, - line: 10, - column: 5, - source: "doSomething(thingId)" - }] - }, - { - filePath: sourceFilePath2, - messages: [{ - message: "Unexpected something.", - severity: 2, - ruleId: ruleid2, - line: 18 - }, - { - message: "Custom error.", - ruleId: ruleid3, - line: 42 - }] - }]; - - it("should return a log with two files, three rules, and four results", () => { - const result = JSON.parse(formatter(code, rules)); - const rule1 = rules.get(ruleid1); - const rule2 = rules.get(ruleid2); - const rule3 = rules.get(ruleid3); - - assert.lengthOf(result.runs[0].results, 4); - - assert.hasAllKeys(result.runs[0].tool.driver.ruleDescriptors, [ruleid1, ruleid2, ruleid3]); - assert.hasAllKeys(result.runs[0].artifacts, [sourceFilePath1, sourceFilePath2]); - - assert.strictEqual(result.runs[0].files[sourceFilePath1].artifactLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].files[sourceFilePath2].artifactLocation.uri, sourceFilePath2); - - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].id, ruleid1); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].shortDescription.text, rule1.meta.docs.description); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].helpUri, rule1.meta.docs.url); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].tags.category, rule1.meta.docs.category); - - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].id, ruleid2); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].shortDescription.text, rule2.meta.docs.description); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].helpUri, rule2.meta.docs.url); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].tags.category, rule2.meta.docs.category); - - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].id, ruleid3); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].shortDescription.text, rule3.meta.docs.description); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].helpUri, rule3.meta.docs.url); - assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].tags.category, rule3.meta.docs.category); - - assert.strictEqual(result.runs[0].results[0].ruleId, "the-rule"); - assert.strictEqual(result.runs[0].results[1].ruleId, ruleid1); - assert.strictEqual(result.runs[0].results[2].ruleId, ruleid2); - assert.strictEqual(result.runs[0].results[3].ruleId, ruleid3); - - assert.strictEqual(result.runs[0].results[0].level, "error"); - assert.strictEqual(result.runs[0].results[1].level, "warning"); - assert.strictEqual(result.runs[0].results[2].level, "error"); - assert.strictEqual(result.runs[0].results[3].level, "warning"); - - assert.strictEqual(result.runs[0].results[0].message.text, "Unexpected value."); - assert.strictEqual(result.runs[0].results[1].message.text, "Some warning."); - assert.strictEqual(result.runs[0].results[2].message.text, "Unexpected something."); - assert.strictEqual(result.runs[0].results[3].message.text, "Custom error."); - - assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].results[2].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); - assert.strictEqual(result.runs[0].results[3].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); - - assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region); - - assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.region.startLine, 10); - assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.region.startColumn, 5); - assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.region.snippet.text, "doSomething(thingId)"); - - assert.isUndefined(result.runs[0].results[2].locations[0].physicalLocation.region); - }); - }); -}); diff --git a/src/ESLint.Formatter/test/sarif.js b/src/ESLint.Formatter/test/sarif.js index 01b55b926..ba6eecefa 100644 --- a/src/ESLint.Formatter/test/sarif.js +++ b/src/ESLint.Formatter/test/sarif.js @@ -10,7 +10,45 @@ //------------------------------------------------------------------------------ const assert = require("chai").assert; -const formatter = require("../sarif"); +const formatter = require("../sarif-with-rules"); + +//------------------------------------------------------------------------------ +// Global Test Content +//------------------------------------------------------------------------------ + +const rules = new Map(); + +rules.set("no-unused-vars", { + meta: { + type: "suggestion", + docs: { + description: "disallow unused variables", + category: "Variables", + recommended: true, + url: "https://eslint.org/docs/rules/no-unused-vars" + }, + fixable: "code" + } +}); +rules.set("no-extra-semi", { + meta: { + type: "suggestion", + + docs: { + description: "disallow unnecessary semicolons", + category: "Possible Errors", + recommended: true, + url: "https://eslint.org/docs/rules/no-extra-semi" + }, + + fixable: "code", + schema: [], + + messages: { + unexpected: "Unnecessary semicolon." + } + } +}); //------------------------------------------------------------------------------ // Tests @@ -25,9 +63,10 @@ describe("formatter:sarif", () => { }]; it("should return a log with one file and no results", () => { - const result = JSON.parse(formatter(code)); - - assert.strictEqual(result.runs[0].artifacts[0].location.uri, sourceFilePath); + const result = JSON.parse(formatter(code, null)); + + assert.hasAllKeys(result.runs[0].artifacts, sourceFilePath); + assert.strictEqual(result.runs[0].artifacts[sourceFilePath].artifactLocation.uri, sourceFilePath); assert.isUndefined(result.runs[0].results); }); }); @@ -47,7 +86,8 @@ describe("formatter:sarif", () => { it("should return a log with one file and one result", () => { const result = JSON.parse(formatter(code)); - assert.strictEqual(result.runs[0].artifacts[0].location.uri, sourceFilePath); + assert.hasAllKeys(result.runs[0].artifacts, sourceFilePath); + assert.strictEqual(result.runs[0].artifacts[sourceFilePath].artifactLocation.uri, sourceFilePath); assert.isDefined(result.runs[0].results); assert.lengthOf(result.runs[0].results, 1); assert.strictEqual(result.runs[0].results[0].level, "error"); @@ -58,6 +98,31 @@ describe("formatter:sarif", () => { }); }); +describe("formatter:sarif", () => { + describe("when passed one message with a rule id", () => { + const ruleid = "no-unused-vars"; + const code = [{ + filePath: "service.js", + messages: [{ + message: "Unexpected value.", + ruleId: ruleid, + source: "getValue()" + }] + }]; + + it("should return a log with one rule", () => { + const result = JSON.parse(formatter(code, rules)); + const rule = rules.get(ruleid); + + assert.hasAllKeys(result.runs[0].tool.driver.ruleDescriptors, ruleid); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].id, ruleid); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].shortDescription.text, rule.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].helpUri, rule.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid].tags.category, rule.meta.docs.category); + }); + }); +}); + describe("formatter:sarif", () => { describe("when passed one message with line but no column nor source string", () => { const code = [{ @@ -70,14 +135,14 @@ describe("formatter:sarif", () => { it("should return a log with one result whose location does not contain a region", () => { const result = JSON.parse(formatter(code)); - + assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region); }); }); }); describe("formatter:sarif", () => { - describe("when passed one message with line and column nor source string", () => { + describe("when passed one message with line and column but no source string", () => { const code = [{ filePath: "service.js", messages: [{ @@ -132,7 +197,7 @@ describe("formatter:sarif", () => { }]; it("should return a log with one result whose location contains a region with line and column #s", () => { - const result = JSON.parse(formatter(code)); + const result = JSON.parse(formatter(code, rules)); assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region.startLine); assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region.startColumn); @@ -142,11 +207,22 @@ describe("formatter:sarif", () => { }); describe("formatter:sarif", () => { - describe("when passed two results with two and one messages, respectively", () => { + describe("when passed two results with two messages each", () => { const sourceFilePath1 = "service.js"; const sourceFilePath2 = "utils.js"; const ruleid1 = "no-unused-vars"; const ruleid2 = "no-extra-semi"; + const ruleid3 = "custom-rule"; + + rules.set(ruleid3, { + meta: { + type: "suggestion", + docs: { + description: "custom description", + category: "Possible Errors" + } + } + }); const code = [{ filePath: sourceFilePath1, messages: [{ @@ -170,36 +246,69 @@ describe("formatter:sarif", () => { severity: 2, ruleId: ruleid2, line: 18 + }, + { + message: "Custom error.", + ruleId: ruleid3, + line: 42 }] }]; - it("should return a log with two files and three results", () => { - const text = formatter(code); - const result = JSON.parse(text); + it("should return a log with two files, three rules, and four results", () => { + const result = JSON.parse(formatter(code, rules)); + const rule1 = rules.get(ruleid1); + const rule2 = rules.get(ruleid2); + const rule3 = rules.get(ruleid3); + + assert.lengthOf(result.runs[0].results, 4); - assert.lengthOf(result.runs[0].results, 3); + assert.hasAllKeys(result.runs[0].tool.driver.ruleDescriptors, [ruleid1, ruleid2, ruleid3]); + assert.hasAllKeys(result.runs[0].artifacts, [sourceFilePath1, sourceFilePath2]); - assert.strictEqual(result.runs[0].artifacts[0].location.uri, sourceFilePath1); - assert.strictEqual(result.runs[0].artifacts[1].location.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].files[sourceFilePath1].artifactLocation.uri, sourceFilePath1); + assert.strictEqual(result.runs[0].files[sourceFilePath2].artifactLocation.uri, sourceFilePath2); + + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].id, ruleid1); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].shortDescription.text, rule1.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].helpUri, rule1.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid1].tags.category, rule1.meta.docs.category); + + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].id, ruleid2); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].shortDescription.text, rule2.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].helpUri, rule2.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid2].tags.category, rule2.meta.docs.category); + + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].id, ruleid3); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].shortDescription.text, rule3.meta.docs.description); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].helpUri, rule3.meta.docs.url); + assert.strictEqual(result.runs[0].tool.driver.ruleDescriptors[ruleid3].tags.category, rule3.meta.docs.category); + + assert.strictEqual(result.runs[0].results[0].ruleId, "the-rule"); + assert.strictEqual(result.runs[0].results[1].ruleId, ruleid1); + assert.strictEqual(result.runs[0].results[2].ruleId, ruleid2); + assert.strictEqual(result.runs[0].results[3].ruleId, ruleid3); assert.strictEqual(result.runs[0].results[0].level, "error"); assert.strictEqual(result.runs[0].results[1].level, "warning"); assert.strictEqual(result.runs[0].results[2].level, "error"); + assert.strictEqual(result.runs[0].results[3].level, "warning"); assert.strictEqual(result.runs[0].results[0].message.text, "Unexpected value."); assert.strictEqual(result.runs[0].results[1].message.text, "Some warning."); assert.strictEqual(result.runs[0].results[2].message.text, "Unexpected something."); + assert.strictEqual(result.runs[0].results[3].message.text, "Custom error."); assert.strictEqual(result.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath1); assert.strictEqual(result.runs[0].results[2].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); + assert.strictEqual(result.runs[0].results[3].locations[0].physicalLocation.artifactLocation.uri, sourceFilePath2); assert.isUndefined(result.runs[0].results[0].locations[0].physicalLocation.region); assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.region.startLine, 10); assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.region.startColumn, 5); assert.strictEqual(result.runs[0].results[1].locations[0].physicalLocation.region.snippet.text, "doSomething(thingId)"); - + assert.isUndefined(result.runs[0].results[2].locations[0].physicalLocation.region); }); }); From 70a34f169d087dcd35335a13c10fe81ec8ea1b5c Mon Sep 17 00:00:00 2001 From: Chris Meyer Date: Tue, 2 Apr 2019 06:36:31 -0700 Subject: [PATCH 6/6] Schema update 04-09 --- src/ESLint.Formatter/sarif.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ESLint.Formatter/sarif.js b/src/ESLint.Formatter/sarif.js index bf248a296..56a3a5d59 100644 --- a/src/ESLint.Formatter/sarif.js +++ b/src/ESLint.Formatter/sarif.js @@ -168,14 +168,14 @@ module.exports = function (results, data) { if (Object.keys(sarifRules).length > 0) { sarifLog.runs[0].tool.driver = { - ruleDescriptors: [] + rules: [] }; var ruleIndex = 0; Object.keys(sarifRules).forEach(function (ruleId) { var rule = sarifRules[ruleId]; rule.ruleIndex = ruleIndex++; - sarifLog.runs[0].tool.driver.ruleDescriptors.push(rule); + sarifLog.runs[0].tool.driver.rules.push(rule); }); }