From cbb3bfcec6dee41fe76fa2aa4f8033dbaf5709cb Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Tue, 26 Dec 2023 12:27:14 +0100 Subject: [PATCH] Add module context access escape hatch --- index.js | 13 +++++++++++++ load-modules.js | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/index.js b/index.js index f5497af..a5d451c 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ const InvalidObject = require("./invalid-object"); // FIXME: recurseDepth, recurseLabel/recurseGoto // TODO: Internal queries, but only in modules, and only as a last resort // TODO: Throw a useful error when trying to $make a non-existent type +// TODO: Refactor using stand-alone utility functions /* Process design: @@ -235,6 +236,7 @@ module.exports = function createDLayer(options) { let combinedContext = { ... generatedContext, ... context, + $getModuleContext: getModuleContext, // FIXME: Figure out a way to annotate errors here with the path at which they occurred, *and* make clear that it was an internal property lookup $getProperty: getProperty, $getPropertyPath: function (object, propertyPath) { @@ -261,6 +263,17 @@ module.exports = function createDLayer(options) { let getContextForModule = loaded.makeContextFactory(combinedContext); + function getModuleContext(moduleName) { + // NOTE: This is an escape hatch to access a module's context from outside of that module; you should not normally need this! + if (loaded.nameToID.has(moduleName)) { + let moduleID = loaded.nameToID.get(moduleName); + console.log({moduleName, moduleID}); + return getContextForModule(moduleID); + } else { + throw new Error(`No module named '${moduleName}' has been loaded`); + } + } + function getProperty(object, property, args = {}) { // TODO: Should this allow a single-argument, property-string-only variant for looking up properties on self? // FIXME: Validatem diff --git a/load-modules.js b/load-modules.js index 03d7d09..8184cbf 100644 --- a/load-modules.js +++ b/load-modules.js @@ -104,9 +104,11 @@ function defaultContext() { module.exports = function (modules) { // TODO: Eventually replace hand-crafted merging logic with merge-by-template, once it can support this usecase properly(tm) // TODO: Fix merge-by-template so that reasonable error messages can be generated here, that are actually aware of eg. the conflicting key + // TODO: Disallow modules with duplicate names? This may be necessary to prevent issues with getModuleContext, which provides name-based context access let types = createTypeTracker(); let typeExtensions = createExtensionTracker(); + let nameToID = new Map(); // TODO: Make this a tracker abstraction? let contextFactories = syncpipe(modules, [ _ => _.map((module) => [ getModuleID(module), module.makeContext ?? defaultContext ]), @@ -118,6 +120,10 @@ module.exports = function (modules) { }, {}); for (let module of modules) { + if (module.name != null) { + nameToID.set(module.name, getModuleID(module)); + } + for (let [ type, factory ] of Object.entries(module.types ?? {})) { types.add(module, type, factory); } @@ -133,6 +139,7 @@ module.exports = function (modules) { root: schema, types: types.get(), extensions: typeExtensions.get(), + nameToID: nameToID, makeContextFactory: function (baseContext) { let cache = new Map();