merge-gitignore.mjs 1.56 KB
// lib/merge-gitignore.mjs
// 合并两份 .gitignore,对**规则行**逐行判重并集合并;注释行透传(相邻去重),空行丢弃(节由注释头承担)。
export function mergeGitignore(baseText, addText) {
  const seenRules = new Set()
  const out = []
  const push = (line) => {
    const trimmed = line.trim()
    if (!trimmed) return        // drop blank lines (输出靠 join('\n')+尾换行;分节由注释行承担)
    if (trimmed.startsWith('#')) {
      // 注释:仅折叠**相邻**完全相同的注释,避免分节标题被吞
      if (out.length && out[out.length - 1].trim() === trimmed) return
      out.push(line)
      return
    }
    // 规则行:全局去重(含 negation `!pattern`,按原文比对,顺序保留首次出现位置)
    if (seenRules.has(trimmed)) return
    seenRules.add(trimmed)
    out.push(line)
  }
  for (const l of baseText.split('\n')) push(l)
  for (const l of addText.split('\n')) push(l)
  let text = out.join('\n').replace(/\n+$/, '') + '\n'
  return text
}

const { pathToFileURL } = await import('node:url') // CLI entry guard:pathToFileURL 规范化 argv[1] 以匹配 import.meta.url(路径含空格 / 非 ASCII / Windows 反斜杠时字面比较会失配)
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  const [basePath, addPath] = process.argv.slice(2)
  const { readFileSync, writeFileSync } = await import('node:fs')
  const base = readFileSync(basePath, 'utf8')
  const add = readFileSync(addPath, 'utf8')
  writeFileSync(basePath, mergeGitignore(base, add))
}