$ npm install bare-module-resolve
Low-level module resolution algorithm for Bare. The algorithm is implemented as a generator function that yields either package manifests to be read or resolution candidates to be tested by the caller. As a convenience, the main export is a synchronous and asynchronous iterable that relies on package manifests being read by a callback. For asynchronous iteration, the callback may return promises which will be awaited before being passed to the generator.
npm i bare-module-resolve
For synchronous resolution:
const resolve = require('bare-module-resolve')
function readPackage (url) {
// Read and parse `url` if it exists, otherwise `null`
}
for (const resolution of resolve('./file.js', new URL('file:///directory/'), readPackage)) {
console.log(resolution)
}
For asynchronous resolution:
const resolve = require('bare-module-resolve')
async function readPackage (url) {
// Read and parse `url` if it exists, otherwise `null`
}
for await (const resolution of resolve('./file.js', new URL('file:///directory/'), readPackage)) {
console.log(resolution)
}
const resolver = resolve(specifier, parentURL[, options][, readPackage])
Resolve specifier
relative to parentURL
, which must be a WHATWG URL
instance. readPackage
is called with a URL
instance for every package manifest to be read and must either return the parsed JSON package manifest, if it exists, or null
. If readPackage
returns a promise, synchronous iteration is not supported.
Options include:
{
// A default "imports" map to apply to all specifiers. Follows the same
// syntax and rules as the "imports" property defined in `package.json`.
imports,
// A list of builtin module specifiers. If matched, the protocol of the
// resolved URL will be `builtinProtocol`.
builtins: [],
// The protocol to use for resolved builtin module specifiers.
builtinProtocol: 'builtin:',
// The supported import conditions. "default" is always recognized.
conditions: [],
// The supported engine versions.
engines: {},
// The file extensions to look for. Must be provided to support extensionless
// specifier resolution and directory support, such as resolving './foo' to
// './foo.js' or './foo/index.js'.
extensions: [],
// A map of preresolved imports with keys being serialized parent URLs and
// values being "imports" maps.
resolutions
}
for (const resolution of resolver)
Synchronously iterate the module resolution candidates. The resolved module is the first candidate that exists, either as a file on a file system, a resource at a URL, or something else entirely.
for await (const resolution of resolver)
Asynchronously iterate the module resolution candidates. If readPackage
returns promises, these will be awaited. The same comments as for (const resolution of resolver)
apply.
The following generator functions implement the resolution algorithm, which has been adapted from the Node.js resolution algorithms for CommonJS and ES modules. Unlike Node.js, Bare uses the same resolution algorithm for both module formats.
To drive the generator functions, a loop like the following can be used:
const generator = resolve.module(specifier, parentURL)
let next = generator.next()
while (next.done !== true) {
const value = next.value
if (value.package) {
const info = /* Read and parse `value.package` if it exists, otherwise `null` */;
next = generator.next(info)
} else {
const resolution = value.resolution
next = generator.next()
}
}
Options are the same as resolve()
for all functions.
const generator = resolve.module(specifier, parentURL[, options])
specifier
starts with a Windows drive letter:
/
to specifier
.options.resolutions
is set:
preresolved(specifier, options.resolutions, parentURL, options)
returns true
:
true
.url(specifier, parentURL, options)
returns true
:
true
.packageImports(specifier, parentURL, options)
returns true
:
true
.specifier
equals .
or ..
, or if specifier
starts with /
, \
, ./
, .\
, ../
, or ..\
:
options.imports
is set:
packageImportsExports(specifier, options.imports, parentURL, true, options)
returns true
:
true
.yielded
be false
.file(specifier, parentURL, false, options)
returns true
:
yielded
to true
.directory(specifier, parentURL, options)
returns true
:
yielded
to true
.yielded
.package(specifier, parentURL, options)
.const generator = resolve.url(url, parentURL[, options])
url
is not a valid URL:
false
.options.imports
is set:
packageImportsExports(url.href, options.imports, parentURL, true, options)
returns true
:
true
.url.protocol
equals node:
:
specifier
be url.pathname
.specifier
equals .
or ..
, or if specifier
starts with /
, \
, ./
, .\
, ../
, or ..\
, throw.package(specifier, parentURL, options)
url
and return true
.const generator = resolve.preresolved(specifier, resolutions, parentURL[, options])
imports
be resolutions[parentURL]
.imports
is a non-null
object:
packageImportsExports(specifier, imports, parentURL, true, options)
false
.const generator = resolve.package(packageSpecifier, parentURL[, options])
packageName
be undefined
.packageSpecifier
is the empty string, throw.options.builtins
includes packageSpecifier
:
options.builtinProtocol
concatenated with packageSpecifier
and return true
.packageSpecifier
does not start with @
:
packageName
to the substring of packageSpecifier
until the first /
or the end of the string.packageSpecifier
does not include /
, throw.packageName
to the substring of packageSpecifier
until the second /
or the end of the string.packageName
starts with .
or includes \
or %
, throw.packageSubpath
be .
concatenated with the substring of packageSpecifier
from the position at the length of packageName
.packageSelf(packageName, packageSubpath, parentURL, options)
returns true
:
true
.packageURL
be the resolution of node_modules/
concatenated with packageName
and /
relative to parentURL
.parentURL
to the substring of parentURL
until the last /
.info
be the result of yielding the resolution of package.json
relative to packageURL
.info
is not null
:
info.engines
is set:
validateEngines(packageURL, info.engines, options)
.info.exports
is set:
packageExports(packageURL, packageSubpath, info.exports, options)
.packageSubpath
is .
:
info.main
is a non-empty string:
packageSubpath
to info.main
.file('index', packageURL, true, options)
.yielded
be false
.
file(packageSubpath, packageURL, false, options)
returns true
:
yielded
to true
.directory(packageSubpath, packageURL, options)
returns true
:
yielded
to true
.yielded
.parentURL
is the file system root:
false
.const generator = resolve.packageSelf(packageName, packageSubpath, parentURL[, options])
packageURL
of lookupPackageScope(parentURL, options)
:
info
be the result of yielding packageURL
.info
is not null
:
info.name
equals packageName
:
false
.info.exports
is set:
packageExports(packageURL, packageSubpath, info.exports, options)
.packageSubpath
is .
:
info.main
is a non-empty string:
packageSubpath
to info.main
.file('index', packageURL, true, options)
.yielded
be false
.
file(packageSubpath, packageURL, false, options)
returns true
:
yielded
to true
.directory(packageSubpath, packageURL, options)
returns true
:
yielded
to true
.yielded
.false
.const generator = resolve.packageExports(packageURL, subpath, exports[, options])
subpath
is .
:
mainExport
be undefined
.exports
is a string or an array:
mainExport
to exports
.exports
is a non-null
object:
exports
start with .
:
.
is a key of exports
:
mainExport
to exports['.']
.mainExport
to exports
.mainExport
is not undefined
:
packageTarget(packageURL, mainExport, null, false, options)
returns true
:
true
.exports
is a non-null
object:
exports
starts with .
:
packageImportsExports(subpath, exports, packageURL, false, options)
returns true
:
true
.const generator = resolve.packageImports(specifier, parentURL[, options])
specifier
is #
or starts with #/
, throw.packageURL
of lookupPackageScope(parentURL, opions)
:
info
be the result of yielding packageURL
.info
is not null
:
info.imports
is set:
packageImportsExports(specifier, info.imports, packageURL, true, options)
returns true
:
true
.#
, throw.false
.options.imports
is set:
packageImportsExports(url.href, options.imports, parentURL, true, options)
returns true
:
true
.false
.const generator = resolve.packageImportsExports(matchKey, matchObject, packageURL, isImports[, options])
matchKey
is a key of matchObject
and matchKey
does not include *
:
target
be matchObject[matchKey]
.packageTarget(packageURL, target, null, isImports, options)
.expansionKeys
be the keys of matchObject
that include *
sorted by patternKeyCompare
.expansionKey
of expansionKeys
:
patternBase
be the substring of expansionKey
until the first *
.matchKey
starts with but isn't equal to patternBase
:
patternTrailer
be the substring of expansionKey
from the position at the index after the first *
.patternTrailer
is the empty string, or if matchKey
ends with patternTrailer
and the length of matchKey
is greater than or equal to the length of expansionKey
:
target
be matchObject[expansionKey]
.patternMatch
be the substring of matchKey
from the position at the length of patternBase
until the length of matchKey
minus the length of patternTrailer
.packageTarget(packageURL, target, patternMatch, isImports, options)
.false
.const generator = resolve.packageTarget(packageURL, target, patternMatch, isImports[, options])
target
is a string:
target
does not start with ./
and isImports
is false
, throw.patternMatch
is not null
:
*
in target
with patternMatch
.url(target, packageURL, options)
returns true
:
true
.target
equals .
or ..
, or if target
starts with /
, ./
, or ../
:
target
relative to packageURL
and return true
.package(target, packageURL, options)
.target
is an array:
targetValue
of target
:
packageTarget(packageURL, targetValue, patternMatch, isImports, options)
returns true
:
true
.target
is a non-null
object:
p
of target
:
p
equals default
or if options.conditions
includes p
:
targetValue
be target[p]
.packageTarget(packageURL, targetValue, patternMatch, isImports, options)
.false
.const generator = resolve.file(filename, parentURL, isIndex[, options])
filename
equals .
or ..
, or if filename
ends with /
or \
:
false
.parentURL
is a file:
URL and filename
includes encoded /
or \
, throw.isIndex
is false
:
filename
relative to parentURL
.ext
of options.extensions
:
filename
concatenated with ext
relative to parentURL
.isIndex
is false
or options.extensions
is non-empty:
true
.false
.const generator = resolve.directory(dirname, parentURL[, options])
directoryURL
be undefined
.dirname
ends with /
or \
:
directoryURL
to the resolution of dirname
relative to parentURL
.directoryURL
to the resolution of dirname
concatenated with /
relative to parentURL
.info
be the result of yielding the resolution of package.json
relative to directoryURL
.info
is not null
:
info.exports
is set:
packageExports(directoryURL, '.', info.exports, options)
.info.main
is a non-empty string:
yielded
be false
.file(info.main, directoryURL, false, options)
returns true
:
yielded
to true
.directory(info.main, directoryURL, options)
returns true
:
yielded
to true
.yielded
.file('index', directoryURL, true, options)
.Apache-2.0
© 2010 - cnpmjs.org x YWFE | Home | YWFE