248 lines
No EOL
11 KiB
JavaScript
248 lines
No EOL
11 KiB
JavaScript
import chalk from "chalk";
|
|
import path from "node:path";
|
|
import process from "node:process";
|
|
import { promptOrUseDefault } from "../../../core/prompts.js";
|
|
import { dasherize } from "../../../core/utils/strings.js";
|
|
import { hasConfigurationNameInConfigFile, swaCliConfigFileExists, swaCliConfigFilename, writeConfigFile } from "../../../core/utils/cli-config.js";
|
|
import { logger } from "../../../core/utils/logger.js";
|
|
import { detectDbConfigFiles, detectProjectFolders, generateConfiguration, isDescendantPath } from "../../../core/frameworks/detect.js";
|
|
import { getChoicesForApiLanguage } from "../../../core/functions-versions.js";
|
|
export async function init(options, showHints = true) {
|
|
const configFilePath = options.config;
|
|
const disablePrompts = options.yes ?? false;
|
|
const outputFolder = process.cwd();
|
|
let configName = options.configName?.trim() ?? "";
|
|
if (configName === "") {
|
|
const response = await promptOrUseDefault(disablePrompts, {
|
|
type: "text",
|
|
name: "configName",
|
|
message: "Choose a configuration name:",
|
|
initial: dasherize(path.basename(outputFolder)),
|
|
validate: (value) => value.trim() !== "" || "Configuration name cannot be empty",
|
|
format: (value) => dasherize(value.trim()),
|
|
});
|
|
configName = response.configName;
|
|
}
|
|
// TODO: start from template
|
|
// if (isEmptyFolder(outputFolder)) {
|
|
// // Do you want to create a new project from a template?
|
|
// }
|
|
const detectedFolders = await detectProjectFolders();
|
|
let app = detectedFolders.app[0];
|
|
let api = detectedFolders.api[0];
|
|
if (detectedFolders.app.length > 1) {
|
|
logger.silly(`More than one (${detectedFolders.app.length}) app folders found`);
|
|
const response = await promptOrUseDefault(disablePrompts, {
|
|
type: "select",
|
|
name: "app",
|
|
message: "Which app folder do you want to use?",
|
|
choices: detectedFolders.app.map((folder) => ({ title: folder.rootPath, value: folder })),
|
|
initial: 0,
|
|
});
|
|
// Workaround for bug https://github.com/terkelg/prompts/issues/205
|
|
app = typeof response.app === "number" ? detectedFolders.app[response.app] : response.app;
|
|
}
|
|
// Check if we can find api folders under selected app folder, and filter selection if we found some
|
|
if (app !== undefined) {
|
|
const childApiFolders = detectedFolders.api.filter((folder) => isDescendantPath(folder.rootPath, app.rootPath));
|
|
if (childApiFolders.length > 0) {
|
|
logger.silly(`Found (${childApiFolders.length}) api folders under the app folder`);
|
|
logger.silly(`- ${childApiFolders.map((f) => `${f.rootPath} (${f.frameworks.map((fr) => fr.name).join(", ")})`).join("\n- ")}`);
|
|
detectedFolders.api = childApiFolders;
|
|
}
|
|
}
|
|
if (detectedFolders.api.length > 1) {
|
|
logger.silly(`More than one (${detectedFolders.api.length}) api folders found`);
|
|
const response = await promptOrUseDefault(disablePrompts, {
|
|
type: "select",
|
|
name: "api",
|
|
message: "Which api folder do you want to use?",
|
|
choices: detectedFolders.api.map((folder) => ({ title: folder.rootPath, value: folder })),
|
|
initial: 0,
|
|
});
|
|
// Workaround for bug https://github.com/terkelg/prompts/issues/205
|
|
api = typeof response.api === "number" ? detectedFolders.api[response.api] : response.api;
|
|
}
|
|
else {
|
|
api = detectedFolders.api[0];
|
|
}
|
|
const dbConfigFiles = await detectDbConfigFiles();
|
|
let dataApi = dbConfigFiles[0];
|
|
if (dbConfigFiles.length > 1) {
|
|
logger.silly(`More than one (${dbConfigFiles.length}) data api folders found`);
|
|
const response = await promptOrUseDefault(disablePrompts, {
|
|
type: "select",
|
|
name: "dataApi",
|
|
message: "Which data api folder do you want to use?",
|
|
choices: dbConfigFiles.map((file) => ({ title: file.rootPath, value: file })),
|
|
initial: 0,
|
|
});
|
|
dataApi = typeof response.dataApi === "number" ? dbConfigFiles[response.dataApi] : response.dataApi;
|
|
}
|
|
let projectConfig;
|
|
try {
|
|
projectConfig = await generateConfiguration(app, api, dataApi);
|
|
}
|
|
catch (error) {
|
|
logger.error(`Cannot generate your project configuration:`);
|
|
logger.error(error, true);
|
|
return;
|
|
}
|
|
printFrameworkConfig(projectConfig);
|
|
const { confirmSettings } = await promptOrUseDefault(disablePrompts, {
|
|
type: "confirm",
|
|
name: "confirmSettings",
|
|
message: "Are these settings correct?",
|
|
initial: true,
|
|
});
|
|
if (!confirmSettings) {
|
|
// Ask for each settings
|
|
projectConfig = await promptConfigSettings(disablePrompts, projectConfig);
|
|
}
|
|
if (swaCliConfigFileExists(configFilePath) && (await hasConfigurationNameInConfigFile(configFilePath, configName))) {
|
|
const { confirmOverwrite } = await promptOrUseDefault(disablePrompts, {
|
|
type: "confirm",
|
|
name: "confirmOverwrite",
|
|
message: `Configuration with name "${configName}" already exists, overwrite?`,
|
|
initial: true,
|
|
});
|
|
if (!confirmOverwrite) {
|
|
logger.log("Aborted, configuration not saved.");
|
|
return;
|
|
}
|
|
}
|
|
const cliConfig = convertToCliConfig(projectConfig);
|
|
await writeConfigFile(configFilePath, configName, cliConfig);
|
|
logger.log(chalk.green(`\nConfiguration successfully saved to ${swaCliConfigFilename}.\n`));
|
|
if (showHints) {
|
|
logger.log(chalk.bold(`Get started with the following commands:`));
|
|
logger.log(`- Use ${chalk.cyan("swa start")} to run your app locally.`);
|
|
if (cliConfig.appBuildCommand || cliConfig.apiBuildCommand) {
|
|
logger.log(`- Use ${chalk.cyan("swa build")} to build your app.`);
|
|
}
|
|
logger.log(`- Use ${chalk.cyan("swa deploy")} to deploy your app to Azure.\n`);
|
|
}
|
|
}
|
|
function convertToCliConfig(config) {
|
|
return {
|
|
appLocation: config.appLocation,
|
|
apiLocation: config.apiLocation,
|
|
outputLocation: config.outputLocation,
|
|
dataApiLocation: config.dataApiLocation,
|
|
apiLanguage: config.apiLanguage,
|
|
apiVersion: config.apiVersion,
|
|
appBuildCommand: config.appBuildCommand,
|
|
apiBuildCommand: config.apiBuildCommand,
|
|
run: config.appDevserverCommand,
|
|
appDevserverUrl: config.appDevserverUrl,
|
|
apiDevserverUrl: config.apiDevserverUrl,
|
|
};
|
|
}
|
|
async function promptConfigSettings(disablePrompts, detectedConfig) {
|
|
const trimValue = (value) => {
|
|
value = value.trim();
|
|
return value === "" ? undefined : value;
|
|
};
|
|
const response = await promptOrUseDefault(disablePrompts, [
|
|
{
|
|
type: "text",
|
|
name: "appLocation",
|
|
message: "What's your app location?",
|
|
initial: detectedConfig.appLocation,
|
|
validate: (value) => value.trim() !== "" || "App location cannot be empty",
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "outputLocation",
|
|
message: "What's your build output location?",
|
|
hint: "If your app doesn't have a build process, use the same location as your app",
|
|
initial: detectedConfig.outputLocation,
|
|
validate: (value) => value.trim() !== "" || "Output location cannot be empty",
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "apiLocation",
|
|
message: "What's your API location? (optional)",
|
|
initial: detectedConfig.apiLocation,
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: (prev) => (prev != null ? "select" : null),
|
|
name: "apiLanguage",
|
|
message: "What's your API language? (optional)",
|
|
choices: [
|
|
{ title: "Node.js", value: "node" },
|
|
{ title: "Python", value: "python" },
|
|
{ title: "Dotnet", value: "dotnet" },
|
|
{ title: "Dotnet isolated", value: "dotnetisolated" },
|
|
],
|
|
},
|
|
{
|
|
type: (prev) => (prev != null ? "select" : null),
|
|
name: "apiVersion",
|
|
message: "What's your API version? (optional)",
|
|
choices: (prev) => getChoicesForApiLanguage(prev),
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "dataApiLocation",
|
|
message: "What's your data API location? (optional)",
|
|
initial: detectedConfig.dataApiLocation,
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "appBuildCommand",
|
|
message: "What command do you use to build your app? (optional)",
|
|
initial: detectedConfig.appBuildCommand,
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "apiBuildCommand",
|
|
message: "What command do you use to build your API? (optional)",
|
|
initial: detectedConfig.apiBuildCommand,
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "appDevserverCommand",
|
|
message: "What command do you use to run your app for development? (optional)",
|
|
initial: detectedConfig.appDevserverCommand,
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "appDevserverUrl",
|
|
message: "What's your app development server URL (optional)",
|
|
initial: detectedConfig.appDevserverUrl,
|
|
format: trimValue,
|
|
},
|
|
{
|
|
type: "text",
|
|
name: "apiDevserverUrl",
|
|
message: "What's your API development server URL (optional)",
|
|
initial: detectedConfig.apiDevserverUrl,
|
|
format: trimValue,
|
|
},
|
|
]);
|
|
return response;
|
|
}
|
|
function printFrameworkConfig(config) {
|
|
logger.log(chalk.bold("\nDetected configuration for your app:"));
|
|
logger.log(`- Framework(s): ${chalk.green(config.name ?? "none")}`);
|
|
logger.log(`- App location: ${chalk.green(config.appLocation)}`);
|
|
logger.log(`- Output location: ${chalk.green(config.outputLocation)}`);
|
|
logger.log(`- API location: ${chalk.green(config.apiLocation ?? "")}`);
|
|
logger.log(`- API language: ${chalk.green(config.apiLanguage ?? "")}`);
|
|
logger.log(`- API version: ${chalk.green(config.apiVersion ?? "")}`);
|
|
logger.log(`- Data API location: ${chalk.green(config.dataApiLocation ?? "")}`);
|
|
logger.log(`- App build command: ${chalk.green(config.appBuildCommand ?? "")}`);
|
|
logger.log(`- API build command: ${chalk.green(config.apiBuildCommand ?? "")}`);
|
|
logger.log(`- App dev server command: ${chalk.green(config.appDevserverCommand ?? "")}`);
|
|
logger.log(`- App dev server URL: ${chalk.green(config.appDevserverUrl ?? "")}\n`);
|
|
logger.log(`- API dev server URL: ${chalk.green(config.apiDevserverUrl ?? "")}\n`);
|
|
}
|
|
//# sourceMappingURL=init.js.map
|