Files
bytedance--flowgram.ai/apps/cli/src/create-app/index.ts
T
wehub-resource-sync 0232b4e2bb
CI / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:09:51 +08:00

163 lines
4.7 KiB
TypeScript

/**
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import https from 'https';
import { execSync } from 'child_process';
import * as tar from 'tar';
import inquirer from 'inquirer';
import fs from 'fs-extra';
import chalk from 'chalk';
const updateFlowGramVersions = (dependencies: any[], latestVersion: string) => {
for (const packageName in dependencies) {
if (packageName.startsWith('@flowgram.ai')) {
dependencies[packageName] = latestVersion;
}
}
};
// 使用 https 下载文件
function downloadFile(url: string, dest: string): Promise<void> {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
https
.get(url, (response) => {
if (response.statusCode !== 200) {
reject(new Error(`Download failed: ${response.statusCode}`));
return;
}
response.pipe(file);
file.on('finish', () => {
file.close();
resolve();
});
})
.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
file.on('error', (err) => {
fs.unlink(dest, () => reject(err));
});
});
}
export const createApp = async (projectName?: string) => {
console.log(chalk.green('Welcome to @flowgram.ai/create-app CLI!'));
const latest = execSync('npm view @flowgram.ai/demo-fixed-layout version --tag=latest latest')
.toString()
.trim();
let folderName = '';
if (!projectName) {
// 询问用户选择 demo 项目
const { repo } = await inquirer.prompt([
{
type: 'list',
name: 'repo',
message: 'Select a demo to create:',
choices: [
{ name: 'Fixed Layout Demo', value: 'demo-fixed-layout' },
{ name: 'Free Layout Demo', value: 'demo-free-layout' },
{ name: 'Fixed Layout Demo Simple', value: 'demo-fixed-layout-simple' },
{ name: 'Free Layout Demo Simple', value: 'demo-free-layout-simple' },
{ name: 'Free Layout Nextjs Demo', value: 'demo-nextjs' },
{ name: 'Free Layout Vite Demo Simple', value: 'demo-vite' },
{ name: 'Demo Playground for infinite canvas', value: 'demo-playground' },
],
},
]);
folderName = repo;
} else {
if (
[
'fixed-layout',
'free-layout',
'fixed-layout-simple',
'free-layout-simple',
'playground',
'nextjs',
].includes(projectName)
) {
folderName = `demo-${projectName}`;
} else {
console.error('Invalid projectName. Please run "npx create-app" to choose demo.');
return;
}
}
try {
const targetDir = path.join(process.cwd());
// 下载 npm 包的 tarball
const downloadPackage = async () => {
try {
const url = `https://registry.npmjs.org/@flowgram.ai/${folderName}/-/${folderName}-${latest}.tgz`;
const tempTarballPath = path.join(process.cwd(), `${folderName}.tgz`);
console.log(chalk.blue(`Downloading ${url} ...`));
await downloadFile(url, tempTarballPath);
fs.ensureDirSync(targetDir);
await tar.x({
file: tempTarballPath,
C: targetDir,
});
fs.renameSync(path.join(targetDir, 'package'), path.join(targetDir, folderName));
fs.unlinkSync(tempTarballPath);
return true;
} catch (error) {
console.error(`Error downloading or extracting package`);
console.error(error);
return false;
}
};
const res = await downloadPackage();
// 替换 package.json 内部的 @flowgram.ai 包版本为 latest
const pkgJsonPath = path.join(targetDir, folderName, 'package.json');
const data = fs.readFileSync(pkgJsonPath, 'utf-8');
const packageLatestVersion = execSync('npm view @flowgram.ai/core version --tag=latest latest')
.toString()
.trim();
const jsonData = JSON.parse(data);
if (jsonData.dependencies) {
updateFlowGramVersions(jsonData.dependencies, packageLatestVersion);
}
if (jsonData.devDependencies) {
updateFlowGramVersions(jsonData.devDependencies, packageLatestVersion);
}
fs.writeFileSync(pkgJsonPath, JSON.stringify(jsonData, null, 2), 'utf-8');
if (res) {
console.log(chalk.green(`${folderName} Demo project created successfully!`));
console.log(chalk.yellow('Run the following commands to start:'));
console.log(chalk.cyan(` cd ${folderName}`));
console.log(chalk.cyan(' npm install'));
console.log(chalk.cyan(' npm start'));
} else {
console.log(chalk.red('Download failed'));
}
} catch (error) {
console.error('Error downloading repo:', error);
return;
}
};