解析算法规范
¥Resolution Algorithm Specification
ESM_RESOLVE(specifier, parentURL)
让 resolved 为未定义。
¥Let resolved be undefined.
如果说明符是有效的 URL,则
¥If specifier is a valid URL, then
将 resolved 设置为将说明符解析和重新序列化为 URL 的结果。
¥Set resolved to the result of parsing and reserializing specifier as a URL.
否则,如果说明符以 "/"、"./" 或 "../" 开头,则
¥Otherwise, if specifier starts with "/", "./", or "../", then
将 resolved 设置为说明符相对于 parentURL 的 URL 解析。
¥Set resolved to the URL resolution of specifier relative to parentURL.
否则,如果说明符以 "" 开头,则
¥Otherwise, if specifier starts with "#", then
将已解析设置为 PACKAGE_IMPORTS_RESOLVE(specifier,parentURL,defaultConditions) 的结果。
¥Set resolved to the result of PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions).
否则,
¥Otherwise,
注意:说明符现在是一个裸说明符。
¥Note: specifier is now a bare specifier.
设置解析 PACKAGE_RESOLVE(specifier,parentURL) 的结果。
¥Set resolved the result of PACKAGE_RESOLVE(specifier, parentURL).
让格式未定义。
¥Let format be undefined.
如果解析的是 "file:" URL,则
¥If resolved is a "file:" URL, then
如果已解析包含 "/" 或 ""(分别为 "%2F" 和 "%5C")的任何百分比编码,则
¥If resolved contains any percent encodings of "/" or "" ("%2F" and "%5C" respectively), then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
如果解析的文件是一个目录,那么
¥If the file at resolved is a directory, then
引发不支持的目录导入错误。
¥Throw an Unsupported Directory Import error.
如果已解析的文件不存在,则
¥If the file at resolved does not exist, then
抛出模块未找到错误。
¥Throw a Module Not Found error.
设置 resolved 为 resolved 的真实路径,保持相同的 URL querystring 和 fragment 组件。
¥Set resolved to the real path of resolved, maintaining the same URL querystring and fragment components.
将格式设置为 ESM_FILE_FORMAT(resolved) 的结果。
¥Set format to the result of ESM_FILE_FORMAT(resolved).
否则,
¥Otherwise,
设置格式与解析的 URL 关联的内容类型的模块格式。
¥Set format the module format of the content type associated with the URL resolved.
返回格式并解析到加载阶段
¥Return format and resolved to the loading phase
PACKAGE_RESOLVE(packageSpecifier, parentURL)
让 packageName 未定义。
¥Let packageName be undefined.
如果 packageSpecifier 是空字符串,则
¥If packageSpecifier is an empty string, then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
如果 packageSpecifier 是 Node.js 内置模块名称,则
¥If packageSpecifier is a Node.js builtin module name, then
返回与 packageSpecifier 连接的字符串 "node:"。
¥Return the string "node:" concatenated with packageSpecifier.
如果 packageSpecifier 不以 "@" 开头,则
¥If packageSpecifier does not start with "@", then
将 packageName 设置为 packageSpecifier 的子字符串,直到第一个 "/" 分隔符或字符串的结尾。
¥Set packageName to the substring of packageSpecifier until the first "/" separator or the end of the string.
否则,
¥Otherwise,
如果 packageSpecifier 不包含 "/" 分隔符,则
¥If packageSpecifier does not contain a "/" separator, then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
将 packageName 设置为 packageSpecifier 的子字符串,直到第二个 "/" 分隔符或字符串的末尾。
¥Set packageName to the substring of packageSpecifier until the second "/" separator or the end of the string.
如果 packageName 以 "." 开头或包含 "" 或 "%",则
¥If packageName starts with "." or contains "" or "%", then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
让 packageSubpath "." 与 packageSpecifier 的子字符串从 packageName 长度的位置连接起来。
¥Let packageSubpath be "." concatenated with the substring of packageSpecifier from the position at the length of packageName.
如果 packageSubpath 以 "/" 结尾,则
¥If packageSubpath ends in "/", then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
令 selfUrl 为 PACKAGE_SELF_RESOLVE(packageName, packageSubpath, ParentURL) 的结果。
¥Let selfUrl be the result of PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL).
如果 selfUrl 不是未定义,则返回 selfUrl。
¥If selfUrl is not undefined, return selfUrl.
虽然 parentURL 不是文件系统根目录,
¥While parentURL is not the file system root,
令 packageURL 为 "node_modules/" 的 URL 解析与 packageSpecifier 连接,相对于 parentURL。
¥Let packageURL be the URL resolution of "node_modules/" concatenated with packageSpecifier, relative to parentURL.
将 parentURL 设置为 parentURL 的父文件夹 URL。
¥Set parentURL to the parent folder URL of parentURL.
如果 packageURL 处的文件夹不存在,则
¥If the folder at packageURL does not exist, then
继续下一个循环迭代。
¥Continue the next loop iteration.
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson 不为 null 并且 pjson.exports 不为 null 或未定义,则
¥If pjson is not null and pjson.exports is not null or undefined, then
返回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的结果。
¥Return the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).
否则,如果 packageSubpath 等于 ".",则
¥Otherwise, if packageSubpath is equal to ".", then
如果 pjson.main 是一个字符串,那么
¥If pjson.main is a string, then
返回 packageURL 中 main 的 URL 解析。
¥Return the URL resolution of main in packageURL.
否则,
¥Otherwise,
返回 packageURL 中 packageSubpath 的 URL 解析。
¥Return the URL resolution of packageSubpath in packageURL.
抛出模块未找到错误。
¥Throw a Module Not Found error.
PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)
令 packageURL 为 LOOKUP_PACKAGE_SCOPE(parentURL) 的结果。
¥Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
如果 packageURL 为 null,则
¥If packageURL is null, then
返回未定义。
¥Return undefined.
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson 为 null 或者 pjson.exports 为 null 或未定义,则
¥If pjson is null or if pjson.exports is null or undefined, then
返回未定义。
¥Return undefined.
如果 pjson.name 等于 packageName,则
¥If pjson.name is equal to packageName, then
返回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的结果。
¥Return the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).
否则,返回未定义。
¥Otherwise, return undefined.
PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)
如果 exports 是一个对象,其键值以 "." 开头,键值不以 "." 开头,则抛出无效包配置错误。
¥If exports is an Object with both a key starting with "." and a key not starting with ".", throw an Invalid Package Configuration error.
如果子路径等于 ".",则
¥If subpath is equal to ".", then
让 mainExport 未定义。
¥Let mainExport be undefined.
如果导出是字符串或数组,或者不包含以 "." 开头的键的对象,则
¥If exports is a String or Array, or an Object containing no keys starting with ".", then
将 mainExport 设置为导出。
¥Set mainExport to exports.
否则,如果导出是包含 "." 属性的对象,则
¥Otherwise if exports is an Object containing a "." property, then
将 mainExport 设置为导出 ["."]。
¥Set mainExport to exports["."].
如果 mainExport 不是未定义的,那么
¥If mainExport is not undefined, then
令已解析为 PACKAGE_TARGET_RESOLVE(packageURL, mainExport, null, false, criteria) 的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, mainExport, null, false, conditions).
如果 resolved 不为 null 或未定义,则返回 resolved。
¥If resolved is not null or undefined, return resolved.
否则,如果 exports 是一个 Object 并且 exports 的所有 key 都以 "." 开头,那么
¥Otherwise, if exports is an Object and all keys of exports start with ".", then
断言:子路径以 "./" 开头。
¥Assert: subpath begins with "./".
令 resolved 为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(subpath,exports,packageURL,false,conditions)的结果。
¥Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( subpath, exports, packageURL, false, conditions).
如果 resolved 不为 null 或未定义,则返回 resolved。
¥If resolved is not null or undefined, return resolved.
抛出包路径未导出错误。
¥Throw a Package Path Not Exported error.
PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)
断言:说明符以 "" 开头。
¥Assert: specifier begins with "#".
如果说明符完全等于 "" 或以 "#/" 开头,则
¥If specifier is exactly equal to "#" or starts with "#/", then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
令 packageURL 为 LOOKUP_PACKAGE_SCOPE(parentURL) 的结果。
¥Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
如果 packageURL 不为 null,则
¥If packageURL is not null, then
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson.imports 是一个非空对象,那么
¥If pjson.imports is a non-null Object, then
令 resolved 为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(specifier, pjson.imports, packageURL, true, Conditions) 的结果。
¥Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions).
如果 resolved 不为 null 或未定义,则返回 resolved。
¥If resolved is not null or undefined, return resolved.
抛出包导入未定义错误。
¥Throw a Package Import Not Defined error.
PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)
如果 matchKey 是 matchObj 的键并且不包含 "*",则
¥If matchKey is a key of matchObj and does not contain ""*, then
令 target 为 matchObj[matchKey] 的值。
¥Let target be the value of matchObj[matchKey].
返回 PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, Conditions) 的结果。
¥Return the result of PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions).
令 expansionKeys 为仅包含单个 "*" 的 matchObj 的键列表,由排序函数 PATTERN_KEY_COMPARE 排序,该函数按特异性降序排列。
¥Let expansionKeys be the list of keys of matchObj containing only a single ""*, sorted by the sorting function PATTERN_KEY_COMPARE which orders in descending order of specificity.
对于 expansionKeys 中的每个密钥 expansionKey,执行
¥For each key expansionKey in expansionKeys, do
设 patternBase 是 expansionKey 的子串,但不包括第一个 "*" 字符。
¥Let patternBase be the substring of expansionKey up to but excluding the first ""* character.
如果 matchKey 以 patternBase 开头但不等于 patternBase,则
¥If matchKey starts with but is not equal to patternBase, then
设 patternTrailer 是第一个 "*" 字符后索引中 expansionKey 的子串。
¥Let patternTrailer be the substring of expansionKey from the index after the first ""* character.
如果 patternTrailer 的长度为零,或者 matchKey 以 patternTrailer 结尾并且 matchKey 的长度大于或等于 expandationKey 的长度,则
¥If patternTrailer has zero length, or if matchKey ends with patternTrailer and the length of matchKey is greater than or equal to the length of expansionKey, then
令 target 为 matchObj[expansionKey] 的值。
¥Let target be the value of matchObj[expansionKey].
令 patternMatch 为 matchKey 的子字符串,从 patternBase 长度的索引开始,直到 matchKey 的长度减去 patternTrailer 的长度。
¥Let patternMatch be the substring of matchKey starting at the index of the length of patternBase up to the length of matchKey minus the length of patternTrailer.
返回 PACKAGE_TARGET_RESOLVE(packageURL,target,patternMatch,isImports,conditions)的结果。
¥Return the result of PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions).
返回空值。
¥Return null.
PATTERN_KEY_COMPARE(keyA, keyB)
断言:keyA 仅包含一个 "*"。
¥Assert: keyA contains only a single ""*.
断言:keyB 仅包含一个 "*"。
¥Assert: keyB contains only a single ""*.
让 baseLengthA 成为 keyA 中 "*" 的索引。
¥Let baseLengthA be the index of ""* in keyA.
让 baseLengthB 成为 keyB 中 "*" 的索引。
¥Let baseLengthB be the index of ""* in keyB.
如果 baseLengthA 大于 baseLengthB,则返回 -1。
¥If baseLengthA is greater than baseLengthB, return -1.
如果 baseLengthB 大于 baseLengthA,则返回 1。
¥If baseLengthB is greater than baseLengthA, return 1.
如果 keyA 的长度大于 keyB 的长度,返回-1。
¥If the length of keyA is greater than the length of keyB, return -1.
如果 keyB 的长度大于 keyA 的长度,则返回 1。
¥If the length of keyB is greater than the length of keyA, return 1.
返回 0。
¥Return 0.
PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions)
如果目标是一个字符串,那么
¥If target is a String, then
如果目标不是以 "./" 开头,则
¥If target does not start with "./", then
如果 isImports 为 false,或者目标以 "../" 或 "/" 开头,或者目标是有效的 URL,则
¥If isImports is false, or if target starts with "../" or "/", or if target is a valid URL, then
抛出一个无效的包目标错误。
¥Throw an Invalid Package Target error.
如果 patternMatch 是一个字符串,那么
¥If patternMatch is a String, then
返回 PACKAGE_RESOLVE(目标,其中 "*" 的每个实例都替换为模式匹配,packageURL + "/")。
¥Return PACKAGE_RESOLVE(target with every instance of ""* replaced by patternMatch, packageURL + "/").
返回 PACKAGE_RESOLVE(目标, packageURL + "/")。
¥Return PACKAGE_RESOLVE(target, packageURL + "/").
如果 "/" 或 "" 上的目标拆分在第一个 "." 段之后包含任何 ""、"."、".." 或 "node_modules" 段,不区分大小写并包括百分比编码变体,则抛出无效包目标错误。
¥If target split on "/" or "" contains any "", ".", "..", or "node_modules" segments after the first "." segment, case insensitive and including percent encoded variants, throw an Invalid Package Target error.
令 resolvedTarget 为 packageURL 和 target 串联的 URL 解析。
¥Let resolvedTarget be the URL resolution of the concatenation of packageURL and target.
断言:packageURL 包含在 resolvedTarget 中。
¥Assert: packageURL is contained in resolvedTarget.
如果 patternMatch 为空,那么
¥If patternMatch is null, then
返回已解决的目标。
¥Return resolvedTarget.
如果在 "/" 或 "" 上拆分的 patternMatch 包含任何 ""、"."、".." 或 "node_modules" 段,不区分大小写并包括百分比编码变体,则抛出无效模块说明符错误。
¥If patternMatch split on "/" or "" contains any "", ".", "..", or "node_modules" segments, case insensitive and including percent encoded variants, throw an Invalid Module Specifier error.
返回 resolvedTarget 的 URL 解析,其中 "*" 的每个实例都替换为 patternMatch。
¥Return the URL resolution of resolvedTarget with every instance of ""* replaced with patternMatch.
否则,如果 target 是非空对象,则
¥Otherwise, if target is a non-null Object, then
如果目标包含任何索引属性键(如 ECMA-262 6.1.7 数组索引 中定义),则抛出无效包配置错误。
¥If target contains any index property keys, as defined in ECMA-262 6.1.7 Array Index, throw an Invalid Package Configuration error.
对于目标的每个属性 p,按对象插入顺序为:
¥For each property p of target, in object insertion order as,
如果 p 等于 "default" 或条件包含 p 的条目,则
¥If p equals "default" or conditions contains an entry for p, then
设 targetValue 为 target 中 p 属性的值。
¥Let targetValue be the value of the p property in target.
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, targetValue,patternMatch,isImports,conditions) 的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions).
如果 resolved 等于 undefined,则继续循环。
¥If resolved is equal to undefined, continue the loop.
返回解决。
¥Return resolved.
返回未定义。
¥Return undefined.
否则,如果 target 是一个数组,那么
¥Otherwise, if target is an Array, then
如果 _target.length 为零,则返回 null。
¥If _target.length is zero, return null.
对于目标中的每个项目 targetValue,执行
¥For each item targetValue in target, do
让 resolved 成为 PACKAGE_TARGET_RESOLVE(packageURL, targetValue,patternMatch,isImports,conditions)的结果,在出现任何 Invalid Package Target 错误时继续循环。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions), continuing the loop on any Invalid Package Target error.
如果 resolved 未定义,则继续循环。
¥If resolved is undefined, continue the loop.
返回解决。
¥Return resolved.
返回或抛出最后的后备解决方案 null 返回或错误。
¥Return or throw the last fallback resolution null return or error.
否则,如果 target 为 null,则返回 null。
¥Otherwise, if target is null, return null.
否则抛出一个 Invalid Package Target 错误。
¥Otherwise throw an Invalid Package Target error.
ESM_FILE_FORMAT(url)
断言:url 对应于现有文件。
¥Assert: url corresponds to an existing file.
如果 url 以 ".mjs" 结尾,则
¥If url ends in ".mjs", then
返回 "module"。
¥Return "module".
如果 url 以 ".cjs" 结尾,则
¥If url ends in ".cjs", then
返回 "commonjs"。
¥Return "commonjs".
如果 url 以 ".json" 结尾,则
¥If url ends in ".json", then
返回 "json"。
¥Return "json".
如果启用了
--experimental-wasm-modules
并且 url 以 ".wasm" 结尾,则¥If
--experimental-wasm-modules
is enabled and url ends in ".wasm", then
返回 "wasm"。
¥Return "wasm".
令 packageURL 为 LOOKUP_PACKAGE_SCOPE(url) 的结果。
¥Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(url).
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
令 packageType 为空。
¥Let packageType be null.
如果 pjson?.type 是 "module" 或 "commonjs",那么
¥If pjson?.type is "module" or "commonjs", then
将 packageType 设置为 pjson.type。
¥Set packageType to pjson.type.
如果 url 以 ".js" 结尾,则
¥If url ends in ".js", then
如果 packageType 不为 null,则
¥If packageType is not null, then
返回包类型。
¥Return packageType.
如果 DETECT_MODULE_SYNTAX(source) 的结果为真,则
¥If the result of DETECT_MODULE_SYNTAX(source) is true, then
返回 "module"。
¥Return "module".
返回 "commonjs"。
¥Return "commonjs".
如果 url 没有任何扩展名,则
¥If url does not have any extension, then
如果 packageType 为 "module" 并且
--experimental-wasm-modules
已启用,并且 url 处的文件包含 WebAssembly 模块的标头,则¥If packageType is "module" and
--experimental-wasm-modules
is enabled and the file at url contains the header for a WebAssembly module, then
返回 "wasm"。
¥Return "wasm".
如果 packageType 不为 null,则
¥If packageType is not null, then
返回包类型。
¥Return packageType.
如果 DETECT_MODULE_SYNTAX(source) 的结果为真,则
¥If the result of DETECT_MODULE_SYNTAX(source) is true, then
返回 "module"。
¥Return "module".
返回 "commonjs"。
¥Return "commonjs".
返回未定义(将在加载阶段抛出)。
¥Return undefined (will throw during load phase).
LOOKUP_PACKAGE_SCOPE(url)
让 scopeURL 为 url。
¥Let scopeURL be url.
虽然 scopeURL 不是文件系统根目录,
¥While scopeURL is not the file system root,
将 scopeURL 设置为 scopeURL 的父 URL。
¥Set scopeURL to the parent URL of scopeURL.
如果 scopeURL 以 "node_modules" 路径段结束,则返回 null。
¥If scopeURL ends in a "node_modules" path segment, return null.
设 pjsonURL 为 scopeURL 中 "package.json" 的解析。
¥Let pjsonURL be the resolution of "package.json" within scopeURL.
如果 pjsonURL 处的文件存在,则
¥if the file at pjsonURL exists, then
返回范围 URL。
¥Return scopeURL.
返回空值。
¥Return null.
READ_PACKAGE_JSON(packageURL)
设 pjsonURL 为 packageURL 中 "package.json" 的解析。
¥Let pjsonURL be the resolution of "package.json" within packageURL.
如果 pjsonURL 处的文件不存在,则
¥If the file at pjsonURL does not exist, then
返回空值。
¥Return null.
如果 packageURL 处的文件未解析为有效的 JSON,则
¥If the file at packageURL does not parse as valid JSON, then
抛出一个无效的包配置错误。
¥Throw an Invalid Package Configuration error.
在 pjsonURL 返回文件的已解析 JSON 源。
¥Return the parsed JSON source of the file at pjsonURL.
DETECT_MODULE_SYNTAX(source)
将源代码解析为 ECMAScript 模块。
¥Parse source as an ECMAScript module.
如果解析成功,则
¥If the parse is successful, then
如果 source 包含顶层
await
、静态import
或export
语句或import.meta
,则返回 true。¥If source contains top-level
await
, staticimport
orexport
statements, orimport.meta
, return true.如果 source 包含任何 CommonJS 封装器变量(
require
、exports
、module
、__filename
或__dirname
)的顶层词法声明(const
、let
或class
),则返回 true。¥If source contains a top-level lexical declaration (
const
,let
, orclass
) of any of the CommonJS wrapper variables (require
,exports
,module
,__filename
, or__dirname
) then return true.否则返回 false。
¥Else return false.