|
1 | 1 | const path = require("path"); |
2 | 2 | const chalk = require("chalk"); |
3 | 3 | const NETLIFYDEV = `[${chalk.cyan("Netlify Dev")}]`; |
4 | | - |
5 | | -const detectors = require("fs") |
| 4 | +const inquirer = require("inquirer"); |
| 5 | +const fs = require("fs"); |
| 6 | +const detectors = fs |
6 | 7 | .readdirSync(path.join(__dirname, "detectors")) |
7 | 8 | .filter(x => x.endsWith(".js")) // only accept .js detector files |
8 | 9 | .map(det => require(path.join(__dirname, `detectors/${det}`))); |
9 | 10 |
|
10 | | -module.exports.serverSettings = devConfig => { |
11 | | - let settings = null; |
| 11 | +module.exports.serverSettings = async devConfig => { |
| 12 | + let settingsArr = [], |
| 13 | + settings = null; |
12 | 14 | for (const i in detectors) { |
13 | | - settings = detectors[i](); |
14 | | - if (settings) { |
15 | | - break; |
| 15 | + const detectorResult = detectors[i](); |
| 16 | + if (detectorResult) settingsArr.push(detectorResult); |
| 17 | + } |
| 18 | + if (settingsArr.length === 1) { |
| 19 | + // vast majority of projects will only have one matching detector |
| 20 | + settings = settingsArr[0]; |
| 21 | + settings.args = settings.possibleArgsArrs[0]; // just pick the first one |
| 22 | + if (!settings.args) { |
| 23 | + console.error( |
| 24 | + "empty args assigned, this is an internal Netlify Dev bug, please report your settings and scripts so we can improve" |
| 25 | + ); |
| 26 | + const { scripts } = JSON.parse( |
| 27 | + fs.readFileSync("package.json", { encoding: "utf8" }) |
| 28 | + ); |
| 29 | + process.exit(1); |
| 30 | + } |
| 31 | + } else if (settingsArr.length > 1) { |
| 32 | + /** multiple matching detectors, make the user choose */ |
| 33 | + // lazy loading on purpose |
| 34 | + inquirer.registerPrompt( |
| 35 | + "autocomplete", |
| 36 | + require("inquirer-autocomplete-prompt") |
| 37 | + ); |
| 38 | + const fuzzy = require("fuzzy"); |
| 39 | + const scriptInquirerOptions = formatSettingsArrForInquirer(settingsArr); |
| 40 | + const { chosenSetting } = await inquirer.prompt({ |
| 41 | + name: "chosenSetting", |
| 42 | + message: `Multiple possible start commands found`, |
| 43 | + type: "autocomplete", |
| 44 | + source: async function(_, input) { |
| 45 | + if (!input || input === "") { |
| 46 | + return scriptInquirerOptions; |
| 47 | + } |
| 48 | + // only show filtered results |
| 49 | + return filterSettings(scriptInquirerOptions, input); |
| 50 | + } |
| 51 | + }); |
| 52 | + settings = chosenSetting; // finally! we have a selected option |
| 53 | + // TODO: offer to save this setting to netlify.toml so you dont keep doing this |
| 54 | + |
| 55 | + /** utiltities for the inquirer section above */ |
| 56 | + function filterSettings(scriptInquirerOptions, input) { |
| 57 | + const filteredSettings = fuzzy.filter( |
| 58 | + input, |
| 59 | + scriptInquirerOptions.map(x => x.name) |
| 60 | + ); |
| 61 | + const filteredSettingNames = filteredSettings.map(x => |
| 62 | + input ? x.string : x |
| 63 | + ); |
| 64 | + return scriptInquirerOptions.filter(t => |
| 65 | + filteredSettingNames.includes(t.name) |
| 66 | + ); |
| 67 | + } |
| 68 | + |
| 69 | + /** utiltities for the inquirer section above */ |
| 70 | + function formatSettingsArrForInquirer(settingsArr) { |
| 71 | + let ans = []; |
| 72 | + settingsArr.forEach(setting => { |
| 73 | + setting.possibleArgsArrs.forEach(args => { |
| 74 | + ans.push({ |
| 75 | + name: `[${chalk.yellow(setting.type)}] ${ |
| 76 | + setting.command |
| 77 | + } ${args.join(" ")}`, |
| 78 | + value: { ...setting, args }, |
| 79 | + short: setting.type + "-" + args.join(" ") |
| 80 | + }); |
| 81 | + }); |
| 82 | + }); |
| 83 | + return ans; |
16 | 84 | } |
17 | 85 | } |
18 | 86 |
|
| 87 | + /** everything below assumes we have settled on one detector */ |
| 88 | + |
19 | 89 | if (devConfig) { |
20 | 90 | settings = settings || {}; |
21 | 91 | if (devConfig.command) { |
22 | | - assignLoudly(settings, "command", devConfig.command.split(/\s/)[0]); |
23 | | - assignLoudly(settings, "args", devConfig.command.split(/\s/).slice(1)); |
| 92 | + settings.command = assignLoudly( |
| 93 | + devConfig.command, |
| 94 | + settings.command.split(/\s/)[0] |
| 95 | + ); |
| 96 | + settings.args = assignLoudly( |
| 97 | + devConfig.command, |
| 98 | + settings.command.split(/\s/).slice(1) |
| 99 | + ); |
24 | 100 | } |
25 | 101 | if (devConfig.port) { |
26 | | - assignLoudly(settings, "proxyPort", devConfig["port"]); |
27 | | - assignLoudly( |
28 | | - settings, |
29 | | - "urlRegexp", |
| 102 | + settings.proxyPort = assignLoudly(devConfig.port, settings.proxyPort); |
| 103 | + const regexp = |
30 | 104 | devConfig.urlRegexp || |
31 | | - new RegExp(`(http://)([^:]+:)${devConfig.port}(/)?`, "g") |
32 | | - ); |
| 105 | + new RegExp(`(http://)([^:]+:)${devConfig.port}(/)?`, "g"); |
| 106 | + settings.urlRegexp = assignLoudly(settings.urlRegexp); |
33 | 107 | } |
34 | | - assignLoudly(settings, "dist", devConfig["publish"]); |
| 108 | + settings.dist = assignLoudly(devConfig.publish, settings.dist); |
35 | 109 | } |
36 | | - |
37 | 110 | return settings; |
38 | 111 | }; |
39 | 112 |
|
40 | | -// mutates the settings field, but tell the user if it does |
41 | | -function assignLoudly(settings, settingsField, newValue) { |
42 | | - if (settings[settingsField] !== newValue) { |
43 | | - // silent if command is exactly same |
| 113 | +// if first arg is undefined, use default, but tell user about it in case it is unintentional |
| 114 | +function assignLoudly( |
| 115 | + optionalValue, |
| 116 | + defaultValue, |
| 117 | + tellUser = dV => |
44 | 118 | console.log( |
45 | 119 | `${NETLIFYDEV} Overriding ${settingsField} with setting derived from netlify.toml [dev] block: `, |
46 | | - newValue |
47 | | - ); |
48 | | - settings[settingsField] === newValue; |
| 120 | + dV |
| 121 | + ) |
| 122 | +) { |
| 123 | + if (defaultValue === undefined) throw new Error("must have a defaultValue"); |
| 124 | + if (defaultValue !== optionalValue && optionalValue === undefined) { |
| 125 | + tellUser(defaultValue); |
| 126 | + return defaultValue; |
| 127 | + } else { |
| 128 | + return optionalValue; |
49 | 129 | } |
50 | 130 | } |
0 commit comments