@ressjs/create-ress-app
Version:
CLI tool for creating ress.js applications
224 lines (223 loc) ⢠9.41 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createApp = createApp;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const inquirer_1 = __importDefault(require("inquirer"));
const child_process_1 = require("child_process");
const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
async function createApp(projectName, options = {
template: 'basic',
typescript: true
}) {
// Get project name if not provided
if (!projectName) {
const { name } = await inquirer_1.default.prompt([
{
type: 'input',
name: 'name',
message: 'What is your project name?',
default: 'my-ress-app',
validate: (input) => {
const validation = (0, validate_npm_package_name_1.default)(input);
if (!validation.validForNewPackages) {
return validation.errors?.[0] || validation.warnings?.[0] || 'Invalid package name';
}
return true;
}
}
]);
projectName = name;
}
// Ensure projectName is defined
if (!projectName) {
throw new Error('Project name is required');
}
// Validate project name
const validation = (0, validate_npm_package_name_1.default)(projectName);
if (!validation.validForNewPackages) {
throw new Error(`Invalid project name: ${validation.errors?.[0] || validation.warnings?.[0]}`);
}
const projectPath = path_1.default.resolve(process.cwd(), projectName);
// Check if directory already exists
if (await fs_extra_1.default.pathExists(projectPath)) {
const { overwrite } = await inquirer_1.default.prompt([
{
type: 'confirm',
name: 'overwrite',
message: `Directory ${projectName} already exists. Overwrite?`,
default: false
}
]);
if (!overwrite) {
console.log(chalk_1.default.yellow('š¦ Operation cancelled.'));
return;
}
await fs_extra_1.default.remove(projectPath);
}
// Use basic template always
let { template } = options;
template = 'basic';
// Use TypeScript always
let { typescript } = options;
typescript = true;
console.log(chalk_1.default.blue(`\\nš Creating project in ${projectPath}...`));
// Copy template
await copyTemplate(template, projectPath, { typescript });
// Update package.json with project name
await updatePackageJson(projectPath, projectName);
console.log(chalk_1.default.green(`ā
Project ${projectName} created successfully!`));
// Install dependencies
if (!options.skipInstall) {
console.log(chalk_1.default.blue('\\nš¦ Installing dependencies...'));
await installDependencies(projectPath);
console.log(chalk_1.default.green('ā
Dependencies installed!'));
}
// Show next steps
showNextSteps(projectName, options.skipInstall);
}
async function copyTemplate(template, targetPath, options) {
const templatesPath = path_1.default.join(__dirname, '../templates');
const templatePath = path_1.default.join(templatesPath, template);
if (!await fs_extra_1.default.pathExists(templatePath)) {
throw new Error(`Template "${template}" not found`);
}
// Copy all files
await fs_extra_1.default.copy(templatePath, targetPath);
}
async function convertToJavaScript(projectPath) {
const glob = await Promise.resolve().then(() => __importStar(require('fast-glob')));
// Find all TypeScript files
const tsFiles = await glob.default(['**/*.ts', '**/*.tsx'], {
cwd: projectPath,
ignore: ['node_modules/**', 'dist/**']
});
for (const file of tsFiles) {
const fullPath = path_1.default.join(projectPath, file);
let content = await fs_extra_1.default.readFile(fullPath, 'utf-8');
// Basic TypeScript to JavaScript conversion
content = convertTsToJs(content);
// Rename file extension
const newPath = fullPath
.replace(/\.tsx?$/, match => match === '.tsx' ? '.jsx' : '.js');
await fs_extra_1.default.writeFile(newPath, content);
// Remove original TypeScript file if name changed
if (newPath !== fullPath) {
await fs_extra_1.default.unlink(fullPath);
}
}
// Update package.json to remove TypeScript dependencies and scripts
const packageJsonPath = path_1.default.join(projectPath, 'package.json');
const packageJson = await fs_extra_1.default.readJson(packageJsonPath);
// Remove TypeScript-specific dependencies
if (packageJson.devDependencies) {
delete packageJson.devDependencies.typescript;
delete packageJson.devDependencies['@types/node'];
delete packageJson.devDependencies['@types/react'];
delete packageJson.devDependencies['@types/react-dom'];
delete packageJson.devDependencies['@types/express'];
}
await fs_extra_1.default.writeJson(packageJsonPath, packageJson, { spaces: 2 });
// Remove TypeScript config files
const configFiles = ['tsconfig.json', 'tsconfig.node.json'];
for (const configFile of configFiles) {
const configPath = path_1.default.join(projectPath, configFile);
if (await fs_extra_1.default.pathExists(configPath)) {
await fs_extra_1.default.unlink(configPath);
}
}
}
function convertTsToJs(content) {
// Remove type annotations and interfaces
content = content
// Remove import type statements
.replace(/import\s+type\s+\{[^}]*\}\s+from\s+[^;]+;?\s*\n?/g, '')
// Remove interface declarations
.replace(/interface\s+\w+\s*\{[^}]*\}\s*\n?/g, '')
// Remove type annotations from function parameters
.replace(/(\w+):\s*[\w\[\]|<>{}.,\s]+(\s*[,)])/g, '$1$2')
// Remove return type annotations
.replace(/\):\s*[\w\[\]|<>{}.,\s]+(\s*[{=>])/g, ')$1')
// Remove variable type annotations
.replace(/:\s*[\w\[\]|<>{}.,\s]+(\s*[=;])/g, '$1')
// Remove generic type parameters
.replace(/<[\w\[\]|<>{}.,\s]*>/g, '')
// Remove 'as' type assertions
.replace(/\s+as\s+[\w\[\]|<>{}.,\s]+/g, '')
// Remove optional property indicators
.replace(/(\w+)\?\s*:/g, '$1:')
// Clean up extra whitespace
.replace(/\n\s*\n\s*\n/g, '\n\n');
return content;
}
async function updatePackageJson(projectPath, projectName) {
const packageJsonPath = path_1.default.join(projectPath, 'package.json');
const packageJson = await fs_extra_1.default.readJson(packageJsonPath);
packageJson.name = projectName;
packageJson.private = true;
await fs_extra_1.default.writeJson(packageJsonPath, packageJson, { spaces: 2 });
}
async function installDependencies(projectPath) {
return new Promise((resolve, reject) => {
const npm = (0, child_process_1.spawn)('npm', ['install'], {
cwd: projectPath,
stdio: 'inherit'
});
npm.on('close', (code) => {
if (code === 0) {
resolve();
}
else {
reject(new Error(`npm install failed with code ${code}`));
}
});
npm.on('error', (error) => {
reject(error);
});
});
}
function showNextSteps(projectName, skipInstall) {
console.log(chalk_1.default.blue('\\nš Get started with:'));
console.log(chalk_1.default.gray(` cd ${projectName}`));
if (skipInstall) {
console.log(chalk_1.default.gray(' npm install'));
}
console.log(chalk_1.default.gray(' npm run dev'));
}
;