URL 模式

现行标准 — 最后更新

参与:
GitHub whatwg/urlpattern (新问题, 开放问题)
在 Matrix 上聊天
提交:
GitHub whatwg/urlpattern/commits
此提交时的快照
@urlpatterns
测试:
web-platform-tests urlpattern/ (正在进行的工作)

摘要

URL 模式标准为基于方便的模式语法匹配 URL 提供了一个网页平台的原语。

1. URL 模式

1.1. 介绍

一个 URL 模式 由多个 组件 组成,每个组件代表一个可以与 URL 的对应组件匹配的 模式

它可以通过为每个组件提供字符串或通过简写字符串构造。它还可以选择相对于基 URL 进行解析。

简写 "https://example.com/:category/*" 对应以下组件:

协议
"https"
用户名
"*"
密码
"*"
主机名
"example.com"
端口
""
路径名
"/:category/*"
查询
"*"
哈希
"*"

它匹配以下 URL:

它不匹配以下 URL:

这是一个相对简单的模式,要求大多数组件要么匹配一个确切的字符串,要么允许任意字符串 ("*")。路径名组件 匹配具有至少两个 / 分隔的路径组件的路径,其中第一个被捕获为 "category"。

简写 "http{s}?://{:subdomain.}?shop.example/products/:id([0-9]+)#reviews" 对应以下组件:

协议
"http{s}?"
用户名
"*"
密码
"*"
主机名
"{:subdomain.}?shop.example"
端口
""
路径名
"/products/:id([0-9]+)"
查询
""
哈希
"reviews"

它匹配以下 URL:

它不匹配以下 URL:

这是一个更复杂的模式,包含:

简写 "../admin/*" 和基 URL "https://discussion.example/forum/?page=2" 对应以下组件:

协议
"https"
用户名
"*"
密码
"*"
主机名
"discussion.example"
端口
""
路径名
"/admin/*"
查询
"*"
哈希
"*"

它匹配以下 URL:

它不匹配以下 URL:

此模式展示了路径名如何相对于基 URL 进行解析,类似于相对 URL 的解析方式。

1.2. URLPattern

typedef (USVString or URLPatternInit) URLPatternInput;

[Exposed=(Window,Worker)]
interface URLPattern {
  constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {});
  constructor(optional URLPatternInput input = {}, optional URLPatternOptions options = {});

  boolean test(optional URLPatternInput input = {}, optional USVString baseURL);

  URLPatternResult? exec(optional URLPatternInput input = {}, optional USVString baseURL);

  readonly attribute USVString protocol;
  readonly attribute USVString username;
  readonly attribute USVString password;
  readonly attribute USVString hostname;
  readonly attribute USVString port;
  readonly attribute USVString pathname;
  readonly attribute USVString search;
  readonly attribute USVString hash;

  readonly attribute boolean hasRegExpGroups;
};

dictionary URLPatternInit {
  USVString protocol;
  USVString username;
  USVString password;
  USVString hostname;
  USVString port;
  USVString pathname;
  USVString search;
  USVString hash;
  USVString baseURL;
};

dictionary URLPatternOptions {
  boolean ignoreCase = false;
};

dictionary URLPatternResult {
  sequence<URLPatternInput> inputs;

  URLPatternComponentResult protocol;
  URLPatternComponentResult username;
  URLPatternComponentResult password;
  URLPatternComponentResult hostname;
  URLPatternComponentResult port;
  URLPatternComponentResult pathname;
  URLPatternComponentResult search;
  URLPatternComponentResult hash;
};

dictionary URLPatternComponentResult {
  USVString input;
  record<USVString, (USVString or undefined)> groups;
};

每个 URLPattern 都有一个关联的URL模式,一个 URL模式

urlPattern = new URLPattern(input)
构建一个新的 URLPattern 对象。input 是一个包含每个URL组件(如主机名、路径名等)的分离模式的对象。缺失的组件将默认为通配符模式。此外,input 可以包含一个 baseURL 属性,该属性为任何缺失的组件提供静态文本模式。
urlPattern = new URLPattern(patternString, baseURL)
构建一个新的 URLPattern 对象。patternString 是一个包含一个或多个组件的模式语法的URL字符串。如果提供了 baseURL,那么 patternString 可以是相对的。此构造函数始终至少设置一个空字符串值,并且不将任何组件默认为通配符模式。
urlPattern = new URLPattern(input, options)
构建一个新的 URLPattern 对象。options 是一个包含其他配置选项的对象,这些选项可以影响组件的匹配方式。目前它只有一个属性 ignoreCase,可以设置为 true 以启用不区分大小写的匹配。

请注意,默认情况下(即在没有 options 参数的情况下),匹配总是区分大小写的。

urlPattern = new URLPattern(patternString, baseURL, options)
构建一个新的 URLPattern 对象。这支持一个 URLPatternOptions 对象,当从 patternString 对象构造模式时,用来描述各个组件的模式以及基本URL。
matches = urlPattern.test(input)
测试 urlPattern 是否匹配给定的参数。input 是一个包含表示每个URL组件的字符串的对象;例如主机名、路径名等。缺失的组件被视为空字符串。此外,input 可以包含一个 baseURL 属性,该属性为任何缺失的组件提供值。如果 urlPattern 按照组件逐一匹配 input,则返回 true。否则,返回 false。
matches = urlPattern.test(url, baseURL)
测试 urlPattern 是否匹配给定的参数。url 是一个URL字符串。如果提供了 baseURL,那么 url 可以是相对的。

如果 urlPattern 按照组件逐一匹配 input,则返回 true。否则,返回 false。

result = urlPattern.exec(input)
根据给定的参数执行 urlPatterninput 是一个包含表示每个URL组件的字符串的对象;例如主机名、路径名等。缺失的组件被视为空字符串。此外,input 可以包含一个 baseURL 属性,为任何缺失的组件提供值。

如果 urlPattern 按照组件逐一匹配 input,则返回一个包含结果的对象。匹配的组值包含在 result 对象内的各组件组对象中;例如 matches.pathname.groups.id。如果 urlPattern 不匹配 input,则 result 为 null。

result = urlPattern.exec(url, baseURL)
根据给定的参数执行 urlPatternurl 是一个URL字符串。如果提供了 baseURL,那么 input 可以是相对的。

如果 urlPattern 按照组件逐一匹配 input,则返回一个包含结果的对象。匹配的组值包含在 result 对象内的各组件组对象中;例如 matches.pathname.groups.id。如果 urlPattern 不匹配 input,则 result 为 null。

urlPattern.protocol

返回 urlPattern 的规范化协议模式字符串。

urlPattern.username

返回 urlPattern 的规范化用户名模式字符串。

urlPattern.password

返回 urlPattern 的规范化密码模式字符串。

urlPattern.hostname

返回 urlPattern 的规范化主机名模式字符串。

urlPattern.port

返回 urlPattern 的规范化端口模式字符串。

urlPattern.pathname

返回 urlPattern 的规范化路径名模式字符串。

urlPattern.search

返回 urlPattern 的规范化搜索模式字符串。

urlPattern.hash

返回 urlPattern 的规范化哈希模式字符串。

urlPattern.hasRegExpGroups

返回 urlPattern 是否包含一个或多个使用正则表达式匹配的组。

new URLPattern(input, baseURL, options) 构造函数步骤为:
  1. 运行 initialize,给定 thisinputbaseURL,以及 options

new URLPattern(input, options) 构造函数步骤为:
  1. 运行 initialize,给定 thisinput,null,以及 options

初始化 一个 URLPattern 给定一个 URLPattern thisURLPatternInput input,字符串或 null baseURL,以及 URLPatternOptions options
  1. this关联的URL模式 设置为根据 inputbaseURLoptions 生成的结果。

protocol 获取器步骤为:
  1. 返回 this关联的URL模式协议组件模式字符串

username 获取器步骤为:
  1. 返回 this关联的URL模式用户名组件模式字符串

password 获取器步骤为:
  1. 返回 this关联的URL模式密码组件模式字符串

hostname 获取器步骤为:
  1. 返回 this关联的URL模式主机名组件模式字符串

port 获取器步骤为:
  1. 返回 this关联的URL模式端口组件模式字符串

pathname 获取器步骤为:
  1. 返回 this关联的URL模式路径名组件模式字符串

search 获取器步骤为:
  1. 返回 this关联的URL模式搜索组件模式字符串

hash 获取器步骤为:
  1. 返回 this关联的URL模式哈希组件模式字符串

hasRegExpGroups 获取器步骤为:
  1. 如果 this关联的URL模式正则表达式组 存在,则返回 true。

  2. 返回 false。

test(input, baseURL) 方法步骤为:
  1. result匹配的结果,给定 this关联的URL模式input,以及(如果有)baseURL

  2. 如果 result 为 null,返回 false。

  3. 返回 true。

exec(input, baseURL) 方法步骤为:
  1. 返回 匹配的结果,给定 this关联的URL模式input,以及(如果有)baseURL

1.3. URL 模式结构体

URL 模式 是一个包含以下 结构体条目:

组件 是一个包含以下 结构体条目:

1.4. 高级操作

若要给定 URLPatternInput input、字符串或空值 baseURLURLPatternOptions options创建一个 URL 模式
  1. init 设为 null。

  2. 如果 input 是一个 标量值字符串,则:

    1. init 设置为运行 解析构造字符串 后的结果,并给定 input

    2. 如果 baseURL 为 null 且 init["protocol"] 不 存在,则抛出一个 TypeError

    3. 如果 baseURL 不为 null,则 设置 init["baseURL"] 为 baseURL

  3. 否则:

    1. 断言inputURLPatternInit

    2. 如果 baseURL 不为 null,则抛出一个 TypeError

    3. init 设置为 input

  4. processedInit 设置为 处理 URLPatternInit 的结果,并给定 init、"pattern"、null、null、null、null、null、null、null 和 null。

  5. 对每个 « "protocol", "username", "password", "hostname", "port", "pathname", "search", "hash" » 的 componentName

    1. 如果 processedInit[componentName] 不 存在,则 设置 processedInit[componentName] 为 "*"。

  6. 如果 processedInit["protocol"] 是一个 特殊方案,且 processedInit["port"] 是一个表示其对应 默认端口 的字符串,使用 ASCII 数字 表示,则将 processedInit["port"] 设置为空字符串。

  7. urlPattern 设为一个新的 URL 模式

  8. urlPattern协议组件 设置为 编译组件 的结果,给定 processedInit["protocol"],规范化协议默认选项

  9. urlPattern用户名组件 设置为 编译组件 的结果,给定 processedInit["username"],规范化用户名默认选项

  10. urlPattern密码组件 设置为 编译组件 的结果,给定 processedInit["password"],规范化密码默认选项

  11. 如果运行 主机名模式是 IPv6 地址 的结果,给定 processedInit["hostname"] 为真,则将 urlPattern主机名组件 设置为 编译组件 的结果,给定 processedInit["hostname"],规范化 IPv6 主机名主机名选项

  12. 否则,将 urlPattern主机名组件 设置为 编译组件 的结果,给定 processedInit["hostname"],规范化主机名主机名选项

  13. urlPattern端口组件 设置为 编译组件 的结果,给定 processedInit["port"],规范化端口默认选项

  14. compileOptions 设置为 默认选项 的副本,忽略大小写 属性设置为 options["ignoreCase"]。

  15. 如果运行 协议组件匹配特殊方案 的结果为真,给定 urlPattern协议组件,则:

    1. pathCompileOptions 设置为 路径名选项 的副本,忽略大小写 属性设置为 options["ignoreCase"]。

    2. urlPattern路径名组件 设置为 编译组件 的结果,给定 processedInit["pathname"],规范化路径名pathCompileOptions

  16. 否则,将 urlPattern路径名组件 设置为 编译组件 的结果,给定 processedInit["pathname"],规范化不透明路径名compileOptions

  17. urlPattern查询组件 设置为 编译组件 的结果,给定 processedInit["search"],规范化查询compileOptions

  18. urlPattern哈希组件 设置为 编译组件 的结果,给定 processedInit["hash"],规范化哈希compileOptions

  19. 返回 urlPattern

若要执行 匹配,给定一个 URL 模式 urlPattern,一个 URLPatternInputURL input,以及一个可选的字符串 baseURLString
  1. protocol 设为空字符串。

  2. username 设为空字符串。

  3. password 设为空字符串。

  4. hostname 设为空字符串。

  5. port 设为空字符串。

  6. pathname 设为空字符串。

  7. search 设为空字符串。

  8. hash 设为空字符串。

  9. inputs 设为空 列表

  10. input 添加到 inputs 中。

  11. 如果 inputURLPatternInit,则:

    1. 如果提供了 baseURLString,则抛出 TypeError

    2. applyResult 设为 处理 URLPatternInit 的结果,给定 input、"url"、protocolusernamepasswordhostnameportpathnamesearchhash。如果抛出异常,捕获并返回 null。

    3. protocol 设为 applyResult["protocol"]。

    4. username 设为 applyResult["username"]。

    5. password 设为 applyResult["password"]。

    6. hostname 设为 applyResult["hostname"]。

    7. port 设为 applyResult["port"]。

    8. pathname 设为 applyResult["pathname"]。

    9. search 设为 applyResult["search"]。

    10. hash 设为 applyResult["hash"]。

  12. 否则:

    1. url 设为 input

    2. 如果 inputUSVString

      1. baseURL 设为 null。

      2. 如果提供了 baseURLString,则:

        1. baseURL 设置为 解析 baseURLString 的结果。

        2. 如果 baseURL 解析失败,返回 null。

        3. baseURLString 添加到 inputs 中。

      3. url 设置为 解析 input 的结果,给定 baseURL

      4. 如果 url 解析失败,返回 null。

    3. 断言url 是一个 URL

    4. protocol 设为 urlscheme

    5. username 设为 urlusername

    6. password 设为 urlpassword

    7. hostname 设为 urlhost序列化,或为空字符串如果值为 null。

    8. port 设为 urlport序列化,或为空字符串如果值为 null。

    9. pathname 设置为 URL 路径序列化 url 的结果。

    10. search 设为 urlquery 或为空字符串如果值为 null。

    11. hash 设为 urlfragment 或为空字符串如果值为 null。

  13. protocolExecResult 设为 RegExpBuiltinExec(urlPattern协议组件正则表达式protocol)。

  14. usernameExecResult 设为 RegExpBuiltinExec(urlPattern用户名组件正则表达式username)。

  15. passwordExecResult 设为 RegExpBuiltinExec(urlPattern密码组件正则表达式password)。

  16. hostnameExecResult 设为 RegExpBuiltinExec(urlPattern主机名组件正则表达式hostname)。

  17. portExecResult 设为 RegExpBuiltinExec(urlPattern端口组件正则表达式port)。

  18. pathnameExecResult 设为 RegExpBuiltinExec(urlPattern路径名组件正则表达式pathname)。

  19. searchExecResult 设为 RegExpBuiltinExec(urlPattern查询组件正则表达式search)。

  20. hashExecResult 设为 RegExpBuiltinExec(urlPattern哈希组件正则表达式hash)。

  21. 如果 protocolExecResultusernameExecResultpasswordExecResulthostnameExecResultportExecResultpathnameExecResultsearchExecResulthashExecResult 为 null,则返回 null。

  22. result 设为一个新的 URLPatternResult

  23. result["inputs"] 设置为 inputs

  24. result["protocol"] 设置为 创建组件匹配结果 的结果,给定 urlPattern协议组件protocolprotocolExecResult

  25. result["username"] 设置为 创建组件匹配结果 的结果,给定 urlPattern用户名组件usernameusernameExecResult

  26. result["password"] 设置为 创建组件匹配结果 的结果,给定 urlPattern密码组件passwordpasswordExecResult

  27. result["hostname"] 设置为 创建组件匹配结果 的结果,给定 urlPattern主机名组件hostnamehostnameExecResult

  28. result["port"] 设置为 创建组件匹配结果 的结果,给定 urlPattern端口组件portportExecResult

  29. result["pathname"] 设置为 创建组件匹配结果 的结果,给定 urlPattern路径名组件pathnamepathnameExecResult

  30. result["search"] 设置为 创建组件匹配结果 的结果,给定 urlPattern查询组件searchsearchExecResult

  31. result["hash"] 设置为 创建组件匹配结果 的结果,给定 urlPattern哈希组件hashhashExecResult

  32. 返回 result

一个 URL 模式 urlPattern 如果以下步骤返回 true,则表示 具有正则表达式组
  1. 如果 urlPattern协议组件 具有正则表达式组 为 true,则返回 true。

  2. 如果 urlPattern用户名组件 具有正则表达式组 为 true,则返回 true。

  3. 如果 urlPattern密码组件 具有正则表达式组 为 true,则返回 true。

  4. 如果 urlPattern主机名组件 具有正则表达式组 为 true,则返回 true。

  5. 如果 urlPattern端口组件 具有正则表达式组 为 true,则返回 true。

  6. 如果 urlPattern路径名组件 具有正则表达式组 为 true,则返回 true。

  7. 如果 urlPattern查询组件 具有正则表达式组 为 true,则返回 true。

  8. 如果 urlPattern哈希组件 具有正则表达式组 为 true,则返回 true。

  9. 返回 false。

1.5. 内部结构

编译组件,给定一个字符串 input编码回调 encoding callback选项 options
  1. part list 设为运行 解析模式字符串 的结果,给定 inputoptionsencoding callback

  2. 将 (regular expression string, name list) 设为运行 生成正则表达式和名称列表 的结果,给定 part listoptions

  3. flags 设为空字符串。

  4. 如果 options忽略大小写 为 true,则将 flags 设为 "vi"。

  5. 否则将 flags 设为 "v"

  6. regular expression 设为 RegExpCreate(regular expression string, flags)。如果抛出异常,捕获它并抛出 TypeError

    该规范使用正则表达式执行所有匹配,但这不是强制性的。实现可以在可能的情况下直接对 部分列表 进行匹配;例如,当没有自定义正则表达式匹配组时。然而,如果存在自定义正则表达式,则必须立即在 编译组件 算法中评估它们,以便在它们无效时抛出错误。

  7. pattern string 设为运行 生成模式字符串 的结果,给定 part listoptions

  8. has regexp groups 设为 false。

  9. 遍历 part list 中的每个 part

    1. 如果 part类型 是 "regexp",则将 has regexp groups 设为 true。

  10. 返回一个新的 组件,其 模式字符串pattern string正则表达式regular expression组名称列表name list,且 具有正则表达式组has regexp groups

创建组件匹配结果,给定一个 组件 component、一个字符串 input,以及一个表示 RegExpBuiltinExec 输出的数组 execResult
  1. result 设为一个新的 URLPatternComponentResult

  2. result["input"] 设为 input

  3. groups 设为一个 记录<USVString, (USVStringundefined)>

  4. index 设为 1。

  5. index 小于 获取(execResult, "length") 时:

    1. name 设为 component组名称列表[index − 1]。

    2. value 设为 获取(execResult, ToString(index))。

    3. groups[name] 设为 value

    4. index 增加 1。

  6. result["groups"] 设为 groups

  7. 返回 result

默认选项 是一个 选项 结构,其中 分隔符代码点 设为空字符串,前缀代码点 也设为空字符串。

主机名选项 是一个 选项 结构,其中 分隔符代码点 设为 ".",前缀代码点 设为空字符串。

路径名选项 是一个 选项 结构,其中 分隔符代码点 设为 "/",前缀代码点 设为 "/"。

要确定一个 协议组件是否匹配特殊方案,给定一个 组件 protocol component
  1. special scheme list 设为包含所有 特殊方案列表

  2. 遍历 special scheme list 中的每个 scheme

    1. test result 设为 RegExpBuiltinExec(protocol component正则表达式scheme)。

    2. 如果 test result 不为 null,则返回 true。

  3. 返回 false。

要确定 主机名模式是否为 IPv6 地址,给定一个 模式字符串 input
  1. 如果 input代码点长度 小于 2,则返回 false。

  2. input code points 设为 input 解释为 代码点列表

  3. 如果 input code points[0] 是 U+005B ([),则返回 true。

  4. 如果 input code points[0] 是 U+007B ({) 且 input code points[1] 是 U+005B ([),则返回 true。

  5. 如果 input code points[0] 是 U+005C (\) 且 input code points[1] 是 U+005B ([),则返回 true。

  6. 返回 false。

1.6. 构造器字符串解析

构造器字符串解析器 是一个 结构

一个 构造器字符串解析器 具有一个关联的 输入,这是一个字符串,必须在创建时设置。

一个 构造器字符串解析器 具有一个关联的 token 列表,一个 token 列表,必须在创建时设置。

一个 构造器字符串解析器 具有一个关联的 结果,一个 URLPatternInit,最初设置为一个新的 URLPatternInit

一个 构造器字符串解析器 具有一个关联的 组件开始,一个数字,最初设置为 0。

一个 构造器字符串解析器 具有一个关联的 token 索引,一个数字,最初设置为 0。

一个 构造器字符串解析器 具有一个关联的 token 增量,一个数字,最初设置为 1。

一个 构造器字符串解析器 具有一个关联的 组深度,一个数字,最初设置为 0。

一个 构造器字符串解析器 具有一个关联的 主机名 IPv6 括号深度,一个数字,最初设置为 0。

一个 构造器字符串解析器 具有一个关联的 协议匹配特殊方案标志,一个布尔值,最初设置为 false。

一个 构造器字符串解析器 具有一个关联的 状态,一个字符串,最初设置为 "init"。它必须是以下之一:

URLPattern 构造器字符串算法与 基本 URL 解析器 算法非常相似,但有一些差异使我们无法直接使用该算法。

首先,URLPattern 构造器字符串解析器基于使用 "lenient" tokenize 策略 生成的 token 操作。相比之下,基本 URL 解析器 基于码点操作。使用 token 允许 URLPattern 构造器字符串解析器更容易区分模式语法中重要的码点和可能是 URL 组件分隔符的码点。例如,它可以轻松处理 "https://a.c:hmm.example.com:8080" 中的命名组 ":hmm",而不会与端口号混淆。

其次,URLPattern 构造器字符串解析器需要避免像 基本 URL 解析器 那样对所有码点应用 URL 规范化。相反,我们只对模式字符串中我们知道安全的部分执行规范化操作,这些部分会在编译每个组件模式字符串时进行处理。

最后,URLPattern 构造器字符串解析器不处理 基本 URL 解析器 状态机的某些部分。例如,它不会特别处理反斜杠,因为它们将被视为模式字符,并且需要大量转义。此外,该解析器可能无法处理某些更复杂的 URL 解析算法,例如带有主机名的文件 URL。这种解析器的目标是处理最常见的 URL,同时允许通过 URLPatternInit 构造器处理任何特定情况。

在构造器字符串算法中,如果指定了较早的组件但没有指定较晚的组件,则通配路径名、搜索和哈希。例如,"https://example.com/foo" 匹配任何搜索和任何哈希。同样,"https://example.com" 匹配该来源上的任何 URL。这类似于 处理 URLPatternInit 中有关更具体组件的概念(例如,搜索比路径名更具体),但构造器语法只有少数几种情况可以在不同时指定较不具体的组件的情况下指定更具体的组件。

用户名和密码组件始终为通配,除非明确指定。

如果指定了主机名而未指定端口,则假定端口为默认端口。如果作者想匹配任何端口,他们必须显式写为 :*。例如,"https://*" 是端口 443 上的任何 HTTPS 来源,而 "https://*:*" 是任何端口上的任何 HTTPS 来源。

解析构造函数字符串,给定一个字符串 input
  1. parser 为一个新的 构造函数字符串解析器,其 输入input,并且 token 列表 是运行 tokenize 得到的,给定 input 和 "lenient"。

  2. parsertoken 索引 小于 parsertoken 列表大小时:

    1. 设置 parsertoken 增量 为 1。

      在解析循环的每次迭代中,parsertoken 索引 将按其 token 增量 进行递增。通常情况下,递增量为 1,但在某些情况下会设置为 0。然后每次循环的顶部,token 增量 总是重置为 1。

    2. 如果 parsertoken 列表[parsertoken 索引] 的 类型 为 "end",则:

      1. 如果 parser状态 是 "init":

        如果我们在 "init" 状态下到达字符串末尾,那么我们未能找到协议终止符,这必须是一个相对的 URLPattern 构造函数字符串。

        1. 运行 回退,给定 parser

          接下来我们确定相对模式从哪个组件开始。相对路径名最为常见,但 URL 和 URLPattern 构造函数字符串也可以从 search 或 hash 组件开始。

        2. 如果运行 是否为 hash 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hash" 和 1。

        3. 否则,如果运行 是否为 search 前缀,给定 parser 的结果为 true:

          1. 运行 更改状态,给定 parser,"search" 和 1。

        4. 否则:

          1. 运行 更改状态,给定 parser,"pathname" 和 0。

        5. parsertoken 索引 增加 parsertoken 增量

        6. 继续

      2. 如果 parser状态 是 "authority":

        如果我们在 "authority" 状态下到达字符串末尾,那么我们未能找到 "@"。因此没有用户名或密码。

        1. 运行 回退并设置状态,给定 parser 和 "hostname"。

        2. parsertoken 索引 增加 parsertoken 增量

        3. 继续

      3. 运行 更改状态,给定 parser,"done" 和 0。

      4. 中断

    3. 如果运行 是否为组开启符,给定 parser 的结果为 true:

      我们忽略 "{ ... }" 模式分组中的所有代码点。允许 URL 组件边界位于分组内是没有意义的;例如 "https://example.c{om/fo}o"。虽然在格式良好的 模式字符串中不支持这种分组,我们在这里处理嵌套分组以避免解析器混乱。

      对于正则表达式或命名组,无需执行此逻辑,因为这些值在 tokenize 算法中被折叠为单个token

      1. parser组深度 增加 1。

      2. parsertoken 索引 增加 parsertoken 增量

      3. 继续

    4. 如果 parser组深度 大于 0:

      1. 如果运行 是否为组关闭符,给定 parser 的结果为 true,则将 parser组深度 减少 1。

      2. 否则:

        1. parsertoken 索引 增加 parsertoken 增量

        2. 继续

    5. 切换 parser状态,并运行相关步骤:

      "init"
      1. 如果运行 是否为协议后缀,给定 parser 的结果为 true:

        1. 运行 回退并设置状态,给定 parser 和 "protocol"。

      "protocol"
      1. 如果运行 是否为协议后缀,给定 parser 的结果为 true:

        1. 运行 计算协议是否匹配特殊方案标志,给定 parser

          我们需要尽早编译协议组件,以确定它是否匹配任何 特殊方案。如果匹配,则某些特殊规则将适用。它决定了路径名是否默认值为 "/",以及我们是否会查找用户名、密码、主机名和端口组件。权限斜线也可能导致我们查找这些组件。否则,我们将其视为 "不透明路径 URL",直接进入路径名组件。

        2. 设置 next state 为 "pathname"。

        3. 设置 skip 为 1。

        4. 如果运行 下一个是权限斜线,给定 parser 的结果为 true:

          1. 设置 next state 为 "authority"。

          2. 设置 skip 为 3。

        5. 否则,如果 parser协议匹配特殊方案标志 为 true,则将 next state 设置为 "authority"。

        6. 运行 更改状态,给定 parsernext stateskip

      "authority"
      1. 如果运行 是否为身份终止符,给定 parser 的结果为 true,则运行 回退并设置状态,给定 parser 和 "username"。

      2. 否则,如果以下任意一个为 true:

        则运行 回退并设置状态,给定 parser 和 "hostname"。

      "username"
      1. 如果运行 是否为密码前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"password" 和 1。

      2. 否则,如果运行 是否为身份终止符,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hostname" 和 1。

      "password"
      1. 如果运行 是否为身份终止符,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hostname" 和 1。

      "hostname"
      1. 如果运行 是否为 IPv6 开启符,给定 parser 的结果为 true,则将 parser主机名 IPv6 括号深度 增加 1。

      2. 否则,如果运行 是否为 IPv6 关闭符,给定 parser 的结果为 true,则将 parser主机名 IPv6 括号深度 减少 1。

      3. 否则,如果运行 是否为端口前缀,给定 parser 的结果为 true,且 parser主机名 IPv6 括号深度 为 0,则运行 更改状态,给定 parser,"port" 和 1。

      4. 否则,如果运行 是否为路径名开始符,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"pathname" 和 0。

      5. 否则,如果运行 是否为 search 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"search" 和 1。

      6. 否则,如果运行 是否为 hash 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hash" 和 1。

      "port"
      1. 如果运行 是否为路径名开始符,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"pathname" 和 0。

      2. 否则,如果运行 是否为 search 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"search" 和 1。

      3. 否则,如果运行 是否为 hash 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hash" 和 1。

      "pathname"
      1. 如果运行 是否为 search 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"search" 和 1。

      2. 否则,如果运行 是否为 hash 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hash" 和 1。

      "search"
      1. 如果运行 是否为 hash 前缀,给定 parser 的结果为 true,则运行 更改状态,给定 parser,"hash" 和 1。

      "hash"
      1. 什么都不做。

      "done"
      1. 断言:此步骤从未到达。

    6. parsertoken 索引 增加 parsertoken 增量

  3. 如果 parser结果 包含 "主机名" 且不包含 "端口",则将 parser结果["端口"] 设置为空字符串。

    这是一个特殊情况,因为当作者未指定端口时,他们通常是指默认端口。如果任何端口都可以接受,作者可以显式将其指定为通配符。例如,"https://example.com/*" 不匹配以 "https://example.com:8443/" 开头的 URL,这是一个不同的来源。
  4. 返回 parser结果

要给定一个构造函数字符串解析器 parser、一个 状态 new state 和一个数字 skip 进行 状态切换:
  1. 如果 parser状态 不是 "init",不是 "authority",也不是 "done",那么将 parser结果[parser状态] 设置为运行 生成组件字符串 给定 parser 的结果。

  2. 如果 parser状态 不是 "init" 且 new state 不是 "done",那么:

    1. 如果 parser状态 是 "protocol","authority","username" 或 "password";new state 是 "port","pathname","search" 或 "hash";并且 parser结果["hostname"] 不 存在,那么将 parser结果["hostname"] 设置为空字符串。

    2. 如果 parser状态 是 "protocol","authority","username","password","hostname" 或 "port";new state 是 "search" 或 "hash";并且 parser结果["pathname"] 不 存在,那么:

      1. 如果 parser协议匹配特殊方案标志 为真,则将 parser结果["pathname"] 设置为 "/"。

      2. 否则,将 parser结果["pathname"] 设置为空字符串。

    3. 如果 parser状态 是 "protocol","authority","username","password","hostname","port" 或 "pathname";new state 是 "hash";并且 parser结果["search"] 不 存在,那么将 parser结果["search"] 设置为空字符串。

  3. parser状态 设置为 new state

  4. parsertoken 索引 增加 skip

  5. parser组件开始 设置为 parsertoken 索引

  6. parsertoken 增量 设置为 0。

要根据构造器字符串解析器 parser执行回退操作:
  1. parsertoken 索引设置为parser组件开始位置

  2. parsertoken 增量设置为0。

要根据构造字符串解析器 parser 和一个状态 state进行"回退并设置状态"操作:
  1. 执行 回退,并传入 parser

  2. parser状态设置为state

要根据构造字符串解析器 parser 和一个数字 index来获取安全的令牌:
  1. 如果index 小于parser令牌列表大小,则返回parser令牌列表[index]。

  2. 断言: parser令牌列表大小大于等于1。

  3. last index等于parser令牌列表大小减去1。

  4. token等于parser令牌列表[last index]。

  5. 断言: token类型为"end"。

  6. 返回token

要根据构造字符串解析器 parser,一个数字index,和一个字符串value运行"是一个非特殊模式字符":
  1. token成为运行获取安全令牌的结果,并传入parserindex

  2. 如果token不是value,则返回false。

  3. 如果以下任一项为true:

    则返回true。

  4. 返回false。

要根据构造字符串解析器 parser 运行"is a protocol suffix":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和":"。

要根据构造字符串解析器 parser 运行"next is authority slashes":
  1. 如果运行is a non-special pattern char的结果为false,传入parserparsertoken index + 1 和"/",则返回false。

  2. 如果运行is a non-special pattern char的结果为false,传入parserparsertoken index + 2 和"/",则返回false。

  3. 返回true。

要根据构造字符串解析器 parser 运行"is an identity terminator":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和"@"。

要根据构造字符串解析器 parser 运行"is a password prefix":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和":"。

要根据构造字符串解析器 parser 运行"is a port prefix":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和":"。

要根据构造字符串解析器 parser 运行"is a pathname start":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和"/"。

要根据构造字符串解析器 parser 运行"is a search prefix":
  1. 如果运行is a non-special pattern char的结果为true,传入parserparsertoken index和"?",则返回true。

  2. 如果parser令牌列表[parsertoken index]的不是"?",则返回false。

  3. previous index等于parsertoken index − 1。

  4. 如果previous index小于0,则返回true。

  5. previous token成为运行获取安全令牌的结果,并传入parserprevious index

  6. 如果以下任一项为true,则返回false:

  7. 返回true。

要根据构造字符串解析器 parser 运行"is a hash prefix":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和"#"。

要根据构造字符串解析器 parser 运行"is a group open":
  1. 如果parser令牌列表[parsertoken index]的类型是"open",则返回true。

  2. 否则返回false。

要根据构造字符串解析器 parser 运行"is a group close":
  1. 如果parser令牌列表[parsertoken index]的类型是"close",则返回true。

  2. 否则返回false。

要根据构造字符串解析器 parser 运行"is an IPv6 open":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和"["。

要根据构造字符串解析器 parser 运行"is an IPv6 close":
  1. 返回运行is a non-special pattern char的结果,传入parserparsertoken index和"]"。

要根据构造字符串解析器 parser 运行"make a component string":
  1. 断言parsertoken index小于parser令牌列表大小

  2. tokenparser令牌列表[parsertoken index]。

  3. component start token为运行获取安全令牌的结果,并传入parserparsercomponent start

  4. component start input indexcomponent start token索引

  5. end indextoken索引

  6. 返回parser输入中从component start input indexend index码点子字符串

要根据构造字符串解析器 parser 运行"compute protocol matches a special scheme flag":
  1. protocol string为运行make a component string的结果,并传入parser

  2. protocol component为运行编译组件的结果,并传入protocol string规范化协议默认选项

  3. 如果运行协议组件与特殊方案匹配的结果为true,设置parserprotocol matches a special scheme flag为true。

2. 模式字符串

模式字符串 是用来匹配一组目标字符串的字符串。一个格式良好的模式字符串符合特定的模式语法。这种模式语法直接基于流行的path-to-regexp JavaScript 库的语法。

它可以被解析以生成一个部分列表,该列表按顺序描述了模式字符串要匹配时必须出现在组件字符串中的内容。

模式字符串可以包含捕获组,默认情况下会匹配尽可能短的字符串,直到组件特定的分隔符(在路径名中为/,在主机名中为.)。例如,路径名模式"/blog/:title"会匹配"/blog/hello-world",但不匹配"/blog/2012/02"。

也可以使用括号内的正则表达式代替,因此路径名模式"/blog/:year(\\d+)/:month(\\d+)"会匹配"/blog/2012/02"。

组也可以使用修饰符来设置为可选或重复。例如,路径名模式"/products/:id?"会匹配"/products"和"/products/2"(但不匹配"/products/")。特别是在路径名中,组会自动要求前导/;为了避免这种情况,可以显式分隔组,如路径名模式"/products/{:id}?"所示。

也可以使用通配符*来尽可能多地匹配,如路径名模式"/products/*"。

2.1. 解析模式字符串

2.1.1. 令牌

令牌列表是一个包含零个或多个令牌列表

令牌是一个结构体,表示模式字符串中的一个词法令牌。

一个令牌具有相关的类型,这是一个字符串,初始值为"invalid-char"。它必须是以下之一:

"open"
令牌表示一个U+007B ({) 码点。
"close"
令牌表示一个U+007D (}) 码点。
"regexp"
令牌表示一个格式为"(<regular expression>)"的字符串。正则表达式必须仅由ASCII码点组成。
"name"
令牌表示一个格式为":<name>"的字符串。name值被限制为与JavaScript标识符一致的码点。
"char"
令牌表示一个有效的模式码点,没有任何特殊的语法含义。
"escaped-char"
令牌表示一个使用反斜杠转义的码点,如"\<char>"。
"other-modifier"
令牌表示一个匹配组修饰符,它是U+003F (?) 或U+002B (+)码点。
"asterisk"
令牌表示一个U+002A (*)码点,可以是一个通配符匹配组或一个匹配组修饰符。
"end"
令牌表示模式字符串的结束。
"invalid-char"
令牌表示模式中无效的码点。这可能是由于码点值本身或其在模式中相对于其他语法元素的位置所致。

一个令牌具有相关的索引,这是一个数字,初始值为0。它是令牌表示的模式字符串中第一个码点的位置。

一个令牌具有相关的,这是一个字符串,初始为空。它包含令牌表示的模式字符串中的码点。

2.1.2. 令牌化

令牌化策略 是一个字符串,必须为 "strict" 或 "lenient"。

令牌化器 是一个结构体

令牌化器 具有相关的 输入,是一个模式字符串,初始值为空字符串。

令牌化器 具有相关的 策略,是一个令牌化策略,初始为"strict"。

令牌化器 具有相关的 令牌列表,是一个令牌列表,初始为一个空的列表

令牌化器 具有相关的 索引,是一个数字,初始为0。

令牌化器 具有相关的 下一个索引,是一个数字,初始为0。

令牌化器 具有相关的 码点,是一个 Unicode 码点,初始为 null。

令牌化给定的字符串input令牌化策略 policy
  1. tokenizer成为一个新的令牌化器

  2. tokenizer输入设置为input

  3. tokenizer策略设置为policy

  4. tokenizer索引小于tokenizer输入码点长度时:

    1. 运行查找并获取下一个码点,给定tokenizertokenizer索引

    2. 如果tokenizer码点是 U+002A (*):

      1. 运行添加一个带有默认位置和长度的令牌,给定tokenizer和"asterisk"。

      2. 继续

    3. 如果tokenizer码点是 U+002B (+) 或 U+003F (?):

      1. 运行添加一个带有默认位置和长度的令牌,给定tokenizer和"other-modifier"。

      2. 继续

    4. 如果tokenizer码点是 U+005C (\):

      1. 如果tokenizer索引等于tokenizer输入码点长度 − 1:

        1. 运行处理令牌化错误,给定tokenizertokenizer下一个索引tokenizer索引

        2. 继续

      2. 转义索引设置为tokenizer下一个索引

      3. 运行获取下一个码点,给定tokenizer

      4. 运行添加一个带有默认长度的令牌,给定tokenizer,"escaped-char",tokenizer下一个索引转义索引

      5. 继续

    5. 如果tokenizer码点是 U+007B ({):

      1. 运行添加一个带有默认位置和长度的令牌,给定tokenizer和"open"。

      2. 继续

    6. 如果tokenizer码点是 U+007D (}):

      1. 运行添加一个带有默认位置和长度的令牌,给定tokenizer和"close"。

      2. 继续

    7. 如果tokenizer码点是 U+003A (:):

      1. name position成为tokenizer下一个索引

      2. name start成为name position

      3. name position小于tokenizer输入码点长度时:

        1. 运行查找并获取下一个码点,给定tokenizername position

        2. 如果name position等于name start,则first code point为true,否则为false。

        3. 运行检查是否为有效名称码点,给定tokenizer码点first code point

        4. 如果valid code point为false,则跳出

        5. name position设置为tokenizer下一个索引

      4. 如果name position小于或等于name start

        1. 运行处理令牌化错误,给定tokenizername starttokenizer索引

        2. 继续

      5. 运行添加一个带有默认长度的令牌,给定tokenizer,"name",name positionname start

      6. 继续

    8. 如果tokenizer码点是 U+0028 (():

      1. depth为 1。

      2. regexp positiontokenizer下一个索引

      3. regexp startregexp position

      4. error为 false。

      5. regexp position小于tokenizer输入码点长度时:

        1. 运行查找并获取下一个码点,给定tokenizerregexp position

        2. 如果运行检查是否为 ASCII的结果表明tokenizer码点为 false:

          1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

          2. error为 true。

          3. 跳出

        3. 如果regexp position等于regexp start,并且tokenizer码点是 U+003F (?):

          1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

          2. error为 true。

          3. 跳出

        4. 如果tokenizer码点是 U+005C (\):

          1. 如果regexp position等于tokenizer输入码点长度 − 1:

            1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

            2. error为 true。

            3. 跳出

          2. 运行获取下一个码点,给定tokenizer

          3. 如果运行检查是否为 ASCII的结果为 false,给定tokenizer码点

            1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

            2. error为 true。

            3. 跳出

          4. regexp position设为tokenizer下一个索引

          5. 继续

        5. 如果tokenizer码点是 U+0029 ()):

          1. depth减 1。

          2. 如果depth为 0:

            1. regexp position设为tokenizer下一个索引

            2. 跳出

        6. 否则如果tokenizer码点是 U+0028 (():

          1. depth加 1。

          2. 如果regexp position等于tokenizer输入码点长度 − 1:

            1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

            2. error为 true。

            3. 跳出

          3. temporary positiontokenizer下一个索引

          4. 运行获取下一个码点,给定tokenizer

          5. 如果tokenizer码点不是 U+003F (?):

            1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

            2. error为 true。

            3. 跳出

          6. tokenizer下一个索引设为temporary position

        7. regexp position设为tokenizer下一个索引

      6. 如果error为 true,继续

      7. 如果depth不为零:

        1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

        2. 继续

      8. regexp lengthregexp position减去regexp start再减 1。

      9. 如果regexp length为零:

        1. 运行处理令牌化错误,给定tokenizerregexp start,以及tokenizer索引

        2. 继续

      10. 运行添加一个令牌,给定tokenizer,"regexp",regexp positionregexp start,以及regexp length

      11. 继续

    9. 运行添加一个带有默认位置和长度的令牌,给定tokenizer和"char"。

  5. 运行添加一个默认长度的令牌,给定tokenizer,"end",tokenizer索引,以及tokenizer索引

  6. 返回tokenizer令牌列表

获取下一个码点,对于给定的令牌生成器 tokenizer:
  1. tokenizer码点设置为tokenizer输入中由tokenizer下一个索引指示的位置的 Unicode 码点。

  2. tokenizer下一个索引增加 1。

查找并获取下一个码点,对于给定的令牌生成器 tokenizer和数字index
  1. tokenizer下一个索引设置为index

  2. 运行获取下一个码点,给定tokenizer

添加一个令牌,对于给定的令牌生成器 tokenizer类型 type,数字next position,数字value position,以及数字value length
  1. 创建一个新的token,作为令牌

  2. token类型设置为type

  3. token索引设置为tokenizer索引

  4. token设置为从value positionvalue length码点子串,位于tokenizer输入中。

  5. token附加到tokenizer令牌列表的末尾。

  6. tokenizer索引设置为next position

添加一个默认长度的令牌,对于给定的令牌生成器 tokenizer类型 type,数字next position,以及数字value position
  1. computed lengthnext position减去value position

  2. 运行添加令牌,给定tokenizertypenext positionvalue position,以及computed length

添加一个具有默认位置和长度的令牌,对于给定的令牌生成器 tokenizer类型 type
  1. 运行添加一个默认长度的令牌,给定tokenizertypetokenizer下一个索引,以及tokenizer索引

处理令牌化错误,对于给定的令牌生成器 tokenizer,数字next position,以及数字value position
  1. 如果tokenizer策略是"strict",则抛出TypeError

  2. 断言tokenizer策略是"lenient"。

  3. 运行添加一个默认长度的令牌,给定tokenizer,"invalid-char",next position,以及value position

要执行是否是有效的名称码点,给定一个 Unicode 码点和一个布尔值first
  1. 如果first为 true,返回检查码点是否包含在IdentifierStart码点集中的结果。

  2. 否则,返回检查码点是否包含在IdentifierPart码点集中的结果。

要确定一个 Unicode 码点是否是 ASCII
  1. 如果码点在 U+0000 到 U+007F 之间(含),则返回 true。

  2. 否则返回 false。

2.1.3. 部分

部分列表是一个包含零个或多个部分列表

部分是一个表示解析器模式字符串的一部分的结构。它最多可以包含一个匹配组,一个固定的文本前缀,一个固定的文本后缀,以及一个修饰符。它可以仅包含一个固定的文本字符串或一个匹配组。

一个部分具有一个关联的类型,该类型是一个字符串,必须在创建时设置。它必须是以下之一:

"fixed-text"
部分表示一个简单的固定文本字符串。
"regexp"
部分表示具有自定义正则表达式的匹配组。
"segment-wildcard"
部分表示匹配组,匹配直到下一个分隔符码点的所有码点。通常用于像":foo"这样的命名组,它没有自定义正则表达式。
"full-wildcard"
部分表示一个贪婪地匹配所有码点的匹配组。通常用于"*"通配符匹配组。

一个部分具有一个关联的,一个字符串,必须在创建时设置。

一个部分具有一个关联的修饰符,一个字符串,必须在创建时设置。它必须是以下之一:

"none"
部分没有修饰符
"optional"
部分具有一个可选的修饰符,由 U+003F (?) 码点指示。
"zero-or-more"
部分具有"零或更多"修饰符,由 U+002A (*) 码点指示。
"one-or-more"
部分具有"一个或更多"修饰符,由 U+002B (+) 码点指示。

一个部分具有一个关联的名称,一个字符串,初始为空字符串。

一个部分具有一个关联的前缀,一个字符串,初始为空字符串。

一个部分具有一个关联的后缀,一个字符串,初始为空字符串。

2.1.4. 选项

选项是一个结构,其中包含控制模式字符串行为的不同设置。这些选项最初来自path-to-regexp。我们只包括在 URLPattern 规范中修改的选项,排除其他选项。为了便于比较,本规范的行为类似于path-to-regexp,其中strictstartend始终设置为false。

选项具有一个关联的分隔符码点,一个字符串,必须在创建时设置。它必须包含一个ASCII 码点或空字符串。此码点被视为段分隔符,并用于确定:foo命名组应匹配的范围。例如,如果分隔符码点是"/",那么"/:foo"将匹配"/bar",但不会匹配"/bar/baz"。如果分隔符码点为空字符串,则示例模式将匹配两个字符串。

选项具有一个关联的前缀码点,一个字符串,必须在创建时设置。它必须包含一个ASCII 码点或空字符串。如果在匹配组前立即发现,该码点被视为自动前缀。这在匹配组被修改为可选或重复时尤为重要。例如,如果前缀码点是"/",那么"/foo/:bar?/baz"会将"/"视为一个前缀,该前缀与命名组一起变得可选。因此,在此示例中,模式将匹配"/foo/baz"。

选项具有一个关联的忽略大小写,一个布尔值,必须在创建时设置。默认值为false。根据设置的值(true或false),此标志分别启用区分大小写或不区分大小写的匹配。为了比较,可以将此大小写视为path-to-regexp中的sensitive选项的反义词。

2.1.5. 解析

编码回调是一个抽象算法,接受给定的字符串inputinput将是模式字符串的一个简单文本片段。实现算法将验证并编码input。它必须返回编码后的字符串或抛出异常。

模式解析器是一个结构

模式解析器具有一个关联的令牌列表,一个令牌列表,初始为空的列表

模式解析器具有一个关联的编码回调,一个编码回调,必须在创建时设置。

模式解析器具有一个关联的段通配符正则表达式,一个字符串,必须在创建时设置。

模式解析器具有一个关联的部分列表,一个部分列表,初始为空的列表

模式解析器具有一个关联的待处理固定值,一个字符串,初始为空字符串。

模式解析器具有一个关联的索引,一个数字,初始为 0。

模式解析器具有一个关联的下一个数字名称,一个数字,初始为 0。

解析一个模式字符串,给定一个模式字符串input选项options,以及编码回调encoding callback
  1. parser为一个新的模式解析器,其编码回调encoding callback,且段通配符正则表达式是运行生成段通配符正则表达式给定的options的结果。

  2. parser令牌列表设置为运行标记化给定input和"strict"的结果。

  3. parser索引小于parser令牌列表大小时:

    此部分的目的是寻找序列:<prefix char><name><regexp><modifier>。这些令牌可以为零到全部。

    "/:foo(bar)?"
    四个令牌
    "/"
    一个"char"令牌
    ":foo"
    一个"name"令牌
    "(bar)"
    一个"regexp"令牌
    "/:foo"
    "char"和"name"令牌
    "/(bar)"
    "char"和"regexp"令牌
    "/:foo?"
    "char"、"name"和"other-modifier"令牌
    "/(bar)?"
    "char"、"regexp"和"other-modifier"令牌
    1. char token为运行尝试消费令牌,给定parser和"char"的结果。

    2. name token为运行尝试消费令牌,给定parser和"name"的结果。

    3. regexp or wildcard token为运行尝试消费正则或通配符令牌,给定parsername token的结果。

    4. 如果name token不为null或regexp or wildcard token不为null:

      如果有一个匹配组,我们需要立即添加部分

      1. prefix为空字符串。

      2. 如果char token不为null,则将prefix设置为char token

      3. 如果prefix不是空字符串且不是options前缀码点

        1. prefix追加到parser待处理固定值的末尾。

        2. prefix设置为空字符串。

      4. 运行从待处理固定值中可能添加部分,给定parser

      5. modifier token为运行尝试消费修饰符令牌给定的parser的结果。

      6. 运行添加部分,给定parserprefixname tokenregexp or wildcard token、空字符串和modifier token

      7. 继续

    5. fixed tokenchar token

      如果没有匹配组,那么我们需要缓冲任何固定文本。在将其作为"fixed-text"部分添加之前,我们希望收集尽可能多的文本。

    6. 如果fixed token为null,则将fixed token设置为运行尝试消费令牌给定的parser和"escaped-char"的结果。

    7. 如果fixed token不为null:

      1. fixed token追加到parser待处理固定值中。

      2. 继续

    8. open token为运行尝试消费令牌给定的parser和"open"的结果。

      接下来我们寻找序列<open><char prefix><name><regexp><char suffix><close><modifier>。open和close是必须的,但其他令牌不是。

      "{a:foo(bar)b}?"
      所有令牌都存在。
      "{:foo}?"
      "open"、"name"、"close"和"other-modifier"令牌
      "{(bar)}?"
      "open"、"regexp"、"close"和"other-modifier"令牌
      "{ab}?"
      "open"、"char"、"close"和"other-modifier"令牌
    9. 如果open token不为null:

      1. prefix为运行消费文本,给定parser的结果。

      2. name token设置为运行尝试消费令牌给定的parser和"name"的结果。

      3. regexp or wildcard token设置为运行尝试消费正则或通配符令牌,给定parsername token的结果。

      4. suffix为运行消费文本,给定parser的结果。

      5. 运行消费必需令牌,给定parser和"close"。

      6. modifier token设置为运行尝试消费修饰符令牌,给定parser的结果。

      7. 运行添加部分,给定parserprefixname tokenregexp or wildcard tokensuffixmodifier token

      8. 继续

    10. 运行从待处理固定值中可能添加部分,给定parser

    11. 运行消费必需令牌,给定parser和"end"。

  4. 返回parser部分列表

完整通配符正则表达式值是字符串".*"。

生成一个段通配符正则表达式,给定一个选项 options
  1. result设为"[^"。

  2. 将运行转义正则表达式字符串给定的options分隔符码点的结果追加到result的末尾。

  3. 将"]+?"追加到result的末尾。

  4. 返回result

尝试消费令牌,给定一个模式解析器 parser类型 type
  1. 断言parser索引小于parser令牌列表大小

  2. next tokenparser令牌列表[parser索引]。

  3. 如果next token类型不是type,则返回null。

  4. parser索引加1。

  5. 返回next token

2.2. 将部分列表转换为正则表达式

从给定的部分列表部分列表选项选项生成正则表达式和名称列表:
  1. 结果为"^"。

  2. 名称列表为一个新的列表

  3. 对每个部分部分列表

    1. 如果部分类型是"固定文本":

      1. 如果部分修饰符是"",则将运行转义正则表达式字符串后的结果附加到结果的末尾。

      2. 否则:

        带有修饰符的"固定文本"部分使用非捕获组。其形式如下。

        (?:<固定文本>)<修饰符>

        1. 将"(?:"附加到结果的末尾。

        2. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

        3. 将")"附加到结果的末尾。

        4. 将运行将修饰符转换为字符串后的结果附加到结果的末尾。

      3. 继续

    2. 断言部分名称不是空字符串。

    3. 附加部分名称名称列表

      我们在并行列表中收集匹配组名称。这主要是为了与path-to-regexp保持一致。尽管可以尝试转换为使用正则表达式命名捕获组,但考虑到算法的复杂性,存在引入意外错误的风险。此外,如果我们最终向网页暴露生成的正则表达式,我们希望与path-to-regexp保持兼容,它表明不太可能切换到使用命名捕获组。

    4. 正则表达式值部分

    5. 如果部分类型是"段通配符",则将正则表达式值设置为运行生成段通配符正则表达式后的结果。

    6. 否则,如果部分类型是"全通配符",则将正则表达式值设置为全通配符正则表达式值

    7. 如果部分前缀是空字符串,且部分后缀是空字符串:

      如果没有前缀后缀,则生成依赖于修饰符。如果没有修饰符或只有可选修饰符,它将使用以下简单形式:

      (<正则表达式值>)<修饰符>

      然而,如果存在重复修饰符,我们将使用更复杂的形式:

      ((?:<正则表达式值>)<修饰符>)

      1. 如果部分修饰符是""或"可 选",则:

        1. 将"("附加到结果的末尾。

        2. 正则表达式值附加到结果的末尾。

        3. 将")"附加到结果的末尾。

        4. 将运行将修饰符转换为字符串后的结果附加到结果的末尾。

      2. 否则:

        1. 将"((?:"附加到结果的末尾。

        2. 正则表达式值附加到结果的末尾。

        3. 将")"附加到结果的末尾。

        4. 将运行将修饰符转换为字符串后的结果附加到结果的末尾。

        5. 将")"附加到结果的末尾。

      3. 继续

    8. 如果部分修饰符是""或"可选":

      本节处理带有前缀后缀的非重复部分。内部捕获组包含主要的正则表达式值。然后,内部组与前缀后缀结合在一个外部非捕获组中。最后,应用修饰符。结果形式如下。

      (?:<前缀>(<正则表达式值>)<后缀>)<修饰符>

      1. 将"(?:"附加到结果的末尾。

      2. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

      3. 将"("附加到结果的末尾。

      4. 正则表达式值附加到结果的末尾。

      5. 将")"附加到结果的末尾。

      6. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

      7. 将")"附加到结果的末尾。

      8. 将运行将修饰符转换为字符串后的结果附加到结果的末尾。

      9. 继续

    9. 断言部分修饰符是"零或更多"或"一个或更多"。

    10. 断言部分前缀不是空字符串,或部分后缀不是空字符串。

      带有前缀后缀的重复部分更加复杂。我们希望排除初始的前缀和最终的后缀,但要在重复元素之间包含它们。为此,我们提供一个单独的初始表达式,排除了前缀。然后,表达式被重复,前缀/后缀值包含在一个可选的重复元素中。如果允许零值,则可以附加一个最终的可选修饰符。结果形式如下。

      (?:<前缀>((?:<正则表达式值>)(?:<后缀><前缀>(?:<正则表达式值>))*)<后缀>)?

    11. 将"(?:"附加到结果的末尾。

    12. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

    13. 将"((?:"附加到结果的末尾。

    14. 正则表达式值附加到结果的末尾。

    15. 将")(?:"附加到结果的末尾。

    16. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

    17. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

    18. 将"(?:"附加到结果的末尾。

    19. 正则表达式值附加到结果的末尾。

    20. 将"))*)"附加到结果的末尾。

    21. 将运行转义正则表达式字符串后的结果附加到结果的末尾。

    22. 将")"附加到结果的末尾。

    23. 如果部分修饰符是"零或更多",则将"?"附加到结果的末尾。

  4. 将"$"附加到结果的末尾。

  5. 返回 (结果, 名称列表)。

转义正则表达式字符串,给定一个字符串 input
  1. 断言输入ASCII字符串

  2. 结果为空字符串。

  3. 索引为0。

  4. 索引小于输入长度时:

    1. c输入[索引]。

    2. 索引加1。

    3. 如果c是以下之一:

      • U+002E (.);
      • U+002B (+);
      • U+002A (*);
      • U+003F (?);
      • U+005E (^);
      • U+0024 ($);
      • U+007B ({);
      • U+007D (});
      • U+0028 (();
      • U+0029 ());
      • U+005B ([);
      • U+005D (]);
      • U+007C (|);
      • U+002F (/); 或
      • U+005C (\),

      则将"\"附加到结果的末尾。

    4. c附加到结果的末尾。

  5. 返回结果

2.3. 将部分列表转换为模式字符串

从给定的部分列表part list选项options生成模式字符串:
  1. result为空字符串。

  2. index list获取部分列表的索引后的结果。

  3. 对每个indexindex list

    1. partpart list[index]。

    2. 如果index大于0,则令previous partpart list[index - 1],否则令其为null。

    3. 如果index小于index list大小 - 1,则令next partpart list[index + 1],否则令其为null。

    4. 如果part类型是"fixed-text":

      1. 如果part修饰符是"none",则:

        1. 将运行转义模式字符串后的结果附加到result的末尾。

        2. 继续

      2. 将"{"附加到result的末尾。

      3. 将运行转义模式字符串后的结果附加到result的末尾。

      4. 将"}"附加到result的末尾。

      5. 将运行将修饰符转换为字符串后的结果附加到result的末尾。

      6. 继续

    5. custom name为true,如果partname[0]不是ASCII数字,否则为false。

    6. needs grouping为true,如果以下条件中至少有一个为真,否则为false:

    7. 如果以下所有条件为真:

      则:
      1. 如果next part类型是"fixed-text":

        1. 如果运行是有效名称码点给定next part的第一个码点和布尔值false为真,则设置needs grouping为true。

      2. 否则:

        1. 如果next partname[0]是ASCII数字,则设置needs grouping为true。

    8. 如果以下所有条件为真:

      则设置needs grouping为true。
    9. 断言partname不是空字符串或null。

    10. 如果needs grouping为true,则将"{"附加到result的末尾。

    11. 将运行转义模式字符串给定part前缀附加到result的末尾。

    12. 如果custom name为true:

      1. 将":"附加到result的末尾。

      2. partname附加到result的末尾。

    13. 如果part类型是"regexp",则:

      1. 将"("附加到result的末尾。

      2. partvalue附加到result的末尾。

      3. 将")"附加到result的末尾。

    14. 否则,如果part类型是"segment-wildcard",且custom name为false:

      1. 将"("附加到result的末尾。

      2. 将运行生成段通配符正则表达式给定options附加到result的末尾。

      3. 将")"附加到result的末尾。

    15. 否则,如果part类型是"full-wildcard":

      1. 如果custom name为false,并且以下条件之一为真:

        • previous part为null;或
        • previous part类型是"fixed-text";或
        • previous part修饰符不是"none";或
        • needs grouping为true;或
        • part前缀不是空字符串
        则将"*"附加到result的末尾。
      2. 否则:

        1. 将"("附加到result的末尾。

        2. 全通配符正则表达式值附加到result的末尾。

        3. 将")"附加到result的末尾。

    16. 如果以下所有条件为真:

      则将U+005C (\)附加到result的末尾。
    17. 将运行转义模式字符串给定part后缀附加到result的末尾。

    18. 如果needs grouping为true,则将"}"附加到result的末尾。

    19. 将运行将修饰符转换为字符串给定part修饰符附加到result的末尾。

  4. 返回result

将字符串input转义为模式字符串:
  1. 断言inputASCII字符串

  2. result为空字符串。

  3. index为0。

  4. index小于input长度时:

    1. cinput[index]。

    2. index加1。

    3. 如果c是以下之一:

      • U+002B (+);
      • U+002A (*);
      • U+003F (?);
      • U+003A (:);
      • U+007B ({);
      • U+007D (});
      • U+0028 (();
      • U+0029 ()); 或
      • U+005C (\),

      则将U+005C (\)附加到result的末尾。

    4. c附加到result的末尾。

  5. 返回result

修饰符modifier转换为字符串:
  1. 如果modifier是"zero-or-more",则返回"*"。

  2. 如果modifier是"optional",则返回"?"。

  3. 如果modifier是"one-or-more",则返回"+"。

  4. 返回空字符串。

3. 规范化

3.1. 编码回调

将字符串value规范化为协议:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. parseResult为运行基本URL解析器给定value后跟"://dummy.test",并以dummyURLurl后的结果。

    注意,这里不使用状态重写,因为它强加了只适用于协议设置器的限制。相反,我们使用协议解析一个虚拟URL,使用正常的解析入口点。

  4. 如果parseResult失败,则抛出TypeError

  5. 返回dummyURL方案

将字符串value规范化为用户名:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. 设置用户名给定dummyURLvalue

  4. 返回dummyURL用户名

将字符串value规范化为密码:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. 设置密码给定dummyURLvalue

  4. 返回dummyURL密码

将字符串value规范化为主机名:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. parseResult为运行基本URL解析器给定value并以dummyURLurl主机名状态状态重写后的结果。

  4. 如果parseResult失败,则抛出TypeError

  5. 返回dummyURL主机序列化的结果,或者如果为null则返回空字符串。

将字符串value规范化为IPv6主机名:
  1. result为空字符串。

  2. 对每个被解释为码点列表value中的码点

    1. 如果以下所有条件为真:

      • 码点不是ASCII十六进制数字
      • 码点不是U+005B ([);
      • 码点不是U+005D (]);且
      • 码点不是U+003A (:),

      则抛出TypeError

    2. 将运行ASCII小写给定码点的结果附加到result的末尾。

  3. 返回result

将字符串portValue规范化为端口,并可选地给定字符串protocolValue
  1. 如果portValue为空字符串,则返回portValue

  2. dummyURL为一个新的URL记录

  3. 如果给定了protocolValue,则将dummyURL方案设置为protocolValue

    注意,我们设置URL记录方案,以便基本URL解析器能够识别和规范化默认端口值。

  4. parseResult为运行基本URL解析器的结果,传入portValue,并使用dummyURL作为URL,并使用端口状态作为状态覆盖

  5. 如果parseResult为失败,则抛出TypeError

  6. 返回dummyURL端口序列化后的值,或者如果为空则返回空字符串。

将字符串value规范化为路径名:
  1. 如果value为空字符串,则返回value

  2. 如果value的第一个码点是U+002F(/),则leading slash为true,否则为false。

  3. 如果leading slash为false,则modified value为"/-",否则为空字符串。

    URL解析器将自动在规范化的路径名前加上前导斜杠。这在这里不起作用,因为该算法在用作编码回调时会处理路径的部分,而不是整个路径。因此,我们通过插入自己的前导斜杠来禁用斜杠的添加。还在此处插入了一个额外的字符,以避免由于虚假的前导斜杠被解释为"/."序列而无意中压缩前导点。然后在下面从结果中删除这些插入的字符。

    注意,实施者可以选择在其URL解析代码中简单地禁用斜杠添加,而不是通过此算法插入和删除字符来支付性能成本。

  4. value附加到modified value的末尾。

  5. dummyURL为一个新的URL记录

  6. parseResult为运行基本URL解析器的结果,传入modified value,并使用dummyURL作为URL,并使用路径开始状态作为状态覆盖

  7. 如果parseResult为失败,则抛出TypeError

  8. resultdummyURLURL路径序列化结果。

  9. 如果leading slash为false,则将result设置为从2到字符串末尾的码点子字符串

  10. 返回result

将字符串value规范化为不透明路径名:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. dummyURL路径设置为空字符串。

  4. parseResult为运行URL解析的结果,传入value,并使用dummyURL作为URL,以及使用不透明路径状态作为状态覆盖

  5. 如果parseResult为失败,则抛出TypeError

  6. 返回URL路径序列化后的dummyURL结果。

将字符串value规范化为查询字符串:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. dummyURL查询设置为空字符串。

  4. parseResult为运行基本URL解析器的结果,传入value,并使用dummyURL作为URL,以及使用查询状态作为状态覆盖

  5. 如果parseResult为失败,则抛出TypeError

  6. 返回dummyURL查询

将字符串value规范化为哈希:
  1. 如果value为空字符串,则返回value

  2. dummyURL为一个新的URL记录

  3. dummyURL片段设置为空字符串。

  4. parseResult为运行基本URL解析器的结果,传入value,并使用dummyURL作为URL,以及使用片段状态作为状态覆盖

  5. 如果parseResult为失败,则抛出TypeError

  6. 返回dummyURL片段

3.2. URLPatternInit 处理

URLPatternInit处理,传入init、字符串type、字符串或null的protocolusernamepasswordhostnameportpathnamesearchhash
  1. result为创建一个新的URLPatternInit的结果。

  2. 如果protocol不为null,设置result["protocol"]为protocol

  3. 如果username不为null,设置result["username"]为username

  4. 如果password不为null,设置result["password"]为password

  5. 如果hostname不为null,设置result["hostname"]为hostname

  6. 如果port不为null,设置result["port"]为port

  7. 如果pathname不为null,设置result["pathname"]为pathname

  8. 如果search不为null,设置result["search"]为search

  9. 如果hash不为null,设置result["hash"]为hash

  10. baseURL为null。

  11. 如果init["baseURL"]存在

    base URL可用于提供额外的上下文,但对于每个组件,如果init包含的组件至少与base URL中的组件一样具体,则不会继承任何内容。

    如果组件在以下两个列表中较晚出现(与它们在URL语法中出现的顺序非常相似),则该组件更具体:

    • 协议、主机名、端口、路径名、查询、哈希

    • 协议、主机名、端口、用户名、密码

    构建URLPattern时,用户名和密码也从不从base URL继承。(不过,在解析作为test()exec()的参数传入的URL时,用户名和密码是从base URL继承的。)

    1. baseURL设置为解析init["baseURL"]的结果。

    2. 如果baseURL为失败,则抛出TypeError

    3. 如果init["protocol"]不存在,则将result["protocol"]设置为处理base URL字符串的结果,传入baseURLschemetype

    4. 如果type不是"pattern",并且init不包含"protocol"、"hostname"、"port"和"username",则将result["username"]设置为处理base URL字符串的结果,传入baseURLusernametype

    5. 如果type不是"pattern",并且init不包含"protocol"、"hostname"、"port"、"username"和"password",则将result["password"]设置为处理base URL字符串的结果,传入baseURLpasswordtype

    6. 如果init不包含"protocol"或"hostname",则:

      1. baseHostbaseURL主机

      2. 如果baseHost为null,则将baseHost设置为空字符串。

      3. result["hostname"]设置为处理base URL字符串的结果,传入baseHosttype

    7. 如果init不包含"protocol"、"hostname"、"port",则:

      1. 如果baseURL端口为null,则将result["port"]设置为空字符串。

      2. 否则,将result["port"]设置为baseURL端口序列化

    8. 如果init不包含"protocol"、"hostname"、"port"、"pathname",则将result["pathname"]设置为处理base URL字符串的结果,传入URL路径序列化baseURLtype

    9. 如果init不包含"protocol"、"hostname"、"port"、"pathname"和"search",则:

      1. baseQuerybaseURL查询

      2. 如果baseQuery为null,则将baseQuery设置为空字符串。

      3. result["search"]设置为处理base URL字符串的结果,传入baseQuerytype

    10. 如果init不包含"protocol"、"hostname"、"port"、"pathname"、"search"和"hash",则:

      1. baseFragmentbaseURL片段

      2. 如果baseFragment为null,则将baseFragment设置为空字符串。

      3. result["hash"]设置为处理base URL字符串的结果,传入baseFragmenttype

  12. 如果init["protocol"]存在,则将result["protocol"]设置为处理init协议的结果,传入init["protocol"]和type

  13. 如果init["username"]存在,则将result["username"]设置为处理init用户名的结果,传入init["username"]和type

  14. 如果init["password"]存在,则将result["password"]设置为处理init密码的结果,传入init["password"]和type

  15. 如果init["hostname"]存在,则将result["hostname"]设置为处理init主机名的结果,传入init["hostname"]和type

  16. 如果init["port"]存在,则将result["port"]设置为处理init端口的结果,传入init["port"]、result["protocol"]和type

  17. 如果init["pathname"]存在

    1. result["pathname"]设置为init["pathname"]。

    2. 如果以下条件全部为真:

      则:

      1. baseURLPath为运行处理base URL字符串的结果,传入URL路径序列化baseURLtype

      2. slash index为在baseURLPath中找到的最后一个U+002F(/)代码点的索引,按代码点序列解释,或为null,如果没有找到代码点。

      3. 如果slash index不为null:

        1. new pathnamebaseURLPath中从0到slash index + 1的代码点子字符串

        2. result["pathname"]附加到new pathname的末尾。

        3. result["pathname"]设置为new pathname

    3. result["pathname"]设置为处理init路径名的结果,传入result["pathname"]、result["protocol"]和type

  18. 如果init["search"]存在,则将result["search"]设置为处理init查询的结果,传入init["search"]和type

  19. 如果init["hash"]存在,则将result["hash"]设置为处理init哈希的结果,传入init["hash"]和type

  20. 返回result

要处理给定的字符串input和字符串typebase URL字符串
  1. 断言input不为null。

  2. 如果type不是"pattern",则返回input

  3. 返回运行转义模式字符串的结果,传入input

要运行判断是否为绝对路径名,给定模式字符串 input和字符串type
  1. 如果input为空字符串,则返回false。

  2. 如果input[0]是U+002F(/),则返回true。

  3. 如果type是"url",则返回false。

  4. 如果input代码点长度小于2,则返回false。

  5. 如果input[0]是U+005C(\),并且input[1]是U+002F(/),则返回true。

  6. 如果input[0]是U+007B({),并且input[1]是U+002F(/),则返回true。

  7. 返回false。

要处理给定的字符串value和字符串type初始化协议
  1. strippedValue为给定的value,去掉一个结尾的U+003A(:),如果有的话。

  2. 如果type是"pattern",则返回strippedValue

  3. 返回运行规范化协议的结果,传入strippedValue

要处理给定的字符串value和字符串type初始化用户名
  1. 如果type是"pattern",则返回value

  2. 返回运行规范化用户名的结果,传入value

要处理给定的字符串value和字符串type初始化密码
  1. 如果type是"pattern",则返回value

  2. 返回运行规范化密码的结果,传入value

要处理给定的字符串value和字符串type初始化主机名
  1. 如果type是"pattern",则返回value

  2. 返回运行规范化主机名的结果,传入value

要处理给定的字符串portValue、字符串protocolValue和字符串type初始化端口
  1. 如果type是"pattern",则返回portValue

  2. 返回运行规范化端口的结果,传入portValueprotocolValue

要处理给定的字符串pathnameValue、字符串protocolValue和字符串type初始化路径名
  1. 如果type是"pattern",则返回pathnameValue

  2. 如果protocolValue特殊方案或为空字符串,则返回运行规范化路径名的结果,传入pathnameValue

    如果protocolValue为空字符串,则表示在构造函数字典中没有为协议提供值。通常我们不会对空字符串字典值进行特殊处理,但在这种情况下,我们将其视为特殊方案,以便默认使用最常见的路径名规范化。

  3. 返回运行规范化不透明路径名的结果,传入pathnameValue

要处理给定的字符串value和字符串type初始化搜索
  1. strippedValue为给定的value,去掉一个开头的U+003F(?),如果有的话。

  2. 如果type是"pattern",则返回strippedValue

  3. 返回运行规范化搜索的结果,传入strippedValue

要处理给定的字符串value和字符串type初始化哈希
  1. strippedValue为给定的value,去掉一个开头的U+0023(#),如果有的话。

  2. 如果type是"pattern",则返回strippedValue

  3. 返回运行规范化哈希的结果,传入strippedValue

4. 在其他规范中使用URL模式

为了促进Web平台的一致性,集成此规范的其他文档应遵循以下指南,除非有充分的理由偏离。

  1. 接受简写。大多数作者的模式将是简单而直接的。因此,API应该接受这些常见情况的简写,并避免让作者采取额外步骤将其转换为完整的URLPattern对象。

  2. 尊重基础URL。就像URL通常相对于其环境的基础URL(最常见的是文档基础URL)进行解析一样,URL模式也应遵循这一点。URLPattern构造函数本身是一个例外,因为它直接暴露了该概念,类似于URL构造函数也不遵循基础URL,尽管平台的其余部分遵循。

  3. 明确正则表达式组。某些API可能仅允许不具有正则表达式组的URL模式,例如,因为用户代理可能在不同的线程或进程中实现它们,而不是执行作者脚本的地方,并且由于安全或性能问题,JavaScript引擎通常不会在那运行。如果是这样,应该清楚地记录这一点(参考是否具有正则表达式组),并且该操作应尽早报告错误(例如,抛出JavaScript异常)。如果可能,应使其具有特征检测功能,以便将来可以解除此限制。避免在未咨询本规范编辑者的情况下创建不同的URL模式子集。

  4. 明确匹配的URL。例如,抓取期间的算法可能操作没有片段的URL。如果是这样,规范应明确说明,并可以建议如果使用了无法匹配的模式(例如,因为它需要非空的片段),则显示开发人员警告。

4.1. 与JavaScript API的集成

typedef (USVString  URLPatternInit  URLPattern) URLPatternCompatible;

JavaScript API应接受以下所有内容:

为了实现这一点,规范应接受URLPatternCompatible作为操作或字典成员的参数,并使用以下算法处理它,使用适当的环境设置对象API基础URL或等效的。

要从一个Web IDL值构建一个URLPattern对象 URLPatternCompatible input,给定URL baseURLrealm realm,执行以下步骤:
  1. 如果input特定类型URLPattern

    1. 返回input

  2. 否则:

    1. pattern新的URLPattern,带有realm

    2. pattern关联URL模式设置为运行从Web IDL值构建URL模式的结果,传入inputbaseURL

    3. 返回pattern

要从一个Web IDL值构建URL模式 URLPatternCompatible input,给定URL baseURL,执行以下步骤:
  1. 如果input特定类型URLPattern

    1. 返回input关联URL模式

  2. 否则,如果input特定类型URLPatternInit

    1. initinput克隆

    2. 如果init["baseURL"]不存在,设置它为baseURL序列化

    3. 返回运行创建URL模式的结果,传入init、null和一个空的有序映射

  3. 否则:

    1. 断言input特定类型USVString

    2. 返回运行创建URL模式的结果,传入inputbaseURL序列化,以及一个空的有序映射

这允许作者简洁地指定大多数模式,并在必要时使用构造函数来访问不常见的选项。基础URL的隐式使用与HTML解析URL算法类似且一致。[HTML]

4.2. 与JSON数据格式的集成

包含URL模式的JSON数据格式应当与JavaScript API的行为保持一致,并接受以下两种格式:

如果某个规范有一个Infra值(例如,在使用将JSON字符串解析为Infra值之后),请使用以下算法,并使用适当的基础URL(默认情况下为JSON资源的URL)。[INFRA]

要从Infra值构建URL模式 rawPattern,给定URL baseURL,执行以下步骤。
  1. serializedBaseURLbaseURL序列化

  2. 如果rawPattern字符串,则:

    1. 返回运行创建URL模式的结果,传入rawPatternserializedBaseURL和一个空的映射

      将来可能需要在此传递非空选项。
  3. 否则,如果rawPattern映射,则:

    1. init为«[ "baseURL" → serializedBaseURL ]»,表示一个类型为URLPatternInit的字典。

    2. 对于每个 keyvaluerawPattern

      1. 如果key不是URLPatternInit或其继承字典标识符value不是字符串,或者该成员的类型未声明为USVString,则返回null。

        如果URLPatternInit增加了其他类型的成员,这将需要更新。
        如果对其他规范有用,将来的规范版本可能还会有一种不那么严格的模式。
      2. init[key]设置为value

    3. 返回运行创建URL模式的结果,传入init、null和一个空的映射

      将来可能需要在此传递非空选项。
  4. 否则,返回null。

规范可能希望在其格式中预留空间,以接受URLPatternOptions的选项、覆盖基础URL或类似内容,因为在这种情况下不可能像在JavaScript API中那样直接构造URLPattern对象。例如,Speculation Rules接受一个"relative_to"键,可以用来切换到使用文档基础URL,而不是JSON资源的URL。[SPECULATION-RULES]

致谢

编辑们要感谢 Alex Russell, Anne van Kesteren, Asa Kusuma, Blake Embrey, Cyrus Kasaaian, Daniel Murphy, Darwin Huang, Devlin Cronin, Domenic Denicola, Dominick Ng, Jake Archibald, Jeffrey Posnick, Jeremy Roman, Jimmy Shen, Joe Gregorio, Joshua Bell, Kenichi Ishibashi, Kenji Baheux, Kenneth Rohde Christiansen, Kingsley Ngan, Kinuko Yasuda, L. David Baron, Luca Casonato, Łukasz Anforowicz, Makoto Shimazu, Marijn Kruisselbrink, Matt Falkenhagen, Matt Giuca, Michael Landry, R. Samuel Klatchko, Rajesh Jagannathan, Ralph Chelala, Sangwhan Moon, Sayan Pal, Victor Costan, Yoshisato Yanagisawa, 以及 Youenn Fablet 对本规范的贡献。

特别感谢Blake Embrey和其他pillarjs/path-to-regexp 贡献者,他们构建了一个出色的开源库,受到了广泛欢迎。

同样特别感谢Kenneth Rohde Christiansen为polyfill所做的工作。他为适应不断变化的URLPattern API做了大量工作。

该标准由 Ben Kelly (Google, wanderview@chromium.org), Jeremy Roman (Google, jbroman@chromium.org),以及 宍戸俊哉 (Shunya Shishido, Google, sisidovski@chromium.org)撰写。

知识产权

本现行标准最初由W3C WICG开发,并根据W3C软件和文档许可证发布。

版权所有 © WHATWG (Apple, Google, Mozilla, Microsoft)。本作品采用知识共享署名 4.0 国际许可协议授权。若有部分内容被纳入源代码,则该部分源代码根据BSD 3-Clause License授权。

这是现行标准。若有兴趣查看专利审查版本,请参阅现行标准审查草案

索引

本规范定义的术语

其他规范定义的术语

参考文献

规范性引用

[ECMASCRIPT]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[HTML]
Anne van Kesteren 等. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[URL]
Anne van Kesteren. URL 标准. 现行标准. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

参考性引用

[SPECULATION-RULES]
推测规则. 草案社区组报告. URL: https://wicg.github.io/nav-speculation/speculation-rules.html

IDL 索引

typedef (USVString or URLPatternInit) URLPatternInput;

[Exposed=(Window,Worker)]
interface URLPattern {
  constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {});
  constructor(optional URLPatternInput input = {}, optional URLPatternOptions options = {});

  boolean test(optional URLPatternInput input = {}, optional USVString baseURL);

  URLPatternResult? exec(optional URLPatternInput input = {}, optional USVString baseURL);

  readonly attribute USVString protocol;
  readonly attribute USVString username;
  readonly attribute USVString password;
  readonly attribute USVString hostname;
  readonly attribute USVString port;
  readonly attribute USVString pathname;
  readonly attribute USVString search;
  readonly attribute USVString hash;

  readonly attribute boolean hasRegExpGroups;
};

dictionary URLPatternInit {
  USVString protocol;
  USVString username;
  USVString password;
  USVString hostname;
  USVString port;
  USVString pathname;
  USVString search;
  USVString hash;
  USVString baseURL;
};

dictionary URLPatternOptions {
  boolean ignoreCase = false;
};

dictionary URLPatternResult {
  sequence<URLPatternInput> inputs;

  URLPatternComponentResult protocol;
  URLPatternComponentResult username;
  URLPatternComponentResult password;
  URLPatternComponentResult hostname;
  URLPatternComponentResult port;
  URLPatternComponentResult pathname;
  URLPatternComponentResult search;
  URLPatternComponentResult hash;
};

dictionary URLPatternComponentResult {
  USVString input;
  record<USVString, (USVString or undefined)> groups;
};

typedef (USVString or URLPatternInit or URLPattern) URLPatternCompatible;

MDN

URLPattern/URLPattern

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/exec

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/hash

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/hostname

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/password

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/pathname

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/port

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/protocol

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/search

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/test

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern/username

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

URLPattern

In only one current engine.

FirefoxNoneSafariNoneChrome95+
Opera?Edge95+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?