webext-schema 7.0.0 → 7.1.1

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.
@@ -17,7 +17,7 @@ jobs:
17
17
  build:
18
18
  strategy:
19
19
  matrix:
20
- node-version: [ 20.x, lts/*, latest ]
20
+ node-version: [ 22.x, lts/*, latest ]
21
21
  runs-on: ubuntu-latest
22
22
  steps:
23
23
  - uses: actions/checkout@v6
@@ -28,4 +28,4 @@ jobs:
28
28
  check-latest: true
29
29
  - run: npm ci
30
30
  - run: npm run lint
31
- - run: npm run testall
31
+ - run: npm run test:all
@@ -0,0 +1,8 @@
1
+ **/.next
2
+ **/.nx/cache
3
+ **/.svelte-kit
4
+ **/build
5
+ **/coverage
6
+ **/dist
7
+ **/docs
8
+ **/codemods/**/__testfixtures__
package/README.md CHANGED
@@ -1,11 +1,19 @@
1
+ # webext-schema
2
+
1
3
  [![build](https://github.com/asamuzaK/webext-schema/workflows/build/badge.svg)](https://github.com/asamuzaK/webext-schema/actions?query=workflow%3Abuild)
2
4
  [![CodeQL](https://github.com/asamuzaK/webext-schema/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/asamuzaK/webext-schema/actions/workflows/github-code-scanning/codeql)
3
5
  [![npm](https://img.shields.io/npm/v/webext-schema)](https://www.npmjs.com/package/webext-schema)
4
6
 
5
- # webext-schema
7
+ [WebExtensions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions "Browser Extensions - Mozilla | MDN") schemas and [MailExtensions](https://developer.thunderbird.net/add-ons/mailextensions "A Guide to Extensions - Thunderbird") schemas fetched from [hg.mozilla.org](https://hg.mozilla.org/).
8
+ Stubbed browser API and a standalone browser utility script are also available.
9
+
10
+ ## Features
6
11
 
7
- [WebExtentions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions "Browser Extensions - Mozilla | MDN") schemas and [MailExtensions](https://developer.thunderbird.net/add-ons/mailextensions "A Guide to Extensions - Thunderbird") schemas fetched from [hg.mozilla.org](https://hg.mozilla.org/).
8
- Stubbed browser API is also available.
12
+ * **Up-to-date Schemas:** Directly fetched from Mozilla's repositories.
13
+ * **Multi-Channel Support:** Choose between `beta`, `central`, and `mail` channels to match your target environment.
14
+ * **Easy API Mocking:** Instantly generate a stubbed `browser` object powered by [Sinon.JS](https://sinonjs.org/) for robust unit testing of your extensions.
15
+ * **Standalone Utility Included:** Comes with `browser.js`, a dependency-free, Promise-wrapped utility script ready to be dropped into your extension project for easier API handling.
16
+ * **Modern ESM & TypeScript:** Native ES Modules support with bundled TypeScript definitions (`index.d.ts`).
9
17
 
10
18
  ## Install
11
19
 
@@ -13,7 +21,7 @@ Stubbed browser API is also available.
13
21
  npm i webext-schema
14
22
  ```
15
23
 
16
- ## Usage
24
+ ## Usage (Schema & Mock)
17
25
 
18
26
  ```javascript
19
27
  import { Schema } from 'webext-schema';
@@ -23,7 +31,7 @@ const schema = new Schema();
23
31
 
24
32
  ### new Schema(<var>channel</var>, <var>sinonConfig</var>)
25
33
 
26
- * @param {string} [channel] - release channel. one of "beta", "central", "release", "esr", "mail".
34
+ * @param {string} [channel] - release channel. one of "beta", "central", "mail".
27
35
  * @param {Object} [sinonConfig] - optional configuration for `sinon.createSandbox()`, see [Sinon.JS](https://sinonjs.org/) for details.
28
36
 
29
37
  Both arguments are optional.
@@ -37,7 +45,7 @@ const schema = new Schema("central", {
37
45
 
38
46
  ### schema.channel
39
47
 
40
- "central", "beta", "release", "esr" for WebExtensions, and "mail" for MailExtensions are available.
48
+ "central", "beta" for WebExtensions, and "mail" for MailExtensions are available.
41
49
  Channel defaults to "beta".
42
50
 
43
51
  ```javascript
@@ -125,3 +133,26 @@ assert.isFunction(port2.onDisconnect.addListener);
125
133
  // reset
126
134
  browser._sandbox.reset();
127
135
  ```
136
+
137
+ ---
138
+
139
+ ## Browser Utility (`browser.js`)
140
+
141
+ A standalone utility script (`browser.js`) is also included in this repository. It provides useful, Promise-wrapped functions for common browser extension APIs (e.g., `browser.tabs`, `browser.runtime`, `browser.storage`).
142
+
143
+ This file is designed to be copied directly into your browser extension project. It has no external dependencies and works natively in your background or content scripts.
144
+
145
+ ### How to use `browser.js`
146
+
147
+ 1. Copy `browser.js` from the `webext-schema` repository into your extension's source directory.
148
+ 2. Import the needed functions into your extension scripts:
149
+
150
+ ```javascript
151
+ import { createTab, getActiveTab, setStorage } from './path/to/browser.js';
152
+
153
+ // Example: Create a new tab and save data
154
+ async function openAndSave() {
155
+ const tab = await createTab({ url: '[https://example.com](https://example.com)' });
156
+ await setStorage({ lastOpenedTabId: tab.id }, 'local');
157
+ }
158
+ ```
package/SECURITY.md ADDED
@@ -0,0 +1,30 @@
1
+ # Security Policy
2
+
3
+ We take security vulnerabilities seriously. Thank you for improving the security of our project.
4
+
5
+ ## Supported Versions
6
+
7
+ We currently provide security updates **only for the latest major release**.
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ Please **DO NOT** open a public issue for security-related vulnerabilities.
12
+
13
+ If you discover a security vulnerability, please report it privately via **GitHub's Private vulnerability reporting** feature.
14
+ You can do this by navigating to the **Security** tab of this repository, selecting **Advisories**, and clicking the **Report a vulnerability** button.
15
+
16
+ To help us resolve the issue efficiently, please include the following details in your report:
17
+
18
+ * **Type of vulnerability** (e.g., XSS, SSRF, Prototype Pollution)
19
+ * **Affected component or file name**
20
+ * **Steps to reproduce** (including proof of concept / PoC code if available)
21
+ * **Potential impact** of the vulnerability
22
+
23
+ ### Our Response Process
24
+
25
+ 1. **Acknowledgment**: We will acknowledge receipt of your report within 48 to 72 hours.
26
+ 2. **Investigation**: We will verify the vulnerability and evaluate its severity.
27
+ 3. **Fix & Release**: We will work on a fix in a private fork and release a patched version as soon as possible.
28
+ 4. **Advisory**: A GitHub Security Advisory will be published if necessary, giving you full credit for the discovery (unless you prefer to remain anonymous).
29
+
30
+ Please adhere to Coordinated Vulnerability Disclosure (CVD) and **do not disclose the vulnerability publicly** until a patch has been released.
package/eslint.config.mjs CHANGED
@@ -1,15 +1,20 @@
1
1
  import jsdoc from 'eslint-plugin-jsdoc';
2
+ import prettierRecommended from 'eslint-plugin-prettier/recommended';
2
3
  import regexp from 'eslint-plugin-regexp';
3
4
  import unicorn from 'eslint-plugin-unicorn';
4
5
  import globals from 'globals';
5
- import neostandard, { plugins as neostdplugins } from 'neostandard';
6
+ import neostandard from 'neostandard';
6
7
 
7
8
  export default [
8
9
  ...neostandard({
9
- semi: true
10
+ noStyle: true
10
11
  }),
11
12
  jsdoc.configs['flat/recommended'],
12
13
  regexp.configs['flat/recommended'],
14
+ prettierRecommended,
15
+ {
16
+ ignores: ['test/file/']
17
+ },
13
18
  {
14
19
  languageOptions: {
15
20
  globals: {
@@ -22,29 +27,32 @@ export default [
22
27
  reportUnusedDisableDirectives: true
23
28
  },
24
29
  plugins: {
25
- '@stylistic': neostdplugins['@stylistic'],
26
30
  regexp,
27
31
  unicorn
28
32
  },
33
+ settings: {
34
+ jsdoc: {
35
+ mode: 'typescript'
36
+ }
37
+ },
29
38
  rules: {
30
- '@stylistic/space-before-function-paren': ['error', {
31
- anonymous: 'always',
32
- asyncArrow: 'always',
33
- named: 'never'
34
- }],
35
- 'import-x/order': ['error', {
36
- alphabetize: {
37
- order: 'ignore',
38
- caseInsensitive: false
39
+ curly: ['error', 'all'],
40
+ 'jsdoc/no-undefined-types': [
41
+ 'error',
42
+ {
43
+ definedTypes: ['ReadonlyArray']
39
44
  }
40
- }],
45
+ ],
41
46
  'no-await-in-loop': 'error',
42
- 'no-use-before-define': ['error', {
43
- allowNamedExports: false,
44
- classes: true,
45
- functions: true,
46
- variables: true
47
- }],
47
+ 'no-use-before-define': [
48
+ 'error',
49
+ {
50
+ allowNamedExports: false,
51
+ classes: true,
52
+ functions: true,
53
+ variables: true
54
+ }
55
+ ],
48
56
  'prefer-object-has-own': 'error',
49
57
  'unicorn/prefer-node-protocol': 'error'
50
58
  }
package/index.js CHANGED
@@ -9,11 +9,17 @@
9
9
  /* api */
10
10
  import process from 'node:process';
11
11
  import { parseCommand } from './modules/commander.js';
12
- import { logErr, throwErr } from './modules/common.js';
13
12
  export { Schema } from './modules/schema.js';
14
13
 
15
14
  /* process */
16
- process.on('uncaughtException', throwErr);
17
- process.on('unhandledRejection', logErr);
15
+ process.on('uncaughtException', err => {
16
+ console.error('Fatal Error (Uncaught Exception):', err);
17
+ process.exit(1);
18
+ });
19
+
20
+ process.on('unhandledRejection', reason => {
21
+ console.error('Fatal Error (Unhandled Rejection):', reason);
22
+ process.exit(1);
23
+ });
18
24
 
19
25
  parseCommand(process.argv);
@@ -2,12 +2,48 @@
2
2
  * browser.js
3
3
  */
4
4
 
5
- /* shared */
6
- import { getType, isObjectNotEmpty, isString, logErr } from './common.js';
7
-
8
5
  /* api */
9
6
  const { permissions, runtime, tabs, windows } = browser;
10
7
 
8
+ /* constants & utils */
9
+ const TYPE_FROM = 8;
10
+ const TYPE_TO = -1;
11
+
12
+ /**
13
+ * log error
14
+ * @param {!object} e - Error
15
+ * @returns {boolean} - false
16
+ */
17
+ const logErr = e => {
18
+ console.error(e);
19
+ return false;
20
+ };
21
+
22
+ /**
23
+ * get type
24
+ * @param {object} o - object to check
25
+ * @returns {string} - type of object
26
+ */
27
+ const getType = o =>
28
+ Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);
29
+
30
+ /**
31
+ * is object, and not an empty object
32
+ * @param {object} o - object to check;
33
+ * @returns {boolean} - result
34
+ */
35
+ const isObjectNotEmpty = o => {
36
+ const items = /Object/i.test(getType(o)) && Object.keys(o);
37
+ return !!items?.length;
38
+ };
39
+
40
+ /**
41
+ * is string
42
+ * @param {object} o - object to check
43
+ * @returns {boolean} - result
44
+ */
45
+ const isString = o => typeof o === 'string' || o instanceof String;
46
+
11
47
  /**
12
48
  * check if permission is granted
13
49
  * @param {object} perm - permissions.Permission
@@ -70,7 +106,9 @@ export const getCloseTabsByDoubleClickValue = async () => {
70
106
  });
71
107
  let userValue;
72
108
  if (isGranted) {
73
- const { browserSettings: { closeTabsByDoubleClick } } = browser;
109
+ const {
110
+ browserSettings: { closeTabsByDoubleClick }
111
+ } = browser;
74
112
  userValue = await closeTabsByDoubleClick.get({});
75
113
  }
76
114
  return userValue ?? null;
@@ -86,7 +124,9 @@ export const setContextMenuOnMouseup = async () => {
86
124
  });
87
125
  let res;
88
126
  if (isGranted) {
89
- const { browserSettings: { contextMenuShowEvent } } = browser;
127
+ const {
128
+ browserSettings: { contextMenuShowEvent }
129
+ } = browser;
90
130
  const { levelOfControl, value } = await contextMenuShowEvent.get({});
91
131
  if (value === 'mouseup') {
92
132
  res = true;
@@ -109,7 +149,9 @@ export const clearContextMenuOnMouseup = async () => {
109
149
  });
110
150
  let res;
111
151
  if (isGranted) {
112
- const { browserSettings: { contextMenuShowEvent } } = browser;
152
+ const {
153
+ browserSettings: { contextMenuShowEvent }
154
+ } = browser;
113
155
  res = await contextMenuShowEvent.clear({});
114
156
  }
115
157
  return !!res;
@@ -125,7 +167,9 @@ export const getNewTabPositionValue = async () => {
125
167
  });
126
168
  let res;
127
169
  if (isGranted) {
128
- const { browserSettings: { newTabPosition } } = browser;
170
+ const {
171
+ browserSettings: { newTabPosition }
172
+ } = browser;
129
173
  res = await newTabPosition.get({});
130
174
  }
131
175
  return res ?? null;
@@ -143,8 +187,9 @@ export const isCommandCustomizable = async () => {
143
187
  let bool;
144
188
  if (isGranted) {
145
189
  const { commands } = browser;
146
- bool = typeof commands.update === 'function' &&
147
- typeof commands.reset === 'function';
190
+ bool =
191
+ typeof commands.update === 'function' &&
192
+ typeof commands.reset === 'function';
148
193
  }
149
194
  return !!bool;
150
195
  };
@@ -165,11 +210,16 @@ export const updateCommand = async (id, value = '') => {
165
210
  let func;
166
211
  if (await isCommandCustomizable()) {
167
212
  const { commands } = browser;
168
- const shortcut =
169
- value.trim().replace(/\+([a-z])$/, (m, c) => `+${c.toUpperCase()}`);
213
+ const shortcut = value
214
+ .trim()
215
+ .replace(/\+([a-z])$/, (m, c) => `+${c.toUpperCase()}`);
170
216
  if (shortcut === '') {
171
217
  func = commands.reset(id);
172
- } else if (/^(?:(?:Alt|Command|(?:Mac)?Ctrl)(?:\+Shift)?|Alt\+(?:Command|(?:Mac)?Ctrl)|Command\+(?:Alt|MacCtrl)|Ctrl\+(?:Alt|MacCtrl)|MacCtrl\+(?:Alt|Command|Ctrl))\+[\dA-Z]|F[1-9]|Media(?:(?:Next|Prev)Track|PlayPause|Stop)$/.test(shortcut)) {
218
+ } else if (
219
+ /^(?:(?:Alt|Command|(?:Mac)?Ctrl)(?:\+Shift)?|Alt\+(?:Command|(?:Mac)?Ctrl)|Command\+(?:Alt|MacCtrl)|Ctrl\+(?:Alt|MacCtrl)|MacCtrl\+(?:Alt|Command|Ctrl))\+[\dA-Z]|F[1-9]|Media(?:(?:Next|Prev)Track|PlayPause|Stop)$/.test(
220
+ shortcut
221
+ )
222
+ ) {
173
223
  func = commands.update({
174
224
  shortcut,
175
225
  name: id
@@ -1027,19 +1077,24 @@ export const warmupTab = async tabId => {
1027
1077
  export const captureVisibleTab = async (windowId, opt) => {
1028
1078
  const info = await runtime.getBrowserInfo();
1029
1079
  let isGranted;
1030
- if (info.vender === 'Mozilla') {
1080
+ if (info.vendor === 'Mozilla') {
1031
1081
  const browserVersion = parseFloat(info.version);
1032
- isGranted = (browserVersion >= 126 && await isPermissionGranted({
1033
- permissions: ['activeTab']
1034
- })) || await isPermissionGranted({
1035
- origins: ['<all_urls>']
1036
- });
1082
+ isGranted =
1083
+ (browserVersion >= 126 &&
1084
+ (await isPermissionGranted({
1085
+ permissions: ['activeTab']
1086
+ }))) ||
1087
+ (await isPermissionGranted({
1088
+ origins: ['<all_urls>']
1089
+ }));
1037
1090
  } else {
1038
- isGranted = await isPermissionGranted({
1039
- permissions: ['activeTab']
1040
- }) || await isPermissionGranted({
1041
- origins: ['<all_urls>']
1042
- });
1091
+ isGranted =
1092
+ (await isPermissionGranted({
1093
+ permissions: ['activeTab']
1094
+ })) ||
1095
+ (await isPermissionGranted({
1096
+ origins: ['<all_urls>']
1097
+ }));
1043
1098
  }
1044
1099
  let url;
1045
1100
  if (isGranted) {
@@ -1089,8 +1144,9 @@ export const getCurrentTheme = async windowId => {
1089
1144
  let currentTheme;
1090
1145
  if (isGranted) {
1091
1146
  const { theme } = browser;
1092
- currentTheme =
1093
- await theme.getCurrent(Number.isInteger(windowId) ? windowId : null);
1147
+ currentTheme = await theme.getCurrent(
1148
+ Number.isInteger(windowId) ? windowId : null
1149
+ );
1094
1150
  }
1095
1151
  return currentTheme ?? null;
1096
1152
  };
@@ -38,13 +38,18 @@ export const parseCommand = args => {
38
38
  commander.exitOverride();
39
39
  commander.version(process.env.npm_package_version, '-v, --version');
40
40
  if (args.includes('clean') || args.includes('c')) {
41
- commander.command('clean').alias('c')
41
+ commander
42
+ .command('clean')
43
+ .alias('c')
42
44
  .description('clean directory')
43
45
  .option('-d, --dir <name>', 'specify directory')
44
46
  .option('-i, --info', 'console info')
45
47
  .action(cleanDirectory);
46
48
  } else if (args.includes('update') || args.includes('u')) {
47
- commander.command('update').alias('u').description('update schemas')
49
+ commander
50
+ .command('update')
51
+ .alias('u')
52
+ .description('update schemas')
48
53
  .option('-c, --channel <name>', 'specify the release channel')
49
54
  .option('-i, --info', 'console info')
50
55
  .action(updateSchemas);
@@ -54,6 +59,4 @@ export const parseCommand = args => {
54
59
  };
55
60
 
56
61
  /* For test */
57
- export {
58
- commander
59
- };
62
+ export { commander };
package/modules/common.js CHANGED
@@ -60,7 +60,7 @@ export const getType = o =>
60
60
  */
61
61
  export const isObjectNotEmpty = o => {
62
62
  const items = /Object/i.test(getType(o)) && Object.keys(o);
63
- return !!(items?.length);
63
+ return !!items?.length;
64
64
  };
65
65
 
66
66
  /**
@@ -94,8 +94,9 @@ export const isExecutable = (file, mask = MASK_BIT) => {
94
94
  let res;
95
95
  const stat = getStat(file);
96
96
  if (stat) {
97
- res = !!(stat.mode & mask) ||
98
- (IS_WIN && /\.(?:bat|cmd|exe|ps1|wsh)$/i.test(file));
97
+ res =
98
+ !!(stat.mode & mask) ||
99
+ (IS_WIN && /\.(?:bat|cmd|exe|ps1|wsh)$/i.test(file));
99
100
  }
100
101
  return !!res;
101
102
  };
@@ -118,8 +119,11 @@ export const getFileTimestamp = file => {
118
119
  */
119
120
  export const getFileNameFromFilePath = (file, subst = SUBST) => {
120
121
  let name;
121
- if (isString(file) && isFile(file) &&
122
- /^[^.]+(?:\..+)?$/.test(path.basename(file))) {
122
+ if (
123
+ isString(file) &&
124
+ isFile(file) &&
125
+ /^[^.]+(?:\..+)?$/.test(path.basename(file))
126
+ ) {
123
127
  [, name] = /^([^.]+)(?:\..+)?$/.exec(path.basename(file));
124
128
  }
125
129
  return name || subst;
@@ -179,7 +183,7 @@ export const createDirectory = async (dir, mode = PERM_DIR) => {
179
183
  mode,
180
184
  recursive: true
181
185
  };
182
- !isDir(dirPath) && await fsPromise.mkdir(dirPath, opt);
186
+ !isDir(dirPath) && (await fsPromise.mkdir(dirPath, opt));
183
187
  return dirPath;
184
188
  };
185
189
 
@@ -193,14 +197,23 @@ export const createDirectory = async (dir, mode = PERM_DIR) => {
193
197
  * @param {number|string} [opt.mode] - file permission
194
198
  * @returns {Promise.<string>} - file path
195
199
  */
196
- export const createFile = async (file, value, opt = {
197
- encoding: null, flag: 'w', mode: PERM_FILE
198
- }) => {
200
+ export const createFile = async (
201
+ file,
202
+ value,
203
+ opt = {
204
+ encoding: null,
205
+ flag: 'w',
206
+ mode: PERM_FILE
207
+ }
208
+ ) => {
199
209
  if (!isString(file)) {
200
210
  throw new TypeError(`Expected String but got ${getType(file)}.`);
201
211
  }
202
- if (!isString(value) && !Buffer.isBuffer(value) &&
203
- !(value instanceof Uint8Array)) {
212
+ if (
213
+ !isString(value) &&
214
+ !Buffer.isBuffer(value) &&
215
+ !(value instanceof Uint8Array)
216
+ ) {
204
217
  throw new TypeError(
205
218
  `Expected String, Buffer, Uint8Array but got ${getType(value)}.`
206
219
  );
package/modules/schema.js CHANGED
@@ -28,9 +28,7 @@ export class Schema {
28
28
  constructor(...args) {
29
29
  const [arg1, arg2] = args;
30
30
  this.#channel =
31
- isString(arg1) && /^(?:central|mail)$/.test(arg1)
32
- ? arg1
33
- : 'beta';
31
+ isString(arg1) && /^(?:central|mail)$/.test(arg1) ? arg1 : 'beta';
34
32
  this._sandbox =
35
33
  (isObjectNotEmpty(arg1) && sinon.createSandbox(arg1)) ||
36
34
  (isObjectNotEmpty(arg2) && sinon.createSandbox(arg2)) ||
@@ -209,12 +207,18 @@ export class Schema {
209
207
  target[key] = item.value;
210
208
  } else if (type === 'function') {
211
209
  target[key] = this._sandbox.stub();
212
- } else if (type === 'object' || $ref ||
213
- Object.hasOwn(item, 'properties')) {
210
+ } else if (
211
+ type === 'object' ||
212
+ $ref ||
213
+ Object.hasOwn(item, 'properties')
214
+ ) {
214
215
  target[key] ??= {};
215
- properties && this._mockProperties(
216
- target[key], properties, `${namespace}.${key}`
217
- );
216
+ properties &&
217
+ this._mockProperties(
218
+ target[key],
219
+ properties,
220
+ `${namespace}.${key}`
221
+ );
218
222
  } else {
219
223
  target[key] = null;
220
224
  }
@@ -339,14 +343,17 @@ export class Schema {
339
343
  for (const [key, value] of schemaItems) {
340
344
  const items = Object.values(value);
341
345
  for (const item of items) {
342
- const {
343
- $import, events, functions, namespace, properties, types
344
- } = item;
346
+ const { $import, events, functions, namespace, properties, types } =
347
+ item;
345
348
  const fileKey = camelize(key.replace(/\.json$/, '')).toLowerCase();
346
349
  const itemKey = namespace.replace(/\./g, '').toLowerCase();
347
- if (fileKey === itemKey || fileKey.startsWith(itemKey) ||
348
- itemKey.startsWith(fileKey) || aliasKeys.includes(itemKey) ||
349
- $import) {
350
+ if (
351
+ fileKey === itemKey ||
352
+ fileKey.startsWith(itemKey) ||
353
+ itemKey.startsWith(fileKey) ||
354
+ aliasKeys.includes(itemKey) ||
355
+ $import
356
+ ) {
350
357
  const mapKey = [];
351
358
  let ns;
352
359
  if (namespace.includes('.')) {
package/modules/update.js CHANGED
@@ -50,7 +50,7 @@ export const getChannelUrl = channel => {
50
50
  default:
51
51
  dir = 'releases/mozilla-beta/';
52
52
  }
53
- return `https://hg.mozilla.org/${dir}raw-file/tip/`;
53
+ return `https://hg-edge.mozilla.org/${dir}raw-file/tip/`;
54
54
  };
55
55
 
56
56
  /**
@@ -70,7 +70,8 @@ export const getSchemaData = async (file, baseUrl) => {
70
70
  const text = await fetchText(href);
71
71
  const schema = JSON5.parse(text);
72
72
  return {
73
- file, schema
73
+ file,
74
+ schema
74
75
  };
75
76
  };
76
77
 
@@ -158,10 +159,7 @@ export const getMailExtSchemaData = async (baseUrl, info) => {
158
159
  }
159
160
  const items = await getFileList(baseUrl);
160
161
  const schemaUrl = `${baseUrl}schemas/`;
161
- const excludeFile = [
162
- 'commands.json',
163
- 'pkcs11.json'
164
- ];
162
+ const excludeFile = ['commands.json', 'pkcs11.json'];
165
163
  const schemas = [];
166
164
  for (const item of items) {
167
165
  if (!excludeFile.includes(item)) {
@@ -185,26 +183,33 @@ export const createUnifiedSchema = async (channel, info) => {
185
183
  const channelUrl = getChannelUrl(channel);
186
184
  const schema = {};
187
185
  if (channel === 'mail') {
188
- const browserItems = [
189
- 'commands.json',
190
- 'pkcs11.json'
191
- ];
192
- const browserUrl =
193
- `${getChannelUrl('central')}browser/components/extensions/schemas/`;
194
- const browserSchemas =
195
- await getListedSchemaData(browserUrl, browserItems, info);
186
+ const browserItems = ['commands.json', 'pkcs11.json'];
187
+ const browserUrl = `${getChannelUrl('central')}browser/components/extensions/schemas/`;
188
+ const browserSchemas = await getListedSchemaData(
189
+ browserUrl,
190
+ browserItems,
191
+ info
192
+ );
196
193
  for (const item of browserSchemas) {
197
194
  const { file, schema: itemSchema } = item;
198
195
  schema[file] = itemSchema;
199
196
  }
200
197
  const toolkitItems = [
201
- 'content_scripts.json', 'experiments.json', 'extension.json', 'i18n.json',
202
- 'management.json', 'permissions.json', 'runtime.json', 'theme.json'
198
+ 'content_scripts.json',
199
+ 'experiments.json',
200
+ 'extension.json',
201
+ 'i18n.json',
202
+ 'management.json',
203
+ 'permissions.json',
204
+ 'runtime.json',
205
+ 'theme.json'
203
206
  ];
204
- const toolkitUrl =
205
- `${getChannelUrl('central')}toolkit/components/extensions/schemas/`;
206
- const toolkitSchemas =
207
- await getListedSchemaData(toolkitUrl, toolkitItems, info);
207
+ const toolkitUrl = `${getChannelUrl('central')}toolkit/components/extensions/schemas/`;
208
+ const toolkitSchemas = await getListedSchemaData(
209
+ toolkitUrl,
210
+ toolkitItems,
211
+ info
212
+ );
208
213
  for (const item of toolkitSchemas) {
209
214
  const { file, schema: itemSchema } = item;
210
215
  schema[file] = itemSchema;
@@ -245,10 +250,16 @@ export const saveSchemaFile = async (channel, info) => {
245
250
  const schema = await createUnifiedSchema(channel, info);
246
251
  const content = `${JSON.stringify(schema, null, INDENT)}\n`;
247
252
  const fileName = channel === 'mail' ? 'mailext' : 'webext';
248
- const filePath =
249
- path.resolve(DIR_CWD, 'schemas', channel, `${fileName}.json`);
253
+ const filePath = path.resolve(
254
+ DIR_CWD,
255
+ 'schemas',
256
+ channel,
257
+ `${fileName}.json`
258
+ );
250
259
  const file = await createFile(filePath, content, {
251
- encoding: CHAR, flag: 'w', mode: PERM_FILE
260
+ encoding: CHAR,
261
+ flag: 'w',
262
+ mode: PERM_FILE
252
263
  });
253
264
  if (file && info) {
254
265
  console.info(`Created: ${file}`);