webext-patterns 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +69 -30
- package/package.json +11 -22
- package/readme.md +17 -15
package/index.js
CHANGED
|
@@ -1,71 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
+
if (ar || !(i in from)) {
|
|
5
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
+
ar[i] = from[i];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
+
};
|
|
11
|
+
var _a;
|
|
12
|
+
exports.__esModule = true;
|
|
13
|
+
exports.removeRedundantPatterns = exports.globToRegex = exports.patternToRegex = exports.getMatchingPatterns = exports.testPatterns = exports.isValidPattern = exports.assertValidPattern = exports.allUrlsRegex = exports.allStarsRegex = exports.patternValidationRegex = void 0;
|
|
14
|
+
// Copied from https://github.com/mozilla/gecko-dev/blob/5836a062726f715fda621338a17b51aff30d0a8c/toolkit/components/extensions/schemas/manifest.json#L729-L741
|
|
15
|
+
exports.patternValidationRegex = /^(https?|wss?|file|ftp|\*):\/\/(\*|\*\.[^*/:]+|[^*/:]+)\/.*$|^file:\/\/\/.*$|^about:/;
|
|
16
|
+
var isFirefox = (_a = globalThis.navigator) === null || _a === void 0 ? void 0 : _a.userAgent.includes('Firefox/');
|
|
17
|
+
exports.allStarsRegex = isFirefox
|
|
6
18
|
? /^(https?|wss?):[/][/][^/]+([/].*)?$/
|
|
7
19
|
: /^https?:[/][/][^/]+([/].*)?$/;
|
|
8
|
-
|
|
9
|
-
|
|
20
|
+
exports.allUrlsRegex = /^(https?|file|ftp):[/]+/;
|
|
21
|
+
function assertValidPattern(matchPattern) {
|
|
10
22
|
if (!isValidPattern(matchPattern)) {
|
|
11
23
|
throw new Error(matchPattern + ' is an invalid pattern. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns for more info.');
|
|
12
24
|
}
|
|
13
25
|
}
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
exports.assertValidPattern = assertValidPattern;
|
|
27
|
+
function isValidPattern(matchPattern) {
|
|
28
|
+
return matchPattern === '<all_urls>' || exports.patternValidationRegex.test(matchPattern);
|
|
16
29
|
}
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
exports.isValidPattern = isValidPattern;
|
|
31
|
+
function testPatterns(url, patterns) {
|
|
32
|
+
if (patterns.includes('<all_urls>') && exports.allUrlsRegex.test(url)) {
|
|
19
33
|
return true;
|
|
20
34
|
}
|
|
21
|
-
if (patterns.includes('*://*/*') && allStarsRegex.test(url)) {
|
|
35
|
+
if (patterns.includes('*://*/*') && exports.allStarsRegex.test(url)) {
|
|
22
36
|
return true;
|
|
23
37
|
}
|
|
24
|
-
for (
|
|
38
|
+
for (var _i = 0, patterns_1 = patterns; _i < patterns_1.length; _i++) {
|
|
39
|
+
var pattern = patterns_1[_i];
|
|
25
40
|
if (patternToRegex(pattern).test(url)) {
|
|
26
41
|
return true;
|
|
27
42
|
}
|
|
28
43
|
}
|
|
29
44
|
return false;
|
|
30
45
|
}
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
exports.testPatterns = testPatterns;
|
|
47
|
+
function getMatchingPatterns(url, patterns) {
|
|
48
|
+
return patterns.filter(function (pattern) { return testPatterns(url, [pattern]); });
|
|
33
49
|
}
|
|
50
|
+
exports.getMatchingPatterns = getMatchingPatterns;
|
|
34
51
|
function getRawPatternRegex(matchPattern) {
|
|
35
52
|
assertValidPattern(matchPattern);
|
|
36
53
|
// Host undefined for file:///
|
|
37
|
-
|
|
54
|
+
var _a = matchPattern.split(/(^[^:]+:[/][/])([^/]+)?/), protocol = _a[1], _b = _a[2], host = _b === void 0 ? '' : _b, pathname = _a[3];
|
|
38
55
|
protocol = protocol
|
|
39
56
|
.replace('*', isFirefox ? '(https?|wss?)' : 'https?') // Protocol wildcard
|
|
40
57
|
.replaceAll(/[/]/g, '[/]'); // Escape slashes
|
|
41
58
|
if (host === '*') {
|
|
42
59
|
host = '[^/]+';
|
|
43
60
|
}
|
|
44
|
-
host
|
|
61
|
+
host && (host = host
|
|
45
62
|
.replace(/^[*][.]/, '([^/]+.)*') // Initial wildcard
|
|
46
63
|
.replaceAll(/[.]/g, '[.]') // Escape dots
|
|
47
|
-
.replace(/[*]$/, '[^.]+'); // Last wildcard
|
|
64
|
+
.replace(/[*]$/, '[^.]+')); // Last wildcard
|
|
48
65
|
pathname = pathname
|
|
49
66
|
.replaceAll(/[/]/g, '[/]') // Escape slashes
|
|
50
67
|
.replaceAll(/[.]/g, '[.]') // Escape dots
|
|
51
68
|
.replaceAll(/[*]/g, '.*'); // Any wildcard
|
|
52
69
|
return '^' + protocol + host + '(' + pathname + ')?$';
|
|
53
70
|
}
|
|
54
|
-
|
|
71
|
+
function patternToRegex() {
|
|
72
|
+
var matchPatterns = [];
|
|
73
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
74
|
+
matchPatterns[_i] = arguments[_i];
|
|
75
|
+
}
|
|
55
76
|
// No pattern, match nothing https://stackoverflow.com/q/14115522/288906
|
|
56
77
|
if (matchPatterns.length === 0) {
|
|
57
78
|
return /$./;
|
|
58
79
|
}
|
|
59
80
|
if (matchPatterns.includes('<all_urls>')) {
|
|
60
|
-
return allUrlsRegex;
|
|
81
|
+
return exports.allUrlsRegex;
|
|
61
82
|
}
|
|
62
83
|
if (matchPatterns.includes('*://*/*')) {
|
|
63
|
-
return allStarsRegex;
|
|
84
|
+
return exports.allStarsRegex;
|
|
64
85
|
}
|
|
65
|
-
return new RegExp(matchPatterns.map(x
|
|
86
|
+
return new RegExp(matchPatterns.map(function (x) { return getRawPatternRegex(x); }).join('|'));
|
|
66
87
|
}
|
|
88
|
+
exports.patternToRegex = patternToRegex;
|
|
67
89
|
// The parens are required by .split() to preserve the symbols
|
|
68
|
-
|
|
90
|
+
var globSymbols = /([?*]+)/;
|
|
69
91
|
function splitReplace(part, index) {
|
|
70
92
|
if (part === '') {
|
|
71
93
|
// Shortcut for speed
|
|
@@ -73,16 +95,17 @@ function splitReplace(part, index) {
|
|
|
73
95
|
}
|
|
74
96
|
if (index % 2 === 0) {
|
|
75
97
|
// Raw text, escape it
|
|
76
|
-
|
|
98
|
+
// eslint-disable-next-line no-use-extend-native/no-use-extend-native -- TODO: Drop after https://github.com/dustinspecker/eslint-plugin-no-use-extend-native/issues/157
|
|
99
|
+
return RegExp.escape(part);
|
|
77
100
|
}
|
|
78
101
|
// Else: Symbol
|
|
79
102
|
if (part.includes('*')) { // Can be more than one and it swallows surrounding question marks
|
|
80
103
|
return '.*';
|
|
81
104
|
}
|
|
82
|
-
return [
|
|
105
|
+
return __spreadArray([], part, true).map(function () { return isFirefox ? '.' : '.?'; }).join('');
|
|
83
106
|
}
|
|
84
107
|
function getRawGlobRegex(glob) {
|
|
85
|
-
|
|
108
|
+
var regexString = glob
|
|
86
109
|
.split(globSymbols)
|
|
87
110
|
// eslint-disable-next-line unicorn/no-array-callback-reference -- tis ok 🤫
|
|
88
111
|
.map(splitReplace)
|
|
@@ -93,19 +116,35 @@ function getRawGlobRegex(glob) {
|
|
|
93
116
|
.replace(/[.][*]$/, '')
|
|
94
117
|
.replace(/^[$]$/, '.+'); // Catch `*` and `*`
|
|
95
118
|
}
|
|
96
|
-
|
|
119
|
+
function globToRegex() {
|
|
120
|
+
var globs = [];
|
|
121
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
122
|
+
globs[_i] = arguments[_i];
|
|
123
|
+
}
|
|
97
124
|
// No glob, match anything; `include_globs: []` is the default
|
|
98
125
|
if (globs.length === 0) {
|
|
99
126
|
return /.*/;
|
|
100
127
|
}
|
|
101
|
-
return new RegExp(globs.map(x
|
|
128
|
+
return new RegExp(globs.map(function (x) { return getRawGlobRegex(x); }).join('|'));
|
|
102
129
|
}
|
|
103
|
-
|
|
130
|
+
exports.globToRegex = globToRegex;
|
|
131
|
+
function removeRedundantPatterns(matchPatterns) {
|
|
104
132
|
if (matchPatterns.includes('<all_urls>')) {
|
|
105
133
|
return ['<all_urls>'];
|
|
106
134
|
}
|
|
107
135
|
if (matchPatterns.includes('*://*/*')) {
|
|
108
136
|
return ['*://*/*'];
|
|
109
137
|
}
|
|
110
|
-
|
|
138
|
+
// Cover identical patterns
|
|
139
|
+
var uniquePatterns = __spreadArray([], new Set(matchPatterns), true);
|
|
140
|
+
return uniquePatterns.filter(function (possibleSubset) {
|
|
141
|
+
// Keep if there are no matches
|
|
142
|
+
return !uniquePatterns.some(function (possibleSuperset) {
|
|
143
|
+
// Don't compare to self
|
|
144
|
+
return possibleSubset !== possibleSuperset
|
|
145
|
+
// Drop if it's a subset
|
|
146
|
+
&& patternToRegex(possibleSuperset).test(possibleSubset);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
111
149
|
}
|
|
150
|
+
exports.removeRedundantPatterns = removeRedundantPatterns;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webext-patterns",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Tool to convert the patterns and globs of your WebExtension manifest to regex",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"browser",
|
|
@@ -32,32 +32,21 @@
|
|
|
32
32
|
"fix": "xo --fix",
|
|
33
33
|
"lint": "xo",
|
|
34
34
|
"prepare": "tsc --sourceMap false",
|
|
35
|
-
"test": "tsc &&
|
|
35
|
+
"test": "tsc && vitest run && xo",
|
|
36
36
|
"watch": "tsc --watch"
|
|
37
37
|
},
|
|
38
|
-
"xo": {
|
|
39
|
-
"envs": [
|
|
40
|
-
"browser",
|
|
41
|
-
"webextensions"
|
|
42
|
-
],
|
|
43
|
-
"rules": {
|
|
44
|
-
"unicorn/better-regex": "off"
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"escape-string-regexp": "^5.0.0"
|
|
49
|
-
},
|
|
50
38
|
"devDependencies": {
|
|
51
|
-
"@sindresorhus/tsconfig": "^
|
|
52
|
-
"@types/chrome": "0.
|
|
53
|
-
"
|
|
54
|
-
"sinon": "^
|
|
55
|
-
"type-fest": "^
|
|
56
|
-
"typescript": "^
|
|
57
|
-
"
|
|
39
|
+
"@sindresorhus/tsconfig": "^8.1.0",
|
|
40
|
+
"@types/chrome": "^0.1.39",
|
|
41
|
+
"globals": "^17.4.0",
|
|
42
|
+
"sinon": "^21.0.3",
|
|
43
|
+
"type-fest": "^5.5.0",
|
|
44
|
+
"typescript": "^6.0.2",
|
|
45
|
+
"vitest": "^4.1.2",
|
|
46
|
+
"xo": "^2.0.2"
|
|
58
47
|
},
|
|
59
48
|
"engines": {
|
|
60
|
-
"node": ">=
|
|
49
|
+
"node": ">=24"
|
|
61
50
|
},
|
|
62
51
|
"webExt": {
|
|
63
52
|
"sourceDir": "demo-extension",
|
package/readme.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
# webext-patterns
|
|
2
|
-
|
|
3
|
-
[badge-gzip]: https://img.shields.io/bundlephobia/minzip/webext-patterns.svg?label=gzipped
|
|
4
|
-
[link-bundlephobia]: https://bundlephobia.com/result?p=webext-patterns
|
|
1
|
+
# webext-patterns
|
|
5
2
|
|
|
6
3
|
> Utilities for [patterns](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#matching_url_patterns) and globs for WebExtensions
|
|
7
4
|
|
|
5
|
+
**Sponsored by [PixieBrix](https://www.pixiebrix.com)** :tada:
|
|
6
|
+
|
|
8
7
|
## Install
|
|
9
8
|
|
|
10
9
|
You can download the [standalone bundle](https://bundle.fregante.com/?pkg=webext-patterns) and include it in your `manifest.json`.
|
|
@@ -19,8 +18,8 @@ npm install webext-patterns
|
|
|
19
18
|
import {
|
|
20
19
|
patternToRegex,
|
|
21
20
|
globToRegex,
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
removeRedundantPatterns,
|
|
22
|
+
testPatterns,
|
|
24
23
|
assertValidPattern,
|
|
25
24
|
isValidPattern,
|
|
26
25
|
} from 'webext-patterns';
|
|
@@ -35,7 +34,7 @@ patternToRegex('http://*/*');
|
|
|
35
34
|
globToRegex('*.example.com');
|
|
36
35
|
// Returns /\.example\.com$/
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
removeRedundantPatterns(['https://*.google.com/*', 'https://google.com/*']);
|
|
39
38
|
// Returns ['https://*.google.com/*']
|
|
40
39
|
|
|
41
40
|
assertValidPattern('https://google.*/*');
|
|
@@ -48,6 +47,9 @@ isValidPattern('https://*.google.com/*');
|
|
|
48
47
|
> **Note**
|
|
49
48
|
> Firefox and Chrome handle patterns very slighly differently. `webext-patterns` defaults to Chrome’s logic, but if it detects a Firefox userAgent it will produce a Firefox-compatible regex.
|
|
50
49
|
|
|
50
|
+
> **Note**
|
|
51
|
+
> This package uses `RegExp.escape`, which requires browsers from May 2025 and later.
|
|
52
|
+
|
|
51
53
|
## API
|
|
52
54
|
|
|
53
55
|
#### patternToRegex(pattern1, pattern2, etc)
|
|
@@ -97,12 +99,12 @@ googleRegex.test('https://google.it/search'); // -> true
|
|
|
97
99
|
googleRegex.test('https://google.de/search'); // -> false
|
|
98
100
|
```
|
|
99
101
|
|
|
100
|
-
####
|
|
102
|
+
#### removeRedundantPatterns([pattern1, pattern2, etc])
|
|
101
103
|
|
|
102
104
|
Accepts an array of patterns and returns a filtered array without the patterns that are already covered by others. For example `"https://*/*"` already covers all "https" URLs, so having `"https://google.com/*"` in the array won't make any difference and therefore it's dropped.
|
|
103
105
|
|
|
104
106
|
```js
|
|
105
|
-
|
|
107
|
+
removeRedundantPatterns([
|
|
106
108
|
"https://*/*",
|
|
107
109
|
"https://google.com/*",
|
|
108
110
|
"https://*.example.com/*",
|
|
@@ -110,18 +112,18 @@ excludeDuplicatePatterns([
|
|
|
110
112
|
// Returns ["https://*/*"]
|
|
111
113
|
```
|
|
112
114
|
|
|
113
|
-
####
|
|
115
|
+
#### testPatterns(url, patterns)
|
|
114
116
|
|
|
115
|
-
Accepts a URL and
|
|
117
|
+
Accepts a URL and an array of patterns and returns `true` if the URL matches any of the patterns. This is a convenience method that wraps `patternToRegex` for single use. If you plan on testing multiple URLs against the same patterns, it's better to convert the patterns to a regex once and reuse that.
|
|
116
118
|
|
|
117
119
|
```js
|
|
118
|
-
|
|
120
|
+
testPatterns('https://google.com/', ['https://*.google.com/*', '*://example.com/*']);
|
|
119
121
|
// Returns true
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
####
|
|
124
|
+
#### getMatchingPatterns(url, patterns)
|
|
123
125
|
|
|
124
|
-
Accepts a URL and
|
|
126
|
+
Accepts a URL and an array of patterns and returns an array of the patterns that match the URL. It returns an empty array if none of the patterns match the URL.
|
|
125
127
|
|
|
126
128
|
#### assertValidPattern(pattern)
|
|
127
129
|
|
|
@@ -146,7 +148,7 @@ isValidPattern('https://google.*/*');
|
|
|
146
148
|
- [webext-permissions](https://github.com/fregante/webext-permissions) - Get any optional permissions that users have granted you.
|
|
147
149
|
- [webext-options-sync](https://github.com/fregante/webext-options-sync) - Helps you manage and autosave your extension's options.
|
|
148
150
|
- [webext-storage-cache](https://github.com/fregante/webext-storage-cache) - Map-like promised cache storage with expiration.
|
|
149
|
-
- [webext-detect
|
|
151
|
+
- [webext-detect](https://github.com/fregante/webext-detect) - Detects where the current browser extension code is being run.
|
|
150
152
|
- [Awesome-WebExtensions](https://github.com/fregante/Awesome-WebExtensions) - A curated list of awesome resources for WebExtensions development.
|
|
151
153
|
- [More…](https://github.com/fregante/webext-fun)
|
|
152
154
|
|