Skip to content

Commit

Permalink
feat(ruleset): make rules optional (#652)
Browse files Browse the repository at this point in the history
  • Loading branch information
P0lip committed Oct 8, 2019
1 parent 9876ac2 commit 4de9dd2
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 10 deletions.
9 changes: 7 additions & 2 deletions src/meta/ruleset.schema.json
Expand Up @@ -66,7 +66,12 @@
}
}
},
"required": [
"rules"
"anyOf": [
{
"required": ["extends"]
},
{
"required": ["rules"]
}
]
}
6 changes: 6 additions & 0 deletions src/rulesets/__tests__/__fixtures__/extends-only-ruleset.json
@@ -0,0 +1,6 @@
{
"extends": [
"./custom-functions-directory-ruleset.json",
"./foo-ruleset.json"
]
}
34 changes: 34 additions & 0 deletions src/rulesets/__tests__/reader.jest.test.ts
Expand Up @@ -14,6 +14,7 @@ const validRequireInfo = path.join(__dirname, './__fixtures__/valid-require-info
const github447 = path.join(__dirname, './__fixtures__/github-issue-447-fixture.yaml');
const enabledAllRuleset = path.join(__dirname, './__fixtures__/enable-all-ruleset.json');
const invalidRuleset = path.join(__dirname, './__fixtures__/invalid-ruleset.json');
const extendsOnlyRuleset = path.join(__dirname, './__fixtures__/extends-only-ruleset.json');
const extendsAllOas2Ruleset = path.join(__dirname, './__fixtures__/extends-oas2-ruleset.json');
const extendsUnspecifiedOas2Ruleset = path.join(__dirname, './__fixtures__/extends-unspecified-oas2-ruleset.json');
const extendsDisabledOas2Ruleset = path.join(__dirname, './__fixtures__/extends-disabled-oas2-ruleset.yaml');
Expand Down Expand Up @@ -95,6 +96,39 @@ describe('Rulesets reader', () => {
);
});

it('given ruleset with no custom rules extending other rulesets', async () => {
const { rules } = await readRuleset(extendsOnlyRuleset);

expect(rules).toEqual({
'bar-rule': {
given: '$.info',
message: 'should be OK',
recommended: true,
severity: DiagnosticSeverity.Warning,
then: {
function: expect.stringMatching(/^random-id-\d$/),
},
},
'foo-rule': {
given: '$.info',
message: 'should be OK',
severity: -1,
then: {
function: expect.stringMatching(/^random-id-\d$/),
},
},
'truthy-rule': {
given: '$.x',
message: 'should be OK',
recommended: true,
severity: DiagnosticSeverity.Warning,
then: {
function: expect.stringMatching(/^random-id-\d$/),
},
},
});
});

it('should inherit properties of extended rulesets', async () => {
const { rules } = await readRuleset(extendsAllOas2Ruleset);

Expand Down
14 changes: 11 additions & 3 deletions src/rulesets/__tests__/validation.test.ts
Expand Up @@ -10,9 +10,17 @@ describe('Ruleset Validation', () => {
expect(assertValidRuleset.bind(null, 'true')).toThrow('Provided ruleset is not an object');
});

it('given object with no rules property should throw', () => {
expect(assertValidRuleset.bind(null, {})).toThrow('Ruleset must have rules property');
expect(assertValidRuleset.bind(null, { rule: {} })).toThrow('Ruleset must have rules property');
it('given object with no rules and no extends properties should throw', () => {
expect(assertValidRuleset.bind(null, {})).toThrow('Ruleset must have rules or extends property');
expect(assertValidRuleset.bind(null, { rule: {} })).toThrow('Ruleset must have rules or extends property');
});

it('given object with extends property only should emit no errors', () => {
expect(assertValidRuleset.bind(null, { extends: [] })).not.toThrow();
});

it('given object with rules property only should emit no errors', () => {
expect(assertValidRuleset.bind(null, { rules: {} })).not.toThrow();
});

it('given invalid ruleset should throw', () => {
Expand Down
5 changes: 4 additions & 1 deletion src/rulesets/reader.ts
Expand Up @@ -102,7 +102,10 @@ const createRulesetProcessor = (
}
}

mergeRules(rules, ruleset.rules, severity === undefined ? 'recommended' : severity);
if (ruleset.rules !== void 0) {
mergeRules(rules, ruleset.rules, severity === undefined ? 'recommended' : severity);
}

if (Array.isArray(ruleset.formats)) {
mergeFormats(rules, ruleset.formats);
}
Expand Down
7 changes: 4 additions & 3 deletions src/rulesets/validation.ts
Expand Up @@ -6,6 +6,7 @@ const AJV = require('ajv');
import * as ruleSchema from '../meta/rule.schema.json';
import * as rulesetSchema from '../meta/ruleset.schema.json';
import { IFunction, IFunctionPaths, IFunctionValues, Rule } from '../types';
import { isObject } from '../utils';

const ajv = new AJV({ allErrors: true, jsonPointers: true });
const validate = ajv.addSchema(ruleSchema).compile(rulesetSchema);
Expand All @@ -23,12 +24,12 @@ export class ValidationError extends AJV.ValidationError {
}

export function assertValidRuleset(ruleset: unknown): IRulesetFile {
if (ruleset === null || typeof ruleset !== 'object') {
if (!isObject(ruleset)) {
throw new Error('Provided ruleset is not an object');
}

if (!('rules' in ruleset!)) {
throw new Error('Ruleset must have rules property');
if (!('rules' in ruleset) && !('extends' in ruleset)) {
throw new Error('Ruleset must have rules or extends property');
}

if (!validate(ruleset)) {
Expand Down
2 changes: 1 addition & 1 deletion src/types/ruleset.ts
Expand Up @@ -28,7 +28,7 @@ export interface IRuleset {
export interface IRulesetFile {
extends?: Array<string | [string, FileRulesetSeverity]>;
formats?: string[];
rules: FileRuleCollection;
rules?: FileRuleCollection;
functionsDir?: string;
functions?: Array<string | [string, JSONSchema4 | JSONSchema6 | JSONSchema7]>;
}

0 comments on commit 4de9dd2

Please sign in to comment.