UNPKG

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