@mintlify/prebuild
Version:
Helpful functions for Mintlify's prebuild step
63 lines (62 loc) • 2.78 kB
JavaScript
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
/**
* Gets git blame data for a file, returning a map of line numbers to ISO date strings.
* Uses author-time (when the change was originally created) rather than committer-time.
* @param filePath - Absolute path to the file
* @param repoPath - Path to the git repository root
* @returns Record<number, string> mapping line numbers (1-indexed) to ISO date strings
*/
export const getGitBlame = async (filePath, repoPath) => {
try {
// Make file path relative to repo root for git blame
const relativeFilePath = filePath.startsWith(repoPath)
? filePath.substring(repoPath.length + 1)
: filePath;
// Use git blame with porcelain format for easier parsing
// --line-porcelain gives us detailed info for each line
const { stdout } = await execAsync(`git blame --line-porcelain "${relativeFilePath}"`, {
cwd: repoPath,
maxBuffer: 10 * 1024 * 1024, // 10MB buffer for large files
});
const lineBlame = {};
const lines = stdout.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (!line)
continue;
// Line starting with commit hash indicates a new blame entry
// Format: <commit-hash> <original-line> <final-line> <num-lines>
const commitMatch = line.match(/^[0-9a-f]{40}\s+\d+\s+(\d+)/);
if (commitMatch && commitMatch[1]) {
const lineNumber = parseInt(commitMatch[1], 10);
// Look ahead for 'author-time' field (Unix timestamp)
let authorTime;
for (let j = i + 1; j < lines.length && j < i + 15; j++) {
const nextLine = lines[j];
if (!nextLine)
continue;
if (nextLine.startsWith('author-time ')) {
const timestamp = parseInt(nextLine.substring('author-time '.length), 10);
authorTime = new Date(timestamp * 1000).toISOString();
break;
}
// Stop when we hit the content line (starts with tab)
if (nextLine.startsWith('\t')) {
break;
}
}
if (authorTime) {
lineBlame[lineNumber] = authorTime;
}
}
}
return lineBlame;
}
catch (error) {
// If git blame fails (e.g., file not in git, no commits), silently return empty blame
// Server will use current date as fallback
return {};
}
};