This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user