summaryrefslogtreecommitdiff
path: root/modules/internal
diff options
context:
space:
mode:
authorEvan Welsh <contact@evanwelsh.com>2020-11-14 14:36:27 -0600
committerPhilip Chimento <philip.chimento@gmail.com>2021-02-08 19:49:06 -0800
commit97c2fd83488d567c1d83481478ac7bee2335505b (patch)
treefcae6afc155843387ea664088f08952d0259af7a /modules/internal
parent126b93e9a3e1772f609e9676caf9a3b204cc1962 (diff)
downloadgjs-97c2fd83488d567c1d83481478ac7bee2335505b.tar.gz
Implement dynamic imports
(Changes from Philip folded in: tests, moving file operations into internal.cpp, some added comments)
Diffstat (limited to 'modules/internal')
-rw-r--r--modules/internal/.eslintrc.yml1
-rw-r--r--modules/internal/loader.js80
2 files changed, 81 insertions, 0 deletions
diff --git a/modules/internal/.eslintrc.yml b/modules/internal/.eslintrc.yml
index b06bc212..2889cc64 100644
--- a/modules/internal/.eslintrc.yml
+++ b/modules/internal/.eslintrc.yml
@@ -19,6 +19,7 @@ globals:
compileModule: readonly
compileInternalModule: readonly
loadResourceOrFile: readonly
+ loadResourceOrFileAsync: readonly
parseURI: readonly
uriExists: readonly
resolveRelativeResourceOrFile: readonly
diff --git a/modules/internal/loader.js b/modules/internal/loader.js
index fde96eb0..f28814c9 100644
--- a/modules/internal/loader.js
+++ b/modules/internal/loader.js
@@ -122,6 +122,79 @@ class ModuleLoader extends InternalModuleLoader {
return this.resolveBareSpecifier(specifier);
}
+
+ moduleResolveAsyncHook(importingModulePriv, specifier) {
+ // importingModulePriv may be falsy in the case of gjs_context_eval()
+ if (!importingModulePriv || !importingModulePriv.uri)
+ throw new ImportError('Cannot resolve relative imports from an unknown file.');
+
+ return this.resolveModuleAsync(specifier, importingModulePriv.uri);
+ }
+
+ /**
+ * Resolves a module import with optional handling for relative imports asynchronously.
+ *
+ * @param {string} specifier the specifier (e.g. relative path, root package) to resolve
+ * @param {string | null} importingModuleURI the URI of the module
+ * triggering this resolve
+ * @returns {import("../types").Module}
+ */
+ async resolveModuleAsync(specifier, importingModuleURI) {
+ const registry = getRegistry(this.global);
+
+ // Check if the module has already been loaded
+ let module = registry.get(specifier);
+ if (module)
+ return module;
+
+ // 1) Resolve path and URI-based imports.
+ const uri = this.resolveSpecifier(specifier, importingModuleURI);
+ if (uri) {
+ module = registry.get(uri.uri);
+
+ // Check if module is already loaded (relative handling)
+ if (module)
+ return module;
+
+ const result = await this.loadURIAsync(uri);
+ if (!result)
+ return null;
+
+ const [text, internal = false] = result;
+
+ const priv = new ModulePrivate(uri.uri, uri.uri, internal);
+ const compiled = this.compileModule(priv, text);
+
+ registry.set(uri.uri, compiled);
+ return compiled;
+ }
+
+ // 2) Resolve internal imports.
+
+ return this.resolveBareSpecifier(specifier);
+ }
+
+ /**
+ * Loads a file or resource URI asynchronously
+ *
+ * @param {Uri} uri the file or resource URI to load
+ * @returns {Promise<[string] | [string, boolean] | null>}
+ */
+ async loadURIAsync(uri) {
+ if (uri.scheme) {
+ const loader = this.schemeHandlers.get(uri.scheme);
+
+ if (loader)
+ return loader.loadAsync(uri);
+ }
+
+ if (uri.scheme === 'file' || uri.scheme === 'resource') {
+ const result = await loadResourceOrFileAsync(uri.uri);
+ return [result];
+ }
+
+ return null;
+ }
}
const moduleLoader = new ModuleLoader(moduleGlobalThis);
@@ -167,4 +240,11 @@ moduleLoader.registerScheme('gi', {
return [generateGIModule(namespace, version), true];
},
+ /**
+ * @param {import("./internalLoader.js").Uri} uri the URI to load asynchronously
+ */
+ loadAsync(uri) {
+ // gi: only does string manipulation, so it is safe to use the same code for sync and async.
+ return this.load(uri);
+ },
});