import fuzzy from 'fuzzy'; import inquirer from 'inquirer'; import { chalk, log } from './command-helpers.js'; /** * Filters the inquirer settings based on the input */ const filterSettings = function (scriptInquirerOptions, input) { const filterOptions = scriptInquirerOptions.map((scriptInquirerOption) => scriptInquirerOption.name); // TODO: remove once https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1394 is fixed // eslint-disable-next-line unicorn/no-array-method-this-argument const filteredSettings = fuzzy.filter(input, filterOptions); const filteredSettingNames = new Set(filteredSettings.map((filteredSetting) => (input ? filteredSetting.string : filteredSetting))); return scriptInquirerOptions.filter((t) => filteredSettingNames.has(t.name)); }; /** * Formats the settings to present it as an array for the inquirer input so that it can choose one */ const formatSettingsArrForInquirer = function (settings, type = 'dev') { return settings.map((setting) => { const cmd = type === 'dev' ? setting.devCommand : setting.buildCommand; return { name: `[${chalk.yellow(setting.framework.name)}] '${cmd}'`, value: { ...setting, commands: [cmd] }, short: `${setting.name}-${cmd}`, }; }); }; /** * Detects and filters the build setting for a project and a command */ export async function detectBuildSettings(command) { const { project, workspacePackage } = command; const buildSettings = await project.getBuildSettings(project.workspace ? workspacePackage : ''); return buildSettings .filter((setting) => { if (project.workspace && project.relativeBaseDirectory && setting.packagePath) { return project.relativeBaseDirectory.startsWith(setting.packagePath); } return true; }) .filter((setting) => setting.devCommand); } /** * Uses `@netlify/build-info` to detect the dev settings and port based on the framework * and the build system that is used. * @param command The base command * @param type The type of command (dev or build) */ export const detectFrameworkSettings = async (command, type = 'dev') => { const { relConfigFilePath } = command.netlify; const settings = await detectBuildSettings(command); if (settings.length === 1) { return settings[0]; } if (type === 'build' && command.netlify.config?.build?.command?.length) { return { ...settings[0], buildCommand: command.netlify.config.build.command, }; } if (settings.length > 1) { // multiple matching detectors, make the user choose const scriptInquirerOptions = formatSettingsArrForInquirer(settings, type); const { chosenSettings } = await inquirer.prompt({ name: 'chosenSettings', message: `Multiple possible ${type} commands found`, // @ts-expect-error is not known by the types as it uses the autocomplete plugin type: 'autocomplete', source(_, input = '') { if (!input) return scriptInquirerOptions; // only show filtered results return filterSettings(scriptInquirerOptions, input); }, }); log(` Update your ${relConfigFilePath} to avoid this selection prompt next time: [build] command = "${chosenSettings.buildCommand}" publish = "${chosenSettings.dist}" [dev] command = "${chosenSettings.devCommand}" `); return chosenSettings; } };