webext-patterns 1.5.1 → 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.
Files changed (3) hide show
  1. package/index.js +68 -37
  2. package/package.json +11 -22
  3. package/readme.md +16 -14
package/index.js CHANGED
@@ -1,71 +1,93 @@
1
- import escapeStringRegexp from 'escape-string-regexp';
2
- // Copied from https://github.com/mozilla/gecko-dev/blob/073cc24f53d0cf31403121d768812146e597cc9d/toolkit/components/extensions/schemas/manifest.json#L487-L491
3
- export const patternValidationRegex = /^(https?|wss?|file|ftp|\*):\/\/(\*|\*\.[^*/]+|[^*/]+)\/.*$|^file:\/\/\/.*$|^resource:\/\/(\*|\*\.[^*/]+|[^*/]+)\/.*$|^about:/;
4
- const isFirefox = globalThis.navigator?.userAgent.includes('Firefox/');
5
- export const allStarsRegex = isFirefox
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
- export const allUrlsRegex = /^(https?|file|ftp):[/]+/;
9
- export function assertValidPattern(matchPattern) {
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
- export function isValidPattern(matchPattern) {
15
- return matchPattern === '<all_urls>' || patternValidationRegex.test(matchPattern);
26
+ exports.assertValidPattern = assertValidPattern;
27
+ function isValidPattern(matchPattern) {
28
+ return matchPattern === '<all_urls>' || exports.patternValidationRegex.test(matchPattern);
16
29
  }
17
- export function doesUrlMatchPatterns(url, ...patterns) {
18
- if (patterns.includes('<all_urls>') && allUrlsRegex.test(url)) {
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 (const pattern of patterns) {
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
- export function findMatchingPatterns(url, ...patterns) {
32
- return patterns.filter(pattern => doesUrlMatchPatterns(url, pattern));
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
- let [, protocol, host = '', pathname] = matchPattern.split(/(^[^:]+:[/][/])([^/]+)?/);
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 &&= 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
- export function patternToRegex(...matchPatterns) {
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 => getRawPatternRegex(x)).join('|'));
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
- const globSymbols = /([?*]+)/;
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
- return escapeStringRegexp(part);
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 [...part].map(() => isFirefox ? '.' : '.?').join('');
105
+ return __spreadArray([], part, true).map(function () { return isFirefox ? '.' : '.?'; }).join('');
83
106
  }
84
107
  function getRawGlobRegex(glob) {
85
- const regexString = glob
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,14 +116,19 @@ function getRawGlobRegex(glob) {
93
116
  .replace(/[.][*]$/, '')
94
117
  .replace(/^[$]$/, '.+'); // Catch `*` and `*`
95
118
  }
96
- export function globToRegex(...globs) {
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 => getRawGlobRegex(x)).join('|'));
128
+ return new RegExp(globs.map(function (x) { return getRawGlobRegex(x); }).join('|'));
102
129
  }
103
- export function excludeDuplicatePatterns(matchPatterns) {
130
+ exports.globToRegex = globToRegex;
131
+ function removeRedundantPatterns(matchPatterns) {
104
132
  if (matchPatterns.includes('<all_urls>')) {
105
133
  return ['<all_urls>'];
106
134
  }
@@ -108,12 +136,15 @@ export function excludeDuplicatePatterns(matchPatterns) {
108
136
  return ['*://*/*'];
109
137
  }
110
138
  // Cover identical patterns
111
- const uniquePatterns = [...new Set(matchPatterns)];
112
- return uniquePatterns.filter(possibleSubset =>
113
- // Keep if there are no matches
114
- !uniquePatterns.some(possibleSuperset =>
115
- // Don't compare to self
116
- possibleSubset !== possibleSuperset
117
- // Drop if it's a subset
118
- && patternToRegex(possibleSuperset).test(possibleSubset)));
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
+ });
119
149
  }
150
+ exports.removeRedundantPatterns = removeRedundantPatterns;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webext-patterns",
3
- "version": "1.5.1",
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 && ava && xo",
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": "^5.0.0",
52
- "@types/chrome": "0.0.268",
53
- "ava": "^6.1.3",
54
- "sinon": "^18.0.0",
55
- "type-fest": "^4.20.0",
56
- "typescript": "^5.4.5",
57
- "xo": "^0.58.0"
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": ">=18"
49
+ "node": ">=24"
61
50
  },
62
51
  "webExt": {
63
52
  "sourceDir": "demo-extension",
package/readme.md CHANGED
@@ -1,10 +1,9 @@
1
- # webext-patterns [![][badge-gzip]][link-bundlephobia]
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
- excludeDuplicatePatterns
23
- doesUrlMatchPatterns,
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
- excludeDuplicatePatterns(['https://*.google.com/*', 'https://google.com/*']);
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
- #### excludeDuplicatePatterns([pattern1, pattern2, etc])
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
- excludeDuplicatePatterns([
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
- #### doesUrlMatchPatterns(url, ...patterns)
115
+ #### testPatterns(url, patterns)
114
116
 
115
- Accepts a URL and any number 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 to the same pattern, it's better to convert the patterns to a regex once and reuse that.
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
- doesUrlMatchPatterns('https://google.com/', 'https://*.google.com/*', '*://example.com/*');
120
+ testPatterns('https://google.com/', ['https://*.google.com/*', '*://example.com/*']);
119
121
  // Returns true
120
122
  ```
121
123
 
122
- #### findMatchingPatterns(url, ...patterns)
124
+ #### getMatchingPatterns(url, patterns)
123
125
 
124
- Accepts a URL and any number 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.
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