[breaking]: FreeSewing v4 (#7297)
Refer to the CHANGELOG for all info. --------- Co-authored-by: Wouter van Wageningen <wouter.vdub@yahoo.com> Co-authored-by: Josh Munic <jpmunic@gmail.com> Co-authored-by: Jonathan Haas <haasjona@gmail.com>
This commit is contained in:
parent
d22fbe78d9
commit
51dc1d9732
6626 changed files with 142053 additions and 150606 deletions
264
packages/studio/lib/utils.mjs
Normal file
264
packages/studio/lib/utils.mjs
Normal file
|
@ -0,0 +1,264 @@
|
|||
import { config } from './config.mjs'
|
||||
import { mkdir, copyFile, opendir } from 'node:fs/promises'
|
||||
import { lstatSync } from 'node:fs'
|
||||
import { join, resolve, dirname } from 'path'
|
||||
import ora from 'ora'
|
||||
import chalk from 'chalk'
|
||||
import prompts from 'prompts'
|
||||
import { execa } from 'execa'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { glob } from 'glob'
|
||||
|
||||
// Current working directory
|
||||
let filename
|
||||
try {
|
||||
filename = __filename
|
||||
} catch {
|
||||
filename = fileURLToPath(new URL(import.meta.url))
|
||||
}
|
||||
const newDesignDir = join(filename, '../..')
|
||||
|
||||
const nl = '\n'
|
||||
const tab = ' '
|
||||
const nlt = nl + tab
|
||||
|
||||
// Checks for node 20 or higher
|
||||
export const checkNodeVersion = () => {
|
||||
const node_version = process.version.slice(1).split('.')[0]
|
||||
if (parseInt(node_version) < config.node) {
|
||||
console.log(
|
||||
chalk.yellow(nlt + `⚠️ FreeSewing requires Node v${config.node} or newer`) +
|
||||
nl +
|
||||
nlt +
|
||||
'We highly recommend using NVM to manage your Node versions:' +
|
||||
nlt +
|
||||
chalk.blue('https://github.com/nvm-sh/nvm') +
|
||||
nl +
|
||||
nlt +
|
||||
'When in doubt, pick an active LTS version, like lts/iron (node 20):' +
|
||||
nlt +
|
||||
chalk.blue('https://nodejs.org/en/about/releases/') +
|
||||
nl +
|
||||
nl
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets user input to figure out what to do
|
||||
export const getChoices = async () => {
|
||||
let finalName = false // we're going to use this to track whether we stay in the naming loop
|
||||
let overwrite = true // should we overwrite existing files?
|
||||
let name // name will go here
|
||||
let sideStep // allows to do something custom
|
||||
const cwd = process.cwd()
|
||||
|
||||
// while we're not finalized on a name
|
||||
while (finalName === false) {
|
||||
// request a name
|
||||
name = (
|
||||
await prompts({
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
message: 'Give a folder name in which we can setup the development environment? 🏷️ ',
|
||||
initial: 'freesewing',
|
||||
})
|
||||
).name
|
||||
|
||||
// check whether a folder with that name already exists
|
||||
const dest = join(cwd, name)
|
||||
try {
|
||||
const dir = await opendir(dest)
|
||||
dir.close()
|
||||
} catch {
|
||||
// the folder didn't exist, so we're good to go
|
||||
finalName = true
|
||||
break
|
||||
}
|
||||
|
||||
// the folder did exist, so now we need to ask what to do
|
||||
const { nextStep } = await prompts({
|
||||
type: 'select',
|
||||
name: 'nextStep',
|
||||
message: 'It looks like that folder already exists. What should we do?',
|
||||
choices: [
|
||||
{ title: 'Go back', value: 'rename', description: 'Choose a different folder name' },
|
||||
{
|
||||
title: 'Overwrite',
|
||||
value: 'overwrite',
|
||||
description: 'Overwrite the contents in the existing folder',
|
||||
},
|
||||
],
|
||||
})
|
||||
sideStep = nextStep
|
||||
|
||||
// if they said rename, we loop again. otherwise
|
||||
if (nextStep !== 'rename') {
|
||||
finalName = true
|
||||
// set the overwrite choice
|
||||
overwrite = nextStep === 'overwrite'
|
||||
}
|
||||
}
|
||||
|
||||
return { name, overwrite }
|
||||
}
|
||||
|
||||
// Helper method to run [yarn|npm] install
|
||||
const installDependencies = async (config, choices) =>
|
||||
await execa(`npm install`, {
|
||||
cwd: config.dest,
|
||||
shell: true,
|
||||
})
|
||||
|
||||
// Tips
|
||||
const showTips = (config, choices) =>
|
||||
console.log(`
|
||||
All done 🤓 Your FreeSewing development environment was initialized in: ${chalk.green.bold(
|
||||
config.dest
|
||||
)}
|
||||
|
||||
The templates for various designs are in the ${chalk.yellow.bold('design')} folder.
|
||||
The other files and folders are the development environment. You can safely ignore those.
|
||||
|
||||
To start your development environment, follow these three steps:
|
||||
|
||||
1) Start by entering the directory: ${chalk.blue.bold('cd ' + config.dest)}
|
||||
2) Then run this command: ${chalk.blue.bold('npm run start')}
|
||||
3) Now open your browser and navigate to ${chalk.green('http://localhost:3000/')}
|
||||
|
||||
Thanks for giving FreeSewing a shot. I hope you'll 💜 it.
|
||||
|
||||
Have fun 🤓
|
||||
|
||||
joost
|
||||
`)
|
||||
|
||||
// Creates the environment based on the user's choices
|
||||
export const createEnvironment = async (choices) => {
|
||||
console.log()
|
||||
config.dest = join(process.cwd(), choices.name)
|
||||
|
||||
// Step 1: Copy template files
|
||||
const spinner1 = ora(
|
||||
chalk.white.bold(' 🟧⬜⬜ Setting up development environment') +
|
||||
chalk.white.dim(' | This should not take long')
|
||||
).start()
|
||||
try {
|
||||
// Create target directory unless we're overwriting
|
||||
if (choices.overwrite) await mkdir(config.dest, { recursive: true })
|
||||
// Now copy files
|
||||
await copyTemplateFiles(config)
|
||||
spinner1.succeed(chalk.white.bold(' 🟩⬜⬜ Development environment created'))
|
||||
} catch (err) {
|
||||
console.log({ err })
|
||||
spinner1.fail(
|
||||
' 🟥⬜⬜ Failed to setup the environment | The development environment will not function'
|
||||
)
|
||||
}
|
||||
|
||||
// Step 2: Install dependencies
|
||||
const spinner2 = ora(
|
||||
chalk.white.bold(' 🟩🟧⬜ Installing dependencies') +
|
||||
chalk.white.dim(' | Please wait, this will take a while')
|
||||
).start()
|
||||
try {
|
||||
await installDependencies(config, choices)
|
||||
spinner2.succeed(chalk.white.bold(' 🟩🟩⬜ Installed dependencies'))
|
||||
} catch (err) {
|
||||
console.log({ err })
|
||||
spinner2.fail(
|
||||
' 🟩🟥⬜ Failed to install dependencies | The development environment will not function'
|
||||
)
|
||||
}
|
||||
|
||||
// Step 3: Initialize git repository
|
||||
if (!choices.sideStep) {
|
||||
const spinner3 = ora(
|
||||
chalk.white.bold(' 🟩🟩🟧 Initializing git repository') +
|
||||
chalk.white.dim(' | You have git, right?')
|
||||
).start()
|
||||
try {
|
||||
await initGitRepo(config.dest)
|
||||
spinner3.succeed(chalk.white.bold(' 🟩🟩🟩 Initialized git repository'))
|
||||
} catch (err) {
|
||||
spinner3.fail(
|
||||
chalk.white.bold(' 🟩🟩🟥 Failed to initialize git repository') +
|
||||
chalk.white.dim(' | This does not stop the development environment from functioning')
|
||||
)
|
||||
console.log({ err })
|
||||
}
|
||||
}
|
||||
|
||||
// All done. Show tips
|
||||
showTips(config, choices)
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the template files from the NPM package contents to the target folder
|
||||
*
|
||||
* @param {object} config - The configuration
|
||||
*/
|
||||
async function copyTemplateFiles(config) {
|
||||
const dir = join(newDesignDir, `template`)
|
||||
const dirs = {}
|
||||
// Need to explicitly add hidden folders
|
||||
const toCopy = [
|
||||
...(await globDir(join(newDesignDir, `template`))),
|
||||
...(await globDir(join(newDesignDir, `template`, `designs`, `.base`))),
|
||||
...(await globDir(join(newDesignDir, `template`, `designs`, `.bella`))),
|
||||
...(await globDir(join(newDesignDir, `template`, `designs`, `.bent`))),
|
||||
...(await globDir(join(newDesignDir, `template`, `designs`, `.breanna`))),
|
||||
...(await globDir(join(newDesignDir, `template`, `designs`, `.brian`))),
|
||||
...(await globDir(join(newDesignDir, `template`, `designs`, `.titan`))),
|
||||
].sort()
|
||||
for (const file of toCopy) {
|
||||
const target = resolve(config.dest, file.slice(dir.length + 1))
|
||||
if (isDir(file)) await mkdir(target, { recursive: true })
|
||||
else {
|
||||
await mkdir(dirname(target), { recursive: true })
|
||||
await copyFile(file, target) // Copy file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a folder from disk with an optional glob pattern
|
||||
*
|
||||
* @param {string} (relative) path to the file to read
|
||||
* @param {funtion} onError - a method to call on error
|
||||
*
|
||||
* @return {string} File contents, or false in case of trouble
|
||||
*/
|
||||
async function globDir(
|
||||
folderPath, // The (relative) path to the folder
|
||||
pattern = '**/*' // Glob pattern to match
|
||||
) {
|
||||
let list = []
|
||||
try {
|
||||
list = await glob(resolve(folderPath) + '/' + pattern)
|
||||
} catch (err) {
|
||||
if (err) console.log(err)
|
||||
return false
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine wheter a file is a folder
|
||||
*/
|
||||
function isDir(path) {
|
||||
return lstatSync(path) ? lstatSync(path).isDirectory() : false
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to initialize a git repository
|
||||
*
|
||||
* @param {string} target - The target folder to use
|
||||
*/
|
||||
function initGitRepo(target) {
|
||||
return execa(
|
||||
`git init -b main && git add . && git commit -m ":tada: Initialized FreeSewing development environment"`,
|
||||
{ cwd: target, shell: true }
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue