forked from caridy/es6-micro-loader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.js
116 lines (108 loc) · 3.24 KB
/
client.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
(function (exports) {
"use strict";
function normalizeName(child, parentBase) {
if (child.charAt(0) === "/") {
child = child.slice(1);
}
if (child.charAt(0) !== ".") {
return child;
}
var parts = child.split("/");
while (parts[0] === "." || parts[0] === "..") {
if (parts.shift() === "..") {
parentBase.pop();
}
}
return parentBase.concat(parts).join("/");
}
var seen = Object.create(null);
var internalRegistry = Object.create(null);
var externalRegistry = Object.create(null);
function ensuredExecute (name) {
var mod = internalRegistry[name];
if (mod && !seen[name]) {
seen[name] = true;
// one time operation to execute the module body
mod.execute();
}
return mod && mod.proxy;
}
function set (name, values) {
externalRegistry[name] = values;
}
function get (name) {
return externalRegistry[name] || ensuredExecute(name);
}
function has (name) {
return !!externalRegistry[name] || !!internalRegistry[name];
}
// exporting the System object
exports.System = {
set: set,
get: get,
has: has,
import: function(name) {
return new Promise(function (resolve, reject) {
var mod = get(normalizeName(name, []));
return mod ? resolve(mod) : reject(new Error("Could not find module " + name));
});
},
register: function (name, deps, wrapper) {
var proxy = Object.create(null),
values = Object.create(null),
mod, meta;
// creating a new entry in the internal registry
internalRegistry[name] = mod = {
// live bindings
proxy: proxy,
// exported values
values: values,
// normalized deps
deps: deps.map(function(dep) {
return normalizeName(dep, name.split("/").slice(0, -1));
}),
// other modules that depends on this so we can push updates into those modules
dependants: [],
// method used to push updates of deps into the module body
update: function(moduleName, moduleObj) {
meta.setters[mod.deps.indexOf(moduleName)](moduleObj);
},
execute: function () {
mod.deps.map(function(dep) {
var imports = externalRegistry[dep];
if (imports) {
mod.update(dep, imports);
} else {
imports = get(dep) && internalRegistry[dep].values; // optimization to pass plain values instead of bindings
if (imports) {
internalRegistry[dep].dependants.push(name);
mod.update(dep, imports);
}
}
});
meta.execute();
}
};
// collecting execute() and setters[]
meta = wrapper(function(identifier, value) {
values[identifier] = value;
mod.lock = true; // locking down the updates on the module to avoid infinite loop
mod.dependants.forEach(function(moduleName) {
if (internalRegistry[moduleName] && !internalRegistry[moduleName].lock) {
internalRegistry[moduleName].update(name, values);
}
});
mod.lock = false;
if (!Object.getOwnPropertyDescriptor(proxy, identifier)) {
Object.defineProperty(proxy, identifier, {
enumerable: true,
get: function() {
return values[identifier];
}
});
}
return value;
});
}
};
})(window);