Test Report

0
0
29
345

ID Title Duration (ms)
1 Configue Options Resolving resolve from a callback 93
2 Configue Options Resolving resolve from a promise 11
3 Configue Options Resolving resolve is executed once 13
4 Configue Options Schema detect wrong option item 2
5 Configue Options Getter get value 4
6 Configue Options Getter get nested value 6
7 Configue Options Getter get defaultValue 4
8 Configue Options Getter get defaultValue if result is set undefined 6
9 Configue Options Options argv are forwarded to nconf 9
10 Configue Options Options env are forwarded to nconf 5
11 Configue Options Files can load data from a json file given as string 10
12 Configue Options Files can load data from a json files given as string array 5
13 Configue Options Files can load data from a json file 4
14 Configue Options Files can load data from a yaml file 68
15 Configue Options Files files are loaded in order 5
16 Configue Options Files can load a default file 9
17 Configue Options Files defaults are loaded in order 4
18 Configue Options Disable enable to disable argv 4
19 Configue Options Post Hooks enable to insert hook 5
20 Configue Options Post Hooks handle error in loading process 3
21 Configue Options CustomWorkflow accept a custom workflow 1
22 Fluent builder get is working fine as factory method 1
23 Fluent builder get is reseting the chain 1
24 Fluent builder options methods sets the good values 1
25 Fluent builder options methods sets the good values 2
26 Hapi plugin Register expose configue handler 23
27 Hapi plugin Register take care to do the resolve 13
28 Hapi plugin Register handle failure in the resolve 7
29 Hapi plugin Request has access to configue 21

Code Coverage Report

100%
147
147
0

lib/configue.js

100%
147
147
0
Line Lint Hits Source
1 'use strict';
2
3 1 const Hoek = require('hoek');
4 1 const Joi = require('joi');
5 1 const Async = require('async');
6 1 const _ = require('lodash');
7 1 const Promise = require('bluebird');
8
9 /**
10 * Plugin Internals
11 * @type {Object}
12 */
13 1 const internals = {};
14
15 // TODO: maybe options
16 1 internals.Configue = module.exports = function Configue(options) {
17 if (!(this instanceof Configue)) {
18 25 return new Configue(options);
19 }
20
21 // load fresh instance of nconf
22 30 delete require.cache[require.resolve('nconf')];
23
24 30 const nconf = internals.nconf = this.nconf = require('nconf');
25 30 const settings = this.settings = Hoek.cloneWithShallow(options, 'provider') || {};
26 30 this.resolved = false;
27
28 30 const results = Joi.validate(settings, internals.schema);
29 31 if (results.error) throw results.error;
30
31 29 nconf.use('memory');
32 29 nconf.clear();
33 }
34
35 // Fluent builder
36 1 const Configue = internals.Configue;
37 1 Configue._options = {};
38 1 ['files', 'defaults', 'disable', 'env', 'argv', 'customWorkflow'].forEach(option => {
39 3 Configue[option] = (opt) => { Configue._options[option] = opt; return Configue; };
40 });
41 1 ['overrides', 'argv', 'env', 'files', 'defaults'].forEach(hook => {
42 2 Configue[hook + 'Hook'] = (opt) => { _.set(Configue._options, `postHooks.${hook}`, opt); return Configue; };
43 });
44 11 Configue.get = () => { const c = new Configue(Configue._options); Configue._options = {} ; return c; };
45
46
47 1 internals.Configue.prototype.resolve = function (callback) {
48 if (callback === undefined) {
49 3 return Promise.fromCallback(callback => _resolve(this, callback))
50 }
51 22 _resolve(this, callback)
52 }
53
54 1 const _resolve = (self, callback) => {
55 1 if (self.resolved) callback()
56
57 25 const markAsDone = (cb) => (err, res) => {
58 self.resolved = true;
59 25 cb(err, res)
60 }
61 25 if (self.settings.customWorkflow)
62 2 self.settings.customWorkflow(self.nconf, markAsDone(callback));
63 23 else internals.applyDefaultWorkflow(self.nconf, self.settings, markAsDone(callback));
64 }
65
66 1 internals.Configue.prototype.get = function get(key, defaultValue) {
67 const result = this.nconf.get(key);
68 27 return result === undefined ? defaultValue : result;
69 }
70
71 /**
72 * Register the <tt>Configue</tt> plugin and process the various steps and hooks
73 * @param server - Hapi server to configure
74 * @param options - options of the Configue Plugin
75 * @param next - plugin continuation
76 */
77 1 const hapiPlugin = internals.Configue.prototype.plugin = function () {
78 const configue = this;
79 4 const plugin = function plugin(server, options, next) {
80 const configure = (err) => {
81 1 if(err) return next(err);
82 3 server.log(['plugin', 'info'], "Registering the configue has decoration");
83 3 const configGetter = configue.get.bind(configue);
84 3 server.decorate('server', 'configue', configGetter);
85 3 server.decorate('request', 'configue', configGetter);
86 3 next()
87 }
88 6 if(configue.resolved) configure()
89 2 else configue.resolve(configure)
90
91
92 }
93 4 plugin.attributes = hapiPlugin.attributes;
94 4 return plugin;
95 };
96
97 1 hapiPlugin.attributes = {
98 pkg: require('../package.json')
99 };
100
101
102 /**
103 * Joi options schema
104 */
105 1 internals.schema = [
106 Joi.object({customWorkflow: Joi.func()}),
107 Joi.object().keys({
108 disable: Joi.object({
109 argv: Joi.boolean(),
110 env: Joi.boolean()
111 }),
112 argv: [Joi.object()],
113 env: [Joi.object(), Joi.array().items(Joi.string()), Joi.string()],
114
115 files: [Joi.string(),
116 Joi.array().items(Joi.object({
117 file: Joi.string().required(),
118 format: Joi.object({stringify: Joi.func(), parse: Joi.func()})
119 })),
120 Joi.array().items(Joi.string())],
121 defaults: [Joi.object(),
122 Joi.array().items(Joi.object())],
123 postHooks: Joi.object({
124 overrides: Joi.func(),
125 argv: Joi.func(),
126 env: Joi.func(),
127 files: Joi.func(),
128 defaults: Joi.func()
129 })
130 })];
131
132 /**
133 * Apply the Default Configuration Workflow
134 * @param nconf - the nconf object
135 * @param settings - plugin config
136 * @param next - callback
137 */
138 1 internals.applyDefaultWorkflow = function applyDefaultWorkflow(nconf, settings, next) {
139 const hooks = settings.postHooks;
140
141 // Load eventual overrides values and then iterates over the different steps (in order: argv, env, files, default)
142 23 return Async.series([
143 this.processHook(hooks, 'overrides'),
144 this.iterateSteps(this.steps, settings)
145 ], next);
146 };
147
148 /**
149 * Iterate asynchronously over the various steps
150 * @param steps - list of configuration steps
151 * @param settings - project settings
152 * @returns {Function}
153 */
154 1 internals.iterateSteps = function iterateSteps(steps, settings) {
155 const hooks = settings.postHooks;
156 23 return (next) => {
157 return Async.eachOfSeries(steps, (stepName, key, done) => {
158 this.stepActions[stepName](settings);
159 89 if (hooks && hooks[stepName])
160 3 this.executePostHook(hooks[stepName], done);
161 86 else done();
162 }, next)
163 };
164 };
165
166 /**
167 * Ordered list of configuration steps
168 * @type {string[]}
169 */
170 1 internals.steps = ['argv', 'env', 'files', 'defaults'];
171 // Definition of associated actions below
172
173 /**
174 * Closure that takes the name of a nconf resource as a parameters and
175 * loads it if it is not disabled in the plugin options
176 *
177 * @param resource - the ressource to be loaded. (argv, env, files...)
178 * @returns {Function}
179 */
180 1 internals.load = function load(resource) {
181 return function onResource(options) {
182 if (!options.disable || ! options.disable[resource]) {
183 44 return internals.nconf[resource](options[resource]);
184 }
185 }
186 };
187
188 /**
189 * Process the hook for a given step
190 * @param hooks
191 * @param stepName
192 * @returns {Function}
193 */
194 1 internals.processHook = function processHook(hooks, stepName) {
195 return (done) => {
196 if (hooks && hooks[stepName])
197 1 this.executePostHook(hooks[stepName], done);
198 22 else done();
199 };
200 };
201
202 /**
203 * Execute a hook
204 * @param hook - a post step hook
205 * @param done - callback
206 */
207 1 internals.executePostHook = function executeHook(hook, done) {
208 return hook(internals.nconf, done);
209 };
210
211 /**
212 * Load the files in options using <tt>nconf.file</tt>
213 * @param options - plugin options
214 */
215 1 internals.loadFiles = function loadFiles(options) {
216 const files = options.files;
217 22 if (Array.isArray(files) && files.length) {
218 4 files.forEach((file) => internals.nconf.file((typeof files[0] === 'string') ? file : file.file, file));
219 // file(.file) is used as namespace for nconf
220 18 } else if (typeof files === 'string' && files.length)
221 1 internals.nconf.file(files);
222 };
223
224 /**
225 * Load the defaults in options using <tt>nconf.defaults</tt>
226 * @param options - plugin options
227 */
228 1 internals.loadDefaults = function loadDefaults(options) {
229 const defaults = options.defaults;
230 22 internals.nconf.defaults(Array.isArray(defaults) ? _.defaults.apply({}, defaults) : defaults);
231 };
232
233 /**
234 * Steps and their associated action function
235 * @type {{argv: Function, env: Function, files: loadFiles}}
236 */
237 1 internals.stepActions = {
238 argv: internals.load('argv'),
239 env: internals.load('env'),
240 files: internals.loadFiles,
241 defaults: internals.loadDefaults
242 };

Linting Report

Nothing to show here, linting is disabled.