From bba46d4f63b849d5f6b8809a5e8f1d3e26b07291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Isager=20Dalsgar=C3=B0?= Date: Fri, 11 Oct 2024 12:27:22 +0200 Subject: [PATCH 1/4] Support `require()` assertions --- README.md | 3 +- index.js | 99 +++++++++++++++++++++++++++---------------------------- test.js | 48 +++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index ffb4024..d551329 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,8 @@ Options include: imports, resolutions, builtins, - conditions + conditions, + assertions } ``` diff --git a/index.js b/index.js index 42d63e9..04b81e6 100644 --- a/index.js +++ b/index.js @@ -112,6 +112,10 @@ const Module = module.exports = exports = class Module { Module._modules.delete(this) } + _run () { + binding.runModule(this._handle, Module._handle, Module._onrun) + } + _transform (isImport, isDynamicImport) { if (isDynamicImport) { this._synthesize() @@ -183,10 +187,6 @@ const Module = module.exports = exports = class Module { this._handle = binding.createSyntheticModule(this._url.href, this._names, Module._handle) } - _run () { - binding.runModule(this._handle, Module._handle, Module._onrun) - } - _evaluate (eagerRun = false) { if ((this._state & constants.states.EVALUATED) !== 0) return @@ -208,15 +208,11 @@ const Module = module.exports = exports = class Module { ) if (eagerRun) this._run() - } - - if (this._type === constants.types.MODULE) { + } else if (this._type === constants.types.MODULE) { this._run() this._exports = binding.getNamespace(this._handle) - } - - if (this._type === constants.types.ADDON) { + } else { if (eagerRun) this._run() } } @@ -256,28 +252,9 @@ const Module = module.exports = exports = class Module { throw errors.MODULE_NOT_FOUND(msg) } - const url = this.resolve(href, referrer._url, { - isImport: true, - referrer - }) - - let type - - switch (assertions.type) { - case 'module': - type = constants.types.MODULE - break - case 'json': - type = constants.types.JSON - break - } + const url = this.resolve(href, referrer._url, { isImport: true, referrer }) - const module = this.load(url, { - isImport: true, - isDynamicImport, - referrer, - type - }) + const module = this.load(url, { isImport: true, isDynamicImport, referrer, assertions }) return module._handle } @@ -383,7 +360,8 @@ const Module = module.exports = exports = class Module { isDynamicImport = false, referrer = null, - type = 0, + assertions, + type = typeForAssertions(assertions), defaultType = referrer ? referrer._defaultType : 0, cache = referrer ? referrer._cache : self._cache, main = referrer ? referrer._main : null, @@ -414,10 +392,10 @@ const Module = module.exports = exports = class Module { module._builtins = builtins module._conditions = conditions - let extension = self._extensionFor(type) || path.extname(url.pathname) + let extension = extensionForType(type) || path.extname(url.pathname) if (extension in self._extensions === false) { - if (defaultType) extension = self._extensionFor(defaultType) || '.js' + if (defaultType) extension = extensionForType(defaultType) || '.js' else extension = '.js' } @@ -537,22 +515,41 @@ const Module = module.exports = exports = class Module { return null } } +} - static _extensionFor (type) { - switch (type) { - case constants.types.SCRIPT: - return '.cjs' - case constants.types.MODULE: - return '.esm' - case constants.types.JSON: - return '.json' - case constants.types.BUNDLE: - return '.bundle' - case constants.types.ADDON: - return '.bare' - default: - return null - } +function extensionForType (type) { + switch (type) { + case constants.types.SCRIPT: + return '.cjs' + case constants.types.MODULE: + return '.esm' + case constants.types.JSON: + return '.json' + case constants.types.BUNDLE: + return '.bundle' + case constants.types.ADDON: + return '.bare' + default: + return null + } +} + +function typeForAssertions (assertions) { + if (typeof assertions !== 'object' || assertions === null) return 0 + + switch (assertions.type) { + case 'script': + return constants.types.SCRIPT + case 'module': + return constants.types.MODULE + case 'json': + return constants.types.JSON + case 'bundle': + return constants.types.BUNDLE + case 'addon': + return constants.types.ADDON + default: + return 0 } } @@ -613,10 +610,10 @@ const createRequire = exports.createRequire = function createRequire (parentURL, return require - function require (specifier) { + function require (specifier, opts = {}) { const resolved = self.resolve(specifier, referrer._url, { referrer }) - const module = self.load(resolved, { referrer }) + const module = self.load(resolved, { referrer, assertions: opts.with }) return module._exports } diff --git a/test.js b/test.js index 8688920..3adcf6e 100644 --- a/test.js +++ b/test.js @@ -1440,6 +1440,54 @@ test('import assertions', (t) => { t.alike(Module.load(new URL(root + '/foo.mjs'), { protocol }).exports.default, { hello: 'world' }) }) +test('dynamic import assertions', async (t) => { + t.teardown(onteardown) + + const protocol = new Module.Protocol({ + exists (url) { + return url.href === root + '/bar' + }, + + read (url) { + if (url.href === root + '/foo.mjs') { + return 'export default import(\'/bar\', { with: { type: \'json\' } })' + } + + if (url.href === root + '/bar') { + return '{ "hello": "world" }' + } + + t.fail() + } + }) + + t.comment(await Module.load(new URL(root + '/foo.mjs'), { protocol }).exports.default) +}) + +test('require assertions', (t) => { + t.teardown(onteardown) + + const protocol = new Module.Protocol({ + exists (url) { + return url.href === root + '/bar' + }, + + read (url) { + if (url.href === root + '/foo.js') { + return 'module.exports = require(\'/bar\', { with: { type: \'json\' } })' + } + + if (url.href === root + '/bar') { + return '{ "hello": "world" }' + } + + t.fail() + } + }) + + t.alike(Module.load(new URL(root + '/foo.js'), { protocol }).exports, { hello: 'world' }) +}) + test('createRequire', (t) => { t.teardown(onteardown) From 0ea6e1037ef710bc20160856234e680cdcdeb0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Isager=20Dalsgar=C3=B0?= Date: Fri, 11 Oct 2024 12:31:33 +0200 Subject: [PATCH 2/4] Rename to attributes to align with specification --- index.js | 16 ++++++++-------- test.js | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index 04b81e6..f452ceb 100644 --- a/index.js +++ b/index.js @@ -241,7 +241,7 @@ const Module = module.exports = exports = class Module { static _handle = binding.init(this, this._onimport, this._onevaluate, this._onmeta) - static _onimport (href, assertions, referrerHref, isDynamicImport) { + static _onimport (href, attributes, referrerHref, isDynamicImport) { const referrer = this._cache[referrerHref] || null if (referrer === null) { @@ -254,7 +254,7 @@ const Module = module.exports = exports = class Module { const url = this.resolve(href, referrer._url, { isImport: true, referrer }) - const module = this.load(url, { isImport: true, isDynamicImport, referrer, assertions }) + const module = this.load(url, { isImport: true, isDynamicImport, referrer, attributes }) return module._handle } @@ -360,8 +360,8 @@ const Module = module.exports = exports = class Module { isDynamicImport = false, referrer = null, - assertions, - type = typeForAssertions(assertions), + attributes, + type = typeForAttributes(attributes), defaultType = referrer ? referrer._defaultType : 0, cache = referrer ? referrer._cache : self._cache, main = referrer ? referrer._main : null, @@ -534,10 +534,10 @@ function extensionForType (type) { } } -function typeForAssertions (assertions) { - if (typeof assertions !== 'object' || assertions === null) return 0 +function typeForAttributes (attributes) { + if (typeof attributes !== 'object' || attributes === null) return 0 - switch (assertions.type) { + switch (attributes.type) { case 'script': return constants.types.SCRIPT case 'module': @@ -613,7 +613,7 @@ const createRequire = exports.createRequire = function createRequire (parentURL, function require (specifier, opts = {}) { const resolved = self.resolve(specifier, referrer._url, { referrer }) - const module = self.load(resolved, { referrer, assertions: opts.with }) + const module = self.load(resolved, { referrer, attributes: opts.with }) return module._exports } diff --git a/test.js b/test.js index 3adcf6e..267c6e3 100644 --- a/test.js +++ b/test.js @@ -1416,7 +1416,7 @@ test('import.meta', (t) => { t.comment(meta.addon.host) }) -test('import assertions', (t) => { +test('import attributes', (t) => { t.teardown(onteardown) const protocol = new Module.Protocol({ @@ -1440,7 +1440,7 @@ test('import assertions', (t) => { t.alike(Module.load(new URL(root + '/foo.mjs'), { protocol }).exports.default, { hello: 'world' }) }) -test('dynamic import assertions', async (t) => { +test('dynamic import attributes', async (t) => { t.teardown(onteardown) const protocol = new Module.Protocol({ @@ -1464,7 +1464,7 @@ test('dynamic import assertions', async (t) => { t.comment(await Module.load(new URL(root + '/foo.mjs'), { protocol }).exports.default) }) -test('require assertions', (t) => { +test('require attributes', (t) => { t.teardown(onteardown) const protocol = new Module.Protocol({ From b73000e3956bf3500597c05a9b87301d9d1b21e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Isager=20Dalsgar=C3=B0?= Date: Fri, 11 Oct 2024 12:41:22 +0200 Subject: [PATCH 3/4] Formatting --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index f452ceb..96507c5 100644 --- a/index.js +++ b/index.js @@ -212,8 +212,8 @@ const Module = module.exports = exports = class Module { this._run() this._exports = binding.getNamespace(this._handle) - } else { - if (eagerRun) this._run() + } else if (eagerRun) { + this._run() } } From 680b45a354169f5d77fa96d44d775b4b9c7f0630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kasper=20Isager=20Dalsgar=C3=B0?= Date: Fri, 11 Oct 2024 13:02:24 +0200 Subject: [PATCH 4/4] Fix README reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d551329..a9b3321 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ Options include: resolutions, builtins, conditions, - assertions + attributes } ```