Skip to content

Commit d941af3

Browse files
mtwebsterclefebvre
authored andcommitted
importer: Add 'clear_cache' function to allow reloading of modules.
We used to do something similar in older versions of cjs before linuxmint/cinnamon@f01bd803d5ae89.
1 parent 3015fd9 commit d941af3

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

cjs/atoms.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class JSTracer;
1818
// clang-format off
1919
#define FOR_EACH_ATOM(macro) \
2020
macro(cause, "cause") \
21+
macro(clear_cache, "clearCache") \
2122
macro(code, "code") \
2223
macro(column_number, "columnNumber") \
2324
macro(connect_after, "connect_after") \

cjs/importer.cpp

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,50 @@ static bool seal_import(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
216216
return true;
217217
}
218218

219+
/* Clear a cached module so it can be re-imported.
220+
* This allows extension/applet reloading without restarting.
221+
*/
222+
GJS_JSAPI_RETURN_CONVENTION
223+
static bool
224+
importer_clear_cache(JSContext *cx,
225+
unsigned argc,
226+
JS::Value *vp)
227+
{
228+
GJS_GET_THIS(cx, argc, vp, args, importer);
229+
230+
if (args.length() < 1 || !args[0].isString()) {
231+
gjs_throw(cx, "clearCache requires a string argument");
232+
return false;
233+
}
234+
235+
JS::RootedString name_str(cx, args[0].toString());
236+
JS::UniqueChars name(JS_EncodeStringToUTF8(cx, name_str));
237+
if (!name)
238+
return false;
239+
240+
// Check if the property exists
241+
bool has_prop;
242+
if (!JS_HasOwnProperty(cx, importer, name.get(), &has_prop))
243+
return false;
244+
245+
if (!has_prop) {
246+
args.rval().setBoolean(false);
247+
return true;
248+
}
249+
250+
gjs_debug(GJS_DEBUG_IMPORTER,
251+
"Clearing cached import '%s'",
252+
name.get());
253+
254+
// Delete the cached module property
255+
JS::ObjectOpResult result;
256+
if (!JS_DeleteProperty(cx, importer, name.get(), result))
257+
return false;
258+
259+
args.rval().setBoolean(result.succeed());
260+
return true;
261+
}
262+
219263
/* An import failed. Delete the property pointing to the import from the parent
220264
* namespace. In complicated situations this might not be sufficient to get us
221265
* fully back to a sane state. If:
@@ -412,9 +456,23 @@ static bool attempt_import(JSContext* cx, JS::HandleObject obj,
412456

413457
Gjs::AutoChar full_path{g_file_get_parse_name(file)};
414458

415-
return define_meta_properties(cx, module_obj, full_path, module_name,
416-
obj) &&
417-
seal_import(cx, obj, module_id, module_name);
459+
if (!define_meta_properties(cx, module_obj, full_path, module_name, obj))
460+
return false;
461+
462+
// Only seal imports on the root importer (where parent is null).
463+
// Sub-importers (like xlet importers) remain unsealed so their modules
464+
// can be cleared from cache and re-imported for xlet reloading.
465+
const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
466+
JS::RootedValue parent(cx);
467+
if (!JS_GetPropertyById(cx, obj, atoms.parent_module(), &parent))
468+
return false;
469+
470+
if (parent.isNull()) {
471+
if (!seal_import(cx, obj, module_id, module_name))
472+
return false;
473+
}
474+
475+
return true;
418476
}
419477

420478
GJS_JSAPI_RETURN_CONVENTION
@@ -696,7 +754,7 @@ static bool importer_resolve(JSContext* cx, JS::HandleObject obj,
696754

697755
const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
698756
if (id == atoms.module_init() || id == atoms.to_string() ||
699-
id == atoms.value_of()) {
757+
id == atoms.value_of() || id == atoms.clear_cache()) {
700758
*resolved = false;
701759
return true;
702760
}
@@ -736,6 +794,7 @@ static const JSPropertySpec gjs_importer_proto_props[] = {
736794

737795
JSFunctionSpec gjs_importer_proto_funcs[] = {
738796
JS_FN("toString", importer_to_string, 0, 0),
797+
JS_FN("clearCache", importer_clear_cache, 1, 0),
739798
JS_FS_END};
740799

741800
[[nodiscard]]

0 commit comments

Comments
 (0)