mcfly/packages/create-mcfly/index.js
Ayo 6edab54354 feat: new architecture to support server framework plugin
- generic `server.serve` config
- new demo workspace
- new basic template
- updated readme

Reviewed-on: https://git.ayo.run/ayo/mcfly/pulls/3
Co-authored-by: Ayo <ayo@ayco.io>
Co-committed-by: Ayo <ayo@ayco.io>
2026-06-04 11:17:09 +00:00

199 lines
5.1 KiB
JavaScript
Executable file

#!/usr/bin/env node
import { consola } from 'consola'
import { colorize } from 'consola/utils'
import { downloadTemplate } from 'giget'
import { spawnSync } from 'node:child_process'
import path from 'node:path'
const [, , directoryArg] = process.argv
/**
* @typedef {Object} PromptAction
* @property {string} prompt - The prompt text to display
* @property {string} [info] - Additional information about the prompt
* @property {string} startMessage - Message to show when starting the action
* @property {string} command - The command to execute
* @property {string} subCommand - The subcommand to execute
* @property {string} error - Error message to display on failure
*/
/**
* Create McFly App
*/
async function create() {
const defaultDirectory = 'mcfly-app'
consola.box(`Hello! Welcome to ${colorize('bold', 'McFly')}!`)
let directory = directoryArg
if (!directory) {
directory =
(await consola.prompt('Give your new project a name:', {
placeholder: defaultDirectory,
})) ?? defaultDirectory
} else {
consola.success(`Using ${directory} as name.`)
}
if (typeof directory !== 'string') {
return
}
directory = getSafeDirectory(directory)
const hasErrors = await downloadTemplateToDirectory(directory)
if (!hasErrors) {
/**
* @type {Array<PromptAction>}
*/
const prompts = [
{
prompt: `Would you like to install the dependencies to ${colorize(
'bold',
directory
)}?`,
info: 'This might take some time depending on your connectivity.',
startMessage: 'Installing dependencies using npm...',
command: `npm`,
subCommand: 'install',
error: `Install dependencies later with ${colorize(
'yellow',
'npm install'
)}`,
},
{
prompt: 'Would you like to initialize your git repository?',
startMessage: 'Initializing git repository...',
command: `git`,
subCommand: 'init',
error: `Initialize git repository later with ${colorize(
'yellow',
'git init'
)}`,
},
]
const intentions = await askPrompts(prompts, directory)
if (!!intentions && intentions.length > 0)
showResults(directory, intentions[0])
}
}
/**
* Returns string that is safe for commands
* @param {string} directory
* @returns string
*/
function getSafeDirectory(directory) {
const { platform } = process
const locale = path[platform === `win32` ? `win32` : `posix`]
const localePath = directory.split(path.sep).join(locale.sep)
return path.normalize(localePath)
}
/**
* Tries to download the template to the directory and returns a Promise whether the operation resulted to errors
* @param {string} directory
* @returns Promise<boolean> hasErrors
*/
async function downloadTemplateToDirectory(directory) {
let hasErrors = false
try {
consola.start(
`Copying template to ${colorize('bold', getSafeDirectory(directory))}...`
)
await downloadTemplate('github:ayo-run/mcfly/templates/basic', {
dir: directory,
})
} catch (_ㆆ) {
if (_ㆆ instanceof Error) {
consola.error(_ㆆ.message)
} else {
consola.error(_ㆆ)
}
consola.info('Try a different name.\n')
hasErrors = true
}
return hasErrors
}
/**
* Iterate over an array of prompts and ask for user intention
* @param {Array<PromptAction>} prompts
* @param {string} cwd
* @returns Promise<Array<boolean> | undefined>
*/
async function askPrompts(prompts, cwd) {
/**
* @type {Array<boolean>}
*/
const results = []
for (const p of prompts) {
const userIntends = await consola.prompt(p.prompt, {
type: 'confirm',
})
if (typeof userIntends !== 'boolean') {
return
}
if (userIntends) {
p.info && consola.info(p.info)
consola.start(p.startMessage)
try {
spawnSync(p.command, [p.subCommand], {
cwd,
shell: true,
timeout: 100_000,
stdio: 'inherit',
})
consola.success('Done!')
} catch (_ㆆ) {
if (_ㆆ instanceof Error) {
consola.error(_ㆆ.message)
} else {
consola.error(_ㆆ)
}
consola.info(p.error + '\n')
}
}
results.push(userIntends)
}
return results
}
/**
* Displays the success result string based on directory and choices
* @param {string} directory
* @param {boolean} installDeps
*/
function showResults(directory, installDeps) {
let nextActions = [
`Go to your project by running ${colorize('yellow', `cd ${directory}`)}`,
]
if (!installDeps) {
nextActions.push(
`Install the dependencies with ${colorize('yellow', 'npm install')}`
)
}
nextActions = nextActions.concat([
`Start the dev server with ${colorize('yellow', 'npm start')}`,
`Join us at ${colorize('blue', 'https://ayco.io/sh/mcfly')}`,
])
const result = `🎉 Your new ${colorize(
'bold',
'McFly'
)} app is ready: ${directory}\n\nNext actions: ${nextActions
.map((action, index) => `\n${index}. ${action}`)
.join('')}`
consola.box(result)
}
create()