-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
95 lines (81 loc) · 3.1 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
const f = require('lodash/fp');
const babylon = require('babylon');
const madge = require('madge');
const {
checkMissingDependencies,
checkCircularDependencies,
checkVoidModules,
} = require('./lib/checks');
const parseDependencies = (functionStr) => {
const parsed = babylon.parse(functionStr, {
sourceType: 'script' });
// get the first argument of the function, then get its desctructued properties
const properties = f.flow(
f.get('program.body.0.expression.params.0.properties'),
f.map('key.name')
)(parsed);
return properties;
};
// returns new modules hash
const createModule = (name, dependencyGraph, existingModules, moduleDefinitions) => {
// check if module already exists
const existingDependency = existingModules[name];
if (existingDependency) {
return existingModules;
}
// create dependencies recursively
const moduleDependencies = dependencyGraph[name];
const updatedDependencies = f.reduce(
(accumulatedModules, name) =>
f.assign(
accumulatedModules,
createModule(name, dependencyGraph, accumulatedModules, moduleDefinitions)
),
existingModules
)(moduleDependencies);
// create module
const createdModule = moduleDefinitions[name](updatedDependencies);
// return dependencies with new module
return f.assign(updatedDependencies, { [name]: createdModule });
};
const createAllModules = (dependencyGraph, existingModules, moduleDefinitions) => f.flow(
f.keys,
f.reduce(
(accumulatedModules, name) =>
createModule(name, dependencyGraph, accumulatedModules, moduleDefinitions),
existingModules
)
)(dependencyGraph);
const createProxy = (dependencies) => {
const proxyHandler = {
// prevent setting object properties
set(target, name) {
console.log(`dependencies cannot be set, tried to set dependency "${name}"`);
throw new Error('modifying dependency');
},
};
return new Proxy(dependencies, proxyHandler);
};
// TODO: use getters for lazy loading?
// TODO: test with existingModules
// TODO: use a prefix for all log messages
// TODO: rename modules, dependencies to ?
// TODO: tests!!
// TODO: readme
// TODO: review package dependencies (lodash)
// TODO: export dependency graph
// TODO: check wrong function signature (no destructuring, multiple args, ...)
module.exports = (moduleDefinitions, existingModules = {}) => {
const dependencyGraph = f.mapValues(
module => parseDependencies(module.toString())
)(moduleDefinitions);
checkMissingDependencies(moduleDefinitions, existingModules, dependencyGraph);
const graphDetails = madge(dependencyGraph);
checkCircularDependencies(graphDetails);
const createdModules = createAllModules(dependencyGraph, existingModules, moduleDefinitions);
checkVoidModules(createdModules, graphDetails);
// remove void modules from return
const availableModules = f.omitBy(module => module == null)(createdModules);
// return proxy
return createProxy(availableModules);
};