jseption 0.0.3 → 0.0.5
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 +112 -4
- package/dist/bytecode.js +162 -2
- package/dist/bytecode.js.map +1 -1
- package/dist/embed.d.ts +5 -0
- package/dist/embed.js +44 -12
- package/dist/embed.js.map +1 -1
- package/dist/interpreter.js +15 -4
- package/dist/interpreter.js.map +1 -1
- package/dist/jit.js +12 -4
- package/dist/jit.js.map +1 -1
- package/dist/jit_runtime.d.ts +2 -0
- package/dist/jit_runtime.js +11 -0
- package/dist/jit_runtime.js.map +1 -1
- package/dist/jseption.d.ts +6 -0
- package/dist/jseption.js +4 -0
- package/dist/jseption.js.map +1 -1
- package/dist/membrane.d.ts +16 -0
- package/dist/membrane.js +576 -0
- package/dist/membrane.js.map +1 -0
- package/dist/module.d.ts +28 -0
- package/dist/module.js +1166 -0
- package/dist/module.js.map +1 -0
- package/dist/opcodes.js +1 -1
- package/dist/opcodes.js.map +1 -1
- package/dist/parser.d.ts +31 -0
- package/dist/parser.js +2862 -62
- package/dist/parser.js.map +1 -1
- package/dist/qjs.js +86 -17
- package/dist/qjs.js.map +1 -1
- package/dist/quickjs.d.ts +8 -0
- package/dist/quickjs.js +21 -2
- package/dist/quickjs.js.map +1 -1
- package/dist/std.d.ts +2 -0
- package/dist/std.js +34 -0
- package/dist/std.js.map +1 -1
- package/dist/values.d.ts +78 -0
- package/dist/values.js +85 -0
- package/dist/values.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/module.js
ADDED
|
@@ -0,0 +1,1166 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ES modules: loading, linking, evaluation (with top-level await), module
|
|
3
|
+
* namespace objects, dynamic import() and import.meta.
|
|
4
|
+
*
|
|
5
|
+
* Ported from quickjs.c (js_create_module_function, js_inner_module_linking,
|
|
6
|
+
* js_resolve_export, js_build_module_ns, js_inner_module_evaluation,
|
|
7
|
+
* js_async_module_execution_fulfilled/rejected, js_dynamic_import), with one
|
|
8
|
+
* change of shape: QuickJS asks a synchronous loader for each module while it
|
|
9
|
+
* resolves the graph, but a browser fetches asynchronously, so here the whole
|
|
10
|
+
* graph is fetched first (in parallel where the loader allows), and linking and
|
|
11
|
+
* evaluation run once every module is there. A loader that answers
|
|
12
|
+
* synchronously makes the whole sequence synchronous.
|
|
13
|
+
*
|
|
14
|
+
* The sandbox stays closed by default: with no loader set, nothing can be
|
|
15
|
+
* imported. The embedder's loader decides what a specifier means.
|
|
16
|
+
*/
|
|
17
|
+
import { JS_EXCEPTION, JS_UNINITIALIZED, JS_IsException, JS_IsObject, JS_NewAtom, JS_AtomGetStr, JS_Call, JS_NewCFunction, JS_EnqueueJob, JS_ToString, JS_Throw, JS_ThrowTypeError, JS_ThrowSyntaxError, JS_ThrowReferenceError, JS_NewObjectProto, JS_DefinePropertyValueStr, JS_GetPropertyStr, JS_GetFunctionData, js_take_exception, js_ensure_meta, js_host_exception_to_guest, hooks, JS_PROP_C_W_E, JS_ATOM_default, JS_ATOM__star_, JS_EVAL_TYPE_MODULE, JS_EVAL_FLAG_COMPILE_ONLY, JS_EVAL_FLAG_STRIP_TYPES, JS_EVAL_FLAG_JSX, } from "./quickjs.js";
|
|
18
|
+
import { JSModuleDef, JSExportEntry, JSFunctionBytecode, new_var_ref_cell, } from "./values.js";
|
|
19
|
+
import { js_closure_from_refs } from "./interpreter.js";
|
|
20
|
+
import { JS_NewPromiseCapability, JS_PromiseState, JS_PromiseResult, perform_promise_then } from "./builtins/promise.js";
|
|
21
|
+
import { JS_ParseJSON } from "./builtins/json.js";
|
|
22
|
+
import { toGuest, drainJobs } from "./embed.js";
|
|
23
|
+
/* the source type an id implies: .ts, .mts and .cts are TypeScript, .tsx TSX, .jsx JSX. When the
|
|
24
|
+
id is a URL (it has a scheme), its query and fragment are not part of the path, so
|
|
25
|
+
`https://app/App.tsx?v=3` and `file:///a.ts#x` are TSX and TypeScript; other ids (file paths)
|
|
26
|
+
are matched as they are, since `?` and `#` are ordinary characters there */
|
|
27
|
+
export function js_module_type_of(id) {
|
|
28
|
+
const path = /^[a-z][a-z0-9+.-]*:/i.test(id) ? id.replace(/[?#].*$/s, '') : id;
|
|
29
|
+
return /\.[mc]?ts$/.test(path) ? 'ts' : /\.tsx$/.test(path) ? 'tsx' : /\.jsx$/.test(path) ? 'jsx' : 'js';
|
|
30
|
+
}
|
|
31
|
+
/* the JS_Eval flags that compile a source type */
|
|
32
|
+
export function js_module_type_flags(type) {
|
|
33
|
+
return (type === 'ts' || type === 'tsx' ? JS_EVAL_FLAG_STRIP_TYPES : 0) | (type === 'jsx' || type === 'tsx' ? JS_EVAL_FLAG_JSX : 0);
|
|
34
|
+
}
|
|
35
|
+
/* Set (or clear, with null) the module loader of a runtime */
|
|
36
|
+
export function JS_SetModuleLoader(rt, loader) {
|
|
37
|
+
rt.module_loader = loader;
|
|
38
|
+
}
|
|
39
|
+
/* the default resolution: relative specifiers against the referrer, URL style */
|
|
40
|
+
export function js_default_module_resolve(specifier, referrer) {
|
|
41
|
+
if (!(specifier.startsWith('./') || specifier.startsWith('../') || specifier.startsWith('/')))
|
|
42
|
+
return specifier;
|
|
43
|
+
if (referrer === null)
|
|
44
|
+
return normalize_path(specifier);
|
|
45
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(referrer)) {
|
|
46
|
+
try {
|
|
47
|
+
return new URL(specifier, referrer).href;
|
|
48
|
+
}
|
|
49
|
+
catch { /* not a URL: fall through */ }
|
|
50
|
+
}
|
|
51
|
+
if (specifier.startsWith('/'))
|
|
52
|
+
return normalize_path(specifier);
|
|
53
|
+
const slash = referrer.lastIndexOf('/');
|
|
54
|
+
const dir = slash >= 0 ? referrer.slice(0, slash + 1) : '';
|
|
55
|
+
return normalize_path(dir + specifier);
|
|
56
|
+
}
|
|
57
|
+
/* collapse `.` and `..` segments of a path */
|
|
58
|
+
function normalize_path(path) {
|
|
59
|
+
const abs = path.startsWith('/');
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const seg of path.split('/')) {
|
|
62
|
+
if (seg === '' || seg === '.')
|
|
63
|
+
continue;
|
|
64
|
+
if (seg === '..') {
|
|
65
|
+
if (out.length > 0 && out[out.length - 1] !== '..')
|
|
66
|
+
out.pop();
|
|
67
|
+
else if (!abs)
|
|
68
|
+
out.push('..');
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
out.push(seg);
|
|
72
|
+
}
|
|
73
|
+
const r = out.join('/');
|
|
74
|
+
return abs ? '/' + r : r;
|
|
75
|
+
}
|
|
76
|
+
/* QuickJS's JS_DetectModule heuristic: after comments, the source starts with `export`, or
|
|
77
|
+
with `import` not followed by `(` or `.` */
|
|
78
|
+
export function JS_DetectModule(input) {
|
|
79
|
+
let p = 0;
|
|
80
|
+
const n = input.length;
|
|
81
|
+
if (input.startsWith('#!')) {
|
|
82
|
+
while (p < n && input[p] !== '\n')
|
|
83
|
+
p++;
|
|
84
|
+
}
|
|
85
|
+
const skip = () => {
|
|
86
|
+
for (;;) {
|
|
87
|
+
while (p < n && /\s/.test(input[p]))
|
|
88
|
+
p++;
|
|
89
|
+
if (input.startsWith('//', p)) {
|
|
90
|
+
while (p < n && input[p] !== '\n')
|
|
91
|
+
p++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (input.startsWith('/*', p)) {
|
|
95
|
+
const e = input.indexOf('*/', p + 2);
|
|
96
|
+
p = e < 0 ? n : e + 2;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const word = () => { const m = /^[A-Za-z_$][\w$]*/.exec(input.slice(p, p + 32)); return m ? m[0] : ''; };
|
|
103
|
+
skip();
|
|
104
|
+
const w = word();
|
|
105
|
+
if (w === 'export')
|
|
106
|
+
return true;
|
|
107
|
+
if (w !== 'import')
|
|
108
|
+
return false;
|
|
109
|
+
p += 6;
|
|
110
|
+
skip();
|
|
111
|
+
return !(input[p] === '(' || input[p] === '.');
|
|
112
|
+
}
|
|
113
|
+
/* ---------------------------------------------------------------------
|
|
114
|
+
Errors
|
|
115
|
+
--------------------------------------------------------------------- */
|
|
116
|
+
function throw_type_error(ctx, msg) {
|
|
117
|
+
JS_ThrowTypeError(ctx, msg);
|
|
118
|
+
return js_take_exception(ctx);
|
|
119
|
+
}
|
|
120
|
+
function throw_syntax_error(ctx, msg) {
|
|
121
|
+
JS_ThrowSyntaxError(ctx, msg);
|
|
122
|
+
return js_take_exception(ctx);
|
|
123
|
+
}
|
|
124
|
+
/* a value thrown by the embedder's loader, as a guest value */
|
|
125
|
+
function host_error_to_guest(ctx, e) {
|
|
126
|
+
try {
|
|
127
|
+
return toGuest(ctx, e);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return throw_type_error(ctx, String(e));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/* a value caught in this file, in the engine's convention: guest values pass through, host
|
|
134
|
+
errors become guest errors */
|
|
135
|
+
function caught(ctx, e) {
|
|
136
|
+
js_host_exception_to_guest(ctx, e);
|
|
137
|
+
return js_take_exception(ctx);
|
|
138
|
+
}
|
|
139
|
+
function mname(ctx, m) { return JS_AtomGetStr(ctx, m.module_name); }
|
|
140
|
+
/* ---------------------------------------------------------------------
|
|
141
|
+
Compiled modules
|
|
142
|
+
--------------------------------------------------------------------- */
|
|
143
|
+
/* every function of a module knows its module (import.meta, the referrer of import()) */
|
|
144
|
+
function js_mark_module_functions(b, m) {
|
|
145
|
+
b.module = m;
|
|
146
|
+
for (const c of b.cpool)
|
|
147
|
+
if (c instanceof JSFunctionBytecode)
|
|
148
|
+
js_mark_module_functions(c, m);
|
|
149
|
+
}
|
|
150
|
+
/* the module record of a compiled module body */
|
|
151
|
+
export function js_module_set_function(m, b) {
|
|
152
|
+
m.func_bytecode = b;
|
|
153
|
+
js_mark_module_functions(b, m);
|
|
154
|
+
}
|
|
155
|
+
/* called by the parser for JS_EVAL_TYPE_MODULE */
|
|
156
|
+
function js_module_compiled(ctx, m, b, flags) {
|
|
157
|
+
js_module_set_function(m, b);
|
|
158
|
+
if (flags & JS_EVAL_FLAG_COMPILE_ONLY)
|
|
159
|
+
return m;
|
|
160
|
+
return js_module_eval_function(ctx, m);
|
|
161
|
+
}
|
|
162
|
+
function module_key(id, kind) {
|
|
163
|
+
return kind === 'json' ? id + '\u0000json' : id;
|
|
164
|
+
}
|
|
165
|
+
/* register a root module (JS_Eval, JS_EvalFunction) under its name, if the name is free */
|
|
166
|
+
function js_register_module(ctx, m) {
|
|
167
|
+
const key = module_key(mname(ctx, m), m.kind === 1 /* JSModuleKind.JSON */ ? 'json' : 'js');
|
|
168
|
+
if (!ctx.module_map.has(key))
|
|
169
|
+
ctx.module_map.set(key, m);
|
|
170
|
+
}
|
|
171
|
+
/* a synthetic module (JSON or host values) with the given named exports */
|
|
172
|
+
function js_new_synthetic_module(ctx, id, kind, exports) {
|
|
173
|
+
const m = new JSModuleDef(JS_NewAtom(ctx, id));
|
|
174
|
+
m.kind = kind;
|
|
175
|
+
m.realm = ctx;
|
|
176
|
+
m.synthetic_exports = new Map();
|
|
177
|
+
for (const [name, v] of exports) {
|
|
178
|
+
const atom = JS_NewAtom(ctx, name);
|
|
179
|
+
m.export_entries.push(new JSExportEntry(atom, atom, 0 /* JSExportType.LOCAL */));
|
|
180
|
+
m.synthetic_exports.set(atom, v);
|
|
181
|
+
}
|
|
182
|
+
return m;
|
|
183
|
+
}
|
|
184
|
+
/* the module for what the loader returned; throws a guest value on failure */
|
|
185
|
+
function js_module_from_load_result(ctx, id, kind, r) {
|
|
186
|
+
let src;
|
|
187
|
+
if (typeof r === 'string')
|
|
188
|
+
src = { source: r };
|
|
189
|
+
else if (r instanceof Uint8Array)
|
|
190
|
+
src = { bytecode: r };
|
|
191
|
+
else if (r !== null && typeof r === 'object')
|
|
192
|
+
src = r;
|
|
193
|
+
else
|
|
194
|
+
throw throw_type_error(ctx, `the module loader returned no module for '${id}'`);
|
|
195
|
+
if (src.exports !== undefined) {
|
|
196
|
+
if (kind === 'json')
|
|
197
|
+
throw throw_type_error(ctx, `'${id}' is a host module, not a JSON module`);
|
|
198
|
+
const exports = new Map();
|
|
199
|
+
for (const k of Object.keys(src.exports)) {
|
|
200
|
+
try {
|
|
201
|
+
exports.set(k, toGuest(ctx, src.exports[k]));
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
throw host_error_to_guest(ctx, e);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const m = js_new_synthetic_module(ctx, id, 2 /* JSModuleKind.HOST */, exports);
|
|
208
|
+
m.url = src.url ?? null;
|
|
209
|
+
return m;
|
|
210
|
+
}
|
|
211
|
+
const type = src.type ?? (src.bytecode ? 'js' : js_module_type_of(id));
|
|
212
|
+
if (kind === 'json' || type === 'json') {
|
|
213
|
+
if (kind !== 'json')
|
|
214
|
+
throw throw_type_error(ctx, `'${id}' is a JSON module: import it with { type: "json" }`);
|
|
215
|
+
if (type !== 'json' && src.type !== undefined)
|
|
216
|
+
throw throw_type_error(ctx, `'${id}' is not a JSON module`);
|
|
217
|
+
if (typeof src.source !== 'string')
|
|
218
|
+
throw throw_type_error(ctx, `the module loader returned no JSON source for '${id}'`);
|
|
219
|
+
const v = JS_ParseJSON(ctx, src.source, id);
|
|
220
|
+
if (JS_IsException(v))
|
|
221
|
+
throw js_take_exception(ctx);
|
|
222
|
+
const m = js_new_synthetic_module(ctx, id, 1 /* JSModuleKind.JSON */, new Map([['default', v]]));
|
|
223
|
+
m.url = src.url ?? null;
|
|
224
|
+
return m;
|
|
225
|
+
}
|
|
226
|
+
let m;
|
|
227
|
+
if (src.bytecode !== undefined) {
|
|
228
|
+
const read = hooks_bytecode.read;
|
|
229
|
+
if (read === null)
|
|
230
|
+
throw throw_type_error(ctx, 'bytecode modules are not supported in this build');
|
|
231
|
+
const v = read(ctx, src.bytecode);
|
|
232
|
+
if (JS_IsException(v))
|
|
233
|
+
throw js_take_exception(ctx);
|
|
234
|
+
if (!(v instanceof JSModuleDef))
|
|
235
|
+
throw throw_type_error(ctx, `the bytecode for '${id}' is not a module`);
|
|
236
|
+
m = v;
|
|
237
|
+
/* the module takes the id it was loaded under */
|
|
238
|
+
m.module_name = JS_NewAtom(ctx, id);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
if (typeof src.source !== 'string')
|
|
242
|
+
throw throw_type_error(ctx, `the module loader returned no source for '${id}'`);
|
|
243
|
+
const flags = JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY | js_module_type_flags(type);
|
|
244
|
+
const v = hooks.JS_EvalInternal(ctx, undefined, src.source, id, flags, -1);
|
|
245
|
+
if (JS_IsException(v))
|
|
246
|
+
throw js_take_exception(ctx);
|
|
247
|
+
m = v;
|
|
248
|
+
}
|
|
249
|
+
m.url = src.url ?? null;
|
|
250
|
+
return m;
|
|
251
|
+
}
|
|
252
|
+
/* set by src/bytecode.ts: read a compiled module from bytes */
|
|
253
|
+
export const hooks_bytecode = { read: null };
|
|
254
|
+
/* the module type a request asks for, or a guest error */
|
|
255
|
+
function js_request_kind(ctx, attrs) {
|
|
256
|
+
if (attrs === null)
|
|
257
|
+
return 'js';
|
|
258
|
+
for (const k of Object.keys(attrs)) {
|
|
259
|
+
if (k !== 'type')
|
|
260
|
+
return throw_syntax_error(ctx, `unsupported import attribute '${k}'`);
|
|
261
|
+
}
|
|
262
|
+
const t = attrs.type;
|
|
263
|
+
if (t === undefined)
|
|
264
|
+
return 'js';
|
|
265
|
+
if (t === 'json')
|
|
266
|
+
return 'json';
|
|
267
|
+
return throw_type_error(ctx, `unsupported module type '${t}'`);
|
|
268
|
+
}
|
|
269
|
+
function js_resolve_specifier(ctx, specifier, referrer, attrs) {
|
|
270
|
+
const loader = ctx.rt.module_loader;
|
|
271
|
+
if (loader === null)
|
|
272
|
+
throw throw_type_error(ctx, `cannot import '${specifier}': no module loader is set`);
|
|
273
|
+
let id;
|
|
274
|
+
try {
|
|
275
|
+
id = loader.resolve ? loader.resolve(specifier, referrer, attrs) : js_default_module_resolve(specifier, referrer);
|
|
276
|
+
}
|
|
277
|
+
catch (e) {
|
|
278
|
+
throw host_error_to_guest(ctx, e);
|
|
279
|
+
}
|
|
280
|
+
if (typeof id !== 'string')
|
|
281
|
+
throw throw_type_error(ctx, `the module loader could not resolve '${specifier}'`);
|
|
282
|
+
return id;
|
|
283
|
+
}
|
|
284
|
+
/* the module for `id`: from the context's map, or fetched with the loader. `cb` runs once,
|
|
285
|
+
synchronously if the module is there or the loader answers synchronously */
|
|
286
|
+
function js_fetch_module(ctx, specifier, id, kind, attrs, cb) {
|
|
287
|
+
const key = module_key(id, kind);
|
|
288
|
+
const existing = ctx.module_map.get(key);
|
|
289
|
+
if (existing !== undefined) {
|
|
290
|
+
cb(undefined, existing);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const inflight = ctx.module_inflight.get(key);
|
|
294
|
+
if (inflight !== undefined) {
|
|
295
|
+
inflight.waiters.push(cb);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const loader = ctx.rt.module_loader;
|
|
299
|
+
if (loader === null) {
|
|
300
|
+
cb(throw_type_error(ctx, `cannot import '${specifier}': no module loader is set`), null);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const entry = { waiters: [cb] };
|
|
304
|
+
ctx.module_inflight.set(key, entry);
|
|
305
|
+
let is_async = false;
|
|
306
|
+
const settle = (err, m) => {
|
|
307
|
+
ctx.module_inflight.delete(key);
|
|
308
|
+
if (m !== null)
|
|
309
|
+
ctx.module_map.set(key, m);
|
|
310
|
+
for (const w of entry.waiters)
|
|
311
|
+
w(err, m);
|
|
312
|
+
/* a load that finished in a host callback: run the guest jobs it started */
|
|
313
|
+
if (is_async)
|
|
314
|
+
drainJobs(ctx);
|
|
315
|
+
};
|
|
316
|
+
const done = (r) => {
|
|
317
|
+
let m;
|
|
318
|
+
try {
|
|
319
|
+
m = js_module_from_load_result(ctx, id, kind, r);
|
|
320
|
+
}
|
|
321
|
+
catch (e) {
|
|
322
|
+
settle(caught(ctx, e), null);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
settle(undefined, m);
|
|
326
|
+
};
|
|
327
|
+
let r;
|
|
328
|
+
try {
|
|
329
|
+
r = loader.load(id, attrs);
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
settle(host_error_to_guest(ctx, e), null);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (r !== null && typeof r === 'object' && typeof r.then === 'function') {
|
|
336
|
+
is_async = true;
|
|
337
|
+
r.then(done, e => settle(host_error_to_guest(ctx, e), null));
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
done(r);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/* Make sure every request of `root`, transitively, has its module. `cb(err)` runs once; it
|
|
344
|
+
runs synchronously when every module was already loaded or loaded synchronously */
|
|
345
|
+
function js_load_graph(ctx, root, cb) {
|
|
346
|
+
let pending = 0;
|
|
347
|
+
let finished = false;
|
|
348
|
+
const visited = new Set();
|
|
349
|
+
const fail = (err) => { if (!finished) {
|
|
350
|
+
finished = true;
|
|
351
|
+
cb(err);
|
|
352
|
+
} };
|
|
353
|
+
const one_done = () => { if (--pending === 0 && !finished) {
|
|
354
|
+
finished = true;
|
|
355
|
+
cb(undefined);
|
|
356
|
+
} };
|
|
357
|
+
const visit = (m) => {
|
|
358
|
+
if (visited.has(m) || finished)
|
|
359
|
+
return;
|
|
360
|
+
visited.add(m);
|
|
361
|
+
const referrer = mname(ctx, m);
|
|
362
|
+
for (const rme of m.req_module_entries) {
|
|
363
|
+
if (finished)
|
|
364
|
+
return;
|
|
365
|
+
if (rme.module !== null) {
|
|
366
|
+
visit(rme.module);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const specifier = JS_AtomGetStr(ctx, rme.module_name);
|
|
370
|
+
const attrs = rme.attributes ?? {};
|
|
371
|
+
const kind = js_request_kind(ctx, rme.attributes);
|
|
372
|
+
if (kind !== 'js' && kind !== 'json') {
|
|
373
|
+
fail(kind);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
let id;
|
|
377
|
+
try {
|
|
378
|
+
id = js_resolve_specifier(ctx, specifier, referrer, attrs);
|
|
379
|
+
}
|
|
380
|
+
catch (e) {
|
|
381
|
+
fail(caught(ctx, e));
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
pending++;
|
|
385
|
+
js_fetch_module(ctx, specifier, id, kind, attrs, (err, m1) => {
|
|
386
|
+
if (finished)
|
|
387
|
+
return;
|
|
388
|
+
if (err !== undefined) {
|
|
389
|
+
fail(err);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
rme.module = m1;
|
|
393
|
+
visit(m1);
|
|
394
|
+
one_done();
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
pending++;
|
|
399
|
+
visit(root);
|
|
400
|
+
one_done();
|
|
401
|
+
}
|
|
402
|
+
/* ---------------------------------------------------------------------
|
|
403
|
+
Module functions and linking (js_create_module_function, js_link_module)
|
|
404
|
+
--------------------------------------------------------------------- */
|
|
405
|
+
function js_create_module_function(ctx, m) {
|
|
406
|
+
if (m.func_created)
|
|
407
|
+
return 0;
|
|
408
|
+
if (m.kind !== 0 /* JSModuleKind.JS */) {
|
|
409
|
+
/* initialize the exported variables */
|
|
410
|
+
for (const me of m.export_entries)
|
|
411
|
+
me.var_ref = new_var_ref_cell(undefined);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
const b = m.func_bytecode;
|
|
415
|
+
/* create the module variables; the other variables are imported from other modules */
|
|
416
|
+
const var_refs = b.closure_var.map(cv => cv.is_local ? new_var_ref_cell(cv.is_lexical ? JS_UNINITIALIZED : undefined) : null);
|
|
417
|
+
const proto = ctx.class_proto[48 /* JSClassID.ASYNC_FUNCTION */] ?? ctx.function_proto;
|
|
418
|
+
const f = js_closure_from_refs(ctx, b, var_refs, proto, false);
|
|
419
|
+
if (JS_IsException(f))
|
|
420
|
+
return -1;
|
|
421
|
+
m.func_obj = f;
|
|
422
|
+
}
|
|
423
|
+
m.func_created = true;
|
|
424
|
+
/* do it on the dependencies */
|
|
425
|
+
for (const rme of m.req_module_entries) {
|
|
426
|
+
if (js_create_module_function(ctx, rme.module) < 0)
|
|
427
|
+
return -1;
|
|
428
|
+
}
|
|
429
|
+
return 0;
|
|
430
|
+
}
|
|
431
|
+
function module_var_refs(m) {
|
|
432
|
+
return JS_GetFunctionData(m.func_obj).var_refs;
|
|
433
|
+
}
|
|
434
|
+
/* the variable of a local export */
|
|
435
|
+
function export_var_ref(m, me) {
|
|
436
|
+
if (me.var_ref === null)
|
|
437
|
+
me.var_ref = module_var_refs(m)[me.var_idx];
|
|
438
|
+
return me.var_ref;
|
|
439
|
+
}
|
|
440
|
+
function same_binding(a, b) {
|
|
441
|
+
if (a.ns !== null || b.ns !== null)
|
|
442
|
+
return a.ns === b.ns;
|
|
443
|
+
return a.module === b.module && a.me.var_idx === b.me.var_idx && a.me.local_name === b.me.local_name;
|
|
444
|
+
}
|
|
445
|
+
/* ResolveExport (js_resolve_export1) */
|
|
446
|
+
function js_resolve_export1(m, export_name, set, out) {
|
|
447
|
+
out.b = null;
|
|
448
|
+
let names = set.get(m);
|
|
449
|
+
if (names === undefined) {
|
|
450
|
+
names = new Set();
|
|
451
|
+
set.set(m, names);
|
|
452
|
+
}
|
|
453
|
+
if (names.has(export_name))
|
|
454
|
+
return 2 /* ResolveResult.CIRCULAR */;
|
|
455
|
+
names.add(export_name);
|
|
456
|
+
const me = m.export_entries.find(e => e.export_name === export_name) ?? null;
|
|
457
|
+
if (me !== null) {
|
|
458
|
+
if (me.export_type === 0 /* JSExportType.LOCAL */) {
|
|
459
|
+
out.b = { module: m, me, ns: null };
|
|
460
|
+
return 0 /* ResolveResult.FOUND */;
|
|
461
|
+
}
|
|
462
|
+
const m1 = m.req_module_entries[me.req_module_idx].module;
|
|
463
|
+
if (me.local_name === JS_ATOM__star_) {
|
|
464
|
+
/* export * as ns from */
|
|
465
|
+
out.b = { module: m, me, ns: m1 };
|
|
466
|
+
return 0 /* ResolveResult.FOUND */;
|
|
467
|
+
}
|
|
468
|
+
return js_resolve_export1(m1, me.local_name, set, out);
|
|
469
|
+
}
|
|
470
|
+
if (export_name === JS_ATOM_default)
|
|
471
|
+
return 1 /* ResolveResult.NOT_FOUND */;
|
|
472
|
+
/* not found in the direct or indirect exports: try the star exports */
|
|
473
|
+
let star = null;
|
|
474
|
+
for (const se of m.star_export_entries) {
|
|
475
|
+
const m1 = m.req_module_entries[se.req_module_idx].module;
|
|
476
|
+
const r = { b: null };
|
|
477
|
+
const ret = js_resolve_export1(m1, export_name, set, r);
|
|
478
|
+
if (ret === 3 /* ResolveResult.AMBIGUOUS */)
|
|
479
|
+
return ret;
|
|
480
|
+
if (ret === 0 /* ResolveResult.FOUND */) {
|
|
481
|
+
if (star !== null) {
|
|
482
|
+
if (!same_binding(star, r.b))
|
|
483
|
+
return 3 /* ResolveResult.AMBIGUOUS */;
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
star = r.b;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (star !== null) {
|
|
491
|
+
out.b = star;
|
|
492
|
+
return 0 /* ResolveResult.FOUND */;
|
|
493
|
+
}
|
|
494
|
+
return 1 /* ResolveResult.NOT_FOUND */;
|
|
495
|
+
}
|
|
496
|
+
function js_resolve_export(m, export_name, out) {
|
|
497
|
+
return js_resolve_export1(m, export_name, new Map(), out);
|
|
498
|
+
}
|
|
499
|
+
function js_resolve_export_throw_error(ctx, res, m, export_name) {
|
|
500
|
+
const n = JS_AtomGetStr(ctx, export_name), mn = mname(ctx, m);
|
|
501
|
+
switch (res) {
|
|
502
|
+
case 2 /* ResolveResult.CIRCULAR */:
|
|
503
|
+
JS_ThrowSyntaxError(ctx, `circular reference when looking for export '${n}' in module '${mn}'`);
|
|
504
|
+
break;
|
|
505
|
+
case 3 /* ResolveResult.AMBIGUOUS */:
|
|
506
|
+
JS_ThrowSyntaxError(ctx, `export '${n}' in module '${mn}' is ambiguous`);
|
|
507
|
+
break;
|
|
508
|
+
default:
|
|
509
|
+
JS_ThrowSyntaxError(ctx, `Could not find export '${n}' in module '${mn}'`);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
/* the variable a resolved binding reads */
|
|
514
|
+
function binding_var_ref(ctx, b) {
|
|
515
|
+
if (b.ns !== null) {
|
|
516
|
+
const ns = js_get_module_ns(ctx, b.ns);
|
|
517
|
+
if (JS_IsException(ns))
|
|
518
|
+
return null;
|
|
519
|
+
return new_var_ref_cell(ns);
|
|
520
|
+
}
|
|
521
|
+
return export_var_ref(b.module, b.me);
|
|
522
|
+
}
|
|
523
|
+
/* Prepare a module to be executed by resolving all the imported variables */
|
|
524
|
+
function js_inner_module_linking(ctx, m, stack, index) {
|
|
525
|
+
if (m.status === 1 /* JSModuleStatus.LINKING */ || m.status === 2 /* JSModuleStatus.LINKED */ ||
|
|
526
|
+
m.status === 4 /* JSModuleStatus.EVALUATING_ASYNC */ || m.status === 5 /* JSModuleStatus.EVALUATED */)
|
|
527
|
+
return index;
|
|
528
|
+
m.status = 1 /* JSModuleStatus.LINKING */;
|
|
529
|
+
m.dfs_index = index;
|
|
530
|
+
m.dfs_ancestor_index = index;
|
|
531
|
+
index++;
|
|
532
|
+
/* push 'm' on stack */
|
|
533
|
+
m.stack_prev = stack.top;
|
|
534
|
+
stack.top = m;
|
|
535
|
+
for (const rme of m.req_module_entries) {
|
|
536
|
+
const m1 = rme.module;
|
|
537
|
+
index = js_inner_module_linking(ctx, m1, stack, index);
|
|
538
|
+
if (index < 0)
|
|
539
|
+
return -1;
|
|
540
|
+
if (m1.status === 1 /* JSModuleStatus.LINKING */)
|
|
541
|
+
m.dfs_ancestor_index = Math.min(m.dfs_ancestor_index, m1.dfs_ancestor_index);
|
|
542
|
+
}
|
|
543
|
+
/* check the indirect exports */
|
|
544
|
+
for (const me of m.export_entries) {
|
|
545
|
+
if (me.export_type === 1 /* JSExportType.INDIRECT */ && me.local_name !== JS_ATOM__star_) {
|
|
546
|
+
const m1 = m.req_module_entries[me.req_module_idx].module;
|
|
547
|
+
const r = { b: null };
|
|
548
|
+
const ret = js_resolve_export(m1, me.local_name, r);
|
|
549
|
+
if (ret !== 0 /* ResolveResult.FOUND */) {
|
|
550
|
+
js_resolve_export_throw_error(ctx, ret, m1, me.local_name);
|
|
551
|
+
return -1;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (m.kind === 0 /* JSModuleKind.JS */) {
|
|
556
|
+
const var_refs = module_var_refs(m);
|
|
557
|
+
for (const mi of m.import_entries) {
|
|
558
|
+
const m1 = m.req_module_entries[mi.req_module_idx].module;
|
|
559
|
+
if (mi.is_star) {
|
|
560
|
+
/* namespace import */
|
|
561
|
+
const ns = js_get_module_ns(ctx, m1);
|
|
562
|
+
if (JS_IsException(ns))
|
|
563
|
+
return -1;
|
|
564
|
+
var_refs[mi.var_idx].set(ns);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
const r = { b: null };
|
|
568
|
+
const ret = js_resolve_export(m1, mi.import_name, r);
|
|
569
|
+
if (ret !== 0 /* ResolveResult.FOUND */) {
|
|
570
|
+
js_resolve_export_throw_error(ctx, ret, m1, mi.import_name);
|
|
571
|
+
return -1;
|
|
572
|
+
}
|
|
573
|
+
const vr = binding_var_ref(ctx, r.b);
|
|
574
|
+
if (vr === null)
|
|
575
|
+
return -1;
|
|
576
|
+
var_refs[mi.var_idx] = vr;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
/* keep the exported variables in the module export entries */
|
|
580
|
+
for (const me of m.export_entries) {
|
|
581
|
+
if (me.export_type === 0 /* JSExportType.LOCAL */)
|
|
582
|
+
export_var_ref(m, me);
|
|
583
|
+
}
|
|
584
|
+
/* initialize the global variables: with `this` true, the module function only runs its
|
|
585
|
+
hoisted definitions */
|
|
586
|
+
const ret = JS_Call(ctx, m.func_obj, true, []);
|
|
587
|
+
if (JS_IsException(ret))
|
|
588
|
+
return -1;
|
|
589
|
+
}
|
|
590
|
+
if (m.dfs_index === m.dfs_ancestor_index) {
|
|
591
|
+
for (;;) {
|
|
592
|
+
/* pop m1 from stack */
|
|
593
|
+
const m1 = stack.top;
|
|
594
|
+
stack.top = m1.stack_prev;
|
|
595
|
+
m1.status = 2 /* JSModuleStatus.LINKED */;
|
|
596
|
+
if (m1 === m)
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return index;
|
|
601
|
+
}
|
|
602
|
+
function js_link_module(ctx, m) {
|
|
603
|
+
const stack = { top: null };
|
|
604
|
+
if (js_inner_module_linking(ctx, m, stack, 0) < 0) {
|
|
605
|
+
while (stack.top !== null) {
|
|
606
|
+
const m1 = stack.top;
|
|
607
|
+
m1.status = 0 /* JSModuleStatus.UNLINKED */;
|
|
608
|
+
stack.top = m1.stack_prev;
|
|
609
|
+
}
|
|
610
|
+
return -1;
|
|
611
|
+
}
|
|
612
|
+
return 0;
|
|
613
|
+
}
|
|
614
|
+
/* ---------------------------------------------------------------------
|
|
615
|
+
Module namespace objects
|
|
616
|
+
--------------------------------------------------------------------- */
|
|
617
|
+
/* GetExportedNames */
|
|
618
|
+
function get_exported_names(m, from_star, visited, out) {
|
|
619
|
+
if (visited.has(m))
|
|
620
|
+
return;
|
|
621
|
+
visited.add(m);
|
|
622
|
+
for (const me of m.export_entries) {
|
|
623
|
+
if (from_star && me.export_name === JS_ATOM_default)
|
|
624
|
+
continue;
|
|
625
|
+
if (!out.includes(me.export_name))
|
|
626
|
+
out.push(me.export_name);
|
|
627
|
+
}
|
|
628
|
+
for (const se of m.star_export_entries) {
|
|
629
|
+
get_exported_names(m.req_module_entries[se.req_module_idx].module, true, visited, out);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
function compare_code_units(a, b) { return a < b ? -1 : a > b ? 1 : 0; }
|
|
633
|
+
/* Build the namespace object of a module: a host Proxy over a frozen-shape, null-prototype
|
|
634
|
+
target, so that native property access sees the live bindings (spec 10.4.6) */
|
|
635
|
+
function js_build_module_ns(ctx, m) {
|
|
636
|
+
const names = [];
|
|
637
|
+
get_exported_names(m, false, new Set(), names);
|
|
638
|
+
const bindings = new Map();
|
|
639
|
+
for (const name of names) {
|
|
640
|
+
const r = { b: null };
|
|
641
|
+
const ret = js_resolve_export(m, name, r);
|
|
642
|
+
if (ret === 3 /* ResolveResult.AMBIGUOUS */)
|
|
643
|
+
continue; /* ambiguous exports are left out */
|
|
644
|
+
if (ret !== 0 /* ResolveResult.FOUND */) {
|
|
645
|
+
js_resolve_export_throw_error(ctx, ret, m, name);
|
|
646
|
+
return JS_EXCEPTION;
|
|
647
|
+
}
|
|
648
|
+
const b = r.b;
|
|
649
|
+
const key = JS_AtomGetStr(ctx, name);
|
|
650
|
+
if (b.ns !== null) {
|
|
651
|
+
/* the namespace of another module: resolved lazily (cycles) */
|
|
652
|
+
const target_module = b.ns;
|
|
653
|
+
bindings.set(key, () => {
|
|
654
|
+
const v = js_get_module_ns(ctx, target_module);
|
|
655
|
+
if (JS_IsException(v))
|
|
656
|
+
throw js_take_exception(ctx);
|
|
657
|
+
return v;
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
const vr = export_var_ref(b.module, b.me);
|
|
662
|
+
bindings.set(key, () => {
|
|
663
|
+
const v = vr.get();
|
|
664
|
+
if (v === JS_UNINITIALIZED) {
|
|
665
|
+
JS_ThrowReferenceError(ctx, `'${key}' is not initialized`);
|
|
666
|
+
throw js_take_exception(ctx);
|
|
667
|
+
}
|
|
668
|
+
return v;
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
const keys = [...bindings.keys()].sort(compare_code_units);
|
|
673
|
+
const target = Object.create(null);
|
|
674
|
+
for (const k of keys)
|
|
675
|
+
Reflect.defineProperty(target, k, { value: undefined, writable: true, enumerable: true, configurable: false });
|
|
676
|
+
Reflect.defineProperty(target, Symbol.toStringTag, { value: 'Module', writable: false, enumerable: false, configurable: false });
|
|
677
|
+
Object.preventExtensions(target);
|
|
678
|
+
const value_of = (k) => bindings.get(k)();
|
|
679
|
+
const handler = Object.assign(Object.create(null), {
|
|
680
|
+
get(t, key, receiver) {
|
|
681
|
+
if (typeof key === 'symbol')
|
|
682
|
+
return Reflect.get(t, key, receiver);
|
|
683
|
+
return bindings.has(key) ? value_of(key) : undefined;
|
|
684
|
+
},
|
|
685
|
+
set() { return false; },
|
|
686
|
+
has(t, key) {
|
|
687
|
+
if (typeof key === 'symbol')
|
|
688
|
+
return Reflect.has(t, key);
|
|
689
|
+
return bindings.has(key);
|
|
690
|
+
},
|
|
691
|
+
deleteProperty(t, key) {
|
|
692
|
+
if (typeof key === 'symbol')
|
|
693
|
+
return Reflect.deleteProperty(t, key);
|
|
694
|
+
return !bindings.has(key);
|
|
695
|
+
},
|
|
696
|
+
getOwnPropertyDescriptor(t, key) {
|
|
697
|
+
if (typeof key === 'symbol')
|
|
698
|
+
return Reflect.getOwnPropertyDescriptor(t, key);
|
|
699
|
+
if (!bindings.has(key))
|
|
700
|
+
return undefined;
|
|
701
|
+
return { value: value_of(key), writable: true, enumerable: true, configurable: false };
|
|
702
|
+
},
|
|
703
|
+
defineProperty(t, key, desc) {
|
|
704
|
+
if (typeof key === 'symbol')
|
|
705
|
+
return Reflect.defineProperty(t, key, desc);
|
|
706
|
+
if (!bindings.has(key))
|
|
707
|
+
return false;
|
|
708
|
+
const value = value_of(key); /* TDZ */
|
|
709
|
+
if (desc.configurable === true || desc.enumerable === false || desc.get !== undefined || desc.set !== undefined ||
|
|
710
|
+
desc.writable === false)
|
|
711
|
+
return false;
|
|
712
|
+
if ('value' in desc)
|
|
713
|
+
return Object.is(desc.value, value);
|
|
714
|
+
return true;
|
|
715
|
+
},
|
|
716
|
+
ownKeys() { return [...keys, Symbol.toStringTag]; },
|
|
717
|
+
});
|
|
718
|
+
const ns = new Proxy(target, handler);
|
|
719
|
+
js_ensure_meta(ns, 11 /* JSClassID.MODULE_NS */).realm = ctx;
|
|
720
|
+
return ns;
|
|
721
|
+
}
|
|
722
|
+
export function js_get_module_ns(ctx, m) {
|
|
723
|
+
if (m.module_ns === undefined) {
|
|
724
|
+
const ns = js_build_module_ns(ctx, m);
|
|
725
|
+
if (JS_IsException(ns))
|
|
726
|
+
return ns;
|
|
727
|
+
m.module_ns = ns;
|
|
728
|
+
}
|
|
729
|
+
return m.module_ns;
|
|
730
|
+
}
|
|
731
|
+
/* the namespace object of a module that has been linked */
|
|
732
|
+
export function JS_GetModuleNamespace(ctx, m) {
|
|
733
|
+
return js_get_module_ns(ctx, m);
|
|
734
|
+
}
|
|
735
|
+
/* ---------------------------------------------------------------------
|
|
736
|
+
Evaluation (js_inner_module_evaluation and the asynchronous completion)
|
|
737
|
+
--------------------------------------------------------------------- */
|
|
738
|
+
/* run a module without top-level await: 0, or -1 with the error in out.error */
|
|
739
|
+
function js_execute_sync_module(ctx, m, out) {
|
|
740
|
+
if (m.kind !== 0 /* JSModuleKind.JS */) {
|
|
741
|
+
for (const me of m.export_entries)
|
|
742
|
+
me.var_ref.set(m.synthetic_exports.get(me.export_name));
|
|
743
|
+
return 0;
|
|
744
|
+
}
|
|
745
|
+
const promise = JS_Call(ctx, m.func_obj, undefined, []);
|
|
746
|
+
if (JS_IsException(promise)) {
|
|
747
|
+
out.error = js_take_exception(ctx);
|
|
748
|
+
return -1;
|
|
749
|
+
}
|
|
750
|
+
const state = JS_PromiseState(ctx, promise);
|
|
751
|
+
if (state === 1 /* JSPromiseState.FULFILLED */)
|
|
752
|
+
return 0;
|
|
753
|
+
if (state === 2 /* JSPromiseState.REJECTED */) {
|
|
754
|
+
out.error = JS_PromiseResult(ctx, promise);
|
|
755
|
+
/* the rejection is reported through the module's own promise */
|
|
756
|
+
perform_promise_then(ctx, promise, [undefined, undefined], [undefined, undefined]);
|
|
757
|
+
return -1;
|
|
758
|
+
}
|
|
759
|
+
out.error = throw_type_error(ctx, 'promise is pending');
|
|
760
|
+
return -1;
|
|
761
|
+
}
|
|
762
|
+
function js_execute_async_module(ctx, m) {
|
|
763
|
+
const promise = JS_Call(ctx, m.func_obj, undefined, []);
|
|
764
|
+
if (JS_IsException(promise)) {
|
|
765
|
+
js_async_module_execution_rejected(ctx, m, js_take_exception(ctx));
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
const on_fulfilled = JS_NewCFunction(ctx, () => { js_async_module_execution_fulfilled(ctx, m); return undefined; }, '', 0);
|
|
769
|
+
const on_rejected = JS_NewCFunction(ctx, (_c, _t, argv) => { js_async_module_execution_rejected(ctx, m, argv[0]); return undefined; }, '', 1);
|
|
770
|
+
perform_promise_then(ctx, promise, [on_fulfilled, on_rejected], [undefined, undefined]);
|
|
771
|
+
}
|
|
772
|
+
function js_inner_module_evaluation(ctx, m, index, stack, out) {
|
|
773
|
+
if (m.status === 4 /* JSModuleStatus.EVALUATING_ASYNC */ || m.status === 5 /* JSModuleStatus.EVALUATED */) {
|
|
774
|
+
if (m.eval_has_exception) {
|
|
775
|
+
out.error = m.eval_exception;
|
|
776
|
+
return -1;
|
|
777
|
+
}
|
|
778
|
+
return index;
|
|
779
|
+
}
|
|
780
|
+
if (m.status === 3 /* JSModuleStatus.EVALUATING */)
|
|
781
|
+
return index;
|
|
782
|
+
m.status = 3 /* JSModuleStatus.EVALUATING */;
|
|
783
|
+
m.dfs_index = index;
|
|
784
|
+
m.dfs_ancestor_index = index;
|
|
785
|
+
m.pending_async_dependencies = 0;
|
|
786
|
+
index++;
|
|
787
|
+
/* push 'm' on stack */
|
|
788
|
+
m.stack_prev = stack.top;
|
|
789
|
+
stack.top = m;
|
|
790
|
+
for (const rme of m.req_module_entries) {
|
|
791
|
+
let m1 = rme.module;
|
|
792
|
+
index = js_inner_module_evaluation(ctx, m1, index, stack, out);
|
|
793
|
+
if (index < 0)
|
|
794
|
+
return -1;
|
|
795
|
+
if (m1.status === 3 /* JSModuleStatus.EVALUATING */) {
|
|
796
|
+
m.dfs_ancestor_index = Math.min(m.dfs_ancestor_index, m1.dfs_ancestor_index);
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
m1 = m1.cycle_root;
|
|
800
|
+
if (m1.eval_has_exception) {
|
|
801
|
+
out.error = m1.eval_exception;
|
|
802
|
+
return -1;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (m1.async_evaluation) {
|
|
806
|
+
m.pending_async_dependencies++;
|
|
807
|
+
m1.async_parent_modules.push(m);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
if (m.pending_async_dependencies > 0) {
|
|
811
|
+
m.async_evaluation = true;
|
|
812
|
+
m.async_evaluation_timestamp = ctx.rt.module_async_evaluation_next_timestamp++;
|
|
813
|
+
}
|
|
814
|
+
else if (m.has_tla) {
|
|
815
|
+
m.async_evaluation = true;
|
|
816
|
+
m.async_evaluation_timestamp = ctx.rt.module_async_evaluation_next_timestamp++;
|
|
817
|
+
js_execute_async_module(ctx, m);
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
if (js_execute_sync_module(ctx, m, out) < 0)
|
|
821
|
+
return -1;
|
|
822
|
+
}
|
|
823
|
+
if (m.dfs_index === m.dfs_ancestor_index) {
|
|
824
|
+
for (;;) {
|
|
825
|
+
/* pop m1 from stack */
|
|
826
|
+
const m1 = stack.top;
|
|
827
|
+
stack.top = m1.stack_prev;
|
|
828
|
+
m1.status = m1.async_evaluation ? 4 /* JSModuleStatus.EVALUATING_ASYNC */ : 5 /* JSModuleStatus.EVALUATED */;
|
|
829
|
+
m1.cycle_root = m;
|
|
830
|
+
if (m1 === m)
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return index;
|
|
835
|
+
}
|
|
836
|
+
/* Run the module function of the module and of all its requested modules. Returns a
|
|
837
|
+
promise (or an exception) */
|
|
838
|
+
function js_evaluate_module(ctx, m) {
|
|
839
|
+
if (m.status === 4 /* JSModuleStatus.EVALUATING_ASYNC */ || m.status === 5 /* JSModuleStatus.EVALUATED */)
|
|
840
|
+
m = m.cycle_root;
|
|
841
|
+
/* a promise may be created only on the cycle_root of a cycle */
|
|
842
|
+
if (m.promise !== undefined)
|
|
843
|
+
return m.promise;
|
|
844
|
+
const funcs = [undefined, undefined];
|
|
845
|
+
const promise = JS_NewPromiseCapability(ctx, funcs);
|
|
846
|
+
if (JS_IsException(promise))
|
|
847
|
+
return promise;
|
|
848
|
+
m.promise = promise;
|
|
849
|
+
m.resolving_funcs = funcs;
|
|
850
|
+
const stack = { top: null };
|
|
851
|
+
const out = { error: undefined };
|
|
852
|
+
if (js_inner_module_evaluation(ctx, m, 0, stack, out) < 0) {
|
|
853
|
+
while (stack.top !== null) {
|
|
854
|
+
const m1 = stack.top;
|
|
855
|
+
m1.status = 5 /* JSModuleStatus.EVALUATED */;
|
|
856
|
+
m1.eval_has_exception = true;
|
|
857
|
+
m1.eval_exception = out.error;
|
|
858
|
+
m1.cycle_root = m;
|
|
859
|
+
stack.top = m1.stack_prev;
|
|
860
|
+
}
|
|
861
|
+
JS_Call(ctx, m.resolving_funcs[1], undefined, [m.eval_exception]);
|
|
862
|
+
}
|
|
863
|
+
else if (!m.async_evaluation) {
|
|
864
|
+
JS_Call(ctx, m.resolving_funcs[0], undefined, [undefined]);
|
|
865
|
+
}
|
|
866
|
+
return m.promise;
|
|
867
|
+
}
|
|
868
|
+
function js_set_module_evaluated(ctx, m) {
|
|
869
|
+
m.status = 5 /* JSModuleStatus.EVALUATED */;
|
|
870
|
+
if (m.promise !== undefined)
|
|
871
|
+
JS_Call(ctx, m.resolving_funcs[0], undefined, [undefined]);
|
|
872
|
+
}
|
|
873
|
+
/* the async parents of a module whose evaluation finished, ready to run */
|
|
874
|
+
function gather_available_ancestors(module, exec_list) {
|
|
875
|
+
for (const m of module.async_parent_modules) {
|
|
876
|
+
if (!exec_list.includes(m) && !m.cycle_root.eval_has_exception) {
|
|
877
|
+
m.pending_async_dependencies--;
|
|
878
|
+
if (m.pending_async_dependencies === 0) {
|
|
879
|
+
exec_list.push(m);
|
|
880
|
+
if (!m.has_tla)
|
|
881
|
+
gather_available_ancestors(m, exec_list);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
function js_async_module_execution_rejected(ctx, module, error) {
|
|
887
|
+
if (module.status === 5 /* JSModuleStatus.EVALUATED */)
|
|
888
|
+
return;
|
|
889
|
+
module.eval_has_exception = true;
|
|
890
|
+
module.eval_exception = error;
|
|
891
|
+
module.status = 5 /* JSModuleStatus.EVALUATED */;
|
|
892
|
+
module.async_evaluation = false;
|
|
893
|
+
for (const m of module.async_parent_modules)
|
|
894
|
+
js_async_module_execution_rejected(ctx, m, error);
|
|
895
|
+
if (module.promise !== undefined)
|
|
896
|
+
JS_Call(ctx, module.resolving_funcs[1], undefined, [error]);
|
|
897
|
+
}
|
|
898
|
+
function js_async_module_execution_fulfilled(ctx, module) {
|
|
899
|
+
if (module.status === 5 /* JSModuleStatus.EVALUATED */)
|
|
900
|
+
return;
|
|
901
|
+
module.async_evaluation = false;
|
|
902
|
+
js_set_module_evaluated(ctx, module);
|
|
903
|
+
const exec_list = [];
|
|
904
|
+
gather_available_ancestors(module, exec_list);
|
|
905
|
+
/* sort by increasing async_evaluation timestamp */
|
|
906
|
+
exec_list.sort((a, b) => a.async_evaluation_timestamp - b.async_evaluation_timestamp);
|
|
907
|
+
for (const m of exec_list) {
|
|
908
|
+
if (m.status === 5 /* JSModuleStatus.EVALUATED */)
|
|
909
|
+
continue; /* rejected meanwhile */
|
|
910
|
+
if (m.has_tla) {
|
|
911
|
+
js_execute_async_module(ctx, m);
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
const out = { error: undefined };
|
|
915
|
+
if (js_execute_sync_module(ctx, m, out) < 0) {
|
|
916
|
+
js_async_module_execution_rejected(ctx, m, out.error);
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
m.async_evaluation = false;
|
|
920
|
+
js_set_module_evaluated(ctx, m);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
/* ---------------------------------------------------------------------
|
|
926
|
+
Running modules
|
|
927
|
+
--------------------------------------------------------------------- */
|
|
928
|
+
/* link and evaluate a module whose graph is loaded: the evaluation promise, or an exception */
|
|
929
|
+
function js_link_and_evaluate(ctx, m) {
|
|
930
|
+
if (js_create_module_function(ctx, m) < 0)
|
|
931
|
+
return JS_EXCEPTION;
|
|
932
|
+
if (js_link_module(ctx, m) < 0)
|
|
933
|
+
return JS_EXCEPTION;
|
|
934
|
+
return js_evaluate_module(ctx, m);
|
|
935
|
+
}
|
|
936
|
+
/* Load the graph of `m`, link and evaluate it, then call `ok(ns)` or `fail(error)` */
|
|
937
|
+
function js_run_module(ctx, m, ok, fail) {
|
|
938
|
+
js_load_graph(ctx, m, err => {
|
|
939
|
+
if (err !== undefined) {
|
|
940
|
+
fail(err);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
const p = js_link_and_evaluate(ctx, m);
|
|
944
|
+
if (JS_IsException(p)) {
|
|
945
|
+
fail(js_take_exception(ctx));
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
const on_ful = JS_NewCFunction(ctx, () => {
|
|
949
|
+
const ns = js_get_module_ns(ctx, m);
|
|
950
|
+
if (JS_IsException(ns))
|
|
951
|
+
fail(js_take_exception(ctx));
|
|
952
|
+
else
|
|
953
|
+
ok(ns);
|
|
954
|
+
return undefined;
|
|
955
|
+
}, '', 0);
|
|
956
|
+
const on_rej = JS_NewCFunction(ctx, (_c, _t, argv) => { fail(argv[0]); return undefined; }, '', 1);
|
|
957
|
+
perform_promise_then(ctx, p, [on_ful, on_rej], [undefined, undefined]);
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
/* JS_EvalFunction of a compiled module (and JS_Eval of a module): with a loader that
|
|
961
|
+
answers synchronously, this is QuickJS's behaviour (load or link errors are thrown, the
|
|
962
|
+
result is the evaluation promise); otherwise a promise that settles with the evaluation */
|
|
963
|
+
function js_module_eval_function(ctx, m) {
|
|
964
|
+
js_register_module(ctx, m);
|
|
965
|
+
let sync = true;
|
|
966
|
+
let result = undefined;
|
|
967
|
+
let error = undefined;
|
|
968
|
+
let has_error = false;
|
|
969
|
+
let funcs = null;
|
|
970
|
+
let promise = undefined;
|
|
971
|
+
js_load_graph(ctx, m, err => {
|
|
972
|
+
if (sync) {
|
|
973
|
+
if (err !== undefined) {
|
|
974
|
+
has_error = true;
|
|
975
|
+
error = err;
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
result = js_link_and_evaluate(ctx, m);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
if (err !== undefined) {
|
|
982
|
+
JS_Call(ctx, funcs[1], undefined, [err]);
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
const p = js_link_and_evaluate(ctx, m);
|
|
986
|
+
if (JS_IsException(p)) {
|
|
987
|
+
JS_Call(ctx, funcs[1], undefined, [js_take_exception(ctx)]);
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
JS_Call(ctx, funcs[0], undefined, [p]);
|
|
991
|
+
});
|
|
992
|
+
if (has_error)
|
|
993
|
+
return JS_Throw(ctx, error);
|
|
994
|
+
if (result !== undefined)
|
|
995
|
+
return result;
|
|
996
|
+
/* still loading */
|
|
997
|
+
sync = false;
|
|
998
|
+
funcs = [undefined, undefined];
|
|
999
|
+
promise = JS_NewPromiseCapability(ctx, funcs);
|
|
1000
|
+
return promise;
|
|
1001
|
+
}
|
|
1002
|
+
function js_new_promise(ctx) {
|
|
1003
|
+
const funcs = [undefined, undefined];
|
|
1004
|
+
const promise = JS_NewPromiseCapability(ctx, funcs);
|
|
1005
|
+
return {
|
|
1006
|
+
promise,
|
|
1007
|
+
resolve: v => { JS_Call(ctx, funcs[0], undefined, [v]); },
|
|
1008
|
+
reject: e => { JS_Call(ctx, funcs[1], undefined, [e]); },
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
/* Evaluate `source` as a module named `url`: a promise for its namespace object. `flags` may hold
|
|
1012
|
+
JS_EVAL_FLAG_STRIP_TYPES and JS_EVAL_FLAG_JSX */
|
|
1013
|
+
export function JS_EvalModule(ctx, source, url, flags = 0) {
|
|
1014
|
+
const p = js_new_promise(ctx);
|
|
1015
|
+
const v = hooks.JS_EvalInternal(ctx, undefined, source, url, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY |
|
|
1016
|
+
(flags & (JS_EVAL_FLAG_STRIP_TYPES | JS_EVAL_FLAG_JSX)), -1);
|
|
1017
|
+
if (JS_IsException(v)) {
|
|
1018
|
+
p.reject(js_take_exception(ctx));
|
|
1019
|
+
return p.promise;
|
|
1020
|
+
}
|
|
1021
|
+
const m = v;
|
|
1022
|
+
js_register_module(ctx, m);
|
|
1023
|
+
js_run_module(ctx, m, p.resolve, p.reject);
|
|
1024
|
+
return p.promise;
|
|
1025
|
+
}
|
|
1026
|
+
/* import(specifier) from the host: a promise for the namespace object */
|
|
1027
|
+
export function JS_ImportModule(ctx, specifier, referrer = null, attributes = null) {
|
|
1028
|
+
const p = js_new_promise(ctx);
|
|
1029
|
+
js_import(ctx, specifier, referrer, attributes, p.resolve, p.reject);
|
|
1030
|
+
return p.promise;
|
|
1031
|
+
}
|
|
1032
|
+
function js_import(ctx, specifier, referrer, attributes, ok, fail) {
|
|
1033
|
+
const kind = js_request_kind(ctx, attributes);
|
|
1034
|
+
if (kind !== 'js' && kind !== 'json') {
|
|
1035
|
+
fail(kind);
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
const attrs = attributes ?? {};
|
|
1039
|
+
let id;
|
|
1040
|
+
try {
|
|
1041
|
+
id = js_resolve_specifier(ctx, specifier, referrer, attrs);
|
|
1042
|
+
}
|
|
1043
|
+
catch (e) {
|
|
1044
|
+
fail(caught(ctx, e));
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
js_fetch_module(ctx, specifier, id, kind, attrs, (err, m) => {
|
|
1048
|
+
if (err !== undefined) {
|
|
1049
|
+
fail(err);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
js_run_module(ctx, m, ok, fail);
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
/* the name a function's code is known by: its module's id, or its script's file name */
|
|
1056
|
+
function js_referrer_of(ctx, b) {
|
|
1057
|
+
if (b === null)
|
|
1058
|
+
return null;
|
|
1059
|
+
if (b.module !== null)
|
|
1060
|
+
return mname(ctx, b.module);
|
|
1061
|
+
if (b.has_debug && b.debug.filename)
|
|
1062
|
+
return JS_AtomGetStr(ctx, b.debug.filename);
|
|
1063
|
+
return null;
|
|
1064
|
+
}
|
|
1065
|
+
/* import(specifier, options) */
|
|
1066
|
+
function js_dynamic_import(ctx, b, specifier, options) {
|
|
1067
|
+
const p = js_new_promise(ctx);
|
|
1068
|
+
if (JS_IsException(p.promise))
|
|
1069
|
+
return p.promise;
|
|
1070
|
+
const reject_now = () => { p.reject(js_take_exception(ctx)); return p.promise; };
|
|
1071
|
+
/* the string conversion must occur here */
|
|
1072
|
+
const spec = JS_ToString(ctx, specifier);
|
|
1073
|
+
if (JS_IsException(spec))
|
|
1074
|
+
return reject_now();
|
|
1075
|
+
let attributes = null;
|
|
1076
|
+
if (options !== undefined) {
|
|
1077
|
+
if (!JS_IsObject(options)) {
|
|
1078
|
+
JS_ThrowTypeError(ctx, 'options must be an object');
|
|
1079
|
+
return reject_now();
|
|
1080
|
+
}
|
|
1081
|
+
const with_obj = JS_GetPropertyStr(ctx, options, 'with');
|
|
1082
|
+
if (JS_IsException(with_obj))
|
|
1083
|
+
return reject_now();
|
|
1084
|
+
if (with_obj !== undefined) {
|
|
1085
|
+
if (!JS_IsObject(with_obj)) {
|
|
1086
|
+
JS_ThrowTypeError(ctx, 'options.with must be an object');
|
|
1087
|
+
return reject_now();
|
|
1088
|
+
}
|
|
1089
|
+
attributes = Object.create(null);
|
|
1090
|
+
let keys;
|
|
1091
|
+
try {
|
|
1092
|
+
keys = Reflect.ownKeys(with_obj);
|
|
1093
|
+
}
|
|
1094
|
+
catch (e) {
|
|
1095
|
+
p.reject(host_error_to_guest(ctx, e));
|
|
1096
|
+
return p.promise;
|
|
1097
|
+
}
|
|
1098
|
+
for (const k of keys) {
|
|
1099
|
+
if (typeof k !== 'string')
|
|
1100
|
+
continue;
|
|
1101
|
+
let d;
|
|
1102
|
+
try {
|
|
1103
|
+
d = Reflect.getOwnPropertyDescriptor(with_obj, k);
|
|
1104
|
+
}
|
|
1105
|
+
catch (e) {
|
|
1106
|
+
p.reject(host_error_to_guest(ctx, e));
|
|
1107
|
+
return p.promise;
|
|
1108
|
+
}
|
|
1109
|
+
if (!d || !d.enumerable)
|
|
1110
|
+
continue;
|
|
1111
|
+
const v = JS_GetPropertyStr(ctx, with_obj, k);
|
|
1112
|
+
if (JS_IsException(v))
|
|
1113
|
+
return reject_now();
|
|
1114
|
+
if (typeof v !== 'string') {
|
|
1115
|
+
JS_ThrowTypeError(ctx, 'module attribute values must be strings');
|
|
1116
|
+
return reject_now();
|
|
1117
|
+
}
|
|
1118
|
+
attributes[k] = v;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
const kind = js_request_kind(ctx, attributes);
|
|
1123
|
+
if (kind !== 'js' && kind !== 'json') {
|
|
1124
|
+
p.reject(kind);
|
|
1125
|
+
return p.promise;
|
|
1126
|
+
}
|
|
1127
|
+
const referrer = js_referrer_of(ctx, b);
|
|
1128
|
+
/* not run synchronously: it could recurse into js_evaluate_module() */
|
|
1129
|
+
JS_EnqueueJob(ctx, () => {
|
|
1130
|
+
js_import(ctx, spec, referrer, attributes, p.resolve, p.reject);
|
|
1131
|
+
return undefined;
|
|
1132
|
+
}, []);
|
|
1133
|
+
return p.promise;
|
|
1134
|
+
}
|
|
1135
|
+
/* import.meta: a null-prototype object with `url` and `resolve` */
|
|
1136
|
+
function js_import_meta(ctx, b) {
|
|
1137
|
+
const m = b?.module ?? null;
|
|
1138
|
+
if (m === null)
|
|
1139
|
+
return JS_ThrowTypeError(ctx, 'import.meta not supported in this context');
|
|
1140
|
+
if (m.meta_obj === undefined) {
|
|
1141
|
+
const meta = JS_NewObjectProto(ctx, null);
|
|
1142
|
+
if (JS_IsException(meta))
|
|
1143
|
+
return meta;
|
|
1144
|
+
const id = mname(ctx, m);
|
|
1145
|
+
JS_DefinePropertyValueStr(ctx, meta, 'url', m.url ?? id, JS_PROP_C_W_E);
|
|
1146
|
+
const resolve = JS_NewCFunction(ctx, (c, _t, argv) => {
|
|
1147
|
+
const spec = JS_ToString(c, argv[0]);
|
|
1148
|
+
if (JS_IsException(spec))
|
|
1149
|
+
return spec;
|
|
1150
|
+
try {
|
|
1151
|
+
return js_resolve_specifier(c, spec, id, {});
|
|
1152
|
+
}
|
|
1153
|
+
catch (e) {
|
|
1154
|
+
return JS_Throw(c, caught(c, e));
|
|
1155
|
+
}
|
|
1156
|
+
}, 'resolve', 1);
|
|
1157
|
+
JS_DefinePropertyValueStr(ctx, meta, 'resolve', resolve, JS_PROP_C_W_E);
|
|
1158
|
+
m.meta_obj = meta;
|
|
1159
|
+
}
|
|
1160
|
+
return m.meta_obj;
|
|
1161
|
+
}
|
|
1162
|
+
hooks.js_module_compiled = js_module_compiled;
|
|
1163
|
+
hooks.js_dynamic_import = js_dynamic_import;
|
|
1164
|
+
hooks.js_import_meta = js_import_meta;
|
|
1165
|
+
hooks.js_module_eval_function = js_module_eval_function;
|
|
1166
|
+
//# sourceMappingURL=module.js.map
|