{"version":3,"file":"listGitFiles.mjs","names":[],"sources":["../../src/listGitFiles.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { log } from '@intlayer/config/built';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport simpleGit from 'simple-git';\n\nexport type DiffMode = 'gitDiff' | 'uncommitted' | 'unpushed' | 'untracked';\n\nconst getGitRootDir = async (): Promise<string | null> => {\n  try {\n    const git = simpleGit();\n    const rootDir = await git.revparse(['--show-toplevel']);\n    return rootDir.trim();\n  } catch (error) {\n    const appLogger = getAppLogger({ log });\n    appLogger(`Error getting git root directory: ${error}`, {\n      level: 'error',\n    });\n    return null;\n  }\n};\n\nexport type ListGitFilesOptions = {\n  mode: DiffMode[];\n  baseRef?: string;\n  currentRef?: string;\n  absolute?: boolean;\n};\n\nexport const listGitFiles = async ({\n  mode,\n  baseRef = 'origin/main',\n  currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n  absolute = true,\n}: ListGitFilesOptions) => {\n  try {\n    const git = simpleGit();\n    const diff: Set<string> = new Set();\n\n    if (mode.includes('untracked')) {\n      const status = await git.status();\n      status.not_added.forEach((file) => {\n        diff.add(file);\n      });\n    }\n\n    if (mode.includes('uncommitted')) {\n      // Get uncommitted changes\n      const uncommittedDiff = await git.diff(['--name-only', 'HEAD']);\n\n      const uncommittedFiles = uncommittedDiff.split('\\n').filter(Boolean);\n\n      uncommittedFiles.forEach((file) => {\n        diff.add(file);\n      });\n    }\n\n    if (mode.includes('unpushed')) {\n      // Get unpushed commits\n      const unpushedDiff = await git.diff(['--name-only', '@{push}...HEAD']);\n\n      const unpushedFiles = unpushedDiff.split('\\n').filter(Boolean);\n\n      unpushedFiles.forEach((file) => {\n        diff.add(file);\n      });\n    }\n\n    if (mode.includes('gitDiff')) {\n      // Get the base branch (usually main/master) from CI environment\n\n      await git.fetch(baseRef);\n\n      const diffBranch = await git.diff([\n        '--name-only',\n        `${baseRef}...${currentRef}`,\n      ]);\n\n      const gitDiffFiles = diffBranch.split('\\n').filter(Boolean);\n\n      gitDiffFiles.forEach((file) => {\n        diff.add(file);\n      });\n    }\n\n    if (absolute) {\n      const gitRootDir = await getGitRootDir();\n      if (!gitRootDir) {\n        return [];\n      }\n      return Array.from(diff).map((file) => join(gitRootDir, file));\n    }\n\n    return Array.from(diff);\n  } catch (error) {\n    console.warn('Failed to get changes list:', error);\n  }\n};\n\nexport type ListGitLinesOptions = {\n  mode: DiffMode[];\n  baseRef?: string;\n  currentRef?: string;\n};\n\nexport const listGitLines = async (\n  filePath: string,\n  {\n    mode,\n    baseRef = 'origin/main',\n    currentRef = 'HEAD', // HEAD points to the current branch's latest commit\n  }: ListGitLinesOptions\n): Promise<number[]> => {\n  const git = simpleGit();\n  // We collect **line numbers** (1-based) that were modified/added by the diff.\n  // Using a Set ensures uniqueness when the same line is reported by several modes.\n  const changedLines: Set<number> = new Set();\n\n  /**\n   * Extracts line numbers from a diff generated with `--unified=0`.\n   * Each hunk header looks like: @@ -<oldStart>,<oldCount> +<newStart>,<newCount> @@\n   * We consider both the \"+\" (new) side for additions and the \"-\" (old) side for deletions.\n   * For deletions, we add the line before and after the deletion point in the current file.\n   */\n  const collectLinesFromDiff = (diffOutput: string) => {\n    const hunkRegex = /@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@/g;\n    let match: RegExpExecArray | null;\n\n    // biome-ignore lint/suspicious/noAssignInExpressions: Used in while loop condition\n    while ((match = hunkRegex.exec(diffOutput)) !== null) {\n      const oldCount = match[2] ? Number(match[2]) : 1;\n      const newStart = Number(match[3]);\n      const newCount = match[4] ? Number(match[4]) : 1;\n\n      // Handle additions/modifications (+ side)\n      if (newCount > 0) {\n        for (let i = 0; i < newCount; i++) {\n          changedLines.add(newStart + i);\n        }\n      }\n\n      // Handle deletions (- side)\n      if (oldCount > 0 && newCount === 0) {\n        // For deletions, add the line before and after the deletion point\n        // The deletion point in the new file is at newStart\n        if (newStart > 1) {\n          changedLines.add(newStart - 1); // Line before deletion\n        }\n        changedLines.add(newStart); // Line after deletion (if it exists)\n      }\n    }\n  };\n\n  // 1. Handle untracked files – when a file is untracked its entire content is new.\n  if (mode.includes('untracked')) {\n    const status = await git.status();\n    const isUntracked = status.not_added.includes(filePath);\n    if (isUntracked) {\n      try {\n        const content = readFileSync(filePath, 'utf-8');\n        content.split('\\n').forEach((_, idx) => {\n          changedLines.add(idx + 1);\n        });\n      } catch {\n        // ignore read errors – file may have been deleted, etc.\n      }\n    }\n  }\n\n  // 2. Uncommitted changes (working tree vs HEAD)\n  if (mode.includes('uncommitted')) {\n    const diffOutput = await git.diff(['--unified=0', 'HEAD', '--', filePath]);\n    collectLinesFromDiff(diffOutput);\n  }\n\n  // 3. Unpushed commits – compare local branch to its upstream\n  if (mode.includes('unpushed')) {\n    const diffOutput = await git.diff([\n      '--unified=0',\n      '@{push}...HEAD',\n      '--',\n      filePath,\n    ]);\n    collectLinesFromDiff(diffOutput);\n  }\n\n  // 4. Regular git diff between baseRef and currentRef (e.g., CI pull-request diff)\n  if (mode.includes('gitDiff')) {\n    await git.fetch(baseRef);\n    const diffOutput = await git.diff([\n      '--unified=0',\n      `${baseRef}...${currentRef}`,\n      '--',\n      filePath,\n    ]);\n    collectLinesFromDiff(diffOutput);\n  }\n\n  // Return the list sorted for convenience\n  return Array.from(changedLines).sort((a, b) => a - b);\n};\n"],"mappings":"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"}