Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Commit

Permalink
Configuration: add ability to load external presets
Browse files Browse the repository at this point in the history
Fixes #109
Closes #1083
  • Loading branch information
markelog committed Jul 8, 2015
1 parent 87956be commit 7246452
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 19 deletions.
46 changes: 36 additions & 10 deletions lib/config/configuration.js
Expand Up @@ -62,6 +62,7 @@ Configuration.prototype.load = function(config) {
var ruleSettings = this._processConfig(currentConfig);

this._loadRules(ruleSettings);
this._useRules();
};

/**
Expand Down Expand Up @@ -372,23 +373,39 @@ Configuration.prototype._loadPlugin = function(plugin) {
* @protected
*/
Configuration.prototype._loadRules = function(ruleSettings) {
this._configuredRules = [];

Object.keys(ruleSettings).forEach(function(optionName) {
var rule = this._rules[optionName];
if (rule) {
if (this._rules[optionName]) {
var optionValue = ruleSettings[optionName];
if (optionValue !== null) {
rule.configure(ruleSettings[optionName]);
this._configuredRules.push(rule);
this._ruleSettings[optionName] = ruleSettings[optionName];

this._ruleSettings[optionName] = ruleSettings[optionName]
}
} else {
if (!~this._unsupportedRuleNames.indexOf(optionName)) {
this._unsupportedRuleNames.push(optionName);
} else {
delete this._ruleSettings[optionName];
}

} else if (this._unsupportedRuleNames.indexOf(optionName) === -1) {
this._unsupportedRuleNames.push(optionName);
}

}, this);
}
};

/**
* Apply the rules
* @protected
*/
Configuration.prototype._useRules = function() {
this._configuredRules = [];

Object.keys(this._ruleSettings).forEach(function(optionName) {
var rule = this._rules[optionName];
rule.configure(this._ruleSettings[optionName]);
this._configuredRules.push(rule);

}, this);
};

/**
* Loads an error filter.
Expand Down Expand Up @@ -577,6 +594,15 @@ Configuration.prototype.hasPreset = function(presetName) {
return this._presets.hasOwnProperty(presetName);
};

/**
* Returns name of the active preset.
*
* @return {String}
*/
Configuration.prototype.getPresetName = function() {
return this._presetName;
};

/**
* Registers built-in Code Style cheking rules.
*/
Expand Down
26 changes: 25 additions & 1 deletion lib/config/node-configuration.js
Expand Up @@ -82,6 +82,30 @@ NodeConfiguration.prototype._loadPlugin = function(plugin) {
return Configuration.prototype._loadPlugin.call(this, plugin);
};

/**
* Loads preset.
*
* @param {String|null} preset
* @private
*/
NodeConfiguration.prototype._loadPreset = function(preset) {
var registeredPresets = this.getRegisteredPresets();

if (preset in registeredPresets) {
Configuration.prototype._loadPreset.call(this, preset);

} else {
var name = path.basename(preset).split('.')[0];

// Suppress it, since missing preset error will be handled by the caller
try {
this.registerPreset(name, this.loadExternal(preset, 'preset'));
} catch (e) {}

Configuration.prototype._loadPreset.call(this, name);
}
};

/**
* Loads an error filter module.
*
Expand Down Expand Up @@ -116,7 +140,7 @@ NodeConfiguration.prototype._loadEsprima = function(esprima) {
*/
NodeConfiguration.prototype._loadAdditionalRule = function(additionalRule) {
if (typeof additionalRule === 'string') {
if(glob.hasMagic(additionalRule)) {
if (glob.hasMagic(additionalRule)) {
glob.sync(path.resolve(this._basePath, additionalRule)).forEach(function(path) {
var Rule = require(path);
Configuration.prototype._loadAdditionalRule.call(this, new Rule());
Expand Down
2 changes: 1 addition & 1 deletion test/specs/cli.js
Expand Up @@ -81,7 +81,7 @@ describe('modules/cli', function() {
preset: 'not-exist'
});

return result.promise.fail(function() {
return result.promise.always(function() {
assert.equal(console.error.getCall(0).args[0], 'Preset "not-exist" does not exist');
console.error.restore();
});
Expand Down
23 changes: 20 additions & 3 deletions test/specs/config/configuration.js
Expand Up @@ -38,6 +38,10 @@ describe('modules/config/configuration', function() {
it('should have no default maximal error count', function() {
assert(configuration.getMaxErrors() === null);
});

it('should have no default preset', function() {
assert(configuration.getPresetName() === null);
});
});

describe('registerRule', function() {
Expand Down Expand Up @@ -363,9 +367,23 @@ describe('modules/config/configuration', function() {
assert(configuration.getProcessedConfig().preset === 'test2');
assert(configuration.getProcessedConfig().maxErrors === 1);
assert(configuration.getProcessedConfig().es3);

assert(configuration.getConfiguredRules()[0].exceptUndefined);
});

it('should load nullify rule from the preset', function() {
configuration.registerDefaultRules();
configuration.registerPreset('test', {
disallowMultipleVarDecl: true
});
configuration.load({
preset: 'test',
disallowMultipleVarDecl: null
});
assert(configuration.getProcessedConfig().preset === 'test');
assert.equal(configuration.getConfiguredRules().length, 0);
});

it('should not add duplicative values to list of unsupported rules', function() {
configuration.registerPreset('test1', {
es3: true,
Expand Down Expand Up @@ -412,15 +430,14 @@ describe('modules/config/configuration', function() {

it('should handle preset with custom rule which is not included', function() {
configuration.registerPreset('test', {
es3: true,
ruleName: 'test',
ruleName: 'test'
});

configuration.load({
preset: 'test'
});

assert(configuration.getUnsupportedRuleNames()[ 0 ], 'ruleName')
assert(configuration.getUnsupportedRuleNames()[ 0 ], 'ruleName');
assert(!('ruleName' in configuration.getProcessedConfig()));
});

Expand Down
72 changes: 68 additions & 4 deletions test/specs/config/node-configuration.js
Expand Up @@ -22,7 +22,7 @@ describe('modules/config/node-configuration', function() {
it('should check type', function() {
assert.throws(
configuration.loadExternal.bind(configuration, 'test', 1),
"test option requires a string or null value"
'test option requires a string or null value'
);
});

Expand All @@ -33,7 +33,7 @@ describe('modules/config/node-configuration', function() {
it('should load relative path', function() {
assert.equal(
typeof configuration.loadExternal('./test/data/plugin/plugin'),
"function"
'function'
);
});

Expand All @@ -42,14 +42,14 @@ describe('modules/config/node-configuration', function() {
typeof configuration.loadExternal(
path.resolve('./test/data/plugin/plugin')
),
"function"
'function'
);
});

it('should load node module', function() {
assert.equal(
typeof configuration.loadExternal('path'),
"object"
'object'
);
});
});
Expand Down Expand Up @@ -90,6 +90,70 @@ describe('modules/config/node-configuration', function() {
});

describe('load', function() {
it('should load existed preset', function() {
configuration.registerDefaultRules();
configuration.registerPreset('test', {
disallowMultipleVarDecl: 'exceptUndefined'
});
configuration.load({preset: 'test'});

assert(configuration.getRegisteredRules()[0].getOptionName(), 'exceptUndefined');
});

it('should load external preset', function() {
configuration.registerDefaultRules();

configuration.load({
preset: path.resolve(__dirname + '/../../../presets/jquery.json')
});

assert.equal(
configuration.getRegisteredRules()[0].getOptionName(),
'requireCurlyBraces'
);
assert.equal(configuration.getPresetName(), 'jquery');
});

it('should try to load preset from node', function() {
configuration.registerDefaultRules();
configuration.load({
preset: 'path'
});

assert.equal(configuration.getPresetName(), 'path');
assert(configuration.getUnsupportedRuleNames().indexOf('resolve') > -1);
});

it('should try to load preset from node_modules', function() {
configuration.registerDefaultRules();
configuration.load({
preset: 'sinon'
});

assert.equal(configuration.getPresetName(), 'sinon');
assert(configuration.getUnsupportedRuleNames().indexOf('spy') > -1);
});

it('should throw if preset is missing', function() {
configuration.registerDefaultRules();
assert.throws(
configuration.load.bind(configuration, {
preset: 'not-exist'
}),
'Preset "not-exist" does not exist'
);
});

it('should try to load preset from node_modules', function() {
configuration.registerDefaultRules();
configuration.load({
preset: 'sinon'
});

assert.equal(configuration.getPresetName(), 'sinon');
assert(configuration.getUnsupportedRuleNames().indexOf('spy') > -1);
});

it('should accept `additionalRules` to register rule instances', function() {
var rule = {
getOptionName: function() {
Expand Down

3 comments on commit 7246452

@hzoo
Copy link
Member

@hzoo hzoo commented on 7246452 Jul 9, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have docs for any of the new features/functionality?

@markelog
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly this commit, didn't change that much, only made behaviour of external entities more logical, current documentation still applies.

At the release time however, i will go through all commits and update relevant parts of the documentation if necessary.

@hzoo
Copy link
Member

@hzoo hzoo commented on 7246452 Jul 9, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows you to use your own or others presets from like npm right? I don't think we had any docs on that?

Please sign in to comment.