← back to gregpriday__copytree

Function bodies 337 total

All specs Real LLM only Function bodies
BinaryTransformer.canTransform method · javascript · L210-L217 (8 LOC)
src/transforms/transformers/BinaryTransformer.js
  canTransform(file) {
    // Check if file is marked as binary
    if (file.isBinary) return true;

    // Check extension
    const ext = (file.path || '').toLowerCase().match(/\.[^.]+$/);
    return ext && this.supportedExtensions.includes(ext[0]);
  }
BinaryTransformer.validateInput method · javascript · L219-L225 (7 LOC)
src/transforms/transformers/BinaryTransformer.js
  validateInput(file) {
    super.validateInput(file);

    if (!file.absolutePath && this.config.get('copytree.binaryFileAction') === 'base64') {
      throw new Error('File absolute path is required for base64 encoding');
    }
  }
FileLoaderTransformer.doTransform method · javascript · L15-L66 (52 LOC)
src/transforms/transformers/FileLoaderTransformer.js
  async doTransform(file) {
    // If content is already loaded, return as-is
    if (file.content !== undefined) {
      return file;
    }

    // Load content from disk
    try {
      let content;

      if (file.isBinary) {
        // For binary files, return placeholder or base64 based on config
        const binaryAction = this.config.get('copytree.binaryFileAction', 'placeholder');

        switch (binaryAction) {
          case 'base64': {
            const buffer = await fs.readFile(file.absolutePath);
            content = buffer.toString('base64');
            break;
          }
          case 'skip':
            return null;
          case 'placeholder':
          default:
            content = this.config.get(
              'copytree.binaryPlaceholderText',
              '[Binary file not included]',
            );
        }
      } else {
        // Load text content
        content = await fs.readFile(file.absolutePath, this.encoding);
      }

      return {
        ..
FileLoaderTransformer.validateInput method · javascript · L68-L74 (7 LOC)
src/transforms/transformers/FileLoaderTransformer.js
  validateInput(file) {
    super.validateInput(file);

    if (!file.absolutePath) {
      throw new Error('File absolute path is required');
    }
  }
StreamingFileLoaderTransformer.constructor method · javascript · L10-L16 (7 LOC)
src/transforms/transformers/StreamingFileLoaderTransformer.js
  constructor(options = {}) {
    super(options);
    this.description = 'Loads file content using streams for memory efficiency';
    this.bufferSize = options.bufferSize || 64 * 1024; // 64KB chunks
    this.maxSize = options.maxSize || this.config.get('copytree.maxFileSize', 10 * 1024 * 1024);
    this.encoding = options.encoding || 'utf8';
  }
StreamingFileLoaderTransformer.doTransform method · javascript · L18-L93 (76 LOC)
src/transforms/transformers/StreamingFileLoaderTransformer.js
  async doTransform(file) {
    try {
      // Skip if already has content
      if (file.content !== undefined) {
        return file;
      }

      // Check file size
      const stats = file.stats || (await fs.stat(file.absolutePath));
      if (stats.size > this.maxSize) {
        return {
          ...file,
          content: `[File too large: ${this.formatBytes(stats.size)}]`,
          isBinary: false,
          transformed: true,
          transformedBy: this.constructor.name,
          streamingSkipped: true,
        };
      }

      // Check if binary
      const isBinary = await this.isBinaryFile(file.absolutePath, stats.size);

      if (isBinary) {
        const binaryAction = this.config.get('copytree.binaryFileAction', 'placeholder');

        if (binaryAction === 'skip') {
          return null;
        } else if (binaryAction === 'base64') {
          // Use streaming for base64 encoding
          const content = await this.streamToBase64(file.absolutePath);
        
StreamingFileLoaderTransformer.streamTextFile method · javascript · L98-L110 (13 LOC)
src/transforms/transformers/StreamingFileLoaderTransformer.js
  async streamTextFile(filePath) {
    return new Promise((resolve, reject) => {
      const chunks = [];
      const stream = fs.createReadStream(filePath, {
        encoding: this.encoding,
        highWaterMark: this.bufferSize,
      });

      stream.on('data', (chunk) => chunks.push(chunk));
      stream.on('end', () => resolve(chunks.join('')));
      stream.on('error', reject);
    });
  }
Repobility · MCP-ready · https://repobility.com
StreamingFileLoaderTransformer.streamToBase64 method · javascript · L115-L129 (15 LOC)
src/transforms/transformers/StreamingFileLoaderTransformer.js
  async streamToBase64(filePath) {
    return new Promise((resolve, reject) => {
      const chunks = [];
      const stream = fs.createReadStream(filePath, {
        highWaterMark: this.bufferSize,
      });

      stream.on('data', (chunk) => chunks.push(chunk));
      stream.on('end', () => {
        const buffer = Buffer.concat(chunks);
        resolve(buffer.toString('base64'));
      });
      stream.on('error', reject);
    });
  }
StreamingFileLoaderTransformer.isBinaryFile method · javascript · L134-L231 (98 LOC)
src/transforms/transformers/StreamingFileLoaderTransformer.js
  async isBinaryFile(filePath, size) {
    if (size === 0) return false;

    // Common binary file extensions
    const binaryExtensions = [
      '.exe',
      '.dll',
      '.so',
      '.dylib',
      '.zip',
      '.tar',
      '.gz',
      '.7z',
      '.rar',
      '.pdf',
      '.doc',
      '.docx',
      '.xls',
      '.xlsx',
      '.ppt',
      '.pptx',
      '.odt',
      '.ods',
      '.odp',
      '.jpg',
      '.jpeg',
      '.png',
      '.gif',
      '.bmp',
      '.ico',
      '.svg',
      '.webp',
      '.mp3',
      '.mp4',
      '.avi',
      '.mov',
      '.wmv',
      '.flv',
      '.webm',
      '.mkv',
      '.wav',
      '.flac',
      '.aac',
      '.ogg',
      '.wma',
      '.ttf',
      '.otf',
      '.woff',
      '.woff2',
      '.eot',
      '.pyc',
      '.pyo',
      '.class',
      '.o',
      '.obj',
      '.a',
      '.lib',
      '.pdb',
      '.idb',
      '.jar',
      '.war',
      '.ear',
      '.db',
      '.sqlite',
      '.sqlite3',
    ]
categorizeByExt function · javascript · L114-L120 (7 LOC)
src/utils/BinaryDetector.js
function categorizeByExt(ext) {
  const lower = (ext || '').toLowerCase();
  for (const [cat, list] of Object.entries(CATEGORIES)) {
    if (list.includes(lower)) return cat;
  }
  return null;
}
detect function · javascript · L130-L211 (82 LOC)
src/utils/BinaryDetector.js
export async function detect(filePath, opts = {}) {
  const sampleBytes = opts.sampleBytes ?? 8192;
  const nonPrintableThreshold = opts.nonPrintableThreshold ?? 0.3;

  const ext = path.extname(filePath);
  let category = categorizeByExt(ext);

  // Allocate buffer only for the sample size to avoid loading large files into memory
  const buf = Buffer.alloc(sampleBytes);
  let bytesRead = 0;
  let fd = null;

  try {
    fd = await fs.open(filePath, 'r');
    const result = await fs.read(fd, buf, 0, sampleBytes, 0);
    bytesRead = result.bytesRead;
  } catch (error) {
    // File doesn't exist or can't be read
    return {
      isBinary: false,
      category: 'text',
      reason: 'error',
      ext,
      error: error.message,
    };
  } finally {
    if (fd !== null) {
      await fs.close(fd);
    }
  }

  const sample = buf.subarray(0, bytesRead);

  // Magic number match
  for (const m of MAGIC) {
    const sig = Buffer.from(m.sig);
    if (sample.length >= sig.length && sample
isConvertibleDocument function · javascript · L219-L224 (6 LOC)
src/utils/BinaryDetector.js
export function isConvertibleDocument(category, ext) {
  if (category !== 'document') return false;
  return ['.pdf', '.doc', '.docx', '.odt', '.rtf', '.epub', '.html', '.htm'].includes(
    (ext || '').toLowerCase(),
  );
}
Clipboard.copyFileReference method · javascript · L27-L79 (53 LOC)
src/utils/clipboard.js
  static async copyFileReference(filePath) {
    if (process.platform === 'win32') {
      try {
        // Use Windows Forms SetFileDropList via Base64-encoded PowerShell command.
        // This bypasses all shell quoting (Base64 encoding) and path glob expansion
        // (StringCollection is passed to SetFileDropList without any wildcard interpretation).
        // Single quotes are doubled for the PS single-quoted string literal.
        const psPath = filePath.replace(/'/g, "''");
        const psCommand = [
          'Add-Type -AssemblyName System.Windows.Forms',
          '$fc = New-Object System.Collections.Specialized.StringCollection',
          `[void]$fc.Add('${psPath}')`,
          '[System.Windows.Forms.Clipboard]::SetFileDropList($fc)',
        ].join('; ');
        const encoded = Buffer.from(psCommand, 'utf16le').toString('base64');
        execSync(`powershell -NoProfile -NonInteractive -EncodedCommand ${encoded}`, {
          stdio: 'pipe',
        });
      } catc
Clipboard.revealInFinder method · javascript · L86-L115 (30 LOC)
src/utils/clipboard.js
  static async revealInFinder(filePath) {
    if (process.platform === 'win32') {
      try {
        // Use spawnSync with array args to avoid cmd.exe interpreting &, |, <, >, ^ in paths
        spawnSync('explorer', [`/select,${filePath}`], { stdio: 'pipe' });
      } catch (error) {
        logger.debug('Failed to reveal file in Explorer:', error.message);
      }
    } else if (process.platform === 'linux') {
      try {
        // Use spawnSync with array args to avoid shell interpreting $, ", ` in paths
        const dir = path.dirname(filePath);
        spawnSync('xdg-open', [dir], { stdio: 'pipe' });
      } catch (error) {
        logger.debug('Failed to reveal file with xdg-open:', error.message);
      }
    } else if (process.platform === 'darwin') {
      try {
        // Use AppleScript to reveal file. spawnSync passes the script as a direct
        // argument (no shell), so single quotes in filePath are safe.
        const escapedFilePath = filePath.replace(/\\/g, '\\\\
CopyTreeError.constructor method · javascript · L5-L14 (10 LOC)
src/utils/errors.js
  constructor(message, code = 'UNKNOWN_ERROR', details = {}) {
    super(message);
    this.name = 'CopyTreeError';
    this.code = code;
    this.details = details;
    this.timestamp = new Date().toISOString();

    // Capture stack trace
    Error.captureStackTrace(this, this.constructor);
  }
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
CopyTreeError.toJSON method · javascript · L16-L25 (10 LOC)
src/utils/errors.js
  toJSON() {
    return {
      name: this.name,
      message: this.message,
      code: this.code,
      details: this.details,
      timestamp: this.timestamp,
      stack: this.stack,
    };
  }
FileSystemError.constructor method · javascript · L43-L48 (6 LOC)
src/utils/errors.js
  constructor(message, path, operation, details = {}) {
    super(message, 'FILESYSTEM_ERROR', { path, operation, ...details });
    this.name = 'FileSystemError';
    this.path = path;
    this.operation = operation;
  }
ValidationError.constructor method · javascript · L66-L71 (6 LOC)
src/utils/errors.js
  constructor(message, field, value, details = {}) {
    super(message, 'VALIDATION_ERROR', { field, value, ...details });
    this.name = 'ValidationError';
    this.field = field;
    this.value = value;
  }
TransformError.constructor method · javascript · L89-L94 (6 LOC)
src/utils/errors.js
  constructor(message, transformer, file, details = {}) {
    super(message, 'TRANSFORM_ERROR', { transformer, file, ...details });
    this.name = 'TransformError';
    this.transformer = transformer;
    this.file = file;
  }
SecretsDetectedError.constructor method · javascript · L135-L141 (7 LOC)
src/utils/errors.js
  constructor(secretsCount, findings = [], details = {}) {
    const message = `Secrets detected: ${secretsCount} secret(s) found`;
    super(message, 'SECRETS_DETECTED', { secretsCount, findings, ...details });
    this.name = 'SecretsDetectedError';
    this.secretsCount = secretsCount;
    this.findings = findings;
  }
handleError function · javascript · L147-L174 (28 LOC)
src/utils/errors.js
function handleError(error, options = {}) {
  const { exit = true, verbose = false, logger = console.error } = options;

  // Convert to CopyTreeError if not already
  if (!(error instanceof CopyTreeError)) {
    error = new CopyTreeError(error.message, 'UNKNOWN_ERROR', {
      originalError: error.name,
      originalStack: error.stack,
    });
  }

  // Log error
  if (verbose) {
    logger(error.toJSON());
  } else {
    logger(`Error: ${error.message}`);
    if (error.code) {
      logger(`Code: ${error.code}`);
    }
  }

  // Exit if requested
  if (exit && process.env.NODE_ENV !== 'test') {
    process.exit(1);
  }

  return error;
}
isRetryableFsError function · javascript · L227-L232 (6 LOC)
src/utils/errors.js
export function isRetryableFsError(error) {
  const code = error?.code || error;
  // Filesystem-specific retryable codes
  const fsRetryableCodes = ['EBUSY', 'EPERM', 'EACCES', 'EMFILE', 'ENFILE', 'EAGAIN', 'EIO'];
  return fsRetryableCodes.includes(code);
}
categorizeError function · javascript · L239-L250 (12 LOC)
src/utils/errors.js
export function categorizeError(error) {
  if (isRetryableError(error)) {
    return 'retryable';
  }

  const errorCode = error.code || error.name || '';
  if (NON_RETRYABLE_ERROR_CODES.includes(errorCode)) {
    return 'non-retryable';
  }

  return 'unknown';
}
Same scanner, your repo: https://repobility.com — Repobility
hashFile function · javascript · L10-L19 (10 LOC)
src/utils/fileHash.js
async function hashFile(filePath, algorithm = 'sha256') {
  const hash = crypto.createHash(algorithm);
  const stream = fs.createReadStream(filePath);

  return new Promise((resolve, reject) => {
    stream.on('data', (data) => hash.update(data));
    stream.on('end', () => resolve(hash.digest('hex')));
    stream.on('error', reject);
  });
}
generateTransformCacheKey function · javascript · L38-L48 (11 LOC)
src/utils/fileHash.js
function generateTransformCacheKey(file, transformerName, options = {}) {
  const components = {
    path: file.path,
    size: file.stats?.size || 0,
    mtime: file.stats?.mtime?.getTime() || 0,
    transformer: transformerName,
    options: JSON.stringify(options, Object.keys(options).sort()),
  };

  return hashContent(JSON.stringify(components));
}
FileLoader.constructor method · javascript · L18-L31 (14 LOC)
src/utils/fileLoader.js
  constructor(options = {}) {
    this.basePath = options.basePath || process.cwd();
    this.includeHidden = options.includeHidden || false;
    this.followSymlinks = options.followSymlinks || false;
    this.maxFileSize = options.maxFileSize || 10 * 1024 * 1024; // 10MB default
    this.config = options.config || {};

    // Extract retry configuration with defaults
    this.retryConfig = {
      maxAttempts: this.config?.copytree?.fs?.retryAttempts ?? 3,
      initialDelay: this.config?.copytree?.fs?.retryDelay ?? 100,
      maxDelay: this.config?.copytree?.fs?.maxDelay ?? 2000,
    };
  }
FileLoader.loadFiles method · javascript · L36-L66 (31 LOC)
src/utils/fileLoader.js
  async loadFiles(patterns = {}) {
    const { include = ['**/*'], exclude = [] } = patterns;

    try {
      // Get file paths using fast-glob
      const filePaths = await fastGlob(include, {
        cwd: this.basePath,
        ignore: exclude,
        dot: this.includeHidden,
        followSymbolicLinks: this.followSymlinks,
        onlyFiles: true,
      });

      // Load file contents
      const files = [];
      for (const filePath of filePaths) {
        const file = await this.loadFile(filePath);
        if (file) {
          files.push(file);
        }
      }

      return files;
    } catch (error) {
      logger.error('Failed to load files', {
        basePath: this.basePath,
        error: error.message,
      });
      throw error;
    }
  }
FileLoader.loadFile method · javascript · L71-L184 (114 LOC)
src/utils/fileLoader.js
  async loadFile(relativePath) {
    const fullPath = path.join(this.basePath, relativePath);

    try {
      // Stat file with retry logic
      const stats = await withFsRetry(() => fs.stat(fullPath), {
        ...this.retryConfig,
        onRetry: ({ code }) => recordRetry(fullPath, code),
      });

      // Skip files that are too large
      if (stats.size > this.maxFileSize) {
        // Record success for stat operation even though we're skipping the file
        recordSuccessAfterRetry(fullPath);
        logger.warn('Skipping large file', {
          path: relativePath,
          size: stats.size,
          maxSize: this.maxFileSize,
        });
        return null;
      }

      // Read file content with retry logic
      const raw = await withFsRetry(() => fs.readFile(fullPath, 'utf8'), {
        ...this.retryConfig,
        onRetry: ({ code }) => recordRetry(fullPath, code),
      });

      // Normalize CRLF to LF for cross-platform consistency
      const content = raw.
FileLoader.detectFileType method · javascript · L189-L263 (75 LOC)
src/utils/fileLoader.js
  detectFileType(filePath, content) {
    const ext = path.extname(filePath).toLowerCase();

    // Code files
    const codeExtensions = {
      '.js': 'javascript',
      '.jsx': 'javascript',
      '.ts': 'typescript',
      '.tsx': 'typescript',
      '.py': 'python',
      '.rb': 'ruby',
      '.php': 'php',
      '.java': 'java',
      '.c': 'c',
      '.cpp': 'cpp',
      '.cs': 'csharp',
      '.go': 'go',
      '.rs': 'rust',
      '.swift': 'swift',
      '.kt': 'kotlin',
    };

    if (codeExtensions[ext]) {
      return codeExtensions[ext];
    }

    // Data files
    const dataExtensions = {
      '.json': 'json',
      '.xml': 'xml',
      '.yaml': 'yaml',
      '.yml': 'yaml',
      '.toml': 'toml',
      '.ini': 'ini',
      '.csv': 'csv',
    };

    if (dataExtensions[ext]) {
      return dataExtensions[ext];
    }

    // Document files
    const docExtensions = {
      '.md': 'markdown',
      '.mdx': 'markdown',
      '.txt': 'text',
      '.rst': 'restructuredte
FileLoader.isTextContent method · javascript · L268-L283 (16 LOC)
src/utils/fileLoader.js
  isTextContent(content) {
    if (typeof content !== 'string') return false;

    // Check for null bytes or other binary indicators
    for (let i = 0; i < Math.min(content.length, 1000); i++) {
      const charCode = content.charCodeAt(i);
      if (
        charCode === 0 ||
        (charCode < 32 && charCode !== 9 && charCode !== 10 && charCode !== 13)
      ) {
        return false;
      }
    }

    return true;
  }
recordRetry function · javascript · L19-L25 (7 LOC)
src/utils/fsErrorReport.js
export function recordRetry(path, code) {
  stats.totalRetries++;
  const entry = stats.byPath.get(path) ?? { retries: 0, lastCode: null, status: 'pending' };
  entry.retries++;
  entry.lastCode = code;
  stats.byPath.set(path, entry);
}
All rows above produced by Repobility · https://repobility.com
recordGiveUp function · javascript · L32-L38 (7 LOC)
src/utils/fsErrorReport.js
export function recordGiveUp(path, code) {
  stats.failed++;
  const entry = stats.byPath.get(path) ?? { retries: 0, lastCode: null, status: 'pending' };
  entry.lastCode = code;
  entry.status = 'failed';
  stats.byPath.set(path, entry);
}
recordPermanent function · javascript · L45-L51 (7 LOC)
src/utils/fsErrorReport.js
export function recordPermanent(path, code) {
  stats.permanent++;
  const entry = stats.byPath.get(path) ?? { retries: 0, lastCode: null, status: 'pending' };
  entry.lastCode = code;
  entry.status = 'permanent';
  stats.byPath.set(path, entry);
}
recordSuccessAfterRetry function · javascript · L57-L64 (8 LOC)
src/utils/fsErrorReport.js
export function recordSuccessAfterRetry(path) {
  const entry = stats.byPath.get(path);
  if (entry && entry.retries > 0 && entry.status === 'pending') {
    stats.succeededAfterRetry++;
    entry.status = 'ok';
    stats.byPath.set(path, entry);
  }
}
summarize function · javascript · L70-L77 (8 LOC)
src/utils/fsErrorReport.js
export function summarize() {
  return {
    totalRetries: stats.totalRetries,
    succeededAfterRetry: stats.succeededAfterRetry,
    failed: stats.failed,
    permanent: stats.permanent,
  };
}
getFailedPaths function · javascript · L91-L99 (9 LOC)
src/utils/fsErrorReport.js
export function getFailedPaths() {
  const failed = [];
  for (const [path, entry] of stats.byPath.entries()) {
    if (entry.status === 'failed') {
      failed.push({ path, code: entry.lastCode, retries: entry.retries });
    }
  }
  return failed;
}
getPermanentErrorPaths function · javascript · L105-L113 (9 LOC)
src/utils/fsErrorReport.js
export function getPermanentErrorPaths() {
  const permanent = [];
  for (const [path, entry] of stats.byPath.entries()) {
    if (entry.status === 'permanent') {
      permanent.push({ path, code: entry.lastCode });
    }
  }
  return permanent;
}
reset function · javascript · L118-L124 (7 LOC)
src/utils/fsErrorReport.js
export function reset() {
  stats.totalRetries = 0;
  stats.succeededAfterRetry = 0;
  stats.failed = 0;
  stats.permanent = 0;
  stats.byPath.clear();
}
GitUtils.isGitRepository method · javascript · L32-L45 (14 LOC)
src/utils/GitUtils.js
  async isGitRepository() {
    if (this._isRepo !== null) {
      return this._isRepo;
    }

    try {
      await this.git.revparse(['--git-dir']);
      this._isRepo = true;
      return true;
    } catch (error) {
      this._isRepo = false;
      return false;
    }
  }
Repobility · MCP-ready · https://repobility.com
GitUtils.getModifiedFiles method · javascript · L51-L84 (34 LOC)
src/utils/GitUtils.js
  async getModifiedFiles() {
    const cacheKey = 'modified-files';
    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    try {
      if (!(await this.isGitRepository())) {
        throw new GitError('Not a git repository', 'getModifiedFiles');
      }

      // Get status
      const status = await this.git.status();

      // Combine all modified files
      const modifiedFiles = [
        ...status.modified,
        ...status.staged,
        ...status.not_added,
        ...status.created,
      ];

      // Remove duplicates and normalize paths
      const uniqueFiles = [...new Set(modifiedFiles)].map((file) => toPosix(file));

      this.cache.set(cacheKey, uniqueFiles);
      this.logger.logDebug(`Found ${uniqueFiles.length} modified files`);

      return uniqueFiles;
    } catch (error) {
      throw new GitError(`Failed to get modified files: ${error.message}`, 'getModifiedFiles', {
        originalError: error,
      });
    }
  }
GitUtils.getChangedFiles method · javascript · L92-L129 (38 LOC)
src/utils/GitUtils.js
  async getChangedFiles(fromRef = 'HEAD', toRef = null) {
    const cacheKey = `changed-files:${fromRef}:${toRef || 'working'}`;
    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    try {
      if (!(await this.isGitRepository())) {
        throw new GitError('Not a git repository', 'getChangedFiles');
      }

      let diffSummary;

      if (toRef) {
        // Diff between two refs
        diffSummary = await this.git.diffSummary([fromRef, toRef]);
      } else {
        // Diff from ref to working directory
        diffSummary = await this.git.diffSummary([fromRef]);
      }

      const changedFiles = diffSummary.files
        .filter((file) => file.file && !file.binary)
        .map((file) => toPosix(file.file));

      this.cache.set(cacheKey, changedFiles);
      this.logger.logDebug(
        `Found ${changedFiles.length} changed files between ${fromRef} and ${toRef || 'working directory'}`,
      );

      return changedFiles;
    } catch (error) {
GitUtils.getFileStatuses method · javascript · L136-L184 (49 LOC)
src/utils/GitUtils.js
  async getFileStatuses(files) {
    if (!files || files.length === 0) {
      return {};
    }

    try {
      if (!(await this.isGitRepository())) {
        return {};
      }

      const status = await this.git.status();
      const statusMap = {};

      // Build status map — simple-git returns renamed as {from, to} objects,
      // so flatten those into their destination paths (strings) for matching.
      const renamedPaths = (status.renamed || []).map((r) => r.to || r);
      const allStatuses = {
        modified: status.modified,
        staged: status.staged,
        not_added: status.not_added,
        created: status.created,
        deleted: status.deleted,
        renamed: renamedPaths,
        conflicted: status.conflicted,
      };

      files.forEach((file) => {
        const posixPath = toPosix(file);

        for (const [statusType, fileList] of Object.entries(allStatuses)) {
          const posixList = fileList.map((f) => toPosix(String(f)));
          if (posix
GitUtils.getCurrentBranch method · javascript · L190-L208 (19 LOC)
src/utils/GitUtils.js
  async getCurrentBranch() {
    const cacheKey = 'current-branch';
    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    try {
      if (!(await this.isGitRepository())) {
        return null;
      }

      const branch = await this.git.revparse(['--abbrev-ref', 'HEAD']);
      this.cache.set(cacheKey, branch);

      return branch;
    } catch (error) {
      this.logger.warn(`Failed to get current branch: ${error.message}`);
      return null;
    }
  }
GitUtils.getLastCommit method · javascript · L214-L244 (31 LOC)
src/utils/GitUtils.js
  async getLastCommit() {
    const cacheKey = 'last-commit';
    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    try {
      if (!(await this.isGitRepository())) {
        return null;
      }

      const log = await this.git.log({ n: 1 });
      const commit = log.latest;

      if (commit) {
        const commitInfo = {
          hash: commit.hash,
          message: commit.message,
          author: commit.author_name,
          date: commit.date,
        };

        this.cache.set(cacheKey, commitInfo);
        return commitInfo;
      }

      return null;
    } catch (error) {
      this.logger.warn(`Failed to get last commit: ${error.message}`);
      return null;
    }
  }
GitUtils.hasUncommittedChanges method · javascript · L250-L262 (13 LOC)
src/utils/GitUtils.js
  async hasUncommittedChanges() {
    try {
      if (!(await this.isGitRepository())) {
        return false;
      }

      const status = await this.git.status();
      return !status.isClean();
    } catch (error) {
      this.logger.warn(`Failed to check uncommitted changes: ${error.message}`);
      return false;
    }
  }
retry function · javascript · L34-L62 (29 LOC)
src/utils/helpers.js
async function retry(fn, options = {}) {
  const {
    maxAttempts = 3,
    initialDelay = 1000,
    maxDelay = 10000,
    backoffMultiplier = 2,
    shouldRetry = (error) => true,
  } = options;

  let lastError;
  let delay = initialDelay;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn(attempt);
    } catch (error) {
      lastError = error;

      if (attempt === maxAttempts || !shouldRetry(error)) {
        throw error;
      }

      await sleep(Math.min(delay, maxDelay));
      delay *= backoffMultiplier;
    }
  }

  throw lastError;
}
getTempDir function · javascript · L75-L83 (9 LOC)
src/utils/helpers.js
async function getTempDir(prefix = 'copytree') {
  const tempBase = os.tmpdir();
  const tempDir = path.join(
    tempBase,
    `${prefix}-${Date.now()}-${shortHash(Math.random().toString())}`,
  );
  await ensureDir(tempDir);
  return tempDir;
}
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
cleanupTempDir function · javascript · L88-L94 (7 LOC)
src/utils/helpers.js
async function cleanupTempDir(tempDir) {
  try {
    await fs.remove(tempDir);
  } catch (error) {
    // Ignore cleanup errors
  }
}
isBinaryExtension function · javascript · L122-L169 (48 LOC)
src/utils/helpers.js
function isBinaryExtension(filePath) {
  const binaryExtensions = new Set([
    'exe',
    'dll',
    'so',
    'dylib',
    'bin',
    'jpg',
    'jpeg',
    'png',
    'gif',
    'bmp',
    'ico',
    'webp',
    'svg',
    'mp3',
    'mp4',
    'avi',
    'mov',
    'wmv',
    'flv',
    'webm',
    'zip',
    'tar',
    'gz',
    'rar',
    '7z',
    'bz2',
    'pdf',
    'doc',
    'docx',
    'xls',
    'xlsx',
    'ppt',
    'pptx',
    'ttf',
    'otf',
    'woff',
    'woff2',
    'eot',
    'db',
    'sqlite',
    'sqlite3',
  ]);

  const ext = getExtension(filePath).toLowerCase();
  return binaryExtensions.has(ext);
}
isImageExtension function · javascript · L176-L192 (17 LOC)
src/utils/helpers.js
function isImageExtension(filePath) {
  const imageExtensions = new Set([
    'jpg',
    'jpeg',
    'png',
    'gif',
    'bmp',
    'ico',
    'webp',
    'svg',
    'tiff',
    'tif',
  ]);

  const ext = getExtension(filePath).toLowerCase();
  return imageExtensions.has(ext);
}
‹ prevpage 5 / 7next ›