{"version":3,"file":"utils-CvmDmCVd.mjs","sources":["../src/utils.ts"],"sourcesContent":["import type { PowerhouseConfig } from \"@powerhousedao/config\";\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport path, { dirname } from \"node:path\";\nexport const POWERHOUSE_CONFIG_FILE = \"powerhouse.config.json\";\nexport const POWERHOUSE_GLOBAL_DIR = path.join(homedir(), \".ph\");\nexport const SUPPORTED_PACKAGE_MANAGERS = [\"npm\", \"yarn\", \"pnpm\", \"bun\"];\n\nexport const packageManagers = {\n  bun: {\n    globalPathRegexp: /[\\\\/].bun[\\\\/]/,\n    installCommand: \"bun add {{dependency}}\",\n    uninstallCommand: \"bun remove {{dependency}}\",\n    workspaceOption: \"\",\n    lockfile: \"bun.lock\",\n    updateCommand: \"bun update {{dependency}}\",\n    buildAffected: \"bun run build:affected\",\n  },\n  pnpm: {\n    globalPathRegexp: /[\\\\/]pnpm[\\\\/]/,\n    installCommand: \"pnpm add {{dependency}}\",\n    uninstallCommand: \"pnpm remove {{dependency}}\",\n    workspaceOption: \"--workspace-root\",\n    lockfile: \"pnpm-lock.yaml\",\n    updateCommand: \"pnpm update {{dependency}}\",\n    buildAffected: \"pnpm run build:affected\",\n  },\n  yarn: {\n    globalPathRegexp: /[\\\\/]yarn[\\\\/]/,\n    installCommand: \"yarn add {{dependency}}\",\n    uninstallCommand: \"yarn remove {{dependency}}\",\n    workspaceOption: \"-W\",\n    lockfile: \"yarn.lock\",\n    updateCommand: \"yarn upgrade {{dependency}}\",\n    buildAffected: \"yarn run build:affected\",\n  },\n  npm: {\n    installCommand: \"npm install {{dependency}}\",\n    uninstallCommand: \"npm uninstall {{dependency}}\",\n    workspaceOption: \"\",\n    lockfile: \"package-lock.json\",\n    updateCommand: \"npm update {{dependency}} --save\",\n    buildAffected: \"npm run build:affected\",\n  },\n};\n\ntype PathValidation = (dir: string) => boolean;\n\nexport type PackageManager = \"npm\" | \"yarn\" | \"pnpm\" | \"bun\";\n\nexport type ProjectInfo = {\n  isGlobal: boolean;\n  path: string;\n  packageManager: PackageManager;\n};\n\nexport function defaultPathValidation() {\n  return true;\n}\n\nexport function isPowerhouseProject(dir: string) {\n  const powerhouseConfigPath = path.join(dir, POWERHOUSE_CONFIG_FILE);\n\n  return fs.existsSync(powerhouseConfigPath);\n}\n\nexport function findNodeProjectRoot(\n  dir: string,\n  pathValidation: PathValidation = defaultPathValidation,\n) {\n  const packageJsonPath = path.join(dir, \"package.json\");\n\n  if (fs.existsSync(packageJsonPath) && pathValidation(dir)) {\n    return dir;\n  }\n\n  const parentDir = dirname(dir);\n\n  if (parentDir === dir) {\n    return null;\n  }\n\n  return findNodeProjectRoot(parentDir, pathValidation);\n}\n\nexport function getProjectInfo(debug?: boolean): ProjectInfo {\n  const currentPath = process.cwd();\n\n  if (debug) {\n    console.log(\">>> currentPath\", currentPath);\n  }\n\n  const projectPath = findNodeProjectRoot(currentPath, isPowerhouseProject);\n\n  if (!projectPath) {\n    return {\n      isGlobal: true,\n      path: POWERHOUSE_GLOBAL_DIR,\n      packageManager: getPackageManagerFromLockfile(POWERHOUSE_GLOBAL_DIR),\n    };\n  }\n\n  return {\n    isGlobal: false,\n    path: projectPath,\n    packageManager: getPackageManagerFromLockfile(projectPath),\n  };\n}\n\n/**\n * Generates a unique drive ID based on the project path.\n * The same project path will always generate the same ID.\n * @param name - The name prefix for the drive ID (e.g., \"vetra\", \"powerhouse\")\n * @returns A unique drive ID in the format \"{name}-{hash}\"\n */\nexport function generateProjectDriveId(name: string): string {\n  const projectInfo = getProjectInfo();\n  const hash = crypto\n    .createHash(\"sha256\")\n    .update(projectInfo.path)\n    .digest(\"hex\");\n  const shortHash = hash.substring(0, 8);\n  return `${name}-${shortHash}`;\n}\n\nexport function getPackageManagerFromLockfile(dir: string): PackageManager {\n  if (fs.existsSync(path.join(dir, packageManagers.pnpm.lockfile))) {\n    return \"pnpm\";\n  } else if (fs.existsSync(path.join(dir, packageManagers.yarn.lockfile))) {\n    return \"yarn\";\n  } else if (fs.existsSync(path.join(dir, packageManagers.bun.lockfile))) {\n    return \"bun\";\n  }\n\n  return \"npm\";\n}\n\nexport function updatePackagesArray(\n  currentPackages: PowerhouseConfig[\"packages\"] = [],\n  dependencies: { name: string; version: string | undefined }[],\n  task: \"install\" | \"uninstall\" = \"install\",\n  provider: \"registry\" | \"local\" = \"registry\",\n): PowerhouseConfig[\"packages\"] {\n  const isInstall = task === \"install\";\n  const mappedPackages = dependencies.map((dep) => ({\n    packageName: dep.name,\n    version: dep.version,\n    provider,\n  }));\n\n  if (isInstall) {\n    // Overwrite existing package if version is different\n    const filteredPackages = currentPackages.filter(\n      (pkg) => !dependencies.find((dep) => dep.name === pkg.packageName),\n    );\n    return [...filteredPackages, ...mappedPackages];\n  }\n\n  return currentPackages.filter(\n    (pkg) => !dependencies.map((dep) => dep.name).includes(pkg.packageName),\n  );\n}\n\n// Modify updateConfigFile to use the new function\nexport function updateConfigFile(\n  dependencies: { name: string; version: string | undefined }[],\n  projectPath: string,\n  task: \"install\" | \"uninstall\" = \"install\",\n  provider: \"registry\" | \"local\" = \"registry\",\n  registryUrl?: string,\n  registryUrlExplicit = false,\n) {\n  const configPath = path.join(projectPath, POWERHOUSE_CONFIG_FILE);\n\n  if (!fs.existsSync(configPath)) {\n    throw new Error(\n      `powerhouse.config.json file not found. projectPath: ${projectPath}`,\n    );\n  }\n\n  const config = JSON.parse(\n    fs.readFileSync(configPath, \"utf-8\"),\n  ) as PowerhouseConfig;\n\n  const updatedConfig: PowerhouseConfig = {\n    ...config,\n    packages: updatePackagesArray(\n      config.packages,\n      dependencies,\n      task,\n      provider,\n    ),\n  };\n\n  if (\n    task === \"install\" &&\n    registryUrl &&\n    (registryUrlExplicit || !config.packageRegistryUrl) &&\n    dependencies.length > 0\n  ) {\n    updatedConfig.packageRegistryUrl = registryUrl;\n  }\n\n  fs.writeFileSync(configPath, JSON.stringify(updatedConfig, null, 2));\n}\n\n/**\n * Recursively searches for a specific file by traversing up the directory tree.\n * Starting from the given path, it checks each parent directory until it finds\n * the target file or reaches the root directory.\n *\n * @param startPath - The absolute path of the directory to start searching from\n * @param targetFile - The name of the file to search for (e.g., 'package.json', 'pnpm-workspace.yaml')\n * @returns The absolute path of the directory containing the target file, or null if not found\n *\n * @example\n * // Find the workspace root directory\n * const workspaceRoot = findContainerDirectory('/path/to/project/src', 'pnpm-workspace.yaml');\n *\n * // Find the nearest package.json\n * const packageDir = findContainerDirectory('/path/to/project/src/components', 'package.json');\n */\nexport const findContainerDirectory = (\n  startPath: string,\n  targetFile: string,\n): string | null => {\n  const filePath = path.join(startPath, targetFile);\n\n  if (fs.existsSync(filePath)) {\n    return startPath;\n  }\n\n  const parentDir = path.dirname(startPath);\n\n  //reached the root directory and haven't found the file\n  if (parentDir === startPath) {\n    return null;\n  }\n\n  return findContainerDirectory(parentDir, targetFile);\n};\n\n/**\n * Updates the styles.css file to include imports for newly installed packages\n * @param dependencies - Array of dependencies that were installed\n * @param projectPath - Path to the project root\n */\nexport function updateStylesFile(\n  dependencies: { name: string; version: string | undefined }[],\n  projectPath: string,\n) {\n  const stylesPath = path.join(projectPath, \"style.css\");\n\n  // Check if styles.css exists\n  if (!fs.existsSync(stylesPath)) {\n    console.warn(\"⚠️ Warning: style.css file not found in project root\");\n    return;\n  }\n\n  const currentStyles = fs.readFileSync(stylesPath, \"utf-8\");\n  let updatedStyles = currentStyles;\n\n  for (const dep of dependencies) {\n    const cssPath = `./node_modules/${dep.name}/dist/style.css`;\n    const fullCssPath = path.join(projectPath, cssPath);\n    const importStatement = `@import '${cssPath}';`;\n\n    // Check if the CSS file exists\n    if (!fs.existsSync(fullCssPath)) {\n      console.warn(`⚠️ Warning: CSS file not found at ${cssPath}`);\n      continue;\n    }\n\n    // Check if import already exists\n    if (currentStyles.includes(importStatement)) {\n      continue;\n    }\n\n    // Find the last @import statement\n    const importLines = currentStyles\n      .split(\"\\n\")\n      .filter((line) => line.trim().startsWith(\"@import\"));\n    const lastImport = importLines[importLines.length - 1];\n\n    if (lastImport) {\n      // Insert new import after the last existing import\n      updatedStyles = currentStyles.replace(\n        lastImport,\n        `${lastImport}\\n${importStatement}`,\n      );\n    } else {\n      // If no imports exist, add at the top of the file\n      updatedStyles = `${importStatement}\\n${currentStyles}`;\n    }\n  }\n\n  // Only write if changes were made\n  if (updatedStyles !== currentStyles) {\n    fs.writeFileSync(stylesPath, updatedStyles);\n  }\n}\n\n/**\n * Removes CSS imports for uninstalled packages from styles.css\n */\nexport function removeStylesImports(\n  dependencies: { name: string; version: string | undefined }[],\n  projectPath: string,\n) {\n  const stylesPath = path.join(projectPath, \"style.css\");\n\n  // Check if styles.css exists\n  if (!fs.existsSync(stylesPath)) {\n    console.warn(\"⚠️ Warning: style.css file not found in project root\");\n    return;\n  }\n\n  const currentStyles = fs.readFileSync(stylesPath, \"utf-8\");\n  let updatedStyles = currentStyles;\n\n  for (const dep of dependencies) {\n    const cssPath = `./node_modules/${dep.name}/dist/style.css`;\n    const importStatement = `@import '${cssPath}';`;\n\n    // Remove the import line if it exists\n    const lines = updatedStyles.split(\"\\n\");\n    const filteredLines = lines.filter(\n      (line) => !line.trim().includes(importStatement),\n    );\n\n    if (filteredLines.length !== lines.length) {\n      updatedStyles = filteredLines.join(\"\\n\");\n    }\n  }\n\n  // Only write if changes were made\n  if (updatedStyles !== currentStyles) {\n    fs.writeFileSync(stylesPath, updatedStyles);\n  }\n}\n"],"names":[],"mappings":"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","debug_id":"fa6f49e1-f268-5ae2-8e22-cc7adc8fbfba"}