Files
nebula.js/commands/create/lib/create.js
Tobias Åström e8ee8a3a14 chore(deps): node24 and update inquirer (#1939)
* chore(deps): node24 and update inquirer

* chore: update gha
2026-03-19 16:09:40 +01:00

200 lines
5.4 KiB
JavaScript

/* eslint-disable no-console */
import path from 'path';
import fs from 'fs';
import { execSync } from 'child_process';
import { createRequire } from 'module';
import { fileURLToPath } from 'url';
import chalk from 'chalk';
import fse from 'fs-extra';
import ejs from 'ejs';
import { select } from '@inquirer/prompts';
const require = createRequire(import.meta.url);
const pkg = require('../package.json');
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
const hasYarn = () => {
try {
execSync('yarnpkg --version', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
};
const author = async (cwd) => {
try {
const email = execSync('git config --get user.email', { cwd }).toString().trim();
const name = execSync('git config --get user.name', { cwd }).toString().trim();
return {
email,
name,
};
} catch (e) {
return {
email: '',
name: '',
};
}
};
const parseAuthor = (str = '') => {
const m = str.match(/([^<(]+)?(<([^\s]+)>)?/);
return {
name: m && m[1] ? m[1].trim() : '',
email: m && m[3] ? m[3].trim() : '',
};
};
function copyFactory(root, destination) {
return (source, target, data) => {
if (data) {
const content = fs.readFileSync(path.resolve(root, ...source.split('/')), { encoding: 'utf8' });
const rendered = ejs.render(content, data);
fs.writeFileSync(path.resolve(destination, ...target.split('/')), rendered);
} else {
fse.copyFileSync(path.resolve(root, ...source.split('/')), path.resolve(destination, ...target.split('/')));
}
};
}
const create = async (argv) => {
const { name } = argv;
const isMashup = argv._.includes('mashup');
const projectFolder = name;
const packageName = name.split('/').slice(-1)[0];
const cwd = process.cwd();
const templatesRoot = path.resolve(moduleDir, '..', 'templates');
const destination = path.resolve(cwd, projectFolder);
let options = {
install: true,
...argv,
pkgm: argv.pkgm || ((await hasYarn()) ? 'yarn' : 'npm'),
author: argv.author ? parseAuthor(argv.author) : await author(),
};
const results = {};
if (await fse.exists(destination)) {
console.error(chalk.red(`Oopsie, looks like '${projectFolder}' already exists. Try a different name.`));
process.exit(1);
}
const prompt = async () => {
if (!isMashup && !argv.picasso) {
const picasso = await select({
message: 'Pick a picasso template',
default: 'none',
choices: [
{ name: 'none', value: 'none' },
{ name: 'minimal', value: 'minimal' },
{ name: 'barchart', value: 'barchart' },
],
});
options = { ...options, picasso };
}
};
const write = async () => {
console.log('\n');
console.log('> Begin generating files...');
const { picasso } = options;
fse.ensureDirSync(destination);
const copy = copyFactory(templatesRoot, destination);
// ==== template files ====
const folders = ['common'];
if (isMashup) {
folders.push('mashup');
} else {
folders.push('sn/common');
if (picasso !== 'none') {
folders.push('sn/picasso/common');
folders.push(`sn/picasso/${picasso}`);
} else {
folders.push('sn/none');
}
}
const data = {
name: packageName,
description: '',
user: options.author.name,
email: options.author.email,
nebulaVersion: pkg.version,
};
const traverse = (sourceFolder, targetFolder = '') => {
const files = fs.readdirSync(path.resolve(templatesRoot, sourceFolder));
files.forEach((file) => {
const p = `${sourceFolder}/${file}`;
const stats = fs.lstatSync(path.resolve(templatesRoot, p));
const next = `${targetFolder}/${file}`.replace(/^\//, '');
if (stats.isDirectory()) {
fse.ensureDirSync(path.resolve(destination, next));
traverse(p, next);
} else if (file[0] === '_') {
const newFileName = file === '_package.json' ? 'package.json' : `.${file.substr(1)}`;
copy(`${sourceFolder}/${file}`, `${targetFolder}/${newFileName}`.replace(/^\//, ''), data);
} else {
copy(`${sourceFolder}/${file}`, next, data);
}
});
};
folders.forEach((folder) => {
traverse(folder);
});
};
const install = async () => {
if (options.install !== false) {
console.log('> Installing dependencies...');
console.log('\n');
const command = `${options.pkgm} install`;
try {
execSync(command, {
cwd: destination,
stdio: 'inherit',
});
console.log('\n');
} catch (e) {
console.log('\n');
console.log(`> Something went wrong when running ${chalk.yellow(command)}, try running the command yourself.`);
results.fail = true;
results.failedInstall = true;
}
}
};
const end = async () => {
const p = options.pkgm;
if (!results.fail) {
console.log(`> Successfully created project ${chalk.yellow(options.name)}`);
}
console.log('> Get started with the following commands:');
console.log('\n');
console.log(chalk.cyan(` cd ${projectFolder}`));
if (options.install === false || results.failedInstall) {
console.log(chalk.cyan(` ${p} install`));
}
console.log(chalk.cyan(` ${p} run start`));
console.log('\n');
};
await prompt();
await write();
await install();
await end();
};
export default create;