diff --git a/lib/cli/cli.js b/lib/cli/cli.js index 08d585990..e8391e193 100644 --- a/lib/cli/cli.js +++ b/lib/cli/cli.js @@ -18,6 +18,7 @@ import { config as slackConfig } from '../plugins/slack/index.js'; import { config as htmlConfig } from '../plugins/html/index.js'; import { messageTypes as matrixMessageTypes } from '../plugins/matrix/index.js'; import { findUpSync } from '../support/fileUtil.js'; +import { registerPluginOptions } from './pluginOptions.js'; const metricList = Object.keys(friendlynames); const require = createRequire(import.meta.url); @@ -25,6 +26,11 @@ const version = require('../../package.json').version; const configFiles = ['.sitespeed.io.json']; +const addedPlugins = yargs(hideBin(process.argv)) + .option('plugins.add', { type: 'array' }) + .parse(); +const globalPluginsToAdd = addedPlugins.plugins?.add || []; + function fixAndroidArgs(args) { return args.map(arg => (arg === '--android' ? '--android.enabled' : arg)); } @@ -220,7 +226,7 @@ function validateInput(argv) { export async function parseCommandLine() { const fixedArgs = fixAndroidArgs(hideBin(process.argv)); const yargsInstance = yargs(fixedArgs); - let parsed = yargsInstance + yargsInstance .parserConfiguration({ 'camel-case-expansion': false, 'deep-merge-config': true @@ -1418,9 +1424,7 @@ export async function parseCommandLine() { describe: 'Include screenshot (from Browsertime) in the annotation. You need to specify a --resultBaseURL for this to work.', group: 'InfluxDB' - }); - - parsed + }) /** Plugins */ .option('plugins.list', { describe: 'List all configured plugins in the log.', @@ -1526,13 +1530,7 @@ export async function parseCommandLine() { describe: 'The max size of the screenshot (width and height).', default: browsertimeConfig.screenshotParams.maxSize, group: 'Screenshot' - }); - /** - InfluxDB cli option - */ - - parsed - // Metrics + }) .option('metrics.list', { describe: 'List all possible metrics in the data folder (metrics.txt).', type: 'boolean', @@ -1877,9 +1875,7 @@ export async function parseCommandLine() { describe: 'Instead of using the local copy of the hosting database, you can use the latest version through the Green Web Foundation API. This means sitespeed.io will make HTTP GET to the the hosting info.', group: 'Sustainable' - }); - - parsed + }) .option('api.key', { describe: 'The API key to use.', group: 'API' @@ -1930,9 +1926,7 @@ export async function parseCommandLine() { .option('api.json', { describe: 'Output the result as JSON.', group: 'API' - }); - - parsed + }) .option('compare.id', { type: 'string', describe: @@ -1993,8 +1987,7 @@ export async function parseCommandLine() { 'Selects the method for calculating the Mann-Whitney U test. auto automatically selects between exact and asymptotic based on sample size, exact uses the exact distribution of U, and symptotic uses a normal approximation.', default: 'auto', group: 'compare' - }); - parsed + }) .option('mobile', { describe: 'Access pages as mobile a fake mobile device. Set UA and width/height. For Chrome it will use device Moto G4.', @@ -2124,8 +2117,12 @@ export async function parseCommandLine() { } return plugins; } - }) - // .describe('browser', 'Specify browser') + }); + // .describe('browser', 'Specify browser') + + await registerPluginOptions(yargsInstance, globalPluginsToAdd); + + let parsed = yargsInstance .wrap(yargsInstance.terminalWidth()) // .check(validateInput) .epilog( diff --git a/lib/cli/pluginOptions.js b/lib/cli/pluginOptions.js new file mode 100644 index 000000000..36cbc1744 --- /dev/null +++ b/lib/cli/pluginOptions.js @@ -0,0 +1,24 @@ +import { importGlobalSilent } from 'import-global'; + +/** + * Dynamically load and register CLI options from plugins. + * + * @param {import('yargs').Argv} yargsInstance - The yargs instance to extend. + * @param {string[]} plugins - Array of plugin module names. + * @returns {Promise} + */ +export async function registerPluginOptions(yargsInstance, plugins) { + for (const pluginName of plugins) { + try { + // Dynamically import the plugin + const plugin = await importGlobalSilent(pluginName); + // If the plugin exports a function to get CLI options, merge them + if (plugin && typeof plugin.getCliOptions === 'function') { + const options = plugin.getCliOptions(); + yargsInstance.options(options); + } + } catch { + // Swallow this silent + } + } +}