import { lineToString } from './pkt-line' export const ZERO_SHA = '0000000000000000000000000000000000000000' export interface Advertisement { /** Ref name -> object SHA (unpeeled). For annotated tags this is the tag object. */ refs: Map /** For annotated tags, the `^{}` peeled line: ref name -> commit SHA. */ peeled: Map capabilities: Set } /** * Parse a git ref advertisement (protocol v0) from a list of pkt-line * payloads (flush-pkts already stripped by the reader). * * Handles three shapes that occur in practice: * - smart-HTTP prelude: a leading `# service=git-upload-pack` line, which * the ssh transport omits; * - a populated repo: ` \0` on the first ref line, * ` ` thereafter, with ` ^{}` peeled lines * for annotated tags; * - an empty repo: a single ` capabilities^{}\0` line that * carries capabilities but advertises no usable ref. */ export function parseAdvertisement(lines: Buffer[]): Advertisement { const refs = new Map() const peeled = new Map() const capabilities = new Set() let first = true for (const raw of lines) { const line = lineToString(raw) if (line.startsWith('# service=')) continue let sha: string let rest: string if (first) { const nul = line.indexOf('\0') const head = nul === -1 ? line : line.slice(0, nul) const caps = nul === -1 ? '' : line.slice(nul + 1) for (const cap of caps.split(' ')) { if (cap) capabilities.add(cap) } first = false const sp = head.indexOf(' ') sha = head.slice(0, sp) rest = head.slice(sp + 1) // Empty-repo sentinel: zero SHA + the literal "capabilities^{}" name. if (sha === ZERO_SHA && rest === 'capabilities^{}') continue } else { const sp = line.indexOf(' ') sha = line.slice(0, sp) rest = line.slice(sp + 1) } if (rest.endsWith('^{}')) { peeled.set(rest.slice(0, -3), sha) } else { refs.set(rest, sha) } } return { refs, peeled, capabilities } }