webext-patterns 1.1.1 → 1.2.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,4 @@ 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;
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,41 @@ 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('|'));
37
76
  }
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.2.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,6 +9,10 @@
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
  ],
@@ -24,6 +28,8 @@
24
28
  ],
25
29
  "scripts": {
26
30
  "build": "tsc",
31
+ "fix": "xo --fix",
32
+ "lint": "xo",
27
33
  "prepare": "tsc --sourceMap false",
28
34
  "test": "tsc && ava && xo",
29
35
  "watch": "tsc --watch"
@@ -37,13 +43,25 @@
37
43
  "unicorn/better-regex": "off"
38
44
  }
39
45
  },
46
+ "dependencies": {
47
+ "escape-string-regexp": "^5.0.0"
48
+ },
40
49
  "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"
50
+ "@sindresorhus/tsconfig": "^3.0.1",
51
+ "@types/chrome": "0.0.190",
52
+ "ava": "^4.3.0",
53
+ "sinon": "^14.0.0",
54
+ "type-fest": "^2.13.1",
55
+ "typescript": "^4.7.4",
56
+ "xo": "^0.50.0"
57
+ },
58
+ "webExt": {
59
+ "sourceDir": "demo-extension",
60
+ "run": {
61
+ "startUrl": [
62
+ "chrome://extensions/",
63
+ "https://example.com/"
64
+ ]
65
+ }
48
66
  }
49
67
  }
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
 
@@ -24,15 +24,34 @@ import {patternToRegex} from 'webext-patterns';
24
24
 
25
25
  ## Usage
26
26
 
27
+ > **Note**
28
+ > Firefox and Chrome handle globs very slighly differently. `webext-patterns` defaults to Chrome’s logic, but if it detects a Firefox userAgent it will produce a Firefox-compatible regex.
29
+
30
+ ```js
31
+ patternToRegex('http://*/*');
32
+ // Returns /^http:[/][/][^/]+[/].+$/
33
+
34
+ globToRegex('*.example.com');
35
+ // Returns /\.example\.com$/
36
+ ```
37
+
38
+ ## API
39
+
40
+ #### patternToRegex(pattern1, pattern2, etc)
41
+
42
+ Accepts any number of `string` arguments and returns a single regex to match all of them.
43
+
44
+ [Match patterns](https://developer.chrome.com/extensions/match_patterns) are used in the manifest’s permissions and content scripts’ `matches` and `exclude_matches` array.
45
+
27
46
  ```js
28
47
  patternToRegex('http://*/*');
29
- // Returns /^http:\/\/?.+\/.+$/
48
+ // Returns /^http:[/][/][^/]+[/].+$/
30
49
 
31
50
  const gmailRegex = patternToRegex('*://mail.google.com/*');
32
51
  gmailRegex.test('https://mail.google.com/a/b/c'); // -> true
33
52
  gmailRegex.test('https://photos.google.com/a/b/c'); // -> false
34
53
 
35
- // Also accepts an array of patterns and returns a single regex
54
+ // Also accepts multiple patterns and returns a single regex
36
55
  const googleRegex = patternToRegex(
37
56
  'https://google.com/*',
38
57
  'https://google.it/*'
@@ -41,12 +60,30 @@ googleRegex.test('https://google.it/search'); // -> true
41
60
  googleRegex.test('https://google.de/search'); // -> false
42
61
  ```
43
62
 
44
- ## API
45
-
46
- #### patternToRegex(pattern1, pattern2, etc)
63
+ #### globToRegex(pattern1, pattern2, etc)
47
64
 
48
65
  Accepts any number of `string` arguments and returns a single regex to match all of them.
49
66
 
67
+ [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.
68
+
69
+ ```js
70
+ globToRegex('*.example.co?');
71
+ // Returns /\.example\.co.?$/ in Firefox
72
+ // Returns /\.example\.co.$/ everywhere else
73
+
74
+ const gmailRegex = globToRegex('*://mai?.google.com/*');
75
+ gmailRegex.test('https://mail.google.com/a/b/c'); // -> true
76
+ gmailRegex.test('https://photos.google.com/a/b/c'); // -> false
77
+
78
+ // Also accepts multiple globs and returns a single regex
79
+ const googleRegex = globToRegex(
80
+ '*google.com*',
81
+ '*google.it*'
82
+ );
83
+ googleRegex.test('https://google.it/search'); // -> true
84
+ googleRegex.test('https://google.de/search'); // -> false
85
+ ```
86
+
50
87
  ## Related
51
88
 
52
89
  ### Permissions