From 4b9610c09c7c6a0ca784db750e4a47c6499f8905 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Tue, 30 Mar 2021 13:27:13 -0700 Subject: [PATCH] add 'extends' property for extending ruleset --- lib/config.js | 28 ++++++++++++++++++++++++++-- rulesets/schema.json | 4 ++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/config.js b/lib/config.js index 645a118d..db25cece 100644 --- a/lib/config.js +++ b/lib/config.js @@ -6,6 +6,7 @@ const fetch = require('node-fetch') const findConfig = require('find-config') const fs = require('fs') const jsonfile = require('jsonfile') +const lodash = require('lodash') const path = require('path') const yaml = require('js-yaml') @@ -26,11 +27,12 @@ function isAbsoluteURL(url) { /** * Load a ruleset config from the specified location. * - * @param {string} configLocation A URL, file location, or directory containing a repolinter config file + * @param {string} [configLocation] A URL, file location, or directory containing a repolinter config file + * @param {array} [processed] list of config files already processed, used to prevent loops * @returns {Object} The loaded repolinter json config * @throws Will throw an error if unable to parse config or if config is invalid */ -async function loadConfig(configLocation) { +async function loadConfig(configLocation, processed = []) { if (configLocation == null) { throw new Error('must specify config location') } @@ -74,6 +76,28 @@ async function loadConfig(configLocation) { } } + // merge extended rulesets + if (ruleset.extends) { + processed.push(configLocation) + if (processed.length > 20) { + // safeguard against infinite loops. expose as flag one day if needed + throw new Error('exceeded maximum 20 ruleset extensions') + } + + let parent + if (isAbsoluteURL(ruleset.extends)) { + parent = ruleset.extends + } else if (isAbsoluteURL(configLocation)) { + parent = new URL(ruleset.extends, configLocation) + } else { + parent = path.resolve(path.dirname(configLocation), ruleset.extends) + } + if (!processed.includes(parent)) { + const parentRuleset = await loadConfig(parent, processed) + ruleset = lodash.merge({}, parentRuleset, ruleset) + } + } + return ruleset } diff --git a/rulesets/schema.json b/rulesets/schema.json index 9e4a176e..8a9922b6 100644 --- a/rulesets/schema.json +++ b/rulesets/schema.json @@ -14,6 +14,10 @@ "properties": { "$schema": { "type": "string" }, "version": { "const": 2 }, + "extends": { + "type": "string", + "title": "URL or path of ruleset file this ruleset extends" + }, "axioms": { "type": "object", "title": "The axioms schema",