解析算法规范
\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
令 matchKey 为与子路径连接的字符串 "./"。
\Let matchKey be the string "./" concatenated with subpath.
令 resolved 为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey,exports,packageURL,false,conditions)的结果。
\Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( matchKey, 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 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, 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.
断言:solvedTarget 包含在 packageURL 中。
\Assert: resolvedTarget is contained in packageURL.
如果 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 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,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".
令 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" or has no file extension, then
如果启用了
--experimental-wasm-modules并且 url 处的文件包含 WebAssembly 模块的标头,则\If
--experimental-wasm-modulesis enabled and the file at url contains the header for a WebAssembly module, then
返回 "wasm"。
\Return "wasm".
否则,
\Otherwise,
返回 "module"。
\Return "module".
返回未定义。
\Return undefined.
否则,
\Otherwise,
返回未定义。
\Return undefined.
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.