Time slots app prototype
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

156 lines
3.9 KiB

const p = console.log
const cwd = process.cwd!
const swd = __dirname
require 'colors'
const fs = require 'fs'
const path = require 'path'
const prompt = require 'prompts'
const spawn = require 'cross-spawn'
def quit msg='Quit'
console.error msg.red
process.exit!
const templates =
'default':
path: 'default'
name: 'Default'
desc: 'Client only application (Imba bundler)'
'vite':
path: 'vite'
name: 'Vite'
desc: 'Client only application (Vite bundler)'
'express':
path: 'express'
name: 'Express'
desc: 'Full stack application (Imba bundler)'
'vitest':
path: 'vitest'
name: 'Vitest'
desc: 'Client only application with vitest (Vite bundler)'
'module':
path: 'module'
name: 'Module'
desc: 'A module that can be used in any JavaScript project (Vite bundler)'
const noCopy = [
'.git'
'dist'
'node_modules'
'package-lock.json'
]
def copy src, dest
return if noCopy.includes path.basename(src)
if path.basename(dest) is '_gitignore'
dest = path.join(path.dirname(dest), '.gitignore')
if fs.statSync(src).isDirectory!
fs.mkdirSync(dest,recursive:yes)
for file of fs.readdirSync(src)
copy path.resolve(src,file), path.resolve(dest,file)
else
fs.copyFileSync(src,dest)
def toValidRepoName name
return unless typeof name is 'string'
return name if name is '.'
name = name.replaceAll(/[^\s\w.-]/g,'').trim!.replaceAll(/\s+/g,'-')
if not name or name is '.'
throw 'Project name can only contain a-z A-Z 0-9 _ . -'
if name is '..'
throw "Project name cannot be '..'"
if fs.existsSync(name)
throw "Project name '{name}' already exists in current directory"
name
def assertCleanGit
try
throw 1 if spawn.sync('git',['status','--porcelain']).output.join('')
catch
quit 'Creating a project in the current directory requires a clean git status'
def main name, opts
const promptOpts = onCancel: do quit!
let projectName
try projectName = toValidRepoName name
catch e p(e.red)
projectName ??= (await prompt {
type: 'text'
message: 'Enter a project name or . for current dir'
initial: name or 'imba-project'
format: toValidRepoName
validate: do
try yes if toValidRepoName($1)
catch e e
name: 'value'
}, promptOpts).value
assertCleanGit! if projectName is '.'
let template = templates[opts.template]
p('Template not found'.red) if opts.template and not template
template ??= (await prompt {
type: 'select'
message: 'Choose a template or find more at ' + 'https://imba.io/templates'.blue
choices: for own key, t of templates
{ title:t.name, description:t.desc, value:t }
initial: 0
name: 'value'
}, promptOpts).value
const src = path.join swd, '..', 'templates', template.path
const dest = path.join cwd, projectName
const packageName = projectName is '.' ? path.basename(cwd) : projectName
const dirStr = "./{projectName is '.' ? '' : projectName}"
unless opts.yes
quit! unless (await prompt {
type: 'confirm'
message: "Create {template.name.cyan} project named {packageName.cyan} in {dirStr.cyan}?"
initial: yes
name: 'value'
}, promptOpts).value
if dest is cwd
assertCleanGit!
elif fs.existsSync dest
quit 'Project dir already exists'
try
copy src, dest
p "\nCreated <{template.name}> project named '{packageName}' in {dirStr}".green
catch e
quit "\nFailed to copy project:\n\n{e}"
p '\nInstalling dependencies'.bold
try
process.chdir(dest) unless projectName is '.'
spawn.sync 'npm', ['pkg', 'set', "name={packageName}"]
spawn.sync 'npm', ['up', '-S'], stdio:'inherit'
catch e
p "\nFailed to install dependencies:\n\n{e}".red
p """
Install the vscode extension for an optimal experience:
{'https://marketplace.visualstudio.com/items?itemName=scrimba.vsimba'.blue}
Join the Imba community on discord for help and friendly discussions:
{'https://discord.gg/mkcbkRw'.blue}
Get started:
{'➜'.cyan} cd {projectName}
{'➜'.cyan} npm run dev
"""
module.exports = main