webext-patterns 1.1.1 → 1.3.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.d.ts CHANGED
@@ -2,3 +2,5 @@ export declare const patternValidationRegex: RegExp;
2
2
  export declare const allStarsRegex: RegExp;
3
3
  export declare const allUrlsRegex: RegExp;
4
4
  export declare function patternToRegex(...matchPatterns: readonly string[]): RegExp;
5
+ export declare function globToRegex(...globs: readonly string[]): RegExp;
6
+ export declare function excludeDuplicatePatterns(matchPatterns: readonly string[]): string[];
package/index.js CHANGED
@@ -1,9 +1,12 @@
1
+ import escapeStringRegexp from 'escape-string-regexp';
1
2
  // Copied from https://github.com/mozilla/gecko-dev/blob/073cc24f53d0cf31403121d768812146e597cc9d/toolkit/components/extensions/schemas/manifest.json#L487-L491
2
3
  export const patternValidationRegex = /^(https?|wss?|file|ftp|\*):\/\/(\*|\*\.[^*/]+|[^*/]+)\/.*$|^file:\/\/\/.*$|^resource:\/\/(\*|\*\.[^*/]+|[^*/]+)\/.*$|^about:/;
3
4
  const isFirefox = typeof navigator === 'object' && navigator.userAgent.includes('Firefox/');
4
- export const allStarsRegex = isFirefox ? /^(https?|wss?):[/][/][^/]+([/].*)?$/ : /^https?:[/][/][^/]+([/].*)?$/;
5
+ export const allStarsRegex = isFirefox
6
+ ? /^(https?|wss?):[/][/][^/]+([/].*)?$/
7
+ : /^https?:[/][/][^/]+([/].*)?$/;
5
8
  export const allUrlsRegex = /^(https?|file|ftp):[/]+/;
6
- function getRawRegex(matchPattern) {
9
+ function getRawPatternRegex(matchPattern) {
7
10
  if (!patternValidationRegex.test(matchPattern)) {
8
11
  throw new Error(matchPattern + ' is an invalid pattern, it must match ' + String(patternValidationRegex));
9
12
  }
@@ -33,5 +36,50 @@ export function patternToRegex(...matchPatterns) {
33
36
  if (matchPatterns.includes('*://*/*')) {
34
37
  return allStarsRegex;
35
38
  }
36
- return new RegExp(matchPatterns.map(x => getRawRegex(x)).join('|'));
39
+ return new RegExp(matchPatterns.map(x => getRawPatternRegex(x)).join('|'));
40
+ }
41
+ // The parens are required by .split() to preserve the symbols
42
+ const globSymbols = /([?*]+)/;
43
+ function splitReplace(part, index) {
44
+ if (part === '') {
45
+ // Shortcut for speed
46
+ return '';
47
+ }
48
+ if (index % 2 === 0) {
49
+ // Raw text, escape it
50
+ return escapeStringRegexp(part);
51
+ }
52
+ // Else: Symbol
53
+ if (part.includes('*')) { // Can be more than one and it swallows surrounding question marks
54
+ return '.*';
55
+ }
56
+ return [...part].map(() => isFirefox ? '.' : '.?').join('');
57
+ }
58
+ function getRawGlobRegex(glob) {
59
+ const regexString = glob
60
+ .split(globSymbols)
61
+ // eslint-disable-next-line unicorn/no-array-callback-reference -- tis ok 🤫
62
+ .map(splitReplace)
63
+ .join('');
64
+ // Drop "start with anything" and "end with anything" sequences because they're the default for regex
65
+ return ('^' + regexString + '$')
66
+ .replace(/^[.][*]/, '')
67
+ .replace(/[.][*]$/, '')
68
+ .replace(/^[$]$/, '.+'); // Catch `*` and `*`
69
+ }
70
+ export function globToRegex(...globs) {
71
+ // No glob, match anything; `include_globs: []` is the default
72
+ if (globs.length === 0) {
73
+ return /.*/;
74
+ }
75
+ return new RegExp(globs.map(x => getRawGlobRegex(x)).join('|'));
76
+ }
77
+ export function excludeDuplicatePatterns(matchPatterns) {
78
+ if (matchPatterns.includes('<all_urls>')) {
79
+ return ['<all_urls>'];
80
+ }
81
+ if (matchPatterns.includes('*://*/*')) {
82
+ return ['*://*/*'];
83
+ }
84
+ return matchPatterns.filter(possibleSubset => !matchPatterns.some(possibleSuperset => possibleSubset !== possibleSuperset && patternToRegex(possibleSuperset).test(possibleSubset)));
37
85
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "webext-patterns",
3
- "version": "1.1.1",
4
- "description": "Tool to convert the patterns of your WebExtension manifest to regex",
3
+ "version": "1.3.0",
4
+ "description": "Tool to convert the patterns and globs of your WebExtension manifest to regex",
5
5
  "keywords": [
6
6
  "browser",
7
7
  "chrome",
@@ -9,10 +9,15 @@
9
9
  "firefox",
10
10
  "glob",
11
11
  "permission",
12
+ "greasemonkey",
13
+ "user scripts",
14
+ "globs",
15
+ "userscript",
12
16
  "match",
13
17
  "webext"
14
18
  ],
15
19
  "repository": "fregante/webext-patterns",
20
+ "funding": "https://github.com/sponsors/fregante",
16
21
  "license": "MIT",
17
22
  "author": "Federico Brigante <me@fregante.com> (https://fregante.com)",
18
23
  "type": "module",
@@ -24,6 +29,8 @@
24
29
  ],
25
30
  "scripts": {
26
31
  "build": "tsc",
32
+ "fix": "xo --fix",
33
+ "lint": "xo",
27
34
  "prepare": "tsc --sourceMap false",
28
35
  "test": "tsc && ava && xo",
29
36
  "watch": "tsc --watch"
@@ -37,13 +44,25 @@
37
44
  "unicorn/better-regex": "off"
38
45
  }
39
46
  },
47
+ "dependencies": {
48
+ "escape-string-regexp": "^5.0.0"
49
+ },
40
50
  "devDependencies": {
41
- "@sindresorhus/tsconfig": "^1.0.2",
42
- "@types/chrome": "0.0.148",
43
- "ava": "^3.15.0",
44
- "sinon": "^11.1.1",
45
- "type-fest": "^1.2.2",
46
- "typescript": "^4.3.5",
47
- "xo": "^0.42.0"
51
+ "@sindresorhus/tsconfig": "^3.0.1",
52
+ "@types/chrome": "0.0.210",
53
+ "ava": "^5.1.1",
54
+ "sinon": "^15.0.1",
55
+ "type-fest": "^3.5.3",
56
+ "typescript": "^4.9.4",
57
+ "xo": "^0.53.1"
58
+ },
59
+ "webExt": {
60
+ "sourceDir": "demo-extension",
61
+ "run": {
62
+ "startUrl": [
63
+ "chrome://extensions/",
64
+ "https://example.com/"
65
+ ]
66
+ }
48
67
  }
49
68
  }
package/readme.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [badge-gzip]: https://img.shields.io/bundlephobia/minzip/webext-patterns.svg?label=gzipped
4
4
  [link-bundlephobia]: https://bundlephobia.com/result?p=webext-patterns
5
5
 
6
- > Tool to convert the [patterns](https://developer.chrome.com/extensions/match_patterns) and [globs](https://wiki.greasespot.net/Include_and_exclude_rules) of your WebExtension manifest to regex
6
+ > Tool to convert the [patterns](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#globs) of your WebExtension manifest to regex
7
7
 
8
8
  This might be incomplete. Please help me test it by adding more pattern and URLs to the [tests](./test.js).
9
9
 
@@ -26,13 +26,35 @@ import {patternToRegex} from 'webext-patterns';
26
26
 
27
27
  ```js
28
28
  patternToRegex('http://*/*');
29
- // Returns /^http:\/\/?.+\/.+$/
29
+ // Returns /^http:[/][/][^/]+[/].+$/
30
+
31
+ globToRegex('*.example.com');
32
+ // Returns /\.example\.com$/
33
+
34
+ excludeDuplicatePatterns(['https://*.google.com/*', 'https://google.com/*']);
35
+ // Returns ['https://*.google.com/*']
36
+ ```
37
+
38
+ > **Note**
39
+ > 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.
40
+
41
+ ## API
42
+
43
+ #### patternToRegex(pattern1, pattern2, etc)
44
+
45
+ Accepts any number of `string` arguments and returns a single regex to match all of them.
46
+
47
+ [Match patterns](https://developer.chrome.com/extensions/match_patterns) are used in the manifest’s permissions and content scripts’ `matches` and `exclude_matches` array.
48
+
49
+ ```js
50
+ patternToRegex('http://*/*');
51
+ // Returns /^http:[/][/][^/]+[/].+$/
30
52
 
31
53
  const gmailRegex = patternToRegex('*://mail.google.com/*');
32
54
  gmailRegex.test('https://mail.google.com/a/b/c'); // -> true
33
55
  gmailRegex.test('https://photos.google.com/a/b/c'); // -> false
34
56
 
35
- // Also accepts an array of patterns and returns a single regex
57
+ // Also accepts multiple patterns and returns a single regex
36
58
  const googleRegex = patternToRegex(
37
59
  'https://google.com/*',
38
60
  'https://google.it/*'
@@ -41,12 +63,43 @@ googleRegex.test('https://google.it/search'); // -> true
41
63
  googleRegex.test('https://google.de/search'); // -> false
42
64
  ```
43
65
 
44
- ## API
45
-
46
- #### patternToRegex(pattern1, pattern2, etc)
66
+ #### globToRegex(pattern1, pattern2, etc)
47
67
 
48
68
  Accepts any number of `string` arguments and returns a single regex to match all of them.
49
69
 
70
+ [Globs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#globs) are used in the manifest’s content scripts’ `include_globs` and `exclude_globs` arrays.
71
+
72
+ ```js
73
+ globToRegex('*.example.co?');
74
+ // Returns /\.example\.co.?$/ in Firefox
75
+ // Returns /\.example\.co.$/ everywhere else
76
+
77
+ const gmailRegex = globToRegex('*://mai?.google.com/*');
78
+ gmailRegex.test('https://mail.google.com/a/b/c'); // -> true
79
+ gmailRegex.test('https://photos.google.com/a/b/c'); // -> false
80
+
81
+ // Also accepts multiple globs and returns a single regex
82
+ const googleRegex = globToRegex(
83
+ '*google.com*',
84
+ '*google.it*'
85
+ );
86
+ googleRegex.test('https://google.it/search'); // -> true
87
+ googleRegex.test('https://google.de/search'); // -> false
88
+ ```
89
+
90
+ #### excludeDuplicatePatterns([pattern1, pattern2, etc])
91
+
92
+ 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.
93
+
94
+ ```js
95
+ excludeDuplicatePatterns([
96
+ "https://*/*",
97
+ "https://google.com/*",
98
+ "https://*.example.com/*",
99
+ ]);
100
+ // Returns ["https://*/*"]
101
+ ```
102
+
50
103
  ## Related
51
104
 
52
105
  ### Permissions