forked from HeyPuter/puter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinit_sync.js
138 lines (118 loc) · 3.84 KB
/
init_sync.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
* @global
* @function logger
* @param {Array<any>} a - The arguments.
*/
/**
* @global
* @function use
* @param {string} arg - The string argument.
* @returns {any} The return value.
*/
/**
* @global
* @function def
* @param {any} arg - The argument.
* @returns {any} The return value.
*/
// An initial logger to log do before we get a more fancy logger
// (which we never really do yet, at the time of writing this);
// something like this was also done in backend and it proved useful.
(scope => {
globalThis.logger = {
info: (...a) => console.log('%c[INIT/INFO]', 'color: #4287f5', ...a),
};
})(globalThis);
logger.info('start -> blocking initialization');
// A global promise (like TeePromise, except we can't import anything yet)
// that will be resolved by `init_async.js` when it completes.
(scope => {
scope.init_promise = (() => {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
promise.resolve = resolve;
promise.reject = reject;
return promise;
})();
})(globalThis);
// This is where `use()` and `def()` are defined.
//
// A global registry for class definitions. This allows us to expose
// classes to service scripts even when the frontend code is bundled.
// Additionally, it allows us to create hooks upon class registration,
// which we use to turn classes which extend HTMLElement into components
// (i.e. give them tag names because that is required).
//
// It's worth noting `use()` and `def()` for service scripts is exposed
// in initgui.js, in the `launch_services()` function. (at the time this
// comment was written)
(scope => {
const registry_ = {
classes_m: {},
classes_l: [],
hooks_on_register: [],
};
const on_self_registered_api = {
on_other_registered: hook => registry_.hooks_on_register.push(hook),
}
scope.lib = {
is_subclass (subclass, superclass) {
if (subclass === superclass) return true;
let proto = subclass.prototype;
while (proto) {
if (proto === superclass.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
};
scope.def = (cls, id) => {
id = id || cls.ID;
if ( id === undefined ) {
throw new Error('Class must have an ID');
}
if ( registry_.classes_m[id] ) {
// throw new Error(`Class with ID ${id} already registered`);
return;
}
registry_.classes_m[id] = cls;
registry_.classes_l.push(cls);
registry_.hooks_on_register.forEach(hook => hook({ cls }));
console.log('registered class', id, registry_);
// Find class that owns 'on_self_registered' hook
let owner = cls;
while (
owner.__proto__ && owner.__proto__.on_self_registered
&& owner.__proto__.on_self_registered === cls.on_self_registered
) {
owner = owner.__proto__;
}
if ( cls.on_self_registered ) {
cls.on_self_registered.call(cls, {
...on_self_registered_api,
is_owner: cls === owner,
});
}
return cls;
};
scope.use = id => {
console.log('use called with id: ', id);
if ( id === undefined ) {
return registry_.classes_m;
}
if ( !registry_.classes_m[id] ) {
throw new Error(`Class with ID ${id} not registered`);
}
console.log(
'okay it\'s going to return:',
registry_.classes_m[id],
'and the entire map is this: ',
registry_.classes_m
)
return registry_.classes_m[id];
}
})(globalThis);
logger.info('end -> blocking initialization');