Skip to content

Commit 3679c7c

Browse files
authored
feat: No longer accept .js config files (#3519)
1 parent 03c767a commit 3679c7c

File tree

6 files changed

+56
-152
lines changed

6 files changed

+56
-152
lines changed

scripts/lib/mocha.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ const runMocha = (args, execMochaOptions = {}, coverageEnabled) => {
2020
shell.echo(`\nSetting mocha timeout from env var: ${MOCHA_TIMEOUT}\n`);
2121
}
2222

23-
// Pass testdouble node loader to support ESM module mocking and
24-
// transpiling on the fly the tests modules.
25-
binArgs.push('-n="loader=testdouble"');
26-
2723
const res = spawnSync(binPath, binArgs, {
2824
...execMochaOptions,
2925
env: {

src/config.js

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,6 @@ import { UsageError, WebExtError } from './errors.js';
1212

1313
const log = createLogger(import.meta.url);
1414

15-
// NOTE: this error message is used in an interpolated string (while the other two help
16-
// messages are being logged as is).
17-
export const WARN_LEGACY_JS_EXT = [
18-
'should be renamed to ".cjs" or ".mjs" file extension to ensure its format is not ambiguous.',
19-
'Config files with the ".js" file extension are deprecated and will not be loaded anymore',
20-
'in a future web-ext major version.',
21-
].join(' ');
22-
23-
export const HELP_ERR_MODULE_FROM_ESM = [
24-
'This config file belongs to a package.json file with "type" set to "module".',
25-
'Change the file extension to ".cjs" or rewrite it as an ES module and use the ".mjs" file extension.',
26-
].join(' ');
27-
28-
export const HELP_ERR_IMPORTEXPORT_CJS = [
29-
'This config file is defined as an ES module, but it belongs to either a project directory',
30-
'with a package.json file with "type" set to "commonjs" or one without any package.json file.',
31-
'Change the file extension to ".mjs" to fix the config loading error.',
32-
].join(' ');
33-
34-
const ERR_IMPORT_FROM_CJS = 'Cannot use import statement outside a module';
35-
const ERR_EXPORT_FROM_CJS = "Unexpected token 'export'";
36-
const ERR_MODULE_FROM_ESM = 'module is not defined in ES module scope';
37-
3815
export function applyConfigToArgv({
3916
argv,
4017
argvFromCLI,
@@ -145,12 +122,18 @@ export async function loadJSConfigFile(filePath) {
145122
`Loading JS config file: "${filePath}" ` +
146123
`(resolved to "${resolvedFilePath}")`,
147124
);
125+
148126
if (filePath.endsWith('.js')) {
149-
log.warn(`WARNING: config file ${filePath} ${WARN_LEGACY_JS_EXT}`);
127+
throw new UsageError(
128+
` Invalid config file "${resolvedFilePath}": the file extension should be` +
129+
'".cjs" or ".mjs". More information at: https://mzl.la/web-ext-config-file',
130+
);
150131
}
132+
151133
let configObject;
152134
try {
153135
const nonce = `${Date.now()}-${Math.random()}`;
136+
154137
let configModule;
155138
if (resolvedFilePath.endsWith('package.json')) {
156139
configModule = parseJSON(
@@ -165,35 +148,36 @@ export async function loadJSConfigFile(filePath) {
165148
// ES modules may expose both a default and named exports and so
166149
// we merge the named exports on top of what may have been set in
167150
// the default export.
151+
if (filePath.endsWith('.cjs')) {
152+
// Remove the additional 'module.exports' named export that Node.js >=
153+
// 24 is returning from the dynamic import call (in addition to being
154+
// also set on the default property as in Node.js < 24).
155+
delete esmConfigMod['module.exports'];
156+
}
168157
configObject = { ...configDefault, ...esmConfigMod };
169158
} else {
170159
configObject = { ...configModule };
171160
}
172161
} catch (error) {
173-
log.debug('Handling error:', error);
174-
let errorMessage = error.message;
175-
if (error.message.startsWith(ERR_MODULE_FROM_ESM)) {
176-
errorMessage = HELP_ERR_MODULE_FROM_ESM;
177-
} else if (
178-
[ERR_IMPORT_FROM_CJS, ERR_EXPORT_FROM_CJS].includes(error.message)
179-
) {
180-
errorMessage = HELP_ERR_IMPORTEXPORT_CJS;
181-
}
182-
throw new UsageError(
183-
`Cannot read config file: ${resolvedFilePath}\n` +
184-
`Error: ${errorMessage}`,
162+
const configFileError = new UsageError(
163+
`Cannot read config file "${resolvedFilePath}":\n${error}`,
185164
);
165+
configFileError.cause = error;
166+
throw configFileError;
186167
}
168+
187169
if (filePath.endsWith('package.json')) {
188170
log.debug('Looking for webExt key inside package.json file');
189171
configObject = configObject.webExt || {};
190172
}
173+
191174
if (Object.keys(configObject).length === 0) {
192175
log.debug(
193176
`Config file ${resolvedFilePath} did not define any options. ` +
194177
'Did you set module.exports = {...}?',
195178
);
196179
}
180+
197181
return configObject;
198182
}
199183

src/program.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,9 @@ export class Program {
331331
if (error.code) {
332332
log.error(`Error code: ${error.code}\n`);
333333
}
334+
if (error.cause && adjustedArgv.verbose) {
335+
log.error(`Error cause: ${error.cause.stack}\n`);
336+
}
334337

335338
log.debug(`Command executed: ${cmd}`);
336339

tests/functional/test.cli.sign.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import {
1313
reportCommandErrors,
1414
} from './common.js';
1515

16-
// Put this as "web-ext-config.js" in the current directory, and replace
16+
// Put this as "web-ext-config.mjs" in the current directory, and replace
1717
// "FAKEAPIKEY" and "FAKEAPISECRET" with the actual values to enable
1818
// "web-ext sign" without passing those values via the CLI parameters.
1919
const GOOD_EXAMPLE_OF_WEB_EXT_CONFIG_JS = `
20-
module.exports = {
20+
export default {
2121
sign: {
2222
apiKey: "FAKEAPIKEY",
2323
apiSecret: "FAKEAPISECRET",
@@ -27,7 +27,7 @@ module.exports = {
2727

2828
// Do NOT use this to specify the API key and secret. It won't work.
2929
const BAD_EXAMPLE_OF_WEB_EXT_CONFIG_JS = `
30-
module.exports = {
30+
export default {
3131
// Bad config: those should be under the "sign" key.
3232
apiKey: "FAKEAPIKEY",
3333
apiSecret: "FAKEAPISECRET",
@@ -86,7 +86,7 @@ describe('web-ext sign', () => {
8686
it('should use config file if required parameters are not in the arguments', () =>
8787
withTempAddonDir({ addonPath: minimalAddonPath }, (srcDir, tmpDir) => {
8888
writeFileSync(
89-
path.join(tmpDir, 'web-ext-config.js'),
89+
path.join(tmpDir, 'web-ext-config.mjs'),
9090
GOOD_EXAMPLE_OF_WEB_EXT_CONFIG_JS,
9191
);
9292

@@ -120,7 +120,7 @@ describe('web-ext sign', () => {
120120

121121
it('should show an error message if the api-key is not set in the config', () =>
122122
withTempAddonDir({ addonPath: minimalAddonPath }, (srcDir, tmpDir) => {
123-
const configFilePath = path.join(tmpDir, 'web-ext-config.js');
123+
const configFilePath = path.join(tmpDir, 'web-ext-config.mjs');
124124
writeFileSync(configFilePath, BAD_EXAMPLE_OF_WEB_EXT_CONFIG_JS);
125125
const argv = [
126126
'sign',
@@ -135,7 +135,7 @@ describe('web-ext sign', () => {
135135
assert.notEqual(exitCode, 0);
136136
assert.match(
137137
stderr,
138-
/web-ext-config.js specified an unknown option: "apiKey"/,
138+
/web-ext-config.mjs specified an unknown option: "apiKey"/,
139139
);
140140
});
141141
}));

0 commit comments

Comments
 (0)