解析器算法规范
\Resolver 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 destructured value of 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.
加载解析为模块格式,格式。
\Load resolved as module format, format.
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 resolved destructured value of 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, "", false, false, criteria) 的结果。
\Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, mainExport, "", false, false, conditions).
如果已解决不为空或未定义,则
\If resolved is not null or undefined, then
返回解决。
\Return resolved.
否则,如果 exports 是一个 Object 并且 exports 的所有 key 都以 "." 开头,那么
\Otherwise, if exports is an Object and all keys of exports start with ".", then
令 matchKey 为与子路径连接的字符串 "./"。
\Let matchKey be the string "./" concatenated with subpath.
让 resolvedMatch 成为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey,exports,packageURL,false,conditions)的结果。
\Let resolvedMatch be result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( matchKey, exports, packageURL, false, conditions).
如果 resolvedMatch.resolve 不为 null 或未定义,则
\If resolvedMatch.resolve is not null or undefined, then
返回解决匹配。
\Return resolvedMatch.
抛出包路径未导出错误。
\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
让 resolvedMatch 成为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(specifier, pjson.imports, packageURL, true, Conditions)的结果。
\Let resolvedMatch be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE(specifier, pjson.imports, packageURL, true, conditions).
如果 resolvedMatch.resolve 不为 null 或未定义,则
\If resolvedMatch.resolve is not null or undefined, then
返回解决匹配。
\Return resolvedMatch.
抛出包导入未定义错误。
\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 end in "/" or contain ""*, then
令 target 为 matchObj[matchKey] 的值。
\Let target be the value of matchObj[matchKey].
令已解析为 PACKAGE_TARGET_RESOLVE(packageURL, target, "", false, isImports, Conditions) 的结果。
\Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, target, "", false, isImports, conditions).
返回对象 { resolved, exact: true }。
\Return the object { resolved, exact: true }.
令 expansionKeys 为 matchObj 的键列表,要么以 "/" 结尾,要么仅包含单个 "*",由排序函数 PATTERN_KEY_COMPARE 排序,该函数按特异性降序排列。
\Let expansionKeys be the list of keys of matchObj either ending in "/" or 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 为空。
\Let patternBase be null.
如果 expansionKey 包含 "",则将 patternBase 设置为 expansionKey 的子字符串,但不包括第一个 "" 字符。
\If expansionKey contains "", set patternBase to the substring of expansionKey up to but excluding the first "" character.
如果 patternBase 不为 null 并且 matchKey 以 patternBase 开头但不等于 patternBase,则
\If patternBase is not null and matchKey starts with but is not equal to patternBase, then
如果 matchKey 以 "/" 结尾,则抛出 Invalid Module Specifier 错误。
\If matchKey ends with "/", throw an Invalid Module Specifier error.
设 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].
令 subpath 为 matchKey 的子字符串,从 patternBase 长度的索引开始,直到 matchKey 的长度减去 patternTrailer 的长度。
\Let subpath 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.
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, true, isImports, Conditions) 的结果。
\Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, target, subpath, true, isImports, conditions).
返回对象 { resolved, exact: true }。
\Return the object { resolved, exact: true }.
否则,如果 patternBase 为空并且 matchKey 以 expandationKey 开头,则
\Otherwise if patternBase is null and matchKey starts with expansionKey, then
令 target 为 matchObj[expansionKey] 的值。
\Let target be the value of matchObj[expansionKey].
设 subpath 是从 expansionKey 长度的索引开始的 matchKey 的子字符串。
\Let subpath be the substring of matchKey starting at the index of the length of expansionKey.
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, false, isImports, Conditions) 的结果。
\Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, target, subpath, false, isImports, conditions).
返回对象 { resolved, exact: false }。
\Return the object { resolved, exact: false }.
返回对象 { resolved: null, exact: true }。
\Return the object { resolved: null, exact: true }.
PATTERN_KEY_COMPARE(keyA, keyB)
断言:keyA 以 "/" 结尾或仅包含一个 "*"。
\Assert: keyA ends with "/" or contains only a single ""*.
断言:keyB 以 "/" 结尾或仅包含一个 "*"。
\Assert: keyB ends with "/" or contains only a single ""*.
令 baseLengthA 为 "" 在 keyA 中的索引加一,如果 keyA 包含 "",否则为 keyA 的长度。
\Let baseLengthA be the index of ""* in keyA plus one, if keyA contains ""*, or the length of keyA otherwise.
令 baseLengthB 为 "" 在 keyB 中的索引加一,如果 keyB 包含 "",否则为 keyB 的长度。
\Let baseLengthB be the index of ""* in keyB plus one, if keyB contains ""*, or the length of keyB otherwise.
如果 baseLengthA 大于 baseLengthB,则返回 -1。
\If baseLengthA is greater than baseLengthB, return -1.
如果 baseLengthB 大于 baseLengthA,则返回 1。
\If baseLengthB is greater than baseLengthA, return 1.
如果 keyA 不包含 "*",则返回 1。
\If keyA does not contain ""*, return 1.
如果 keyB 不包含 "*",则返回 -1。
\If keyB does not contain ""*, 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, subpath, pattern, internal, conditions)
如果目标是一个字符串,那么
\If target is a String, then
如果模式为 false,子路径具有非零长度并且目标不以 "/" 结尾,则抛出无效模块说明符错误。
\If pattern is false, subpath has non-zero length and target does not end with "/", throw an Invalid Module Specifier error.
如果目标不是以 "./" 开头,则
\If target does not start with "./", then
如果内部为 true 并且目标不以 "../" 或 "/" 开头并且不是有效的 URL,则
\If internal is true and target does not start with "../" or "/" and is not a valid URL, then
如果模式为真,那么
\If pattern is true, then
返回 PACKAGE_RESOLVE(目标,其中 "*" 的每个实例都替换为子路径,packageURL + "/")。
\Return PACKAGE_RESOLVE(target with every instance of ""* replaced by subpath, packageURL + "/").
返回 PACKAGE_RESOLVE(目标 + 子路径, packageURL + "/")。
\Return PACKAGE_RESOLVE(target + subpath, packageURL + "/").
否则,抛出一个 Invalid Package Target 错误。
\Otherwise, throw an Invalid Package Target error.
如果 "/" 或 "" 上的目标拆分在第一个段之后包含任何 "."、".." 或 "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.
断言:solvedTarget 包含在 packageURL 中。
\Assert: resolvedTarget is contained in packageURL.
如果 "/" 或 "" 上的子路径拆分包含任何 "."、".." 或 "node_modules" 段,不区分大小写并包括百分比编码变体,则抛出无效模块说明符错误。
\If subpath split on "/" or "" contains any ".", "..", or "node_modules" segments, case insensitive and including percent encoded variants, throw an Invalid Module Specifier error.
如果模式为真,那么
\If pattern is true, then
返回 resolvedTarget 的 URL 解析,其中 "*" 的每个实例都替换为子路径。
\Return the URL resolution of resolvedTarget with every instance of ""* replaced with subpath.
否则,
\Otherwise,
返回 subpath 和 resolvedTarget 串联的 URL 解析。
\Return the URL resolution of the concatenation of subpath and resolvedTarget.
否则,如果 target 是非空对象,则
\Otherwise, if target is a non-null Object, then
如果导出包含任何索引属性键,如 ECMA-262 6.1.7 数组索引 中所定义,则抛出无效包配置错误。
\If exports 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, subpath,pattern,internal,conditions)的结果。
\Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, subpath, pattern, internal, 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, subpath,pattern,internal,conditions)的结果,在任何无效的包目标错误上继续循环。
\Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, subpath, pattern, internal, 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".
令 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).
如果 pjson?.type 存在且为 "module",则
\If pjson?.type exists and is "module", then
如果 url 以 ".js" 结尾,则
\If url ends in ".js", then
返回 "module"。
\Return "module".
抛出不支持的文件扩展名错误。
\Throw an Unsupported File Extension error.
否则,
\Otherwise,
抛出不支持的文件扩展名错误。
\Throw an Unsupported File Extension error.
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.