index.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import path from 'path';
  6. import { execSync } from 'child_process';
  7. import inquirer from 'inquirer';
  8. import fs from 'fs-extra';
  9. import { Command } from 'commander';
  10. import chalk from 'chalk';
  11. import * as tar from 'tar';
  12. import https from 'https';
  13. import http from 'http';
  14. const program = new Command();
  15. const args = process.argv.slice(2);
  16. const updateFlowGramVersions = (dependencies: any[], latestVersion: string) => {
  17. for (const packageName in dependencies) {
  18. if (packageName.startsWith('@flowgram.ai')) {
  19. dependencies[packageName] = latestVersion;
  20. }
  21. }
  22. };
  23. // 使用 http/https 下载文件
  24. function downloadFile(url: string, dest: string): Promise<void> {
  25. return new Promise((resolve, reject) => {
  26. const lib = url.startsWith('https') ? https : http;
  27. const file = fs.createWriteStream(dest);
  28. const request = lib.get(url, (response) => {
  29. if (response.statusCode !== 200) {
  30. reject(new Error(`Download failed: ${response.statusCode}`));
  31. return;
  32. }
  33. response.pipe(file);
  34. file.on('finish', () => {
  35. file.close();
  36. resolve();
  37. });
  38. });
  39. request.on('error', (err) => {
  40. fs.unlink(dest, () => reject(err));
  41. });
  42. file.on('error', (err) => {
  43. fs.unlink(dest, () => reject(err));
  44. });
  45. });
  46. }
  47. const main = async () => {
  48. console.log(chalk.green('Welcome to @flowgram.ai/create-app CLI!123123'));
  49. const latest = execSync(
  50. 'npm view @flowgram.ai/demo-fixed-layout version --tag=latest latest'
  51. )
  52. .toString()
  53. .trim();
  54. let folderName = '';
  55. if (!args?.length) {
  56. const { repo } = await inquirer.prompt([
  57. {
  58. type: 'list',
  59. name: 'repo',
  60. message: 'Select a demo to create:',
  61. choices: [
  62. { name: 'Fixed Layout Demo', value: 'demo-fixed-layout' },
  63. { name: 'Free Layout Demo', value: 'demo-free-layout' },
  64. { name: 'Fixed Layout Demo Simple', value: 'demo-fixed-layout-simple' },
  65. { name: 'Free Layout Demo Simple', value: 'demo-free-layout-simple' },
  66. { name: 'Free Layout Nextjs Demo', value: 'demo-nextjs' },
  67. { name: 'Free Layout Vite Demo Simple', value: 'demo-vite' },
  68. { name: 'Demo Playground for infinite canvas', value: 'demo-playground' },
  69. ],
  70. },
  71. ]);
  72. folderName = repo;
  73. } else {
  74. if (
  75. [
  76. 'fixed-layout',
  77. 'free-layout',
  78. 'fixed-layout-simple',
  79. 'free-layout-simple',
  80. 'playground',
  81. 'nextjs',
  82. ].includes(args[0])
  83. ) {
  84. folderName = `demo-${args[0]}`;
  85. } else {
  86. console.error('Invalid argument. Please run "npx create-app" to choose demo.');
  87. return;
  88. }
  89. }
  90. try {
  91. const targetDir = path.join(process.cwd());
  92. const downloadPackage = async () => {
  93. try {
  94. const tempTarballPath = path.join(process.cwd(), `${folderName}.tgz`);
  95. const url = `https://registry.npmjs.org/@flowgram.ai/${folderName}/-/${folderName}-${latest}.tgz`;
  96. console.log(chalk.blue(`Downloading ${url} ...`));
  97. await downloadFile(url, tempTarballPath);
  98. fs.ensureDirSync(targetDir);
  99. await tar.x({
  100. file: tempTarballPath,
  101. C: targetDir,
  102. });
  103. fs.renameSync(path.join(targetDir, 'package'), path.join(targetDir, folderName));
  104. fs.unlinkSync(tempTarballPath);
  105. return true;
  106. } catch (error) {
  107. console.error(`Error downloading or extracting package`);
  108. console.error(error);
  109. return false;
  110. }
  111. };
  112. const res = await downloadPackage();
  113. const pkgJsonPath = path.join(targetDir, folderName, 'package.json');
  114. const data = fs.readFileSync(pkgJsonPath, 'utf-8');
  115. const packageLatestVersion = execSync(
  116. 'npm view @flowgram.ai/core version --tag=latest latest'
  117. )
  118. .toString()
  119. .trim();
  120. const jsonData = JSON.parse(data);
  121. if (jsonData.dependencies) {
  122. updateFlowGramVersions(jsonData.dependencies, packageLatestVersion);
  123. }
  124. if (jsonData.devDependencies) {
  125. updateFlowGramVersions(jsonData.devDependencies, packageLatestVersion);
  126. }
  127. fs.writeFileSync(pkgJsonPath, JSON.stringify(jsonData, null, 2), 'utf-8');
  128. if (res) {
  129. console.log(chalk.green(`${folderName} Demo project created successfully!`));
  130. console.log(chalk.yellow('Run the following commands to start:'));
  131. console.log(chalk.cyan(` cd ${folderName}`));
  132. console.log(chalk.cyan(' npm install'));
  133. console.log(chalk.cyan(' npm start'));
  134. } else {
  135. console.log(chalk.red('Download failed'));
  136. }
  137. } catch (error) {
  138. console.error('Error downloading repo:', error);
  139. return;
  140. }
  141. };
  142. program.version('1.0.0').description('Create a demo project');
  143. program.parse(process.argv);
  144. main();