/** * One parsed commit entry from the git reflog. * * Produced by the generated PEG parser (`parse_rl`) and consumed by the * formatters. `scan` additionally stamps matching entries with `tag`. */ export type ReflogEntry = { /** * The full 40-character commit hash. */ commit_hash: string; /** * The commit message body, one element per * blank-line-separated block. */ commit_text: string[]; /** * The commit author line, when present. */ author?: string | undefined; /** * Commit timestamp as epoch milliseconds. */ date?: number | undefined; /** * Short hashes of the merge parents, for a * merge commit. */ merge?: string[] | undefined; /** * Tag names whose commit matches this entry; * added by `scan`. */ tag?: string[] | undefined; }; /** * The subset of a scan returned by `scan_all` — tags and reflog only, with no * tag/reflog cross-referencing or remote-URL resolution performed yet. */ export type ScanAllResult = { /** * Every tag name in the repository. */ tag_list: string[]; /** * Map of tag name to commit hash. */ tag_hashes: Map; /** * The parsed reflog entries. */ reflog: ReflogEntry[]; }; /** * The complete result of scanning a repository, returned by `scan`. */ export type ScanResult = { /** * Every tag name in the repository. */ tag_list: string[]; /** * Map of tag name to commit hash. */ tag_hashes: Map; /** * The parsed reflog entries, with * `tag` stamped onto matches. */ reflog: ReflogEntry[]; /** * Tag names whose commit was not * found in the reflog. */ not_found: string[]; /** * The repository's web base URL, * or `null` when no hosted * `origin` remote exists. */ repo_url: string | null; }; /** * Scan the current repository: gather its tags, reflog, and remote URL. * * @returns {ScanResult} `{ tag_list, tag_hashes, reflog, not_found, repo_url }` * — the tag names, a tag-to-commit Map, the parsed reflog (each entry * stamped with its `tag` when one matches a tag's commit), the tags * whose commit was not found in the reflog, and the repository's web * URL (or `null` when no hosted `origin` remote exists). * @throws {Error} When git cannot be run or a command fails. * * @example * const { reflog, repo_url } = scan(); * * @see scan_all * @see convert_to_md */ export function scan(): ScanResult; /** * Output cap, in bytes, for every git command whose output grows with the * repository. * * Node's `execSync`/`execFileSync` default to a 1 MiB `maxBuffer` and, when a * child exceeds it, kill the process with SIGTERM and throw `ENOBUFS` — losing * the output rather than truncating it. `git log --reflog` crosses 1 MiB on * any repository with a few thousand commits (jssm hit it at ~7,000), so the * default silently converted "your project got big" into a hard changelog * failure. `git tag -l` and `for-each-ref refs/tags` have the same exposure on * tag-heavy repositories. * * 256 MiB is a cap, not an allocation: Node grows the buffer as output * arrives, so a small repository pays nothing for the headroom. The cap is * kept finite deliberately, so a pathological or hostile repository still * fails loudly instead of exhausting memory. * * @type {number} */ export const GIT_MAX_BUFFER: number; /** * Read the raw reflog text for the current repository. * * Runs `git --no-pager log --reflog` and appends a trailing blank line so the * output satisfies the reflog grammar consumed by `parse_rl`. * * Reads with {@link GIT_MAX_BUFFER} rather than Node's 1 MiB default: this is * the largest output the tool consumes, and it grows with the repository's * history, so the default turned large repositories into `ENOBUFS` failures. * * @returns {string} The raw reflog text, ready to hand to `parse_rl`. * @throws {Error} When git cannot be run or the command fails, or when the * reflog exceeds {@link GIT_MAX_BUFFER} (`ENOBUFS`). * * @example * parse_rl(get_reflog_data()); // structured ReflogEntry[] * * @see parse_rl */ export function get_reflog_data(): string; /** * List every tag name in the current repository. * * Runs `git tag -l`, trimming blank lines so the result contains only real * tag names. * * @returns {string[]} The tag names, in git's listing order. * @throws {Error} When git cannot be run or the command fails. * * @example * get_tag_list(); // ['1.0.0', '1.1.0', 'nightly'] * * @see tags_to_hashes */ export function get_tag_list(): string[]; /** * Resolve a tag name to the hash of the commit it points at. * * Spawned shell-free with execFileSync, so a tag name containing shell * metacharacters cannot be reinterpreted by a shell. * * @param {string} tag A git tag name. * @returns {string} The commit hash the tag resolves to. * @throws {Error} When the tag does not exist or git cannot be run. * * @example * tag_to_hash('1.6.8'); // 'a1b2c3d4...' */ export function tag_to_hash(tag: string): string; /** * Resolve a set of tag names to their commit hashes in a single git call. * * Uses `git for-each-ref` once for the whole repository — far cheaper than * one `git rev-list` per tag. Tags not present in the repository are simply * omitted from the result. * * @param {string[]} tags Tag names to resolve. * @returns {Map} Map of tag name to commit hash, containing * only the tags that exist. * @throws {Error} When git cannot be run or the command fails. * * @example * tags_to_hashes(['1.0.0', 'nope']); // Map { '1.0.0' => 'a1b2...' } * * @see get_tag_list * @see get_tags_as_hashes */ export function tags_to_hashes(tags: string[]): Map; /** * List every tag in the repository and resolve each to its commit hash. * * A convenience composition of `get_tag_list` and `tags_to_hashes`. * * @returns {Map} Map of tag name to commit hash. * @throws {Error} When git cannot be run or a command fails. * * @example * get_tags_as_hashes(); // Map { '1.0.0' => 'a1b2...', ... } * * @see get_tag_list * @see tags_to_hashes */ export function get_tags_as_hashes(): Map; /** * Read the URL of the `origin` remote. * * Spawned shell-free with execFileSync, so the fixed git argument list * cannot be reinterpreted by a shell. * * @returns {string | null} The `origin` remote URL as a trimmed string, or * `null` when there is no `origin` remote (or git cannot be run). * * @example * get_remote_url(); // 'git@github.com:owner/repo.git' * * @see remote_to_web_url */ export function get_remote_url(): string | null; /** * Convert a git remote URL into the repository's web base URL. * * Handles the SSH scp-style form (`git@host:owner/repo.git`), the * `scheme://` forms (`https://`, `ssh://`, `git://`), embedded credentials, * a port, and a trailing `.git`. A local-path remote, or any remote whose * host is not a dotted hostname, yields `null` — no web URL can be built * from it. * * @param {string | null} remote A git remote URL, or `null`. * @returns {string | null} The `https://host/owner/repo` web base, or `null` * when the remote is missing or is not a hosted URL. * * @example * remote_to_web_url('git@github.com:o/r.git'); // 'https://github.com/o/r' * remote_to_web_url('/home/u/r.git'); // null * * @see get_remote_url */ export function remote_to_web_url(remote: string | null): string | null; /** * Serialize scanned changelog data to a JSON file. * * @param {object} options Destructured options bag. * @param {string} options.target Output path the JSON is written to. * @param {ScanResult} options.data The scan result to serialize. * @returns {void} * @throws {Error} When the target path cannot be written. * * @example * convert_to_json({ target: './changelog.json', data: scan() }); * * @see scan * @see convert_to_md */ export function convert_to_json({ target, data }: { target: string; data: ScanResult; }): void; /** * Render scanned changelog data as a complete Markdown document. * * @param {object} options Destructured options bag. * @param {string} [options.target] Output path; informational only, nothing * is written here. * @param {ScanResult} options.data A scan result: `{ reflog, tag_list, * tag_hashes, repo_url }`. * @param {(item: ReflogEntry, tr: import('./i18n.js').Translator, repo_url: (string | null)) => string} [options.item_formatter] * Optional per-entry renderer; defaults to default_formatter. * @param {(item: ReflogEntry) => string} [options.item_separator] * Optional separator renderer; defaults to default_separator. * @param {string} [options.preface] Optional preface string; defaults to the * localized preface. * @param {boolean} [options.short] When true, include only the most recent * `short_length` entries. * @param {number} [options.short_length] Entry count for the short form * (default 10). * @param {boolean} [options.has_both] When true (and `short`), append a link * to the long-form file. * @param {string} [options.longname] Long-form filename, used by the * `has_both` link. * @param {import('./i18n.js').Translator} [options.translator] A translator * for the changelog language; defaults to English. * @returns {string} The complete changelog as a Markdown string. * * @example * convert_to_md({ data: scan() }); * * @see scan * @see default_formatter */ export function convert_to_md({ target, data, item_formatter, item_separator, preface, short, short_length, has_both, longname, translator }: { target?: string | undefined; data: ScanResult; item_formatter?: ((item: ReflogEntry, tr: import("./i18n.js").Translator, repo_url: (string | null)) => string) | undefined; item_separator?: ((item: ReflogEntry) => string) | undefined; preface?: string | undefined; short?: boolean | undefined; short_length?: number | undefined; has_both?: boolean | undefined; longname?: string | undefined; translator?: i18n.Translator | undefined; }): string; /** * Turn a tag name into an HTML-anchor-safe slug. * * Every character that is not a Unicode letter, a Unicode digit, an * underscore, or a hyphen is replaced with `__`, so non-Latin tag names * survive while punctuation is escaped. Input is assumed to be NFC-normalized; * a decomposed combining mark would be stripped. * * @param {string} text The tag name to convert. * @returns {string} The anchor-safe slug. * * @example * slug('v1.0/beta'); // 'v1__0__beta' * slug('versión-2'); // 'versión-2' * * @see to_link */ export function slug(text: string): string; /** * Render one parsed reflog entry as a Markdown changelog section. * * @param {ReflogEntry} item A reflog entry: `commit_hash` and `commit_text`, * plus the optional `tag` (a tag name, or an array of tag * names when a commit carries several), `date`, `author`, * and `merge`. * @param {import('./i18n.js').Translator} [tr] A translator from * i18n.make_translator; defaults to English. * @param {string | null} [repo_url] The repository's web base URL. When * given, the commit hash is linked to * `/commit/`; when absent, the hash is * rendered as plain inline code with no link. * @returns {string} The entry rendered as Markdown. * * @example * default_formatter({ commit_hash: 'abc', commit_text: ['Fix a bug'] }); * * @see convert_to_md * @see default_separator */ export function default_formatter(item: ReflogEntry, tr?: import("./i18n.js").Translator, repo_url?: string | null): string; /** * Produce the Markdown separator placed between changelog entries. * * A fixed run of blank lines and non-breaking spaces; the entry argument is * accepted for interface symmetry with custom separators but is unused. * * @param {ReflogEntry} [item] The reflog entry following the separator; unused. * @returns {string} The separator Markdown. * * @example * default_separator(); // '\n\n\n\n\n \n\n \n\n' * * @see default_formatter * @see convert_to_md */ export function default_separator(item?: ReflogEntry): string; /** * Scan the repository (or use supplied data) and write the short-form changelog. * * @param {string} [target] Output path; defaults to './CHANGELOG.md'. * @param {boolean} [has_both] When true, append a link to the long-form file. * @param {number} [short_length] Number of recent entries to include. * @param {string} [longname] Long-form filename, used by the `has_both` link. * @param {ScanResult} [data] Optional pre-computed scan result; the repo * is scanned if omitted. * @param {import('./i18n.js').Translator} [translator] A translator for the * changelog language; defaults to English. * @returns {void} * @throws {Error} When the target path cannot be written or git fails. * * @example * write_short_md('./CHANGELOG.md', true, 10, 'CHANGELOG.long.md'); * * @see write_long_md * @see convert_to_md */ export function write_short_md(target?: string, has_both?: boolean, short_length?: number, longname?: string, data?: ScanResult, translator?: import("./i18n.js").Translator): void; /** * Scan the repository (or use supplied data) and write the full-history changelog. * * @param {string} [target] Output path; defaults to './CHANGELOG.long.md'. * @param {ScanResult} [data] Optional pre-computed scan result; the repo is * scanned if omitted. * @param {import('./i18n.js').Translator} [translator] A translator for the * changelog language; defaults to English. * @returns {void} * @throws {Error} When the target path cannot be written or git fails. * * @example * write_long_md('./CHANGELOG.long.md'); * * @see write_short_md * @see convert_to_md */ export function write_long_md(target?: string, data?: ScanResult, translator?: import("./i18n.js").Translator): void; /** * Parse raw `git log --reflog` text into structured commit entries. * * A re-export of the parser generated from `src/peg/reflog_parser.peg`. * Each `commit ...` block becomes one {@link ReflogEntry}. * * @type {(input: string) => ReflogEntry[]} * @param {string} input The raw reflog text to parse. * @returns {ReflogEntry[]} The parsed commit entries in reflog order. * @throws {Error} A peggy `SyntaxError` when the input does not match * the reflog grammar. * * @example * parse_rl(get_reflog_data()); // [{ commit_hash: 'a1b2...', ... }] * * @see get_reflog_data */ export const parse_rl: (input: string) => ReflogEntry[]; import i18n = require("./i18n.js");