project.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import { existsSync, readFileSync, writeFileSync } from "fs";
  6. import path from "path";
  7. import { getLatestVersion } from "./npm";
  8. import chalk from "chalk";
  9. interface PackageJson {
  10. dependencies: { [key: string]: string };
  11. devDependencies?: { [key: string]: string };
  12. peerDependencies?: { [key: string]: string };
  13. [key: string]: any;
  14. }
  15. export class Project {
  16. flowgramVersion?: string;
  17. projectPath: string;
  18. packageJsonPath: string;
  19. packageJson: PackageJson;
  20. srcPath: string;
  21. protected constructor() {}
  22. async init() {
  23. // get nearest package.json
  24. let projectPath: string = process.cwd();
  25. while (
  26. projectPath !== "/" &&
  27. !existsSync(path.join(projectPath, "package.json"))
  28. ) {
  29. projectPath = path.join(projectPath, "..");
  30. }
  31. if (projectPath === "/") {
  32. throw new Error("Please run this command in a valid project");
  33. }
  34. this.projectPath = projectPath;
  35. this.srcPath = path.join(projectPath, "src");
  36. this.packageJsonPath = path.join(projectPath, "package.json");
  37. this.packageJson = JSON.parse(readFileSync(this.packageJsonPath, "utf8"));
  38. this.flowgramVersion =
  39. this.packageJson.dependencies["@flowgram.ai/fixed-layout-editor"] ||
  40. this.packageJson.dependencies["@flowgram.ai/free-layout-editor"] ||
  41. this.packageJson.dependencies["@flowgram.ai/editor"];
  42. }
  43. async addDependency(dependency: string) {
  44. let name: string;
  45. let version: string;
  46. // 处理作用域包(如 @types/react@1.0.0)
  47. const lastAtIndex = dependency.lastIndexOf("@");
  48. if (lastAtIndex <= 0) {
  49. // 没有@符号 或者@在开头(如 @types/react)
  50. name = dependency;
  51. version = await getLatestVersion(name);
  52. } else {
  53. // 正常分割包名和版本
  54. name = dependency.substring(0, lastAtIndex);
  55. version = dependency.substring(lastAtIndex + 1);
  56. // 如果版本部分为空,获取最新版本
  57. if (!version.trim()) {
  58. version = await getLatestVersion(name);
  59. }
  60. }
  61. this.packageJson.dependencies[name] = version;
  62. writeFileSync(
  63. this.packageJsonPath,
  64. JSON.stringify(this.packageJson, null, 2),
  65. );
  66. }
  67. async addDependencies(dependencies: string[]) {
  68. for (const dependency of dependencies) {
  69. await this.addDependency(dependency);
  70. }
  71. }
  72. writeToPackageJsonFile() {
  73. writeFileSync(
  74. this.packageJsonPath,
  75. JSON.stringify(this.packageJson, null, 2),
  76. );
  77. }
  78. printInfo() {
  79. console.log(chalk.bold("Project Info:"));
  80. console.log(chalk.black(` - Flowgram Version: ${this.flowgramVersion}`));
  81. console.log(chalk.black(` - Project Path: ${this.projectPath}`));
  82. }
  83. static async getSingleton() {
  84. const info = new Project();
  85. await info.init();
  86. return info;
  87. }
  88. }