webext-schema 7.1.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.
@@ -0,0 +1,8 @@
1
+ **/.next
2
+ **/.nx/cache
3
+ **/.svelte-kit
4
+ **/build
5
+ **/coverage
6
+ **/dist
7
+ **/docs
8
+ **/codemods/**/__testfixtures__
package/SECURITY.md CHANGED
@@ -4,13 +4,7 @@ We take security vulnerabilities seriously. Thank you for improving the security
4
4
 
5
5
  ## Supported Versions
6
6
 
7
- The following versions of this project are currently supported with security updates:
8
-
9
- | Version | Supported |
10
- | ------- | ------------------ |
11
- | 7.x.x | :white_check_mark: |
12
- | 6.x.x | :white_check_mark: |
13
- | < 6.0.0 | :x: |
7
+ We currently provide security updates **only for the latest major release**.
14
8
 
15
9
  ## Reporting a Vulnerability
16
10
 
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,23 +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
- }],
39
+ curly: ['error', 'all'],
40
+ 'jsdoc/no-undefined-types': [
41
+ 'error',
42
+ {
43
+ definedTypes: ['ReadonlyArray']
44
+ }
45
+ ],
35
46
  'no-await-in-loop': 'error',
36
- 'no-use-before-define': ['error', {
37
- allowNamedExports: false,
38
- classes: true,
39
- functions: true,
40
- variables: true
41
- }],
47
+ 'no-use-before-define': [
48
+ 'error',
49
+ {
50
+ allowNamedExports: false,
51
+ classes: true,
52
+ functions: true,
53
+ variables: true
54
+ }
55
+ ],
42
56
  'prefer-object-has-own': 'error',
43
57
  'unicorn/prefer-node-protocol': 'error'
44
58
  }
@@ -34,7 +34,7 @@ const getType = o =>
34
34
  */
35
35
  const isObjectNotEmpty = o => {
36
36
  const items = /Object/i.test(getType(o)) && Object.keys(o);
37
- return !!(items?.length);
37
+ return !!items?.length;
38
38
  };
39
39
 
40
40
  /**
@@ -106,7 +106,9 @@ export const getCloseTabsByDoubleClickValue = async () => {
106
106
  });
107
107
  let userValue;
108
108
  if (isGranted) {
109
- const { browserSettings: { closeTabsByDoubleClick } } = browser;
109
+ const {
110
+ browserSettings: { closeTabsByDoubleClick }
111
+ } = browser;
110
112
  userValue = await closeTabsByDoubleClick.get({});
111
113
  }
112
114
  return userValue ?? null;
@@ -122,7 +124,9 @@ export const setContextMenuOnMouseup = async () => {
122
124
  });
123
125
  let res;
124
126
  if (isGranted) {
125
- const { browserSettings: { contextMenuShowEvent } } = browser;
127
+ const {
128
+ browserSettings: { contextMenuShowEvent }
129
+ } = browser;
126
130
  const { levelOfControl, value } = await contextMenuShowEvent.get({});
127
131
  if (value === 'mouseup') {
128
132
  res = true;
@@ -145,7 +149,9 @@ export const clearContextMenuOnMouseup = async () => {
145
149
  });
146
150
  let res;
147
151
  if (isGranted) {
148
- const { browserSettings: { contextMenuShowEvent } } = browser;
152
+ const {
153
+ browserSettings: { contextMenuShowEvent }
154
+ } = browser;
149
155
  res = await contextMenuShowEvent.clear({});
150
156
  }
151
157
  return !!res;
@@ -161,7 +167,9 @@ export const getNewTabPositionValue = async () => {
161
167
  });
162
168
  let res;
163
169
  if (isGranted) {
164
- const { browserSettings: { newTabPosition } } = browser;
170
+ const {
171
+ browserSettings: { newTabPosition }
172
+ } = browser;
165
173
  res = await newTabPosition.get({});
166
174
  }
167
175
  return res ?? null;
@@ -179,8 +187,9 @@ export const isCommandCustomizable = async () => {
179
187
  let bool;
180
188
  if (isGranted) {
181
189
  const { commands } = browser;
182
- bool = typeof commands.update === 'function' &&
183
- typeof commands.reset === 'function';
190
+ bool =
191
+ typeof commands.update === 'function' &&
192
+ typeof commands.reset === 'function';
184
193
  }
185
194
  return !!bool;
186
195
  };
@@ -201,11 +210,16 @@ export const updateCommand = async (id, value = '') => {
201
210
  let func;
202
211
  if (await isCommandCustomizable()) {
203
212
  const { commands } = browser;
204
- const shortcut =
205
- value.trim().replace(/\+([a-z])$/, (m, c) => `+${c.toUpperCase()}`);
213
+ const shortcut = value
214
+ .trim()
215
+ .replace(/\+([a-z])$/, (m, c) => `+${c.toUpperCase()}`);
206
216
  if (shortcut === '') {
207
217
  func = commands.reset(id);
208
- } 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
+ ) {
209
223
  func = commands.update({
210
224
  shortcut,
211
225
  name: id
@@ -1063,19 +1077,24 @@ export const warmupTab = async tabId => {
1063
1077
  export const captureVisibleTab = async (windowId, opt) => {
1064
1078
  const info = await runtime.getBrowserInfo();
1065
1079
  let isGranted;
1066
- if (info.vender === 'Mozilla') {
1080
+ if (info.vendor === 'Mozilla') {
1067
1081
  const browserVersion = parseFloat(info.version);
1068
- isGranted = (browserVersion >= 126 && await isPermissionGranted({
1069
- permissions: ['activeTab']
1070
- })) || await isPermissionGranted({
1071
- origins: ['<all_urls>']
1072
- });
1082
+ isGranted =
1083
+ (browserVersion >= 126 &&
1084
+ (await isPermissionGranted({
1085
+ permissions: ['activeTab']
1086
+ }))) ||
1087
+ (await isPermissionGranted({
1088
+ origins: ['<all_urls>']
1089
+ }));
1073
1090
  } else {
1074
- isGranted = await isPermissionGranted({
1075
- permissions: ['activeTab']
1076
- }) || await isPermissionGranted({
1077
- origins: ['<all_urls>']
1078
- });
1091
+ isGranted =
1092
+ (await isPermissionGranted({
1093
+ permissions: ['activeTab']
1094
+ })) ||
1095
+ (await isPermissionGranted({
1096
+ origins: ['<all_urls>']
1097
+ }));
1079
1098
  }
1080
1099
  let url;
1081
1100
  if (isGranted) {
@@ -1125,8 +1144,9 @@ export const getCurrentTheme = async windowId => {
1125
1144
  let currentTheme;
1126
1145
  if (isGranted) {
1127
1146
  const { theme } = browser;
1128
- currentTheme =
1129
- await theme.getCurrent(Number.isInteger(windowId) ? windowId : null);
1147
+ currentTheme = await theme.getCurrent(
1148
+ Number.isInteger(windowId) ? windowId : null
1149
+ );
1130
1150
  }
1131
1151
  return currentTheme ?? null;
1132
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}`);
package/package.json CHANGED
@@ -25,32 +25,23 @@
25
25
  "sinon": "^22.1.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@types/firefox-webext-browser": "^143.0.0",
29
- "@types/node": "^26.1.1",
28
+ "@types/firefox-webext-browser": "^143.0.1",
29
+ "@types/node": "^26.6.4",
30
30
  "@types/sinon": "^22.0.0",
31
31
  "c8": "^12.0.0",
32
- "eslint": "^9.39.5",
33
- "eslint-plugin-jsdoc": "^63.2.2",
34
- "eslint-plugin-regexp": "^3.1.1",
35
- "eslint-plugin-unicorn": "^64.0.0",
36
- "globals": "^17.7.0",
37
- "mocha": "^11.7.6",
38
- "neostandard": "^0.13.0",
32
+ "eslint": "^10.12.0",
33
+ "eslint-config-prettier": "^10.1.8",
34
+ "eslint-plugin-jsdoc": "^65.2.1",
35
+ "eslint-plugin-prettier": "^5.5.6",
36
+ "eslint-plugin-regexp": "^3.3.1",
37
+ "eslint-plugin-unicorn": "^77.0.0",
38
+ "globals": "^17.13.0",
39
+ "mocha": "^12.0.3",
40
+ "neostandard": "^0.14.0",
41
+ "prettier": "^3.9.9",
42
+ "prettier-plugin-brace-style": "^0.10.3",
39
43
  "typescript": "^7.0.2",
40
- "undici": "^8.9.0"
41
- },
42
- "overrides": {
43
- "c8": {
44
- "yargs": "^18.0.0"
45
- },
46
- "eslint": {
47
- "js-yaml": "^4.3.0"
48
- },
49
- "mocha": {
50
- "diff": "^8.0.3",
51
- "js-yaml": "^4.3.0"
52
- },
53
- "serialize-javascript": "^7.0.4"
44
+ "undici": "^8.11.2"
54
45
  },
55
46
  "scripts": {
56
47
  "build": "npm run tsc && npm run lint && npm run test",
@@ -66,5 +57,5 @@
66
57
  "update:central": "node index update --channel=central -i",
67
58
  "update:mail": "node index update --channel=mail -i"
68
59
  },
69
- "version": "7.1.0"
60
+ "version": "7.1.1"
70
61
  }
@@ -0,0 +1,14 @@
1
+ export default {
2
+ plugins: ['prettier-plugin-brace-style'],
3
+ arrowParens: 'avoid',
4
+ braceStyle: '1tbs',
5
+ semi: true,
6
+ singleQuote: true,
7
+ trailingComma: 'none',
8
+ overrides: [
9
+ {
10
+ files: ['*.md', '*.mdx'],
11
+ options: {}
12
+ }
13
+ ]
14
+ };