Skip to content

Commit 0120022

Browse files
FIX: @W-19184117@: Our JSON schema fields primaryLocationIndex, locat… (#319)
1 parent 2fe37fb commit 0120022

File tree

11 files changed

+70
-44
lines changed

11 files changed

+70
-44
lines changed

packages/code-analyzer-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@salesforce/code-analyzer-core",
33
"description": "Core Package for the Salesforce Code Analyzer",
4-
"version": "0.31.0",
4+
"version": "0.32.0-SNAPSHOT",
55
"author": "The Salesforce Code Analyzer Team",
66
"license": "BSD-3-Clause",
77
"homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview",

packages/code-analyzer-core/src/code-analyzer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,8 +635,8 @@ function validateTargetLivesWithinWorkspace(target: string, workspaceFilesAndFol
635635
function validateEngineRunResults(engineName: string, apiEngineRunResults: engApi.EngineRunResults, ruleSelection: RuleSelection): void {
636636
for (const violation of apiEngineRunResults.violations) {
637637
validateViolationRuleName(violation, engineName, ruleSelection);
638-
validateViolationPrimaryLocationIndex(violation, engineName);
639638
validateViolationCodeLocations(violation, engineName);
639+
validateViolationPrimaryLocationIndex(violation, engineName);
640640
}
641641
}
642642

@@ -656,6 +656,9 @@ function validateViolationPrimaryLocationIndex(violation: engApi.Violation, engi
656656
}
657657

658658
function validateViolationCodeLocations(violation: engApi.Violation, engineName: string): void {
659+
if (violation.codeLocations.length === 0) {
660+
throw new Error(getMessage('EngineReturnedViolationWithEmptyCodeLocationArray', engineName, violation.ruleName));
661+
}
659662
for (const codeLocation of violation.codeLocations) {
660663
const absFile: string = toAbsolutePath(codeLocation.file);
661664
fs.existsSync(absFile)

packages/code-analyzer-core/src/messages.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ const MESSAGE_CATALOG : MessageCatalog = {
136136
FileOrFolderDoesNotExist:
137137
`The file or folder '%s' does not exist.`,
138138

139+
UndefinedCodeLocationComment:
140+
`Undefined Code Location`,
141+
139142
AtLeastOneFileOrFolderMustBeIncludedInWorkspace:
140143
`At least one file or folder must be included in the workspace.`,
141144

@@ -169,6 +172,9 @@ const MESSAGE_CATALOG : MessageCatalog = {
169172
EngineReturnedViolationForUnselectedRule:
170173
`Engine failure. The engine '%s' returned a violation for rule '%s' which was not selected.`,
171174

175+
EngineReturnedViolationWithEmptyCodeLocationArray:
176+
`Engine failure. The engine '%s' returned a violation for rule '%s' that contains an an empty code location array. Rule violations must have at least one code location object.`,
177+
172178
EngineReturnedViolationWithInvalidPrimaryLocationIndex:
173179
`Engine failure. The engine '%s' returned a violation for rule '%s' that contains an out of bounds primary location index value of %d. Expected a non-negative integer that is less than %d.`,
174180

packages/code-analyzer-core/src/output-formats/results/csv-run-results-format.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class CsvRunResultsFormatter implements RunResultsFormatter {
2121
'endLine', 'endColumn', 'message', 'resources'],
2222
cast: {
2323
object: value => {
24+
/* istanbul ignore else */
2425
if (Array.isArray(value)) {
2526
return { value: value.join(','), quoted: true };
2627
}
@@ -64,4 +65,4 @@ function toCsvRow(violation: Violation, runDir: string): CsvRow {
6465
message: violation.getMessage(),
6566
resources: violation.getResourceUrls()
6667
}
67-
}
68+
}

packages/code-analyzer-core/src/output-formats/results/json-run-results-format.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,16 @@ export type JsonViolationOutput = {
5454
tags: string[]
5555

5656
// The index of the primary code location within the code locations array
57-
primaryLocationIndex?: number
57+
primaryLocationIndex: number
5858

59-
// An array of code locations associated with the violation
60-
locations?: JsonCodeLocationOutput[]
59+
// An non-empty array of code locations associated with the violation
60+
locations: JsonCodeLocationOutput[]
6161

6262
// The violation message
6363
message: string
6464

6565
// An array of urls for resources associated with the violation
66-
resources?: string[]
66+
resources: string[]
6767
}
6868
export type JsonCodeLocationOutput = {
6969
// The path, relative to runDir, of the file associated with the violation

packages/code-analyzer-core/src/output-formats/results/xml-run-results-format.ts

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,42 +38,39 @@ export class XmlRunResultsFormatter implements RunResultsFormatter {
3838
for (const tag of violationOutput.tags) {
3939
tagsNode.node('tag').text(tag);
4040
}
41-
if (violationOutput.primaryLocationIndex != null) {
42-
violationNode.node('primaryLocationIndex').text(`${violationOutput.primaryLocationIndex}`);
43-
}
44-
if (violationOutput.locations) {
45-
const pathLocationsNode: xmlbuilder.XMLElement = violationNode.node('locations');
46-
for (const location of violationOutput.locations) {
47-
const locationNode: xmlbuilder.XMLElement = pathLocationsNode.node('location');
48-
if (location.file !== undefined) {
49-
locationNode.node('file').text(location.file);
50-
}
51-
if (location.startLine !== undefined) {
52-
locationNode.node('startLine').text(`${location.startLine}`);
53-
}
54-
if (location.startColumn !== undefined) {
55-
locationNode.node('startColumn').text(`${location.startColumn}`);
56-
}
57-
if (location.endLine !== undefined) {
58-
locationNode.node('endLine').text(`${location.endLine}`);
59-
}
60-
if (location.endColumn !== undefined) {
61-
locationNode.node('endColumn').text(`${location.endColumn}`);
62-
}
63-
if (location.comment !== undefined) {
64-
locationNode.node('comment').text(location.comment);
65-
}
41+
violationNode.node('primaryLocationIndex').text(`${violationOutput.primaryLocationIndex}`);
42+
43+
const pathLocationsNode: xmlbuilder.XMLElement = violationNode.node('locations');
44+
for (const location of violationOutput.locations) {
45+
const locationNode: xmlbuilder.XMLElement = pathLocationsNode.node('location');
46+
if (location.file !== undefined) {
47+
locationNode.node('file').text(location.file);
48+
}
49+
if (location.startLine !== undefined) {
50+
locationNode.node('startLine').text(`${location.startLine}`);
51+
}
52+
if (location.startColumn !== undefined) {
53+
locationNode.node('startColumn').text(`${location.startColumn}`);
54+
}
55+
if (location.endLine !== undefined) {
56+
locationNode.node('endLine').text(`${location.endLine}`);
57+
}
58+
if (location.endColumn !== undefined) {
59+
locationNode.node('endColumn').text(`${location.endColumn}`);
60+
}
61+
if (location.comment !== undefined) {
62+
locationNode.node('comment').text(location.comment);
6663
}
6764
}
65+
6866
violationNode.node('message').text(violationOutput.message);
69-
if (violationOutput.resources) {
70-
const resourcesNode: xmlbuilder.XMLElement = violationNode.node('resources');
71-
for (const resource of violationOutput.resources) {
72-
resourcesNode.node('resource').text(resource);
73-
}
67+
68+
const resourcesNode: xmlbuilder.XMLElement = violationNode.node('resources');
69+
for (const resource of violationOutput.resources) {
70+
resourcesNode.node('resource').text(resource);
7471
}
7572
}
7673

7774
return violationsNode.end({ pretty: true, allowEmpty: true });
7875
}
79-
}
76+
}

packages/code-analyzer-core/src/results.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,8 @@ export class UndefinedCodeLocation implements CodeLocation {
163163
return undefined;
164164
}
165165

166-
// istanbul ignore next - Unused method, required for interface
167-
getComment(): undefined {
168-
return undefined;
166+
getComment(): string {
167+
return getMessage('UndefinedCodeLocationComment');
169168
}
170169

171170
getEndLine(): undefined {

packages/code-analyzer-core/test/code-analyzer.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,22 @@ describe("Tests for the run method of CodeAnalyzer", () => {
416416
getMessage('EngineReturnedViolationWithInvalidPrimaryLocationIndex', 'stubEngine2', 'stub2RuleC', -2, 3));
417417
});
418418

419+
it("When an engine returns a violatoin that has zero code locations, then an error is thrown", async() => {
420+
const badViolation: engApi.Violation = {
421+
ruleName: 'stub1RuleC',
422+
message: 'SomeViolationMessage2',
423+
codeLocations: [],
424+
primaryLocationIndex: 0,
425+
resourceUrls: ["https://example.com/aViolationSpecificUrl1",]
426+
};
427+
badViolation.primaryLocationIndex = 0;
428+
stubEngine1.resultsToReturn = {
429+
violations: [badViolation]
430+
};
431+
await expect(codeAnalyzer.run(selection, sampleRunOptions)).rejects.toThrow(
432+
getMessage('EngineReturnedViolationWithEmptyCodeLocationArray', 'stubEngine1', 'stub1RuleC'));
433+
});
434+
419435
it("When an engine returns a violation that has a primary location index that is not an integer, then an error is thrown", async () => {
420436
const badViolation: engApi.Violation = stubs.getSampleViolationForStub1RuleC();
421437
badViolation.primaryLocationIndex = 0.5;

packages/code-analyzer-core/test/test-data/expectedOutputFiles/unexpectedEngineErrorViolation.goldfile.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
})();
5050

5151
// ==== START OF VIOLATIONS ====
52-
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":1,"sev1":1,"sev2":0,"sev3":0,"sev4":0,"sev5":0},"versions":{"code-analyzer":"{{CORE_VERSION}}","throwingEngine":"3.0.0"},"violations":[{"rule":"UnexpectedEngineError","engine":"throwingEngine","severity":1,"tags":[],"primaryLocationIndex":0,"locations":[{}],"message":"The engine with name 'throwingEngine' threw an unexpected error: SomeErrorMessageFromThrowingEngine","resources":[]}]};
52+
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":1,"sev1":1,"sev2":0,"sev3":0,"sev4":0,"sev5":0},"versions":{"code-analyzer":"{{CORE_VERSION}}","throwingEngine":"3.0.0"},"violations":[{"rule":"UnexpectedEngineError","engine":"throwingEngine","severity":1,"tags":[],"primaryLocationIndex":0,"locations":[{"comment":"Undefined Code Location"}],"message":"The engine with name 'throwingEngine' threw an unexpected error: SomeErrorMessageFromThrowingEngine","resources":[]}]};
5353
// ==== END OF VIOLATIONS ====
5454

5555
class Model {

packages/code-analyzer-core/test/test-data/expectedOutputFiles/unexpectedEngineErrorViolation.goldfile.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
"tags": [],
2121
"primaryLocationIndex": 0,
2222
"locations": [
23-
{}
23+
{
24+
"comment": "Undefined Code Location"
25+
}
2426
],
2527
"message": "The engine with name 'throwingEngine' threw an unexpected error: SomeErrorMessageFromThrowingEngine",
2628
"resources": []

0 commit comments

Comments
 (0)