UNPKG

2.35 kBJavaScriptView Raw
1var N = require('libnested')
2
3var isModule = require('./is')
4var assertGiven = require('./assertGiven')
5var getNeeded = require('./entry')
6
7module.exports = function combine () {
8 var nestedModules = Array.prototype.slice.call(arguments)
9 var modules = flattenNested(nestedModules)
10
11 assertDependencies(modules)
12
13 var combinedModules = {}
14
15 for (var key in modules) {
16 var module = modules[key]
17 var needed = getNeeded(combinedModules, module.needs)
18 var given = module.create(needed)
19
20 assertGiven(module.gives, given, key)
21
22 addGivenToCombined(given, combinedModules, module)
23 }
24
25 if (isEmpty(combinedModules)) {
26 throw new Error('could not resolve any modules')
27 }
28
29 return combinedModules
30}
31
32function isString (s) {
33 return typeof s === 'string'
34}
35
36function isEmpty (e) {
37 for (var k in e) return false
38 return true
39}
40
41function isObject (o) {
42 return o && typeof o === 'object'
43}
44
45function append (obj, path, value) {
46 var a = N.get(obj, path)
47 if (!a) N.set(obj, path, a = [])
48 a.push(value)
49}
50
51function flattenNested (modules) {
52 return modules.reduce(function (a, b) {
53 eachModule(b, function (value, path) {
54 var k = path.join('/')
55 a[k] = value
56 })
57 return a
58 }, {})
59}
60
61function assertDependencies (modules) {
62 var allNeeds = {}
63 var allGives = {}
64
65 for (var key in modules) {
66 var module = modules[key]
67 N.each(module.needs, function (v, path) {
68 N.set(allNeeds, path, key)
69 })
70 if (isString(module.gives)) {
71 N.set(allGives, [module.gives], true)
72 } else {
73 N.each(module.gives, function (v, path) {
74 N.set(allGives, path, true)
75 })
76 }
77 }
78
79 N.each(allNeeds, function (key, path) {
80 if (!N.get(allGives, path)) { throw new Error('unmet need: `' + path.join('.') + '`, needed by module ' + ((isNaN(key)) ? '`' + key + '`' : '')) }
81 })
82}
83
84function addGivenToCombined (given, combined, module) {
85 if (isString(module.gives)) {
86 append(combined, [module.gives], given)
87 } else {
88 N.each(module.gives, function (_, path) {
89 var fun = N.get(given, path)
90 append(combined, path, fun)
91 })
92 }
93}
94
95function eachModule (obj, iter, path) {
96 path = path || []
97 if (isModule(obj)) iter(obj, path.concat(k))
98 for (var k in obj) {
99 if (isObject(obj[k])) {
100 eachModule(obj[k], iter, path.concat(k))
101 }
102 }
103}