| 69 | }; |
| 70 | |
| 71 | export const extractUrlPatterns = (lines: string[]): URLRuleEntry[] => { |
| 72 | const rules = []; |
| 73 | for (const line of lines) { |
| 74 | const mt = /@(match|include|exclude)\s+([^\t\r\n]+?)([\r\n]|$)/.exec(line); |
| 75 | if (!mt) continue; |
| 76 | const [_, tag0, content0] = mt; |
| 77 | const tag = tag0; |
| 78 | let content = content0; |
| 79 | if (content.charAt(0) !== "/") { |
| 80 | if (tag === "match") { |
| 81 | // @match |
| 82 | let m: RegExpExecArray | null; |
| 83 | |
| 84 | if (content === "*") { |
| 85 | // 特殊处理 @match * |
| 86 | // * 会对应成 *://*/ |
| 87 | content = "*://*/"; |
| 88 | } else { |
| 89 | m = /^(\*|[-a-z]+|http\*):\/\/(\*?[^*/:]*)(:[^*/]*)?/.exec(content); |
| 90 | if (!m) { |
| 91 | // 如不是正确 match pattern, 为了兼容 TM,尝试 fallback 处理 |
| 92 | // 例如 "// @match www.youtube.com/*" |
| 93 | let tu; |
| 94 | try { |
| 95 | tu = new URL(`undefined-protocol://${content}`); // e.g. "undefined-protocol://example.com/*" |
| 96 | } catch (_e) { |
| 97 | // 尝试失败则不忽略 (例如 "undefined-protocol://hello-world^^" ) |
| 98 | } |
| 99 | if (tu?.protocol === "undefined-protocol:" && tu.hostname && tu.pathname) { |
| 100 | content = `*://${tu.hostname}${tu.pathname}${tu.search}`; |
| 101 | m = /^(\*|[-a-z]+|http\*):\/\/(\*?[^*/:]*)(:[^*/]*)?/.exec(content); |
| 102 | } |
| 103 | } |
| 104 | // 若无法匹对,则表示该表达式应为错误match pattern格式,忽略处理。 |
| 105 | if (m) { |
| 106 | // 特殊处理:自动除去 port (TM的行为是以下完全等价) |
| 107 | // https://www.google.com/* |
| 108 | // https://www.google.com:/* |
| 109 | // https://www.google.com:80/* |
| 110 | // https://www.google.com:*/* |
| 111 | // 所有port都会被视作匹配 (80, 443, ...) |
| 112 | // 因此SC的处理只需要去除 :80 的部份,即可使用原生 match pattern |
| 113 | |
| 114 | // 特殊处理 https http |
| 115 | let scheme = m[1]; |
| 116 | if (scheme === "http*") { |
| 117 | scheme = "*"; |
| 118 | } |
| 119 | |
| 120 | let path = content.substring(m[0].length); |
| 121 | // 特殊处理: 没有path的话,自动补斜线,即可使用原生 match pattern |
| 122 | // 特殊处理: path的斜线前有*,TM视之为port的一部份,会自动去除 |
| 123 | if (!path || path === "*") { |
| 124 | path = "/"; |
| 125 | } else if (path.startsWith("*/")) { |
| 126 | path = path.substring(1); |
| 127 | } |
| 128 | |