@swell/cli
Version:
Swell's command line interface/utility
217 lines (216 loc) • 8.7 kB
JavaScript
import { confirm, input, select } from '@inquirer/prompts';
import { Args, Flags } from '@oclif/core';
import path from 'node:path';
import ora from 'ora';
import { CreateAppCommand } from '../../create-app-command.js';
import { newConfig, swellConfigFileExists } from '../../lib/app-config.js';
import { toAppId, toAppName } from '../../lib/create/index.js';
import style from '../../lib/style.js';
export default class CreateApp extends CreateAppCommand {
appType = '';
static args = {
id: Args.string({
default: '',
description: `id of the app to create`,
}),
};
static description = 'Create an app.';
static examples = [
{
command: 'swell create app',
description: 'Create app following command prompts.',
},
{
command: 'swell create app my_app -y',
description: 'Create app and accept all default values.',
},
{
command: 'swell create app -p yarn',
description: 'Create app with yarn package manager instead of npm by default.',
},
{
command: 'swell create app -p none',
description: 'Create app without installing TypeScript bindings, etc.',
},
];
static flags = {
pkg: Flags.string({
char: 'p',
default: 'npm',
description: `use npm or yarn to install default dependencies, or none to disable`,
options: ['npm', 'yarn', 'none'],
}),
type: Flags.string({
char: 't',
description: `create a specific app type`,
options: ['admin', 'integration', 'storefront', 'theme'],
}),
};
async createSwellConfig({ allowOverwrite = true, inputId = '', inputStorefrontApp, inputType, inputYes, nestedPath = true, }) {
let confirmYes = inputYes;
const type = inputType ||
(confirmYes
? 'admin'
: await select({
choices: [
{ name: 'Admin', value: 'admin' },
{ name: 'Integration', value: 'integration' },
{ name: 'Storefront', value: 'storefront' },
{ name: 'Theme', value: 'theme' },
],
message: `What is the primary purpose of the app?`,
}));
const typeLabel = type === 'theme' ? 'theme' : 'app';
const typeLabelTitle = type === 'theme' ? 'Theme' : 'App';
const name = confirmYes
? toAppName(inputId)
: await input({
default: inputId ? toAppName(inputId) : '',
message: `${typeLabelTitle} name`,
validate: (answer) => answer.length > 2,
});
let appId = toAppId(inputId || '');
if (!appId) {
appId = await input({
default: toAppId(name),
message: `${typeLabelTitle} ID`,
validate: (answer) => answer.length > 2,
});
appId = toAppId(appId);
confirmYes = Boolean(inputYes && appId);
}
const version = confirmYes
? '1.0.0'
: await input({
default: '1.0.0',
message: `${typeLabelTitle} version`,
});
const description = confirmYes
? ''
: await input({
default: 'Something special',
message: `Describe your ${typeLabel}`,
});
let storefrontInstalledApps;
let storefrontAppId;
let installedStorefrontApp;
if (type === 'theme') {
storefrontInstalledApps = await this.getInstalledStorefrontApps();
if (storefrontInstalledApps === false) {
return;
}
storefrontAppId =
inputStorefrontApp ||
(storefrontInstalledApps.length > 1
? await select({
choices: storefrontInstalledApps.map(({ app, id }) => ({
name: app.name,
value: id,
})),
message: `Which storefront app is your theme for?`,
})
: storefrontInstalledApps[0].id);
installedStorefrontApp = storefrontInstalledApps.find((installedApp) => inputStorefrontApp
? inputStorefrontApp === installedApp.app_private_id ||
inputStorefrontApp === installedApp.app_public_id ||
inputStorefrontApp === installedApp.app_id ||
inputStorefrontApp === toAppId(installedApp.app_private_id)
: installedApp.id === storefrontAppId);
if (!installedStorefrontApp) {
this.error(`Could not find an installed storefront app by id: ${storefrontAppId}`);
}
}
const swellConfigJson = {
description,
id: appId,
name,
type,
version,
...(type === 'theme'
? {
theme: {
storefront: {
app: toAppId(installedStorefrontApp.app_private_id),
},
},
}
: {
permissions: [],
}),
};
const appPath = path.join(process.cwd(), inputId || appId);
if (swellConfigFileExists(appPath)) {
if (allowOverwrite) {
if (!confirmYes) {
const continueCreateApp = await confirm({
message: `An app already exists in the target path ${appPath}. Overwrite?`,
});
if (!continueCreateApp) {
return;
}
}
}
else {
this.error(`An app already exists in the target path ${appPath}.`);
}
}
this.log(`\nCreating ${this.appType === 'theme' ? 'theme' : 'app'} ${style.appConfigValue(name)} in ${appPath}/swell.json`);
this.log(`\n${JSON.stringify(swellConfigJson, null, 2)}\n`);
const confirmCreateApp = confirmYes
? true
: await confirm({
message: 'Ok to continue?',
});
if (!confirmCreateApp) {
return;
}
const config = newConfig(nestedPath ? inputId || appId : '');
config.clear();
config.set(swellConfigJson);
return { appId, config, installedStorefrontApp, swellConfigJson };
}
async run() {
const { args, flags } = await this.parse(CreateApp);
const { id } = args;
const { pkg, yes } = flags;
const confirmYes = Boolean(yes && id);
const createParams = await this.createSwellConfig({
inputId: id,
inputStorefrontApp: flags['storefront-app'],
inputType: flags.type,
inputYes: confirmYes,
});
if (!createParams) {
return;
}
const { appId, config, installedStorefrontApp } = createParams;
!confirmYes && this.log();
const spinner = ora();
spinner.start('Creating app...');
if (pkg !== 'none') {
await this.tryPackageSetup(appId, config, pkg);
}
await this.createAppConfigFolders(config);
spinner.succeed(`${style.appConfigValue(config.get('name'))} app created.\n`);
let createdFrontend;
let createdTheme;
if (installedStorefrontApp) {
createdTheme = await this.createThemeApp(config, flags, installedStorefrontApp);
}
else if (config.get('type') === 'storefront') {
createdFrontend = await this.createStorefrontApp(config, flags);
}
else {
createdFrontend = await this.createFrontendApp(config, flags);
}
this.log('\nNext steps:');
this.log(`Run ${style.command('swell app push')} to push configurations to your test store.`);
this.log(`Run ${style.command('swell app install')} to install the app in another store or environment.`);
if (createdFrontend) {
this.log(`Run ${style.command('swell app frontend dev')} to start a local dev server for your frontend app.`);
}
else if (createdTheme) {
this.log(`Run ${style.command('swell app theme dev')} to start a local dev server for your theme.`);
}
}
}