Skip to content

Commit

Permalink
Support require() attributes (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
kasperisager authored Oct 11, 2024
1 parent 29e5a51 commit c648e63
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 55 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ Options include:
imports,
resolutions,
builtins,
conditions
conditions,
attributes
}
```
Expand Down
103 changes: 50 additions & 53 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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

Expand All @@ -208,16 +208,12 @@ 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) {
if (eagerRun) this._run()
} else if (eagerRun) {
this._run()
}
}

Expand Down Expand Up @@ -245,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) {
Expand All @@ -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
const url = this.resolve(href, referrer._url, { isImport: true, referrer })

switch (assertions.type) {
case 'module':
type = constants.types.MODULE
break
case 'json':
type = constants.types.JSON
break
}

const module = this.load(url, {
isImport: true,
isDynamicImport,
referrer,
type
})
const module = this.load(url, { isImport: true, isDynamicImport, referrer, attributes })

return module._handle
}
Expand Down Expand Up @@ -383,7 +360,8 @@ const Module = module.exports = exports = class Module {
isDynamicImport = false,

referrer = null,
type = 0,
attributes,
type = typeForAttributes(attributes),
defaultType = referrer ? referrer._defaultType : 0,
cache = referrer ? referrer._cache : self._cache,
main = referrer ? referrer._main : null,
Expand Down Expand Up @@ -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'
}

Expand Down Expand Up @@ -537,22 +515,41 @@ const Module = module.exports = exports = class Module {
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
}
}

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 typeForAttributes (attributes) {
if (typeof attributes !== 'object' || attributes === null) return 0

switch (attributes.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
}
}

Expand Down Expand Up @@ -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, attributes: opts.with })

return module._exports
}
Expand Down
50 changes: 49 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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 attributes', 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 attributes', (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)

Expand Down

0 comments on commit c648e63

Please sign in to comment.