stonyx 0.2.3-alpha.56 → 0.2.3-alpha.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/modules.js +78 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ stonyx test # Bootstrap + run tests
|
|
|
27
27
|
stonyx help # Show all available commands
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Stonyx reads `config/environment.ts` (preferred) or `config/environment.js`, initializes all `@stonyx/*` modules
|
|
30
|
+
Stonyx reads `config/environment.ts` (preferred) or `config/environment.js`, initializes all `@stonyx/*` modules declared in your `dependencies` or `devDependencies`, and runs your application.
|
|
31
31
|
|
|
32
32
|
## Documentation
|
|
33
33
|
|
package/dist/modules.js
CHANGED
|
@@ -18,8 +18,24 @@ function configureLog(chronicle, module, config) {
|
|
|
18
18
|
function initializeModule(moduleName, moduleClass, modules, initPromises) {
|
|
19
19
|
const moduleInstance = new moduleClass();
|
|
20
20
|
modules.push(moduleInstance);
|
|
21
|
-
|
|
21
|
+
// A module class with no `init()` has nothing to initialise, so it is ready
|
|
22
|
+
// the moment it is instantiated. Without this its registered promise dangles
|
|
23
|
+
// — the only resolve on this path lives inside the `init()` wrapper below,
|
|
24
|
+
// which is never created. Third of the three never-resolved paths named in
|
|
25
|
+
// #120, and the one that scoping registration to `discovered` does NOT close,
|
|
26
|
+
// because such a module IS discovered — measured, not reasoned: with only
|
|
27
|
+
// the registration fix applied the suite read 180/1 with T24 the sole
|
|
28
|
+
// failure. Resolving here is truthful, because the module really did load,
|
|
29
|
+
// and that is what separates it from resolving on a discovery `continue`,
|
|
30
|
+
// where there is no module to be ready.
|
|
31
|
+
//
|
|
32
|
+
// `?.` for the reason the resolve below carries it: `initializeModule` is
|
|
33
|
+
// also reached from the standalone path as `initializeModule(projectName, …)`,
|
|
34
|
+
// and `projectName` is never a key in `modulePromises`.
|
|
35
|
+
if (!moduleInstance.init) {
|
|
36
|
+
modulePromises[moduleName]?.resolve();
|
|
22
37
|
return;
|
|
38
|
+
}
|
|
23
39
|
initPromises.push((async () => {
|
|
24
40
|
await moduleInstance.init();
|
|
25
41
|
modulePromises[moduleName]?.resolve();
|
|
@@ -78,17 +94,35 @@ export default async function loadModules(config, rootPath, chronicle) {
|
|
|
78
94
|
const modules = [];
|
|
79
95
|
const initPromises = [];
|
|
80
96
|
const rootPackage = await readFile(`${rootPath}/package.json`, { json: true });
|
|
81
|
-
|
|
97
|
+
// DISCOVERY SOURCE (abofs/stonyx#106 rule 3).
|
|
98
|
+
//
|
|
99
|
+
// This local used to be named `dependencies` while holding `devDependencies`
|
|
100
|
+
// and nothing else. That name is the ruled root cause of #106: every reader
|
|
101
|
+
// of this function — including its own docs — believed discovery scanned
|
|
102
|
+
// both maps, because the identifier said so. It did not. An installed stonyx
|
|
103
|
+
// module declared in `dependencies` was invisible, which is precisely how the
|
|
104
|
+
// published fleet pins the core, so the loader could not see its own
|
|
105
|
+
// siblings.
|
|
106
|
+
//
|
|
107
|
+
// Rule 3 widens the source to the DE-DUPLICATED union of both maps. Object
|
|
108
|
+
// spread IS the de-duplication and is load-bearing: a module declared in both
|
|
109
|
+
// maps collapses to one key, so it is registered once and instantiated once.
|
|
110
|
+
// A bare `[ ...Object.keys(deps), ...Object.keys(devDeps) ]` concat produces a
|
|
111
|
+
// byte-identical suite aggregate while instantiating such a module twice and
|
|
112
|
+
// running its `init()` twice — T22's instance-count assertion owns that kill.
|
|
113
|
+
const declaredDependencies = {
|
|
114
|
+
...(rootPackage.dependencies || {}),
|
|
115
|
+
...(rootPackage.devDependencies || {}),
|
|
116
|
+
};
|
|
82
117
|
const projectName = typeof rootPackage.name === 'string' ? rootPackage.name : '';
|
|
83
118
|
// Expose rootPath to public configuration
|
|
84
119
|
config.rootPath = rootPath;
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
120
|
+
// The `@stonyx/` prefix filter STAYS (#106 keeps it explicitly). Widening it
|
|
121
|
+
// to `@` — or dropping it — makes the loader warn on every non-Stonyx
|
|
122
|
+
// dependency and leaves their `modulePromises` entries permanently
|
|
123
|
+
// unresolved. T3 owns that kill. What is a module is decided below, by the
|
|
124
|
+
// `stonyx-module` keyword; this is only a name test that bounds the scan.
|
|
125
|
+
const moduleDependencies = Object.keys(declaredDependencies).filter((moduleName) => moduleName.startsWith('@stonyx/'));
|
|
92
126
|
// DISCOVERY, hoisted above the pre-flight.
|
|
93
127
|
//
|
|
94
128
|
// The pre-flight must check exactly what the loader loads, and no more.
|
|
@@ -119,6 +153,41 @@ export default async function loadModules(config, rootPath, chronicle) {
|
|
|
119
153
|
keywords,
|
|
120
154
|
});
|
|
121
155
|
}
|
|
156
|
+
// Setup module promises prior to initialization — over `discovered`, NOT
|
|
157
|
+
// over `moduleDependencies`.
|
|
158
|
+
//
|
|
159
|
+
// This loop used to run above discovery and consume the declared list. That
|
|
160
|
+
// was already the shape at base, but rule 3 widened what the declared list
|
|
161
|
+
// contains, and the widening turned a fast named throw into an unbounded
|
|
162
|
+
// boot hang. A name registered here but never resolved leaves
|
|
163
|
+
// `waitForModule` pending forever; discovery `continue`s past two kinds of
|
|
164
|
+
// name without reaching either of this file's two resolve sites — a manifest
|
|
165
|
+
// that is not there, and a package without the `stonyx-module` keyword.
|
|
166
|
+
// `@stonyx/logs` ships without that keyword and is an ordinary `dependencies`
|
|
167
|
+
// entry, so this is a shape the fleet actually has.
|
|
168
|
+
//
|
|
169
|
+
// name in `dependencies`, not installed, another module awaits it
|
|
170
|
+
// base 5693744 throws "…was not registered in project dependencies", 3 ms
|
|
171
|
+
// a57045e one console.warn, then loadModules never settles
|
|
172
|
+
//
|
|
173
|
+
// Registering only what discovery admitted restores the fail-fast for both,
|
|
174
|
+
// and for `devDependencies`-declared names too — that half is INHERITED, not
|
|
175
|
+
// introduced here, and it is a real behaviour change: hang becomes throw.
|
|
176
|
+
// T13 pins it, and the PR body names it.
|
|
177
|
+
//
|
|
178
|
+
// The alternative — resolving in each `continue` branch — also removes the
|
|
179
|
+
// hang and is worse: `waitForModule` would report success for a module that
|
|
180
|
+
// was never loaded, silently. T23 asserts the named rejection precisely so
|
|
181
|
+
// that remedy cannot pass.
|
|
182
|
+
//
|
|
183
|
+
// Ordering is safe: nothing between here and the old site touches
|
|
184
|
+
// `modulePromises`, discovery only reads manifests, and registration still
|
|
185
|
+
// completes before the first `init()` can run.
|
|
186
|
+
for (const { name: moduleName } of discovered) {
|
|
187
|
+
const promise = {};
|
|
188
|
+
modulePromises[moduleName] = promise;
|
|
189
|
+
promise.ready = new Promise(resolve => promise.resolve = resolve);
|
|
190
|
+
}
|
|
122
191
|
// Pre-flight: invariant I1, "one core". Before ANY module entry point is
|
|
123
192
|
// imported, because the point of the check is the module that would NOT
|
|
124
193
|
// throw — it would load, initialise, and register its hooks on a second
|