Skip to content
This repository has been archived by the owner on Jun 18, 2019. It is now read-only.

Commit

Permalink
feat(ConfigOptionsResolver): adds ConfigOptionsResolver to resolve …
Browse files Browse the repository at this point in the history
…`options`
  • Loading branch information
mdreizin authored Aug 8, 2016
1 parent 1426e96 commit cd1ded5
Show file tree
Hide file tree
Showing 35 changed files with 1,152 additions and 490 deletions.
148 changes: 66 additions & 82 deletions src/Config.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,104 @@
import {
isFunction,
isObject,
defaultsDeep,
mergeWith,
set,
unset,
get,
has
} from 'lodash';
import ConfigExtendTransform from './ConfigExtendTransform';
import ConfigDependency from './ConfigDependency';

/**
* @function
* @name ConfigTransform
* @param {Config} config
* @returns {*}
*/

/**
* @typedef {Object|ConfigTransform} ConfigDefaultsOptions
* @private
* @type {String}
*/
const DEPENDENCY_TREE = 'DEPENDENCY_TREE';

/**
* @typedef {Object|ConfigTransform} ConfigMergeOptions
* @private
* @type {WeakMap}
*/
const FACTORY = new WeakMap();

/**
* @typedef {String|Object<String,ConfigTransform>|Object<String,ConfigTransform[]>} ConfigExtendOptions
* @private
* @type {WeakMap}
*/
const DEFAULTS_COMMAND = new WeakMap();

/**
* @private
* @type {String}
* @type {WeakMap}
*/
const DEPENDENCY_TREE = 'DEPENDENCY_TREE';
const MERGE_COMMAND = new WeakMap();

/**
* @private
* @type {WeakMap}
*/
const LOADER = new WeakMap();
const EXTEND_COMMAND = new WeakMap();

/**
* @private
* @param {Object|Function} value
* @param {Config} context
* @returns {*}
* @param {Config} config
* @param {ConfigCommand} command
* @param {...*} values
* @returns {Config}
*/
const evalValue = (value, context) => isFunction(value) ? value.call(context, context) : value;
const executeCommand = (config, command, ...values) => {
for (const value of values) {
command.execute(config, value);
}

return config;
};

/**
* @class
*/
class Config {
/**
* @constructor
* @param {ConfigLoader} loader
* @param {ConfigFactory} factory
* @param {ConfigDefaultsCommand} defaultsCommand
* @param {ConfigMergeCommand} mergeCommand
* @param {ConfigExtendCommand} extendCommand
*/
constructor(loader) {
LOADER.set(this, loader);
constructor(factory, defaultsCommand, mergeCommand, extendCommand) {
FACTORY.set(this, factory);
DEFAULTS_COMMAND.set(this, defaultsCommand);
MERGE_COMMAND.set(this, mergeCommand);
EXTEND_COMMAND.set(this, extendCommand);
}

/**
* @protected
* @readonly
* @type {ConfigLoader}
* @type {ConfigFactory}
*/
get loader() {
return LOADER.get(this);
get factory() {
return FACTORY.get(this);
}

/**
* @readonly
* @type {ConfigDefaultsCommand}
*/
get defaultsCommand() {
return DEFAULTS_COMMAND.get(this);
}

/**
* @readonly
* @type {ConfigMergeCommand}
*/
get mergeCommand() {
return MERGE_COMMAND.get(this);
}

/**
* @readonly
* @type {ConfigExtendCommand}
*/
get extendCommand() {
return EXTEND_COMMAND.get(this);
}

/**
Expand Down Expand Up @@ -116,17 +146,11 @@ class Config {
* };
* });
* @description Adds `values` if they are missing
* @param {...ConfigDefaultsOptions} values
* @param {...ConfigOptions} values
* @returns {Config}
*/
defaults(...values) {
for (const value of Object.values(values)) {
const properties = evalValue(value, this);

defaultsDeep(this, properties);
}

return this;
return executeCommand(this, this.defaultsCommand, ...values);
}

/**
Expand All @@ -147,21 +171,11 @@ class Config {
* };
* });
* @description Merges `values`
* @param {...ConfigMergeOptions} values
* @param {...ConfigOptions} values
* @returns {Config}
*/
merge(...values) {
for (const value of Object.values(values)) {
const properties = evalValue(value, this);

mergeWith(this, properties, (x, y) => { // eslint-disable-line consistent-return
if (Array.isArray(x)) {
return x.concat(y);
}
});
}

return this;
return executeCommand(this, this.mergeCommand, ...values);
}

/**
Expand Down Expand Up @@ -204,41 +218,11 @@ class Config {
* }]
* });
* @description Helps to extend config using local file or shareable config file which should be hosted under `node_modules`
* @param {...ConfigExtendTransform} values
* @param {...ConfigExtendPossibleOptions} values
* @returns {Config}
*/
extend(...values) {
const map = ConfigExtendTransform.initWith(...values);

for (const [key, value] of map.entries()) {
const config = this.loader.loadConfig(key);

if (config instanceof Config) {
this.dependencyTree.children.push(config.dependencyTree);

let prevConfig = config.clone();

value.forEach(x => {
const currConfig = x.call(this, prevConfig);

if (!isObject(currConfig)) {
prevConfig = {};
} else {
prevConfig = currConfig;
}

if (!(prevConfig instanceof Config)) {
prevConfig = new Config(this.loader).merge(prevConfig);
}
});

if (prevConfig instanceof Config) {
this.merge(prevConfig.toObject());
}
}
}

return this;
return executeCommand(this, this.extendCommand, ...values);
}

/**
Expand All @@ -257,7 +241,7 @@ class Config {
* @returns {Config}
*/
clone() {
return new Config(this.loader).merge(this.toObject());
return new Config(this.factory, this.defaultsCommand, this.mergeCommand, this.extendCommand).merge(this.toObject());
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/ConfigBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class ConfigBuilder {
}

/**
* @private
* @readonly
* @type {ConfigFactory}
*/
Expand Down
21 changes: 21 additions & 0 deletions src/ConfigCleanupTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @private
* @type {String[]}
*/
const EXCLUDE_FIELDS = [
'filename',
'DEPENDENCY_TREE'
];

/**
* Removes system properties
* @param {Config} config
* @returns {Config}
*/
export default config => {
EXCLUDE_FIELDS.forEach(function(name) {
delete config[name];
});

return config;
};
35 changes: 35 additions & 0 deletions src/ConfigCommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @private
* @type {WeakMap}
*/
const OPTIONS_RESOLVER = new WeakMap();

/**
* @class
*/
class ConfigCommand {
/**
* @constructor
* @param {ConfigOptionsResolver} optionsResolver
*/
constructor(optionsResolver) {
OPTIONS_RESOLVER.set(this, optionsResolver);
}

/**
* @abstract
* @param {Config} config
* @param {ConfigOptions} options
* @returns {void}
*/
execute(config, options) {} // eslint-disable-line no-unused-vars

/**
* @type {ConfigOptionsResolver}
*/
get optionsResolver() {
return OPTIONS_RESOLVER.get(this);
}
}

export default ConfigCommand;
Loading

0 comments on commit cd1ded5

Please sign in to comment.