webext-patterns 1.0.0 → 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.
Files changed (4) hide show
  1. package/index.d.ts +3 -0
  2. package/index.js +51 -3
  3. package/package.json +29 -16
  4. package/readme.md +46 -7
package/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  export declare const patternValidationRegex: RegExp;
2
+ export declare const allStarsRegex: RegExp;
3
+ export declare const allUrlsRegex: RegExp;
2
4
  export declare function patternToRegex(...matchPatterns: readonly string[]): RegExp;
5
+ export declare function globToRegex(...globs: readonly string[]): RegExp;
package/index.js CHANGED
@@ -1,7 +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
- function getRawRegex(matchPattern) {
5
+ export const allStarsRegex = isFirefox
6
+ ? /^(https?|wss?):[/][/][^/]+([/].*)?$/
7
+ : /^https?:[/][/][^/]+([/].*)?$/;
8
+ export const allUrlsRegex = /^(https?|file|ftp):[/]+/;
9
+ function getRawPatternRegex(matchPattern) {
5
10
  if (!patternValidationRegex.test(matchPattern)) {
6
11
  throw new Error(matchPattern + ' is an invalid pattern, it must match ' + String(patternValidationRegex));
7
12
  }
@@ -21,8 +26,51 @@ function getRawRegex(matchPattern) {
21
26
  return '^' + protocol + host + '(' + pathname + ')?$';
22
27
  }
23
28
  export function patternToRegex(...matchPatterns) {
29
+ // No pattern, match nothing https://stackoverflow.com/q/14115522/288906
30
+ if (matchPatterns.length === 0) {
31
+ return /$./;
32
+ }
24
33
  if (matchPatterns.includes('<all_urls>')) {
25
- return /^(https?|file|ftp):[/]+/;
34
+ return allUrlsRegex;
35
+ }
36
+ if (matchPatterns.includes('*://*/*')) {
37
+ return allStarsRegex;
38
+ }
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 /.*/;
26
74
  }
27
- return new RegExp(matchPatterns.map(getRawRegex).join('|'));
75
+ return new RegExp(globs.map(x => getRawGlobRegex(x)).join('|'));
28
76
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "webext-patterns",
3
- "version": "1.0.0",
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,7 +28,9 @@
24
28
  ],
25
29
  "scripts": {
26
30
  "build": "tsc",
27
- "prepack": "tsc --sourceMap false",
31
+ "fix": "xo --fix",
32
+ "lint": "xo",
33
+ "prepare": "tsc --sourceMap false",
28
34
  "test": "tsc && ava && xo",
29
35
  "watch": "tsc --watch"
30
36
  },
@@ -34,21 +40,28 @@
34
40
  "webextensions"
35
41
  ],
36
42
  "rules": {
37
- "unicorn/better-regex": "off",
38
- "unicorn/no-array-callback-reference": "off",
39
- "comma-dangle": [
40
- "error",
41
- "always-multiline"
42
- ]
43
+ "unicorn/better-regex": "off"
43
44
  }
44
45
  },
46
+ "dependencies": {
47
+ "escape-string-regexp": "^5.0.0"
48
+ },
45
49
  "devDependencies": {
46
- "@sindresorhus/tsconfig": "^0.8.0",
47
- "@types/chrome": "0.0.128",
48
- "ava": "^3.15.0",
49
- "sinon": "^9.2.4",
50
- "type-fest": "^0.20.2",
51
- "typescript": "^4.1.3",
52
- "xo": "^0.37.1"
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
+ }
53
66
  }
54
67
  }
package/readme.md CHANGED
@@ -3,13 +3,15 @@
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
 
10
10
  ## Install
11
11
 
12
- You can just download the [standalone bundle](https://packd.fregante.now.sh/webext-patterns) (it might take a minute to download) and include the file in your `manifest.json`, or:
12
+ You can download the [standalone bundle](https://bundle.fregante.com/?pkg=webext-patterns) and include it in your `manifest.json`.
13
+
14
+ Or use `npm`:
13
15
 
14
16
  ```sh
15
17
  npm install webext-patterns
@@ -22,15 +24,34 @@ import {patternToRegex} from 'webext-patterns';
22
24
 
23
25
  ## Usage
24
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
+
25
46
  ```js
26
47
  patternToRegex('http://*/*');
27
- // Returns /^http:\/\/?.+\/.+$/
48
+ // Returns /^http:[/][/][^/]+[/].+$/
28
49
 
29
50
  const gmailRegex = patternToRegex('*://mail.google.com/*');
30
51
  gmailRegex.test('https://mail.google.com/a/b/c'); // -> true
31
52
  gmailRegex.test('https://photos.google.com/a/b/c'); // -> false
32
53
 
33
- // Also accepts an array of patterns and returns a single regex
54
+ // Also accepts multiple patterns and returns a single regex
34
55
  const googleRegex = patternToRegex(
35
56
  'https://google.com/*',
36
57
  'https://google.it/*'
@@ -39,12 +60,30 @@ googleRegex.test('https://google.it/search'); // -> true
39
60
  googleRegex.test('https://google.de/search'); // -> false
40
61
  ```
41
62
 
42
- ## API
43
-
44
- #### patternToRegex(pattern1, pattern2, etc)
63
+ #### globToRegex(pattern1, pattern2, etc)
45
64
 
46
65
  Accepts any number of `string` arguments and returns a single regex to match all of them.
47
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
+
48
87
  ## Related
49
88
 
50
89
  ### Permissions