CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
close-keywords.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| d62fb36 | 1 | /** |
| 2 | * Block J7 — Closing keywords. | |
| 3 | * | |
| 4 | * Parses PR body + commit messages for GitHub-style "closes #N" phrases and | |
| 5 | * returns the de-duplicated set of issue numbers that should auto-close when | |
| 6 | * the PR merges. Pure; zero IO. | |
| 7 | * | |
| 8 | * Accepted verbs (case-insensitive): | |
| 9 | * close(s|d), fix(es|ed), resolve(s|d) | |
| 10 | * | |
| 11 | * Optional punctuation between the verb and the issue ref ("Fixes: #12", | |
| 12 | * "Closes #12.") is tolerated. Refs must be bare `#<number>` — cross-repo | |
| 13 | * refs like `owner/repo#12` are intentionally ignored for v1 because | |
| 14 | * cross-repo auto-close requires authorisation we don't track yet. | |
| 15 | */ | |
| 16 | ||
| 17 | const VERB = "close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved"; | |
| 18 | ||
| 19 | // Word boundary on the verb, optional colon / hyphen / whitespace, then a | |
| 20 | // bare `#<number>`. Ignore matches preceded by `/` (owner/repo#N cross-repo). | |
| 21 | const CLOSE_RE = new RegExp( | |
| 22 | `(^|[^a-z0-9/])(${VERB})\\s*[:\\-]?\\s*#(\\d+)`, | |
| 23 | "gi" | |
| 24 | ); | |
| 25 | ||
| 26 | /** | |
| 27 | * Extract the sorted de-duplicated list of issue numbers referenced with a | |
| 28 | * closing verb in the supplied text. Returns [] on empty / no match. | |
| 29 | */ | |
| 30 | export function extractClosingRefs(text: string | null | undefined): number[] { | |
| 31 | if (!text) return []; | |
| 32 | const out = new Set<number>(); | |
| 33 | for (const m of text.matchAll(CLOSE_RE)) { | |
| 34 | const n = parseInt(m[3], 10); | |
| 35 | if (Number.isFinite(n) && n > 0) out.add(n); | |
| 36 | } | |
| 37 | return [...out].sort((a, b) => a - b); | |
| 38 | } | |
| 39 | ||
| 40 | /** | |
| 41 | * Extract closing refs from N source strings (e.g. PR body + commit messages) | |
| 42 | * and return the merged de-duped list. | |
| 43 | */ | |
| 44 | export function extractClosingRefsMulti( | |
| 45 | sources: Array<string | null | undefined> | |
| 46 | ): number[] { | |
| 47 | const all = new Set<number>(); | |
| 48 | for (const s of sources) { | |
| 49 | for (const n of extractClosingRefs(s)) all.add(n); | |
| 50 | } | |
| 51 | return [...all].sort((a, b) => a - b); | |
| 52 | } | |
| 53 | ||
| 54 | export const __internal = { CLOSE_RE }; |