// Git LFS pointers. // // A repository that tracks a large file with Git LFS commits a small text // file in its place, naming the object by its hash. The file itself is on an // LFS server, which this one is not. So a reader that finds a pointer holds // the name of an image, never its pixels, and a page that shows one has to // say so rather than print 132 bytes of text as a PNG. /** The first line of every pointer this reader knows. */ const VERSION_LINE = 'version https://git-lfs.github.com/spec/v1'; /** A pointer is a few short lines. Anything longer is the file itself. */ const MAX_POINTER_BYTES = 1024; const OID_LINE = /^oid sha256:([0-9a-f]{64})$/m; const SIZE_LINE = /^size (\d{1,19})$/m; /** * @typedef {Object} LfsPointer * @property {string} oid - sha256 of the file the pointer stands for * @property {number} size - length of that file in bytes */ /** * Read a blob as a Git LFS pointer. * @param {Uint8Array|null|undefined} bytes * @returns {LfsPointer|null} null for any blob that is the file itself */ export function lfsPointer(bytes) { if (!bytes || bytes.length === 0 || bytes.length > MAX_POINTER_BYTES) { return null; } let text; try { // A pointer is UTF-8 text. Bytes that are not decode as nothing, which // is the answer for every file that carries its own content. text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); } catch { return null; } if (!text.startsWith(VERSION_LINE)) return null; const oid = OID_LINE.exec(text); const size = SIZE_LINE.exec(text); if (!oid || !size) return null; return { oid: oid[1], size: Number(size[1]) }; }