diff --git a/docs/guides/3-javascript.md b/docs/guides/3-javascript.md index 50cd0b4eb..d60ac9d13 100644 --- a/docs/guides/3-javascript.md +++ b/docs/guides/3-javascript.md @@ -132,28 +132,3 @@ const spectral = new Spectral({ resolver: customFileResolver }); The custom resolver we've just created will resolve all remote file refs relatively to the current working directory. More on that can be found in the [json-ref-resolver repo](https://github.com/stoplightio/json-ref-resolver). - -### Using a Custom De-duplication Strategy - -By default, Spectral will de-duplicate results based on the result code and document location. You can customize this -behavior with the `computeFingerprint` option. For example, here is the default fingerprint implementation: - -The final reported results are de-duplicated based on their computed fingerprint. - -```ts -const spectral = new Spectral({ - computeFingerprint: (rule: IRuleResult, hash) => { - let id = String(rule.code); - - if (rule.path && rule.path.length) { - id += JSON.stringify(rule.path); - } else if (rule.range) { - id += JSON.stringify(rule.range); - } - - if (rule.source) id += rule.source; - - return hash(id); - }, -}); -``` diff --git a/packages/core/src/utils/__tests__/__fixtures__/non-duplicate-validation-results.json b/packages/core/src/utils/__tests__/__fixtures__/non-duplicate-validation-results.json new file mode 100644 index 000000000..bbee30ae0 --- /dev/null +++ b/packages/core/src/utils/__tests__/__fixtures__/non-duplicate-validation-results.json @@ -0,0 +1,80 @@ +[ + { + "code": "valid-schema-example-in-content", + "message": "\"schema.example\" property type should be integer", + "path": [ + "paths", + "/resource", + "get", + "responses", + "200", + "content", + "application/json", + "schema", + "example" + ], + "severity": 0, + "range": { + "start": { + "line": 20, + "character": 15 + }, + "end": { + "line": 20, + "character": 19 + } + } + }, + { + "code": "valid-schema-example-in-content", + "message": "\"schema.example\" has some other valid problem", + "path": [ + "paths", + "/resource", + "get", + "responses", + "200", + "content", + "application/json", + "schema", + "example" + ], + "severity": 0, + "range": { + "start": { + "line": 20, + "character": 15 + }, + "end": { + "line": 20, + "character": 19 + } + } + }, + { + "code": "valid-schema-example-in-content", + "message": "\"schema.example\" property type should be integer", + "path": [ + "paths", + "/resource", + "get", + "responses", + "200", + "content", + "application/json", + "schema", + "example" + ], + "severity": 0, + "range": { + "start": { + "line": 20, + "character": 15 + }, + "end": { + "line": 20, + "character": 19 + } + } + } +] diff --git a/packages/core/src/utils/__tests__/prepareResults.test.ts b/packages/core/src/utils/__tests__/prepareResults.test.ts index 02c8c7b41..16ccc73bf 100644 --- a/packages/core/src/utils/__tests__/prepareResults.test.ts +++ b/packages/core/src/utils/__tests__/prepareResults.test.ts @@ -40,4 +40,16 @@ describe('prepareResults util', () => { expect(prepareResults(onlyDuplicates, defaultComputeResultFingerprint).length).toBe(1); }); + + it('deduplicate only exact validation results', () => { + // verifies that results with the same code/path but different messages will not be de-duplicated + expect(prepareResults(duplicateValidationResults, defaultComputeResultFingerprint)).toEqual([ + expect.objectContaining({ + code: 'valid-example-in-schemas', + }), + expect.objectContaining({ + code: 'valid-schema-example-in-content', + }), + ]); + }); }); diff --git a/packages/core/src/utils/prepareResults.ts b/packages/core/src/utils/prepareResults.ts index 634865962..4b220fa54 100644 --- a/packages/core/src/utils/prepareResults.ts +++ b/packages/core/src/utils/prepareResults.ts @@ -21,6 +21,10 @@ export const defaultComputeResultFingerprint: ComputeFingerprintFunc = (rule, ha id += rule.source; } + if (rule.message !== void 0) { + id += rule.message; + } + return hash(id); };