@gitkraken/core-gitlens 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/dist/git/models/issue.d.ts +2 -2
  3. package/dist/git/models/issue.js.map +1 -1
  4. package/dist/git/models/issueOrPullRequest.d.ts +2 -1
  5. package/dist/git/models/pullRequest.d.ts +1 -0
  6. package/dist/git/models/pullRequest.js.map +1 -1
  7. package/dist/git/utils/revision.utils.d.ts +3 -0
  8. package/dist/git/utils/revision.utils.js +5 -1
  9. package/dist/git/utils/revision.utils.js.map +1 -1
  10. package/dist/plus/git-github/api/github.d.ts +4 -0
  11. package/dist/plus/git-github/api/github.js +31 -4
  12. package/dist/plus/git-github/api/github.js.map +1 -1
  13. package/dist/plus/git-github/api/types.d.ts +4 -0
  14. package/dist/plus/git-github/providers/github/revision.js +12 -1
  15. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  16. package/dist/plus/integrations/collectionMetadata.d.ts +22 -7
  17. package/dist/plus/integrations/collectionMetadata.js +49 -6
  18. package/dist/plus/integrations/collectionMetadata.js.map +1 -1
  19. package/dist/plus/integrations/models/integration.d.ts +1 -1
  20. package/dist/plus/integrations/models/integration.js.map +1 -1
  21. package/dist/plus/integrations/providers/azure/azure.d.ts +3 -2
  22. package/dist/plus/integrations/providers/azure/azure.js +35 -6
  23. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  24. package/dist/plus/integrations/providers/azure/models.d.ts +3 -1
  25. package/dist/plus/integrations/providers/azure/models.js +8 -5
  26. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  27. package/dist/plus/integrations/providers/azure/search.d.ts +6 -4
  28. package/dist/plus/integrations/providers/azure/search.js +29 -10
  29. package/dist/plus/integrations/providers/azure/search.js.map +1 -1
  30. package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -2
  31. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  32. package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
  33. package/dist/plus/integrations/providers/models.js +11 -8
  34. package/dist/plus/integrations/providers/models.js.map +1 -1
  35. package/dist/plus/integrations/providers/providersApi.js +5 -4
  36. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  37. package/dist/plus/integrations/providers/utils/jiraIssueDrains.d.ts +4 -21
  38. package/dist/plus/integrations/providers/utils/jiraIssueDrains.js +13 -48
  39. package/dist/plus/integrations/providers/utils/jiraIssueDrains.js.map +1 -1
  40. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +20 -6
  41. package/dist/plus/integrations/providers/utils/providerPaging.js +50 -13
  42. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  43. package/dist/plus/integrations/reads/drains.d.ts +1 -0
  44. package/dist/plus/integrations/reads/issues.js +1 -1
  45. package/dist/plus/integrations/reads/issues.js.map +1 -1
  46. package/dist/plus/integrations/reads/paging.js +1 -1
  47. package/dist/plus/integrations/reads/paging.js.map +1 -1
  48. package/dist/plus/integrations/results.d.ts +12 -7
  49. package/dist/plus/integrations/results.js +3 -4
  50. package/dist/plus/integrations/results.js.map +1 -1
  51. package/docs/integrations.md +9 -5
  52. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.15.3] - 2026-10-21
10
+
11
+ ### Fixed
12
+
13
+ - Fixes Azure DevOps work items reporting an open state when their workflow category is unavailable and no closed date is known, including cheap etag reads. Filtered work item searches and counts now select by workflow category, so Removed work items without closed dates appear under Closed ([#6041](https://github.com/gitkraken/vscode-gitlens/issues/6041)).
14
+
15
+ ## [0.15.2] - 2026-10-20
16
+
17
+ ### Changed
18
+
19
+ - Changes the `'unreadable-items'` warning for a Jira or Jira Data Center issue that `@gitkraken/provider-apis` can't read to take its `unreadableItems` from the structured `skippedItems` of the failure instead of parsing its message, so a page that skipped more than ten issues now names every one of them and reports `complete: true`, where it named ten and reported `complete: false`, and a key-looking token in an error reason no longer adds a key. `complete` is `false` when a skipped issue had no key, when the SDK's report was malformed (no list of keys, or more than keys in it), or when it said issues were skipped and named none. `keys` holds the spelling Jira returned, which is also how a published issue's id spells its key, and doesn't answer a lookup by another case or by a key the issue had before it moved, so compare case-normalized on both sides. The raw `CollectionMetadata` a drained read returns (`getIssuesForProjectWithTruncationResult`, `searchMyIssuesWithTruncationResult`) now merges `skippedItems` across the pages of a drain (keys in order, totals added) and across the reads of a user's relationships, which are merged into one failure per scope however they word it or split the skipped issues over their pages (keys in order; `total` is the larger of their totals, at least the keys named), so a user's relationships publish one warning for a project's skipped issues, with the message of the report that names more keys. The `total` of a drain is the sum of its pages' totals, so a key repeated across pages that shifted counts once per page. Before, the pages of a drain were folded into the first page's failure. A failure that carries `skippedItems` is never classified by its message, so a skipped issue whose own error names a status (`401`) is not an authentication failure, and a failure that doesn't carry it is no longer taken for a skip, whatever its message says. Failures no longer carry the `unreadableItems` property #6011 added to them; the warning still does ([#6035](https://github.com/gitkraken/vscode-gitlens/issues/6035)) (plus/integrations)
20
+
9
21
  ## [0.15.1] - 2026-10-19
10
22
 
11
23
  ### Added
@@ -792,7 +804,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
792
804
 
793
805
  - Initial release. Bundles `@gitlens/utils`, `@gitlens/git`, `@gitlens/git-cli`, `@gitlens/ai`, and `@gitlens/git-github` into a single core npm package with subpath exports.
794
806
 
795
- [unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.1...HEAD
807
+ [unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.3...HEAD
808
+ [0.15.3]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.2...gitkraken:releases/core/v0.15.3
809
+ [0.15.2]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.1...gitkraken:releases/core/v0.15.2
796
810
  [0.15.1]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.15.0...gitkraken:releases/core/v0.15.1
797
811
  [0.15.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.14.0...gitkraken:releases/core/v0.15.0
798
812
  [0.14.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.13.0...gitkraken:releases/core/v0.14.0
@@ -200,7 +200,7 @@ export declare class Issue implements IssueShape {
200
200
  readonly createdDate: Date;
201
201
  readonly updatedDate: Date;
202
202
  readonly closed: boolean;
203
- readonly state: IssueOrPullRequestState;
203
+ readonly state: IssueOrPullRequestState | undefined;
204
204
  readonly author: IssueMember | undefined;
205
205
  readonly assignees: IssueMember[];
206
206
  readonly repository?: IssueRepository | undefined;
@@ -217,7 +217,7 @@ export declare class Issue implements IssueShape {
217
217
  readonly iterations?: IssueIteration[] | undefined;
218
218
  readonly projection?: IssueProjection | undefined;
219
219
  readonly type = "issue";
220
- constructor(provider: ProviderReference, id: string, nodeId: string | undefined, title: string, url: string, createdDate: Date, updatedDate: Date, closed: boolean, state: IssueOrPullRequestState, author: IssueMember | undefined, assignees: IssueMember[], repository?: IssueRepository | undefined, closedDate?: Date | undefined, labels?: IssueLabel[] | undefined, commentsCount?: number | undefined, thumbsUpCount?: number | undefined, body?: string | undefined, project?: IssueProject | undefined, number?: string | undefined, issueType?: string | undefined, providerState?: IssueProviderState | undefined, bodyFormat?: IssueBodyFormat | undefined, iterations?: IssueIteration[] | undefined, projection?: IssueProjection | undefined);
220
+ constructor(provider: ProviderReference, id: string, nodeId: string | undefined, title: string, url: string, createdDate: Date, updatedDate: Date, closed: boolean, state: IssueOrPullRequestState | undefined, author: IssueMember | undefined, assignees: IssueMember[], repository?: IssueRepository | undefined, closedDate?: Date | undefined, labels?: IssueLabel[] | undefined, commentsCount?: number | undefined, thumbsUpCount?: number | undefined, body?: string | undefined, project?: IssueProject | undefined, number?: string | undefined, issueType?: string | undefined, providerState?: IssueProviderState | undefined, bodyFormat?: IssueBodyFormat | undefined, iterations?: IssueIteration[] | undefined, projection?: IssueProjection | undefined);
221
221
  static is(issue: unknown): issue is Issue;
222
222
  }
223
223
  export type IssueBodyFormat = 'markdown' | 'jira-wiki';
@@ -1 +1 @@
1
- {"version":3,"file":"issue.js","names":[],"sources":["../../../../git/src/models/issue.ts"],"sourcesContent":["import { loggable } from '@gitlens/utils/decorators/log.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\n/** Selects which issue states a read should include. `all` covers open + closed. */\nexport type IssueStateFilter = 'open' | 'closed' | 'all';\n\n/**\n * One relationship a filtered issue search can constrain on.\n *\n * The last two are USER-INDEPENDENT — they describe the issue, not the caller — and neither is a SCOPE: either\n * one alone matches every such issue on the host, so a search using one still needs a repository/org scope.\n */\nexport type IssueSearchRelationship =\n\t/** Authored by the current user. */\n\t| 'authored'\n\t/** Assigned to the current user. */\n\t| 'assigned'\n\t/** Mentions the current user. */\n\t| 'mentioned'\n\t/** Assigned to ANYONE. Excludes unassigned issues — see {@link IssueSearchCriteria.relationships}. */\n\t| 'any-assignee'\n\t/** Assigned to nobody. The complement of `any-assignee`, not a broadening of it. */\n\t| 'unassigned';\n\n/**\n * A field an issue read can be ordered by, provider-neutral. No provider expresses all of them: each read\n * validates the requested key against the capability its provider declares and refuses one it can't express\n * server-side, rather than serving a differently-ordered list under the name of the one that was asked for.\n *\n * `closed` and `resolved` are deliberately SEPARATE, not two names for the same date. Azure DevOps tracks both\n * and they differ (an issue can be closed without being resolved and resolved without being closed), and Jira\n * has no close date at all — it models the equivalent as `resolutiondate`. Collapsing them would force one of\n * those two providers to lie about which date it ordered by.\n */\nexport type IssueSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated'\n\t/** Close date. Only where the provider orders by it server-side — notably NOT GitHub. */\n\t| 'closed'\n\t/** Resolution date (Jira `resolutiondate`, Azure `ResolvedDate`). Distinct from `closed`. */\n\t| 'resolved'\n\t/** Number of comments. */\n\t| 'comments'\n\t/** Reactions/upvotes. */\n\t| 'reactions'\n\t/** The provider's own priority field. */\n\t| 'priority'\n\t/** Due date. */\n\t| 'dueDate'\n\t/** Alphabetical by title. */\n\t| 'title';\n\n/**\n * How an issue read is ordered, as `field:direction` — the same shape `BranchSorting`/`TagSorting` already use,\n * so it is one serializable string a consumer can persist, compare, or bind straight to a setting or a dropdown.\n */\nexport type IssueSorting = `${IssueSortField}:asc` | `${IssueSortField}:desc`;\n\n/**\n * The order every issue read that HAS a default applies when the caller asks for none: most recently updated\n * first, which is what those reads served before ordering was an option.\n *\n * One definition rather than one per layer, because it is a promise made in several places at once — the criteria\n * model documents it, the GitHub query emits it, and the result-ceiling warning quotes it — and three copies would\n * be free to disagree about what \"the default\" is.\n *\n * Note it is not a default every read has, and the two layers differ. The API client's account-wide \"my issues\"\n * search (`GitHubApi.searchMyIssues`) never requested an order, so a direct caller omitting `sort` still gets\n * GitHub's relevance order — the default is opt-in there, to keep that read's already-shipped results unchanged.\n * The FACADE does apply it: GitHub declares `updated:desc` among its account-wide keys, so\n * `readAccountWideIssuesPage` resolves the omission to this default and forwards it, and that read's emitted query\n * gained a `sort:updated` qualifier it did not have before. A read whose surface cannot express even this key is\n * the only one the facade leaves in the provider's own order.\n */\nexport const defaultIssueSort: IssueSorting = 'updated:desc';\n\n/**\n * What a filtered issue search narrows on: a provider-neutral criteria set, translated to each provider's own\n * query language by its integration.\n *\n * Structured rather than a provider query string so a consumer can render filter chips and hide the ones a\n * provider can't express, and so the same criteria mean the same thing on a provider whose query language looks\n * nothing like GitHub's search syntax. Every field is validated against the provider's declared capability\n * BEFORE the read runs, all-or-nothing: a criterion the provider can't express server-side refuses the whole\n * read rather than serving a list that was never narrowed. Client-side narrowing is not an option — the dropped\n * items still counted toward the page and cursor the provider produced, so a post-filter would leave the items\n * describing a different result set than the paging that came with them.\n */\nexport interface IssueSearchCriteria {\n\t/**\n\t * Relationships to constrain on, OR-ed together (each becomes its own provider query, unioned and deduped).\n\t * Omitted means NO relationship constraint at all — every issue in scope, assigned or not — which requires a\n\t * repository/org scope.\n\t *\n\t * `any-assignee` and `unassigned` partition the scope between them and are mutually exclusive; passing both is\n\t * refused rather than silently dropping one. Note that \"all visible issues\" is the OMITTED case, NOT\n\t * `any-assignee`, which excludes unassigned issues.\n\t */\n\trelationships?: IssueSearchRelationship[];\n\t/**\n\t * Free text, matched by the provider's own relevance rules — NOT a substring match, and not a way to smuggle\n\t * qualifiers: a token that would read as one is dropped, as are quotes and control characters, so text can\n\t * never re-scope the search. The structured criteria are the qualifier channel.\n\t */\n\ttext?: string;\n\t/** Issue states to include. Omitted reads open issues only. */\n\tstate?: IssueStateFilter;\n\t/** Labels the issue must carry — AND-ed, matching GitHub's own `label:` semantics. */\n\tlabels?: string[];\n\tmilestone?: string;\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Issues with no linked pull request. */\n\twithoutLinkedPullRequest?: boolean;\n\t/** Includes issues in archived repositories, which are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated like every other criterion — all-or-nothing against {@link IssueSearchCapabilities.sorts}: a key\n\t * the provider can't express server-side refuses the WHOLE read rather than falling back to the default.\n\t * Serving another order is not a smaller error than serving a wider result: combined with the provider's\n\t * result ceiling it returns a different subset than was asked for, and the paging that comes with it describes\n\t * that other subset.\n\t *\n\t * Do not change it mid-pagination. A cursor carries the sort it was produced under, and threading it under a\n\t * different key is refused rather than serving a sequence with gaps and repeats: drop the cursor instead.\n\t */\n\tsort?: IssueSorting;\n}\n\n/**\n * Which {@link IssueSearchCriteria} fields a provider's filtered issue search can express server-side.\n *\n * An empty `relationships` with every flag false means the provider has NO filtered issue search — the read is\n * refused outright, so a consumer should offer neither the surface nor its chips.\n */\nexport interface IssueSearchCapabilities {\n\t/** Relationships the search can constrain on. Empty means the search itself is unsupported. */\n\trelationships: IssueSearchRelationship[];\n\ttext: boolean;\n\tlabels: boolean;\n\tmilestone: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\twithoutLinkedPullRequest: boolean;\n\t/** Whether {@link IssueSearchCriteria.state} can select anything other than the provider's default (open). */\n\tstates: boolean;\n\t/**\n\t * Sort keys the search can express IN SERVER. Always contains at least `updated:desc` — the historical default\n\t * — when the search exists at all, so it is never empty for a usable surface; a provider without a filtered\n\t * search reports an empty `relationships`, which is already the signal that there is no surface to order.\n\t */\n\tsorts: IssueSorting[];\n}\n\n/**\n * The read that produced an issue row, as a key for `getIssueFieldPresence` (`@gitlens/integrations`). It names a\n * READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type IssueProjection =\n\t/** A single-item read. */\n\t| 'point'\n\t/** The filtered search. */\n\t| 'search'\n\t/** The account-wide list, and the trackers' \"my issues\". */\n\t| 'account'\n\t/** A repository-scoped list. */\n\t| 'repos'\n\t/** A tracker project's issues (`listIssueTrackerIssuesPage`, `getIssuesForProject`). */\n\t| 'project'\n\t/** The batch read. */\n\t| 'batch';\n\nexport interface IssueShape extends IssueOrPullRequest {\n\t/** `undefined` when the provider can't resolve the author, e.g. a deleted GitHub account */\n\tauthor: IssueMember | undefined;\n\tassignees: IssueMember[];\n\t/** The provider's own workflow state, when it exposes one beyond the normalized open/closed state. */\n\tproviderState?: IssueProviderState;\n\trepository?: IssueRepository;\n\tlabels?: IssueLabel[];\n\tbody?: string;\n\t/**\n\t * The syntax used by `body`. When omitted, consumers should treat `body` as Markdown — except that Azure DevOps\n\t * work items and Bitbucket Cloud issues carry HTML with no `bodyFormat` set.\n\t */\n\tbodyFormat?: IssueBodyFormat;\n\tproject?: IssueProject;\n\tissueType?: string;\n\t/** An issue can belong to several Jira sprints; Azure reports one iteration. */\n\titerations?: IssueIteration[];\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: IssueProjection;\n}\n\n@loggable(i => i.id)\nexport class Issue implements IssueShape {\n\treadonly type = 'issue';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closed: boolean,\n\t\tpublic readonly state: IssueOrPullRequestState,\n\t\tpublic readonly author: IssueMember | undefined,\n\t\tpublic readonly assignees: IssueMember[],\n\t\tpublic readonly repository?: IssueRepository,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly labels?: IssueLabel[],\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly body?: string,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly number?: string,\n\t\tpublic readonly issueType?: string,\n\t\tpublic readonly providerState?: IssueProviderState,\n\t\tpublic readonly bodyFormat?: IssueBodyFormat,\n\t\tpublic readonly iterations?: IssueIteration[],\n\t\tpublic readonly projection?: IssueProjection,\n\t) {}\n\n\tstatic is(issue: unknown): issue is Issue {\n\t\treturn issue instanceof Issue;\n\t}\n}\n\nexport type IssueBodyFormat = 'markdown' | 'jira-wiki';\n\nexport const enum RepositoryAccessLevel {\n\tAdmin = 100,\n\tMaintain = 40,\n\tWrite = 30,\n\tTriage = 20,\n\tRead = 10,\n\tNone = 0,\n}\n\nexport interface IssueLabel {\n\tcolor?: string;\n\tname: string;\n}\n\n/**\n * Sprint metadata is optional because some providers only report an iteration path. An absent `isActive`\n * means unknown, not inactive, so consumers must not use it to exclude those iterations by default.\n */\nexport interface IssueIteration {\n\t/**\n\t * A sprint id on Jira, the verbatim iteration path on Azure — so it is only meaningful within the provider's\n\t * project, never across providers. Unique at read time but NOT durable: Azure rewrites the path when an\n\t * iteration node is renamed or re-parented, so don't persist it as a long-lived id.\n\t */\n\tid: string;\n\tname: string;\n\tisActive?: boolean;\n\tstartDate?: Date;\n\tendDate?: Date;\n}\n\nexport interface IssueMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member. Optional on purpose: a fallback string\n\t * invented here (`'unknown'`, `''`) can't be told apart from a real name downstream, so it can't be undone by a\n\t * consumer that needs to render something else — or nothing at all, as when the member feeds an AI prompt.\n\t * Each consumer picks its own presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\nexport type IssueProviderState = {\n\tid?: string;\n\tname: string;\n\tcolor?: string;\n\t/** The provider's workflow category. `CANCELED` is abandoned work (Linear's canceled and duplicate states, Azure's\n\t * `Removed` category): closed like `DONE`, kept apart so a consumer can tell the two outcomes apart. */\n\tcategory?: 'TO_DO' | 'IN_PROGRESS' | 'DONE' | 'CANCELED';\n};\n\nexport interface IssueProject {\n\tid: string;\n\tname: string;\n\tresourceId: string;\n\tresourceName: string;\n}\n\nexport interface IssueRepository {\n\towner: string;\n\trepo: string;\n\taccessLevel?: RepositoryAccessLevel;\n\turl?: string;\n\tid?: string;\n}\n\nexport type IssueRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+EA,MAAa,mBAAiC;AA6HvC,IAAM,QAAA,SAAN,MAAM,MAA4B;CAIvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CA1BjB,OAAgB;CAEhB,YACC,UACA,IACA,QACA,OACA,KACA,aACA,aACA,QACA,OACA,QACA,WACA,YACA,YACA,QACA,eACA,eACA,MACA,SACA,QACA,WACA,eACA,YACA,YACA,YACC;EAxBe,KAAA,WAAA;EACA,KAAA,KAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,MAAA;EACA,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,SAAA;EACA,KAAA,gBAAA;EACA,KAAA,gBAAA;EACA,KAAA,OAAA;EACA,KAAA,UAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,gBAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;CACd;CAEH,OAAO,GAAG,OAAgC;EACzC,OAAO,iBAAA;CACR;AACD;AAlCC,QAAA,SAAA,WAAA,CAAA,UAAS,MAAK,EAAE,EAAE,CAAA,GAAA,KAAA;AAsCnB,IAAkB,wBAAX,yBAAA,uBAAA;CACN,sBAAA,sBAAA,WAAA,OAAA;CACA,sBAAA,sBAAA,cAAA,MAAA;CACA,sBAAA,sBAAA,WAAA,MAAA;CACA,sBAAA,sBAAA,YAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,KAAA;;AACD,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"issue.js","names":[],"sources":["../../../../git/src/models/issue.ts"],"sourcesContent":["import { loggable } from '@gitlens/utils/decorators/log.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\n/** Selects which issue states a read should include. `all` covers open + closed. */\nexport type IssueStateFilter = 'open' | 'closed' | 'all';\n\n/**\n * One relationship a filtered issue search can constrain on.\n *\n * The last two are USER-INDEPENDENT — they describe the issue, not the caller — and neither is a SCOPE: either\n * one alone matches every such issue on the host, so a search using one still needs a repository/org scope.\n */\nexport type IssueSearchRelationship =\n\t/** Authored by the current user. */\n\t| 'authored'\n\t/** Assigned to the current user. */\n\t| 'assigned'\n\t/** Mentions the current user. */\n\t| 'mentioned'\n\t/** Assigned to ANYONE. Excludes unassigned issues — see {@link IssueSearchCriteria.relationships}. */\n\t| 'any-assignee'\n\t/** Assigned to nobody. The complement of `any-assignee`, not a broadening of it. */\n\t| 'unassigned';\n\n/**\n * A field an issue read can be ordered by, provider-neutral. No provider expresses all of them: each read\n * validates the requested key against the capability its provider declares and refuses one it can't express\n * server-side, rather than serving a differently-ordered list under the name of the one that was asked for.\n *\n * `closed` and `resolved` are deliberately SEPARATE, not two names for the same date. Azure DevOps tracks both\n * and they differ (an issue can be closed without being resolved and resolved without being closed), and Jira\n * has no close date at all — it models the equivalent as `resolutiondate`. Collapsing them would force one of\n * those two providers to lie about which date it ordered by.\n */\nexport type IssueSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated'\n\t/** Close date. Only where the provider orders by it server-side — notably NOT GitHub. */\n\t| 'closed'\n\t/** Resolution date (Jira `resolutiondate`, Azure `ResolvedDate`). Distinct from `closed`. */\n\t| 'resolved'\n\t/** Number of comments. */\n\t| 'comments'\n\t/** Reactions/upvotes. */\n\t| 'reactions'\n\t/** The provider's own priority field. */\n\t| 'priority'\n\t/** Due date. */\n\t| 'dueDate'\n\t/** Alphabetical by title. */\n\t| 'title';\n\n/**\n * How an issue read is ordered, as `field:direction` — the same shape `BranchSorting`/`TagSorting` already use,\n * so it is one serializable string a consumer can persist, compare, or bind straight to a setting or a dropdown.\n */\nexport type IssueSorting = `${IssueSortField}:asc` | `${IssueSortField}:desc`;\n\n/**\n * The order every issue read that HAS a default applies when the caller asks for none: most recently updated\n * first, which is what those reads served before ordering was an option.\n *\n * One definition rather than one per layer, because it is a promise made in several places at once — the criteria\n * model documents it, the GitHub query emits it, and the result-ceiling warning quotes it — and three copies would\n * be free to disagree about what \"the default\" is.\n *\n * Note it is not a default every read has, and the two layers differ. The API client's account-wide \"my issues\"\n * search (`GitHubApi.searchMyIssues`) never requested an order, so a direct caller omitting `sort` still gets\n * GitHub's relevance order — the default is opt-in there, to keep that read's already-shipped results unchanged.\n * The FACADE does apply it: GitHub declares `updated:desc` among its account-wide keys, so\n * `readAccountWideIssuesPage` resolves the omission to this default and forwards it, and that read's emitted query\n * gained a `sort:updated` qualifier it did not have before. A read whose surface cannot express even this key is\n * the only one the facade leaves in the provider's own order.\n */\nexport const defaultIssueSort: IssueSorting = 'updated:desc';\n\n/**\n * What a filtered issue search narrows on: a provider-neutral criteria set, translated to each provider's own\n * query language by its integration.\n *\n * Structured rather than a provider query string so a consumer can render filter chips and hide the ones a\n * provider can't express, and so the same criteria mean the same thing on a provider whose query language looks\n * nothing like GitHub's search syntax. Every field is validated against the provider's declared capability\n * BEFORE the read runs, all-or-nothing: a criterion the provider can't express server-side refuses the whole\n * read rather than serving a list that was never narrowed. Client-side narrowing is not an option — the dropped\n * items still counted toward the page and cursor the provider produced, so a post-filter would leave the items\n * describing a different result set than the paging that came with them.\n */\nexport interface IssueSearchCriteria {\n\t/**\n\t * Relationships to constrain on, OR-ed together (each becomes its own provider query, unioned and deduped).\n\t * Omitted means NO relationship constraint at all — every issue in scope, assigned or not — which requires a\n\t * repository/org scope.\n\t *\n\t * `any-assignee` and `unassigned` partition the scope between them and are mutually exclusive; passing both is\n\t * refused rather than silently dropping one. Note that \"all visible issues\" is the OMITTED case, NOT\n\t * `any-assignee`, which excludes unassigned issues.\n\t */\n\trelationships?: IssueSearchRelationship[];\n\t/**\n\t * Free text, matched by the provider's own relevance rules — NOT a substring match, and not a way to smuggle\n\t * qualifiers: a token that would read as one is dropped, as are quotes and control characters, so text can\n\t * never re-scope the search. The structured criteria are the qualifier channel.\n\t */\n\ttext?: string;\n\t/** Issue states to include. Omitted reads open issues only. */\n\tstate?: IssueStateFilter;\n\t/** Labels the issue must carry — AND-ed, matching GitHub's own `label:` semantics. */\n\tlabels?: string[];\n\tmilestone?: string;\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Issues with no linked pull request. */\n\twithoutLinkedPullRequest?: boolean;\n\t/** Includes issues in archived repositories, which are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated like every other criterion — all-or-nothing against {@link IssueSearchCapabilities.sorts}: a key\n\t * the provider can't express server-side refuses the WHOLE read rather than falling back to the default.\n\t * Serving another order is not a smaller error than serving a wider result: combined with the provider's\n\t * result ceiling it returns a different subset than was asked for, and the paging that comes with it describes\n\t * that other subset.\n\t *\n\t * Do not change it mid-pagination. A cursor carries the sort it was produced under, and threading it under a\n\t * different key is refused rather than serving a sequence with gaps and repeats: drop the cursor instead.\n\t */\n\tsort?: IssueSorting;\n}\n\n/**\n * Which {@link IssueSearchCriteria} fields a provider's filtered issue search can express server-side.\n *\n * An empty `relationships` with every flag false means the provider has NO filtered issue search — the read is\n * refused outright, so a consumer should offer neither the surface nor its chips.\n */\nexport interface IssueSearchCapabilities {\n\t/** Relationships the search can constrain on. Empty means the search itself is unsupported. */\n\trelationships: IssueSearchRelationship[];\n\ttext: boolean;\n\tlabels: boolean;\n\tmilestone: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\twithoutLinkedPullRequest: boolean;\n\t/** Whether {@link IssueSearchCriteria.state} can select anything other than the provider's default (open). */\n\tstates: boolean;\n\t/**\n\t * Sort keys the search can express IN SERVER. Always contains at least `updated:desc` — the historical default\n\t * — when the search exists at all, so it is never empty for a usable surface; a provider without a filtered\n\t * search reports an empty `relationships`, which is already the signal that there is no surface to order.\n\t */\n\tsorts: IssueSorting[];\n}\n\n/**\n * The read that produced an issue row, as a key for `getIssueFieldPresence` (`@gitlens/integrations`). It names a\n * READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type IssueProjection =\n\t/** A single-item read. */\n\t| 'point'\n\t/** The filtered search. */\n\t| 'search'\n\t/** The account-wide list, and the trackers' \"my issues\". */\n\t| 'account'\n\t/** A repository-scoped list. */\n\t| 'repos'\n\t/** A tracker project's issues (`listIssueTrackerIssuesPage`, `getIssuesForProject`). */\n\t| 'project'\n\t/** The batch read. */\n\t| 'batch';\n\nexport interface IssueShape extends IssueOrPullRequest {\n\t/** `undefined` when the provider can't resolve the author, e.g. a deleted GitHub account */\n\tauthor: IssueMember | undefined;\n\tassignees: IssueMember[];\n\t/** The provider's own workflow state, when it exposes one beyond the normalized open/closed state. */\n\tproviderState?: IssueProviderState;\n\trepository?: IssueRepository;\n\tlabels?: IssueLabel[];\n\tbody?: string;\n\t/**\n\t * The syntax used by `body`. When omitted, consumers should treat `body` as Markdown — except that Azure DevOps\n\t * work items and Bitbucket Cloud issues carry HTML with no `bodyFormat` set.\n\t */\n\tbodyFormat?: IssueBodyFormat;\n\tproject?: IssueProject;\n\tissueType?: string;\n\t/** An issue can belong to several Jira sprints; Azure reports one iteration. */\n\titerations?: IssueIteration[];\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: IssueProjection;\n}\n\n@loggable(i => i.id)\nexport class Issue implements IssueShape {\n\treadonly type = 'issue';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closed: boolean,\n\t\tpublic readonly state: IssueOrPullRequestState | undefined,\n\t\tpublic readonly author: IssueMember | undefined,\n\t\tpublic readonly assignees: IssueMember[],\n\t\tpublic readonly repository?: IssueRepository,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly labels?: IssueLabel[],\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly body?: string,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly number?: string,\n\t\tpublic readonly issueType?: string,\n\t\tpublic readonly providerState?: IssueProviderState,\n\t\tpublic readonly bodyFormat?: IssueBodyFormat,\n\t\tpublic readonly iterations?: IssueIteration[],\n\t\tpublic readonly projection?: IssueProjection,\n\t) {}\n\n\tstatic is(issue: unknown): issue is Issue {\n\t\treturn issue instanceof Issue;\n\t}\n}\n\nexport type IssueBodyFormat = 'markdown' | 'jira-wiki';\n\nexport const enum RepositoryAccessLevel {\n\tAdmin = 100,\n\tMaintain = 40,\n\tWrite = 30,\n\tTriage = 20,\n\tRead = 10,\n\tNone = 0,\n}\n\nexport interface IssueLabel {\n\tcolor?: string;\n\tname: string;\n}\n\n/**\n * Sprint metadata is optional because some providers only report an iteration path. An absent `isActive`\n * means unknown, not inactive, so consumers must not use it to exclude those iterations by default.\n */\nexport interface IssueIteration {\n\t/**\n\t * A sprint id on Jira, the verbatim iteration path on Azure — so it is only meaningful within the provider's\n\t * project, never across providers. Unique at read time but NOT durable: Azure rewrites the path when an\n\t * iteration node is renamed or re-parented, so don't persist it as a long-lived id.\n\t */\n\tid: string;\n\tname: string;\n\tisActive?: boolean;\n\tstartDate?: Date;\n\tendDate?: Date;\n}\n\nexport interface IssueMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member. Optional on purpose: a fallback string\n\t * invented here (`'unknown'`, `''`) can't be told apart from a real name downstream, so it can't be undone by a\n\t * consumer that needs to render something else — or nothing at all, as when the member feeds an AI prompt.\n\t * Each consumer picks its own presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\nexport type IssueProviderState = {\n\tid?: string;\n\tname: string;\n\tcolor?: string;\n\t/** The provider's workflow category. `CANCELED` is abandoned work (Linear's canceled and duplicate states, Azure's\n\t * `Removed` category): closed like `DONE`, kept apart so a consumer can tell the two outcomes apart. */\n\tcategory?: 'TO_DO' | 'IN_PROGRESS' | 'DONE' | 'CANCELED';\n};\n\nexport interface IssueProject {\n\tid: string;\n\tname: string;\n\tresourceId: string;\n\tresourceName: string;\n}\n\nexport interface IssueRepository {\n\towner: string;\n\trepo: string;\n\taccessLevel?: RepositoryAccessLevel;\n\turl?: string;\n\tid?: string;\n}\n\nexport type IssueRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+EA,MAAa,mBAAiC;AA6HvC,IAAM,QAAA,SAAN,MAAM,MAA4B;CAIvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CA1BjB,OAAgB;CAEhB,YACC,UACA,IACA,QACA,OACA,KACA,aACA,aACA,QACA,OACA,QACA,WACA,YACA,YACA,QACA,eACA,eACA,MACA,SACA,QACA,WACA,eACA,YACA,YACA,YACC;EAxBe,KAAA,WAAA;EACA,KAAA,KAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,MAAA;EACA,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,SAAA;EACA,KAAA,gBAAA;EACA,KAAA,gBAAA;EACA,KAAA,OAAA;EACA,KAAA,UAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,gBAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;CACd;CAEH,OAAO,GAAG,OAAgC;EACzC,OAAO,iBAAA;CACR;AACD;AAlCC,QAAA,SAAA,WAAA,CAAA,UAAS,MAAK,EAAE,EAAE,CAAA,GAAA,KAAA;AAsCnB,IAAkB,wBAAX,yBAAA,uBAAA;CACN,sBAAA,sBAAA,WAAA,OAAA;CACA,sBAAA,sBAAA,cAAA,MAAA;CACA,sBAAA,sBAAA,WAAA,MAAA;CACA,sBAAA,sBAAA,YAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,KAAA;;AACD,EAAA,CAAA,CAAA"}
@@ -11,7 +11,8 @@ export interface IssueOrPullRequest {
11
11
  readonly updatedDate: Date;
12
12
  readonly closedDate?: Date;
13
13
  readonly closed: boolean;
14
- readonly state: IssueOrPullRequestState;
14
+ /** Unset when the provider cannot classify the workflow state and supplies no closed date. */
15
+ readonly state: IssueOrPullRequestState | undefined;
15
16
  readonly commentsCount?: number;
16
17
  readonly thumbsUpCount?: number;
17
18
  }
@@ -28,6 +28,7 @@ export type PullRequestProjection =
28
28
  /** The coordinate and branch batch reads. */
29
29
  'batch';
30
30
  export interface PullRequestShape extends IssueOrPullRequest {
31
+ readonly state: IssueOrPullRequestState;
31
32
  readonly author: PullRequestMember;
32
33
  /**
33
34
  * Canonical base-repository identity returned by the provider. Some providers
@@ -1 +1 @@
1
- {"version":3,"file":"pullRequest.js","names":[],"sources":["../../../../git/src/models/pullRequest.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueProject, IssueRepository } from './issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState as PullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\nexport type { PullRequestState };\n\n/**\n * The read that produced a pull request row, as a key for `getPullRequestFieldPresence` (`@gitlens/integrations`). It\n * names a READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type PullRequestProjection =\n\t/** A single-item read: by number, for a branch, or for a commit. */\n\t| 'point'\n\t/** The filtered search with the full projection, and the host's \"my pull requests\" search. */\n\t| 'search'\n\t/** The filtered search with `summary`. */\n\t| 'search-summary'\n\t/** The free-text search (`searchPullRequests`). */\n\t| 'text-search'\n\t/** An account-wide sweep with the full projection (`includeReviews`). */\n\t| 'account'\n\t/** An account-wide list or sweep with the lightweight projection. */\n\t| 'account-summary'\n\t/** A repository-scoped list or sweep. */\n\t| 'repos'\n\t/** A repository-scoped list with `summary`. */\n\t| 'repos-summary'\n\t/** The coordinate and branch batch reads. */\n\t| 'batch';\n\nexport interface PullRequestShape extends IssueOrPullRequest {\n\treadonly author: PullRequestMember;\n\t/**\n\t * Canonical base-repository identity returned by the provider. Some providers\n\t * scope pull-request ids to a repository, so consumers must not have to infer\n\t * identity from optional refs or URLs.\n\t */\n\treadonly repository?: IssueRepository;\n\treadonly mergedDate?: Date;\n\treadonly refs?: PullRequestRefs;\n\treadonly isDraft?: boolean;\n\treadonly additions?: number;\n\treadonly deletions?: number;\n\treadonly filesChanged?: number;\n\treadonly body?: string;\n\treadonly mergeableState?: PullRequestMergeableState;\n\treadonly reviewDecision?: PullRequestReviewDecision;\n\treadonly reviewRequests?: PullRequestReviewer[];\n\t/**\n\t * Reviews already submitted, as opposed to the still-pending {@link reviewRequests}. Absent means the read\n\t * didn't fetch reviews; empty means nobody has reviewed — but only where the read actually fetched them, which\n\t * is provider- and read-dependent: ask `getPullRequestFieldPresence` (`@gitlens/integrations`) for the row's\n\t * `reviews` group rather than trusting an empty array.\n\t * {@link PullRequestReviewer.commitOid} is the narrower promise: only the full GitHub/GHE projection has it.\n\t */\n\treadonly latestReviews?: PullRequestReviewer[];\n\treadonly assignees?: PullRequestMember[];\n\treadonly project?: IssueProject;\n\treadonly stack?: PullRequestStackInfo;\n\treadonly number?: number;\n\treadonly authoredByMe?: boolean;\n\t/**\n\t * The current account as this pull request's members identify it: the identity {@link authoredByMe} was matched\n\t * against, present exactly when that was. A consumer matching {@link reviewRequests} or {@link latestReviews}\n\t * entries to the current user compares against this, not the account `getCurrentAccount` returns: Azure DevOps\n\t * Server gives one person a different id in each collection than at the server level, and the members carry the\n\t * collection's. Core matches `username` too only on GitHub and GitHub Enterprise, whose rows key people by login.\n\t */\n\treadonly viewer?: { readonly id: string; readonly username?: string };\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: PullRequestProjection;\n}\n\n@loggable(i => i.id)\n@serializable\nexport class PullRequest implements PullRequestShape {\n\treadonly type = 'pullrequest';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly author: PullRequestMember,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly repository: IssueRepository,\n\t\tpublic readonly state: PullRequestState,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly mergedDate?: Date,\n\t\tpublic readonly mergeableState?: PullRequestMergeableState,\n\t\tpublic readonly viewerCanUpdate?: boolean,\n\t\tpublic readonly refs?: PullRequestRefs,\n\t\tpublic readonly isDraft?: boolean,\n\t\tpublic readonly additions?: number,\n\t\tpublic readonly deletions?: number,\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly reviewDecision?: PullRequestReviewDecision,\n\t\tpublic readonly reviewRequests?: PullRequestReviewer[],\n\t\tpublic readonly latestReviews?: PullRequestReviewer[],\n\t\tpublic readonly assignees?: PullRequestMember[],\n\t\tpublic readonly statusCheckRollupState?: PullRequestStatusCheckRollupState,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly version?: number,\n\t\t/** Commits on the head that aren't on the base. Appended rather than slotted with the other counts:\n\t\t * this constructor is positional and every mapper passes through it. */\n\t\tpublic readonly commitCount?: number,\n\t\tpublic readonly stack?: PullRequestStackInfo,\n\t\tpublic readonly filesChanged?: number,\n\t\t/** The pull request's description, as markdown. */\n\t\tpublic readonly body?: string,\n\t\tpublic readonly number?: number,\n\t\tpublic readonly authoredByMe?: boolean,\n\t\tpublic readonly projection?: PullRequestProjection,\n\t\tpublic readonly viewer?: { readonly id: string; readonly username?: string },\n\t) {}\n\n\tget closed(): boolean {\n\t\treturn this.state === 'closed';\n\t}\n\n\tstatic is(pr: unknown): pr is PullRequest {\n\t\treturn pr instanceof PullRequest;\n\t}\n\n\tstatic formatDate(pr: PullRequestShape, format?: string | null): string {\n\t\treturn formatDate(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate, format ?? 'MMMM Do, YYYY h:mma');\n\t}\n\n\tstatic formatDateFromNow(pr: PullRequestShape): string {\n\t\treturn fromNow(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate);\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tpr: PullRequestShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? PullRequest.formatDate(pr, formatting.dateFormat)\n\t\t\t: PullRequest.formatDateFromNow(pr);\n\t}\n}\n\nexport const enum PullRequestReviewDecision {\n\tApproved = 'Approved',\n\tChangesRequested = 'ChangesRequested',\n\tReviewRequired = 'ReviewRequired',\n}\n\nexport const enum PullRequestMergeableState {\n\tUnknown = 'Unknown',\n\tMergeable = 'Mergeable',\n\tConflicting = 'Conflicting',\n\tFailingChecks = 'FailingChecks',\n\tBlockedByPolicy = 'BlockedByPolicy',\n}\n\nexport const enum PullRequestStatusCheckRollupState {\n\tSuccess = 'success',\n\tPending = 'pending',\n\tFailed = 'failed',\n}\n\nexport const enum PullRequestMergeMethod {\n\tMerge = 'merge',\n\tSquash = 'squash',\n\tRebase = 'rebase',\n}\n\nexport const enum PullRequestReviewState {\n\tApproved = 'APPROVED',\n\tChangesRequested = 'CHANGES_REQUESTED',\n\tCommented = 'COMMENTED',\n\tDismissed = 'DISMISSED',\n\tPending = 'PENDING',\n\tReviewRequested = 'REVIEW_REQUESTED',\n}\n\nexport interface PullRequestComparisonRefs {\n\trepoPath: string;\n\tbase: { ref: string; label: string };\n\thead: { ref: string; label: string };\n}\n\nexport interface PullRequestMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member — same contract as `IssueMember.name`: a\n\t * fallback invented here can't be told apart from a real name downstream, so each consumer picks its own\n\t * presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\n/** Provider-neutral relationship facets shared by PR listings and filtered PR search. */\nexport enum PullRequestFilter {\n\tAuthor = 'author',\n\tAssignee = 'assignee',\n\tReviewRequested = 'review-requested',\n\t/**\n\t * PRs the user has already reviewed (GitHub `reviewed-by:@me`), as opposed to `ReviewRequested` (a\n\t * still-pending request). Distinguishes \"waiting on the author after my review\" from \"waiting for my\n\t * review\". Not expressible on the repo-scoped listing — no provider SDK exposes a reviewed-by axis there —\n\t * so it is advertised for the account-wide read and for the filtered search (which can still bound itself\n\t * to repositories or an org), never under `supportedPullRequestFilters`.\n\t */\n\tReviewed = 'reviewed-by',\n\tMention = 'mention',\n}\n\n/** Selects which pull request states a read should include. `all` covers open + closed + merged. */\nexport type PullRequestStateFilter = 'open' | 'closed' | 'merged' | 'all';\n\n/**\n * A field a pull-request read can be ordered by, provider-neutral.\n *\n * Only two, and deliberately so — unlike {@link IssueSortField} this is the INTERSECTION of what GitHub's PR\n * search can order by server-side and what a {@link PullRequestShape} carries, because the filtered PR search\n * always merges its relationship × state facets in the facade and so must re-order the union itself (see\n * `getPullRequestComparator`). `created` and `updated` are both. A field GitHub cannot order PRs by, or one a\n * merged page can't reproduce, is left out rather than advertised and then approximated: relevance is unstable\n * and has no comparable value on a merge, and priority is not a pull-request concept on any provider that has PRs.\n */\nexport type PullRequestSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated';\n\n/**\n * How a pull-request read is ordered, as `field:direction` — the same serializable shape {@link IssueSorting}\n * and `BranchSorting` use, so a consumer can persist it, compare it, or bind it straight to a setting or dropdown.\n */\nexport type PullRequestSorting = `${PullRequestSortField}:asc` | `${PullRequestSortField}:desc`;\n\n/**\n * The order the filtered pull-request search applies when the caller asks for none: most recently updated first,\n * which is what it served before ordering was an option. Named once rather than per layer — the criteria model\n * documents it, the GitHub query emits it, and the result-ceiling warning quotes it — so the three cannot\n * disagree about what \"the default\" is.\n */\nexport const defaultPullRequestSort: PullRequestSorting = 'updated:desc';\n\n/**\n * What the filtered pull-request search narrows on.\n *\n * Structured rather than a provider query string so callers can send free text without giving it a qualifier\n * channel, and can check {@link PullRequestSearchCapabilities} before issuing a read. Every requested criterion\n * is validated all-or-nothing before the provider runs; unsupported criteria never fall through to a wider\n * result set whose paging would no longer describe the returned items.\n *\n * Relationships are OR-ed, as are states. Omitting `relationships` removes the current-user constraint, which is\n * only safe when the manager call supplies a repository or organization scope. Omitting `states` reads open PRs.\n */\nexport interface PullRequestSearchCriteria {\n\t/**\n\t * Free text matched by the provider's own relevance rules. Tokens that look like provider qualifiers are\n\t * removed before the query is built, so text cannot change the search's scope or state.\n\t */\n\ttext?: string;\n\t/** Current-user relationship facets to union. Empty/omitted means no relationship constraint. */\n\trelationships?: PullRequestFilter[];\n\t/** Pull request states to union. Empty/omitted reads open PRs; `all` subsumes every other member. */\n\tstates?: PullRequestStateFilter[];\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Includes PRs from archived repositories. They are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * Narrows on draft state: `true` returns only drafts, `false` only ready-for-review PRs. Omitted places no\n\t * constraint. A boolean rather than a truthy flag because `false` is a distinct request, not the absence of one.\n\t */\n\tdraft?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated all-or-nothing against {@link PullRequestSearchCapabilities.sorts} like every other criterion: a\n\t * key the provider can't express server-side refuses the WHOLE read rather than falling back to the default,\n\t * because combined with the provider's result ceiling another order returns a different subset than was asked\n\t * for and the paging that comes with it describes that other subset. Do not change it mid-pagination — a\n\t * cursor carries the sort it was produced under; drop the cursor instead of threading it under a new key.\n\t */\n\tsort?: PullRequestSorting;\n}\n\n/**\n * Which {@link PullRequestSearchCriteria} fields and manager-level scopes a provider can express server-side.\n * An empty `relationships` means the provider has no filtered PR search at all.\n */\nexport interface PullRequestSearchCapabilities {\n\t/** Current-user relationship facets the provider can union. Empty means the search itself is unsupported. */\n\trelationships: PullRequestFilter[];\n\t/** Individual state values the provider can union in one logical search. */\n\tstates: PullRequestStateFilter[];\n\ttext: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\tincludeArchived: boolean;\n\t/** Whether the provider can constrain the search by draft state server-side. */\n\tdraft: boolean;\n\t/** Whether the manager's repository-descriptor scope is supported. */\n\trepositoryScope: boolean;\n\t/** Whether the manager's organization scope is supported. */\n\torganizationScope: boolean;\n\t/**\n\t * Sort keys the search can express server-side. Always contains at least `updated:desc` — the historical\n\t * default — when the search exists at all, so it is never empty for a usable surface; a provider without a\n\t * filtered PR search reports an empty `relationships`, which is already the signal there is no surface to order.\n\t */\n\tsorts: PullRequestSorting[];\n}\n\nexport interface PullRequestRef {\n\t/**\n\t * `undefined` when the ref's repository was deleted (a removed fork): GitHub's rows say so, with `exists` false.\n\t * provider-apis' converters fill `''` instead, so test for a value rather than for `undefined`.\n\t */\n\towner: string | undefined;\n\t/** `undefined` (or `''`) when the ref's repository was deleted, as {@link owner}. */\n\trepo: string | undefined;\n\tbranch: string;\n\tsha: string;\n\texists: boolean;\n\t/**\n\t * Web URL of the ref's repository. `undefined` when the provider cannot resolve it — Azure DevOps embeds an\n\t * abbreviated repository reference in a pull request, so a fork's URL may need a lookup that can fail.\n\t */\n\turl: string | undefined;\n\t/** HTTPS clone URL of the ref's repository, when the provider exposes it. */\n\tcloneHttps?: string;\n\t/** SSH clone URL of the ref's repository, when the provider exposes it. */\n\tcloneSsh?: string;\n\t/** Best-effort flag: whether the ref's repository is a fork. `undefined` when the provider can't tell. */\n\tisFork?: boolean;\n}\n\nexport interface PullRequestRefs {\n\tbase: PullRequestRef & { url: string };\n\thead: PullRequestRef;\n\tisCrossRepository: boolean;\n}\n\n/**\n * A pull request's membership in a stack — an ordered chain of dependent pull requests where each\n * targets the branch of the one below it.\n *\n * `baseRef` is the stack's ultimate target (its trunk) and is NOT the same as `refs.base`, which for\n * anything above the bottom layer names the layer below. Use `refs.base` to diff a single layer; use\n * `baseRef` to answer where the work ultimately lands.\n */\nexport interface PullRequestStackInfo {\n\t/**\n\t * Opaque, and NOT comparable across read paths: GitHub's GraphQL selection returns a node id\n\t * (`PRS_kwDO…`) while its REST stacks endpoint returns a numeric id (`1347135`) that we stringify —\n\t * both verified against the same live stack. Use {@link number} to identify a stack; two views of one\n\t * stack agree there and will not agree here.\n\t */\n\tid: string;\n\t/** Identifies the stack within its repository. */\n\tnumber: number;\n\t/** Total pull requests in the stack. */\n\tsize: number;\n\t/** This pull request's layer, 1-based, where 1 is closest to `baseRef`. */\n\tposition: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n}\n\n/**\n * One layer of a stack — the pull request occupying it, and the head ref a rebase or push needs to act\n * on. Unlike {@link PullRequestStackInfo}, which locates a single pull request within a stack, this is\n * the per-layer detail a caller walking the whole stack needs, e.g. to cascade a rebase bottom to top.\n */\nexport interface PullRequestStackLayer {\n\t/** The pull request's number. */\n\tnumber: number;\n\t/** The pull request's head branch name, without a remote prefix. */\n\theadRef: string;\n\t/** The head branch's tip when the stack was read. */\n\theadSha: string;\n\t/** `true` once this layer has landed. */\n\tmerged: boolean;\n\t/** `true` while this layer is still a draft. */\n\tdraft: boolean;\n}\n\n/**\n * A stack's layers, ordered bottom to top. `baseRef` is the stack's ultimate target (its trunk), the\n * same distinction drawn on {@link PullRequestStackInfo} — it is NOT the base of any individual layer\n * above the bottom, which targets the layer below it instead.\n */\nexport interface PullRequestStackLayers {\n\t/** Opaque and not comparable across read paths — see {@link PullRequestStackInfo.id}. */\n\tid: string;\n\tnumber: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n\t/** The stack's layers, ordered bottom (closest to {@link baseRef}) to top. */\n\tlayers: PullRequestStackLayer[];\n}\n\nexport interface PullRequestReviewer {\n\tisCodeOwner?: boolean;\n\treviewer: PullRequestMember;\n\tstate: PullRequestReviewState;\n\t/**\n\t * The head commit oid this review was submitted against (GitHub). Lets a consumer tell \"the PR moved past\n\t * my review\" (oid !== the PR's current head) from a review still at the tip — without a per-review\n\t * timestamp. Only populated where the full GitHub/GHE projection is selected: the filtered search read, and\n\t * an account-wide sweep that opts in with `includeReviews`. Undefined elsewhere, including reviews the\n\t * repo-scoped read carries natively.\n\t */\n\tcommitOid?: string;\n\t/**\n\t * The reviewer is a group the current user is a member of (a team or another group, directly or through a group\n\t * nested in it) rather than a person: a request to it is one the user can answer as a member, not one addressed to\n\t * them by name. Only the Azure DevOps reads that resolve the user's groups set it; absent elsewhere, including for\n\t * groups a read could not tell the user belongs to.\n\t */\n\tisMyGroup?: boolean;\n}\n\nexport type PullRequestRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"pullRequest.js","names":[],"sources":["../../../../git/src/models/pullRequest.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueProject, IssueRepository } from './issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState as PullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\nexport type { PullRequestState };\n\n/**\n * The read that produced a pull request row, as a key for `getPullRequestFieldPresence` (`@gitlens/integrations`). It\n * names a READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type PullRequestProjection =\n\t/** A single-item read: by number, for a branch, or for a commit. */\n\t| 'point'\n\t/** The filtered search with the full projection, and the host's \"my pull requests\" search. */\n\t| 'search'\n\t/** The filtered search with `summary`. */\n\t| 'search-summary'\n\t/** The free-text search (`searchPullRequests`). */\n\t| 'text-search'\n\t/** An account-wide sweep with the full projection (`includeReviews`). */\n\t| 'account'\n\t/** An account-wide list or sweep with the lightweight projection. */\n\t| 'account-summary'\n\t/** A repository-scoped list or sweep. */\n\t| 'repos'\n\t/** A repository-scoped list with `summary`. */\n\t| 'repos-summary'\n\t/** The coordinate and branch batch reads. */\n\t| 'batch';\n\nexport interface PullRequestShape extends IssueOrPullRequest {\n\treadonly state: PullRequestState;\n\treadonly author: PullRequestMember;\n\t/**\n\t * Canonical base-repository identity returned by the provider. Some providers\n\t * scope pull-request ids to a repository, so consumers must not have to infer\n\t * identity from optional refs or URLs.\n\t */\n\treadonly repository?: IssueRepository;\n\treadonly mergedDate?: Date;\n\treadonly refs?: PullRequestRefs;\n\treadonly isDraft?: boolean;\n\treadonly additions?: number;\n\treadonly deletions?: number;\n\treadonly filesChanged?: number;\n\treadonly body?: string;\n\treadonly mergeableState?: PullRequestMergeableState;\n\treadonly reviewDecision?: PullRequestReviewDecision;\n\treadonly reviewRequests?: PullRequestReviewer[];\n\t/**\n\t * Reviews already submitted, as opposed to the still-pending {@link reviewRequests}. Absent means the read\n\t * didn't fetch reviews; empty means nobody has reviewed — but only where the read actually fetched them, which\n\t * is provider- and read-dependent: ask `getPullRequestFieldPresence` (`@gitlens/integrations`) for the row's\n\t * `reviews` group rather than trusting an empty array.\n\t * {@link PullRequestReviewer.commitOid} is the narrower promise: only the full GitHub/GHE projection has it.\n\t */\n\treadonly latestReviews?: PullRequestReviewer[];\n\treadonly assignees?: PullRequestMember[];\n\treadonly project?: IssueProject;\n\treadonly stack?: PullRequestStackInfo;\n\treadonly number?: number;\n\treadonly authoredByMe?: boolean;\n\t/**\n\t * The current account as this pull request's members identify it: the identity {@link authoredByMe} was matched\n\t * against, present exactly when that was. A consumer matching {@link reviewRequests} or {@link latestReviews}\n\t * entries to the current user compares against this, not the account `getCurrentAccount` returns: Azure DevOps\n\t * Server gives one person a different id in each collection than at the server level, and the members carry the\n\t * collection's. Core matches `username` too only on GitHub and GitHub Enterprise, whose rows key people by login.\n\t */\n\treadonly viewer?: { readonly id: string; readonly username?: string };\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: PullRequestProjection;\n}\n\n@loggable(i => i.id)\n@serializable\nexport class PullRequest implements PullRequestShape {\n\treadonly type = 'pullrequest';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly author: PullRequestMember,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly repository: IssueRepository,\n\t\tpublic readonly state: PullRequestState,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly mergedDate?: Date,\n\t\tpublic readonly mergeableState?: PullRequestMergeableState,\n\t\tpublic readonly viewerCanUpdate?: boolean,\n\t\tpublic readonly refs?: PullRequestRefs,\n\t\tpublic readonly isDraft?: boolean,\n\t\tpublic readonly additions?: number,\n\t\tpublic readonly deletions?: number,\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly reviewDecision?: PullRequestReviewDecision,\n\t\tpublic readonly reviewRequests?: PullRequestReviewer[],\n\t\tpublic readonly latestReviews?: PullRequestReviewer[],\n\t\tpublic readonly assignees?: PullRequestMember[],\n\t\tpublic readonly statusCheckRollupState?: PullRequestStatusCheckRollupState,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly version?: number,\n\t\t/** Commits on the head that aren't on the base. Appended rather than slotted with the other counts:\n\t\t * this constructor is positional and every mapper passes through it. */\n\t\tpublic readonly commitCount?: number,\n\t\tpublic readonly stack?: PullRequestStackInfo,\n\t\tpublic readonly filesChanged?: number,\n\t\t/** The pull request's description, as markdown. */\n\t\tpublic readonly body?: string,\n\t\tpublic readonly number?: number,\n\t\tpublic readonly authoredByMe?: boolean,\n\t\tpublic readonly projection?: PullRequestProjection,\n\t\tpublic readonly viewer?: { readonly id: string; readonly username?: string },\n\t) {}\n\n\tget closed(): boolean {\n\t\treturn this.state === 'closed';\n\t}\n\n\tstatic is(pr: unknown): pr is PullRequest {\n\t\treturn pr instanceof PullRequest;\n\t}\n\n\tstatic formatDate(pr: PullRequestShape, format?: string | null): string {\n\t\treturn formatDate(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate, format ?? 'MMMM Do, YYYY h:mma');\n\t}\n\n\tstatic formatDateFromNow(pr: PullRequestShape): string {\n\t\treturn fromNow(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate);\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tpr: PullRequestShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? PullRequest.formatDate(pr, formatting.dateFormat)\n\t\t\t: PullRequest.formatDateFromNow(pr);\n\t}\n}\n\nexport const enum PullRequestReviewDecision {\n\tApproved = 'Approved',\n\tChangesRequested = 'ChangesRequested',\n\tReviewRequired = 'ReviewRequired',\n}\n\nexport const enum PullRequestMergeableState {\n\tUnknown = 'Unknown',\n\tMergeable = 'Mergeable',\n\tConflicting = 'Conflicting',\n\tFailingChecks = 'FailingChecks',\n\tBlockedByPolicy = 'BlockedByPolicy',\n}\n\nexport const enum PullRequestStatusCheckRollupState {\n\tSuccess = 'success',\n\tPending = 'pending',\n\tFailed = 'failed',\n}\n\nexport const enum PullRequestMergeMethod {\n\tMerge = 'merge',\n\tSquash = 'squash',\n\tRebase = 'rebase',\n}\n\nexport const enum PullRequestReviewState {\n\tApproved = 'APPROVED',\n\tChangesRequested = 'CHANGES_REQUESTED',\n\tCommented = 'COMMENTED',\n\tDismissed = 'DISMISSED',\n\tPending = 'PENDING',\n\tReviewRequested = 'REVIEW_REQUESTED',\n}\n\nexport interface PullRequestComparisonRefs {\n\trepoPath: string;\n\tbase: { ref: string; label: string };\n\thead: { ref: string; label: string };\n}\n\nexport interface PullRequestMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member — same contract as `IssueMember.name`: a\n\t * fallback invented here can't be told apart from a real name downstream, so each consumer picks its own\n\t * presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\n/** Provider-neutral relationship facets shared by PR listings and filtered PR search. */\nexport enum PullRequestFilter {\n\tAuthor = 'author',\n\tAssignee = 'assignee',\n\tReviewRequested = 'review-requested',\n\t/**\n\t * PRs the user has already reviewed (GitHub `reviewed-by:@me`), as opposed to `ReviewRequested` (a\n\t * still-pending request). Distinguishes \"waiting on the author after my review\" from \"waiting for my\n\t * review\". Not expressible on the repo-scoped listing — no provider SDK exposes a reviewed-by axis there —\n\t * so it is advertised for the account-wide read and for the filtered search (which can still bound itself\n\t * to repositories or an org), never under `supportedPullRequestFilters`.\n\t */\n\tReviewed = 'reviewed-by',\n\tMention = 'mention',\n}\n\n/** Selects which pull request states a read should include. `all` covers open + closed + merged. */\nexport type PullRequestStateFilter = 'open' | 'closed' | 'merged' | 'all';\n\n/**\n * A field a pull-request read can be ordered by, provider-neutral.\n *\n * Only two, and deliberately so — unlike {@link IssueSortField} this is the INTERSECTION of what GitHub's PR\n * search can order by server-side and what a {@link PullRequestShape} carries, because the filtered PR search\n * always merges its relationship × state facets in the facade and so must re-order the union itself (see\n * `getPullRequestComparator`). `created` and `updated` are both. A field GitHub cannot order PRs by, or one a\n * merged page can't reproduce, is left out rather than advertised and then approximated: relevance is unstable\n * and has no comparable value on a merge, and priority is not a pull-request concept on any provider that has PRs.\n */\nexport type PullRequestSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated';\n\n/**\n * How a pull-request read is ordered, as `field:direction` — the same serializable shape {@link IssueSorting}\n * and `BranchSorting` use, so a consumer can persist it, compare it, or bind it straight to a setting or dropdown.\n */\nexport type PullRequestSorting = `${PullRequestSortField}:asc` | `${PullRequestSortField}:desc`;\n\n/**\n * The order the filtered pull-request search applies when the caller asks for none: most recently updated first,\n * which is what it served before ordering was an option. Named once rather than per layer — the criteria model\n * documents it, the GitHub query emits it, and the result-ceiling warning quotes it — so the three cannot\n * disagree about what \"the default\" is.\n */\nexport const defaultPullRequestSort: PullRequestSorting = 'updated:desc';\n\n/**\n * What the filtered pull-request search narrows on.\n *\n * Structured rather than a provider query string so callers can send free text without giving it a qualifier\n * channel, and can check {@link PullRequestSearchCapabilities} before issuing a read. Every requested criterion\n * is validated all-or-nothing before the provider runs; unsupported criteria never fall through to a wider\n * result set whose paging would no longer describe the returned items.\n *\n * Relationships are OR-ed, as are states. Omitting `relationships` removes the current-user constraint, which is\n * only safe when the manager call supplies a repository or organization scope. Omitting `states` reads open PRs.\n */\nexport interface PullRequestSearchCriteria {\n\t/**\n\t * Free text matched by the provider's own relevance rules. Tokens that look like provider qualifiers are\n\t * removed before the query is built, so text cannot change the search's scope or state.\n\t */\n\ttext?: string;\n\t/** Current-user relationship facets to union. Empty/omitted means no relationship constraint. */\n\trelationships?: PullRequestFilter[];\n\t/** Pull request states to union. Empty/omitted reads open PRs; `all` subsumes every other member. */\n\tstates?: PullRequestStateFilter[];\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Includes PRs from archived repositories. They are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * Narrows on draft state: `true` returns only drafts, `false` only ready-for-review PRs. Omitted places no\n\t * constraint. A boolean rather than a truthy flag because `false` is a distinct request, not the absence of one.\n\t */\n\tdraft?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated all-or-nothing against {@link PullRequestSearchCapabilities.sorts} like every other criterion: a\n\t * key the provider can't express server-side refuses the WHOLE read rather than falling back to the default,\n\t * because combined with the provider's result ceiling another order returns a different subset than was asked\n\t * for and the paging that comes with it describes that other subset. Do not change it mid-pagination — a\n\t * cursor carries the sort it was produced under; drop the cursor instead of threading it under a new key.\n\t */\n\tsort?: PullRequestSorting;\n}\n\n/**\n * Which {@link PullRequestSearchCriteria} fields and manager-level scopes a provider can express server-side.\n * An empty `relationships` means the provider has no filtered PR search at all.\n */\nexport interface PullRequestSearchCapabilities {\n\t/** Current-user relationship facets the provider can union. Empty means the search itself is unsupported. */\n\trelationships: PullRequestFilter[];\n\t/** Individual state values the provider can union in one logical search. */\n\tstates: PullRequestStateFilter[];\n\ttext: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\tincludeArchived: boolean;\n\t/** Whether the provider can constrain the search by draft state server-side. */\n\tdraft: boolean;\n\t/** Whether the manager's repository-descriptor scope is supported. */\n\trepositoryScope: boolean;\n\t/** Whether the manager's organization scope is supported. */\n\torganizationScope: boolean;\n\t/**\n\t * Sort keys the search can express server-side. Always contains at least `updated:desc` — the historical\n\t * default — when the search exists at all, so it is never empty for a usable surface; a provider without a\n\t * filtered PR search reports an empty `relationships`, which is already the signal there is no surface to order.\n\t */\n\tsorts: PullRequestSorting[];\n}\n\nexport interface PullRequestRef {\n\t/**\n\t * `undefined` when the ref's repository was deleted (a removed fork): GitHub's rows say so, with `exists` false.\n\t * provider-apis' converters fill `''` instead, so test for a value rather than for `undefined`.\n\t */\n\towner: string | undefined;\n\t/** `undefined` (or `''`) when the ref's repository was deleted, as {@link owner}. */\n\trepo: string | undefined;\n\tbranch: string;\n\tsha: string;\n\texists: boolean;\n\t/**\n\t * Web URL of the ref's repository. `undefined` when the provider cannot resolve it — Azure DevOps embeds an\n\t * abbreviated repository reference in a pull request, so a fork's URL may need a lookup that can fail.\n\t */\n\turl: string | undefined;\n\t/** HTTPS clone URL of the ref's repository, when the provider exposes it. */\n\tcloneHttps?: string;\n\t/** SSH clone URL of the ref's repository, when the provider exposes it. */\n\tcloneSsh?: string;\n\t/** Best-effort flag: whether the ref's repository is a fork. `undefined` when the provider can't tell. */\n\tisFork?: boolean;\n}\n\nexport interface PullRequestRefs {\n\tbase: PullRequestRef & { url: string };\n\thead: PullRequestRef;\n\tisCrossRepository: boolean;\n}\n\n/**\n * A pull request's membership in a stack — an ordered chain of dependent pull requests where each\n * targets the branch of the one below it.\n *\n * `baseRef` is the stack's ultimate target (its trunk) and is NOT the same as `refs.base`, which for\n * anything above the bottom layer names the layer below. Use `refs.base` to diff a single layer; use\n * `baseRef` to answer where the work ultimately lands.\n */\nexport interface PullRequestStackInfo {\n\t/**\n\t * Opaque, and NOT comparable across read paths: GitHub's GraphQL selection returns a node id\n\t * (`PRS_kwDO…`) while its REST stacks endpoint returns a numeric id (`1347135`) that we stringify —\n\t * both verified against the same live stack. Use {@link number} to identify a stack; two views of one\n\t * stack agree there and will not agree here.\n\t */\n\tid: string;\n\t/** Identifies the stack within its repository. */\n\tnumber: number;\n\t/** Total pull requests in the stack. */\n\tsize: number;\n\t/** This pull request's layer, 1-based, where 1 is closest to `baseRef`. */\n\tposition: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n}\n\n/**\n * One layer of a stack — the pull request occupying it, and the head ref a rebase or push needs to act\n * on. Unlike {@link PullRequestStackInfo}, which locates a single pull request within a stack, this is\n * the per-layer detail a caller walking the whole stack needs, e.g. to cascade a rebase bottom to top.\n */\nexport interface PullRequestStackLayer {\n\t/** The pull request's number. */\n\tnumber: number;\n\t/** The pull request's head branch name, without a remote prefix. */\n\theadRef: string;\n\t/** The head branch's tip when the stack was read. */\n\theadSha: string;\n\t/** `true` once this layer has landed. */\n\tmerged: boolean;\n\t/** `true` while this layer is still a draft. */\n\tdraft: boolean;\n}\n\n/**\n * A stack's layers, ordered bottom to top. `baseRef` is the stack's ultimate target (its trunk), the\n * same distinction drawn on {@link PullRequestStackInfo} — it is NOT the base of any individual layer\n * above the bottom, which targets the layer below it instead.\n */\nexport interface PullRequestStackLayers {\n\t/** Opaque and not comparable across read paths — see {@link PullRequestStackInfo.id}. */\n\tid: string;\n\tnumber: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n\t/** The stack's layers, ordered bottom (closest to {@link baseRef}) to top. */\n\tlayers: PullRequestStackLayer[];\n}\n\nexport interface PullRequestReviewer {\n\tisCodeOwner?: boolean;\n\treviewer: PullRequestMember;\n\tstate: PullRequestReviewState;\n\t/**\n\t * The head commit oid this review was submitted against (GitHub). Lets a consumer tell \"the PR moved past\n\t * my review\" (oid !== the PR's current head) from a review still at the tip — without a per-review\n\t * timestamp. Only populated where the full GitHub/GHE projection is selected: the filtered search read, and\n\t * an account-wide sweep that opts in with `includeReviews`. Undefined elsewhere, including reviews the\n\t * repo-scoped read carries natively.\n\t */\n\tcommitOid?: string;\n\t/**\n\t * The reviewer is a group the current user is a member of (a team or another group, directly or through a group\n\t * nested in it) rather than a person: a request to it is one the user can answer as a member, not one addressed to\n\t * them by name. Only the Azure DevOps reads that resolve the user's groups set it; absent elsewhere, including for\n\t * groups a read could not tell the user belongs to.\n\t */\n\tisMyGroup?: boolean;\n}\n\nexport type PullRequestRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { GitRevisionRange, GitRevisionRangeNotation, uncommitted } from "../models/revision.js";
2
+ import { ResolvedRevision } from "../providers/revision.js";
2
3
  //#region ../git/src/utils/revision.utils.d.ts
3
4
  /** Checks if the rev looks like a revision with a navigation suffixes (like ^, @, ~, or :) */
4
5
  export declare function isRevisionWithSuffix(rev: string): boolean;
@@ -33,5 +34,7 @@ export declare function getRevisionRangeParts(revRange: GitRevisionRange): {
33
34
  } | undefined;
34
35
  export declare function isRevisionRange(rev: string | undefined, rangeType?: 'any' | 'qualified' | 'qualified-double-dot' | 'qualified-triple-dot'): rev is GitRevisionRange;
35
36
  export declare function stripOrigin<T extends string | GitRevisionRange | undefined>(ref: T): T;
37
+ /** Whether the file at `relativePath` doesn't exist at a resolved revision — nothing touched it yet, or its last change there deleted it or moved it away (a copy is reported instead of a rename when `diff.renames=copies`) */
38
+ export declare function isResolvedRevisionMissing(resolved: ResolvedRevision, relativePath: string): boolean;
36
39
  //#endregion
37
40
  //# sourceMappingURL=revision.utils.d.ts.map
@@ -94,7 +94,11 @@ function isRevisionRange(rev, rangeType = "any") {
94
94
  function stripOrigin(ref) {
95
95
  return ref?.replace(/(?:^|(?<=..))origin\//, "");
96
96
  }
97
+ /** Whether the file at `relativePath` doesn't exist at a resolved revision — nothing touched it yet, or its last change there deleted it or moved it away (a copy is reported instead of a rename when `diff.renames=copies`) */
98
+ function isResolvedRevisionMissing(resolved, relativePath) {
99
+ return resolved.sha === "0000000000000000000000000000000000000000-" || resolved.status === "D" || (resolved.status === "R" || resolved.status === "C") && resolved.path != null && resolved.path !== relativePath;
100
+ }
97
101
  //#endregion
98
- export { createRevisionRange, getAbbreviatedShaLength, getRevisionRangeParts, isRevisionRange, isRevisionWithSuffix, isSha, isShaWithOptionalRevisionSuffix, isShaWithParentSuffix, isUncommitted, isUncommittedStaged, isUncommittedStagedWithParentSuffix, isUncommittedWithParentSuffix, resetAbbreviatedShaLength, setAbbreviatedShaLength, shortenRevision, stripOrigin };
102
+ export { createRevisionRange, getAbbreviatedShaLength, getRevisionRangeParts, isResolvedRevisionMissing, isRevisionRange, isRevisionWithSuffix, isSha, isShaWithOptionalRevisionSuffix, isShaWithParentSuffix, isUncommitted, isUncommittedStaged, isUncommittedStagedWithParentSuffix, isUncommittedWithParentSuffix, resetAbbreviatedShaLength, setAbbreviatedShaLength, shortenRevision, stripOrigin };
99
103
 
100
104
  //# sourceMappingURL=revision.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"revision.utils.js","names":[],"sources":["../../../../git/src/utils/revision.utils.ts"],"sourcesContent":["import type { GitRevisionRange, GitRevisionRangeNotation } from '../models/revision.js';\nimport { deletedOrMissing, uncommitted, uncommittedStaged } from '../models/revision.js';\n\nconst rangeRegex = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)?(\\.\\.\\.?)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)?$/;\nconst qualifiedRangeRegex = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)(\\.\\.\\.?)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)$/;\nconst qualifiedDoubleDotRange = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)(\\.\\.)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)$/;\nconst qualifiedTripleDotRange = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)(\\.\\.\\.)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)$/;\nconst shaWithOptionalRevisionSuffixRegex = /(^[0-9a-f]{40}([\\^@~:]\\S*)?$)|(^[0]{40}(:|-)$)/;\nconst revisionWithSuffixRegex = /^\\S+[\\^@~:]\\S*$/;\nconst shaRegex = /(^[0-9a-f]{40}$)|(^[0]{40}(:|-)$)/;\nconst shaShortRegex = /(^[0-9a-f]{7,40}$)|(^[0]{40}(:|-)$)/;\nconst shaParentRegex = /(^[0-9a-f]{40})\\^[0-3]?$/;\nconst shaShortenRegex = /^(.*?)([\\^@~:].*)?$/;\nconst uncommittedRegex = /^[0]{40}(?:[\\^@~:]\\S*)?:?$/;\nconst uncommittedStagedRegex = /^[0]{40}([\\^@~]\\S*)?:$/;\n\nfunction isMatch(regex: RegExp, rev: string | undefined) {\n\treturn !rev ? false : regex.test(rev);\n}\n\n/** Checks if the rev looks like a revision with a navigation suffixes (like ^, @, ~, or :) */\nexport function isRevisionWithSuffix(rev: string): boolean {\n\treturn isMatch(revisionWithSuffixRegex, rev) && rev.length > 40;\n}\n\n/** Checks if the rev looks like a SHA-1 hash\n * @param allowShort If true, allows short SHAs (7-40 characters)\n */\nexport function isSha(rev: string, allowShort: boolean = false): boolean {\n\treturn isMatch(allowShort ? shaShortRegex : shaRegex, rev);\n}\n\n/** Checks if the rev looks like a SHA-1 hash with an optional revision navigation suffixes (like ^, @, ~, or :) */\nexport function isShaWithOptionalRevisionSuffix(rev: string): boolean {\n\treturn isMatch(shaWithOptionalRevisionSuffixRegex, rev);\n}\n\n/** Checks if the rev looks like a SHA-1 hash with a ^ parent suffix */\nexport function isShaWithParentSuffix(rev: string): boolean {\n\treturn isMatch(shaParentRegex, rev);\n}\n\nexport function isUncommitted(rev: string | undefined, exact: boolean = false): boolean {\n\treturn rev === uncommitted || rev === uncommittedStaged || (!exact && isMatch(uncommittedRegex, rev));\n}\n\nexport function isUncommittedStaged(rev: string | undefined, exact: boolean = false): boolean {\n\treturn rev === uncommittedStaged || (!exact && isMatch(uncommittedStagedRegex, rev));\n}\n\nexport function isUncommittedWithParentSuffix(rev: string | undefined): rev is `${typeof uncommitted}${'^' | ':^'}` {\n\treturn rev === `${uncommitted}^` || rev === `${uncommittedStaged}^`;\n}\n\nexport function isUncommittedStagedWithParentSuffix(\n\trev: string | undefined,\n): rev is `${typeof uncommitted}${'^' | ':^'}` {\n\treturn rev === `${uncommittedStaged}^`;\n}\n\nlet abbreviatedShaLength = 7;\nexport function getAbbreviatedShaLength(): number {\n\treturn abbreviatedShaLength;\n}\n\nexport function setAbbreviatedShaLength(length: number): void {\n\tabbreviatedShaLength = length;\n}\n\n/** Resets the abbreviated SHA length to the default (7). For test isolation. */\nexport function resetAbbreviatedShaLength(): void {\n\tabbreviatedShaLength = 7;\n}\n\nexport function shortenRevision(\n\trev: string | undefined,\n\toptions?: {\n\t\tstrings?: { uncommitted?: string; uncommittedStaged?: string; working?: string };\n\t},\n): string {\n\tif (rev === deletedOrMissing) return '(deleted)';\n\tif (!rev) return options?.strings?.working ?? '';\n\tif (isUncommitted(rev)) {\n\t\treturn isUncommittedStaged(rev)\n\t\t\t? (options?.strings?.uncommittedStaged ?? 'Index')\n\t\t\t: (options?.strings?.uncommitted ?? 'Working Tree');\n\t}\n\tif (isRevisionRange(rev) || !isShaWithOptionalRevisionSuffix(rev)) return rev;\n\n\t// Don't allow shas to be shortened to less than 5 characters\n\tconst len = Math.max(5, getAbbreviatedShaLength());\n\n\t// If we have a suffix, append it\n\tconst match = shaShortenRegex.exec(rev);\n\tif (match != null) {\n\t\tconst [, rev, suffix] = match;\n\n\t\tif (suffix != null) {\n\t\t\treturn `${rev.substring(0, len)}${suffix}`;\n\t\t}\n\t}\n\n\treturn rev.substring(0, len);\n}\n\nexport function createRevisionRange(\n\tleft: string | undefined,\n\tright: string | undefined,\n\tnotation: GitRevisionRangeNotation,\n): GitRevisionRange {\n\treturn `${left ?? ''}${notation}${right ?? ''}`;\n}\n\nexport function getRevisionRangeParts(\n\trevRange: GitRevisionRange,\n): { left: string | undefined; right: string | undefined; notation: GitRevisionRangeNotation } | undefined {\n\tconst match = rangeRegex.exec(revRange);\n\tif (match == null) return undefined;\n\n\tconst [, left, notation, right] = match;\n\treturn {\n\t\tleft: left || undefined,\n\t\tright: right || undefined,\n\t\tnotation: notation as GitRevisionRangeNotation,\n\t};\n}\n\nexport function isRevisionRange(\n\trev: string | undefined,\n\trangeType: 'any' | 'qualified' | 'qualified-double-dot' | 'qualified-triple-dot' = 'any',\n): rev is GitRevisionRange {\n\tif (rev == null) return false;\n\n\tswitch (rangeType) {\n\t\tcase 'qualified':\n\t\t\treturn qualifiedRangeRegex.test(rev);\n\t\tcase 'qualified-double-dot':\n\t\t\treturn qualifiedDoubleDotRange.test(rev);\n\t\tcase 'qualified-triple-dot':\n\t\t\treturn qualifiedTripleDotRange.test(rev);\n\t\tdefault:\n\t\t\treturn rangeRegex.test(rev);\n\t}\n}\n\n//** Strips `origin/` from a reference or range, because we \"fake\" origin as the default remote */\nexport function stripOrigin<T extends string | GitRevisionRange | undefined>(ref: T): T {\n\treturn ref?.replace(/(?:^|(?<=..))origin\\//, '') as T;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"revision.utils.js","names":[],"sources":["../../../../git/src/utils/revision.utils.ts"],"sourcesContent":["import type { GitRevisionRange, GitRevisionRangeNotation } from '../models/revision.js';\nimport { deletedOrMissing, uncommitted, uncommittedStaged } from '../models/revision.js';\nimport type { ResolvedRevision } from '../providers/revision.js';\n\nconst rangeRegex = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)?(\\.\\.\\.?)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)?$/;\nconst qualifiedRangeRegex = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)(\\.\\.\\.?)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)$/;\nconst qualifiedDoubleDotRange = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)(\\.\\.)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)$/;\nconst qualifiedTripleDotRange = /^([\\w\\-/]+(?:\\.[\\w\\-/]+)*)(\\.\\.\\.)([\\w\\-/]+(?:\\.[\\w\\-/]+)*)$/;\nconst shaWithOptionalRevisionSuffixRegex = /(^[0-9a-f]{40}([\\^@~:]\\S*)?$)|(^[0]{40}(:|-)$)/;\nconst revisionWithSuffixRegex = /^\\S+[\\^@~:]\\S*$/;\nconst shaRegex = /(^[0-9a-f]{40}$)|(^[0]{40}(:|-)$)/;\nconst shaShortRegex = /(^[0-9a-f]{7,40}$)|(^[0]{40}(:|-)$)/;\nconst shaParentRegex = /(^[0-9a-f]{40})\\^[0-3]?$/;\nconst shaShortenRegex = /^(.*?)([\\^@~:].*)?$/;\nconst uncommittedRegex = /^[0]{40}(?:[\\^@~:]\\S*)?:?$/;\nconst uncommittedStagedRegex = /^[0]{40}([\\^@~]\\S*)?:$/;\n\nfunction isMatch(regex: RegExp, rev: string | undefined) {\n\treturn !rev ? false : regex.test(rev);\n}\n\n/** Checks if the rev looks like a revision with a navigation suffixes (like ^, @, ~, or :) */\nexport function isRevisionWithSuffix(rev: string): boolean {\n\treturn isMatch(revisionWithSuffixRegex, rev) && rev.length > 40;\n}\n\n/** Checks if the rev looks like a SHA-1 hash\n * @param allowShort If true, allows short SHAs (7-40 characters)\n */\nexport function isSha(rev: string, allowShort: boolean = false): boolean {\n\treturn isMatch(allowShort ? shaShortRegex : shaRegex, rev);\n}\n\n/** Checks if the rev looks like a SHA-1 hash with an optional revision navigation suffixes (like ^, @, ~, or :) */\nexport function isShaWithOptionalRevisionSuffix(rev: string): boolean {\n\treturn isMatch(shaWithOptionalRevisionSuffixRegex, rev);\n}\n\n/** Checks if the rev looks like a SHA-1 hash with a ^ parent suffix */\nexport function isShaWithParentSuffix(rev: string): boolean {\n\treturn isMatch(shaParentRegex, rev);\n}\n\nexport function isUncommitted(rev: string | undefined, exact: boolean = false): boolean {\n\treturn rev === uncommitted || rev === uncommittedStaged || (!exact && isMatch(uncommittedRegex, rev));\n}\n\nexport function isUncommittedStaged(rev: string | undefined, exact: boolean = false): boolean {\n\treturn rev === uncommittedStaged || (!exact && isMatch(uncommittedStagedRegex, rev));\n}\n\nexport function isUncommittedWithParentSuffix(rev: string | undefined): rev is `${typeof uncommitted}${'^' | ':^'}` {\n\treturn rev === `${uncommitted}^` || rev === `${uncommittedStaged}^`;\n}\n\nexport function isUncommittedStagedWithParentSuffix(\n\trev: string | undefined,\n): rev is `${typeof uncommitted}${'^' | ':^'}` {\n\treturn rev === `${uncommittedStaged}^`;\n}\n\nlet abbreviatedShaLength = 7;\nexport function getAbbreviatedShaLength(): number {\n\treturn abbreviatedShaLength;\n}\n\nexport function setAbbreviatedShaLength(length: number): void {\n\tabbreviatedShaLength = length;\n}\n\n/** Resets the abbreviated SHA length to the default (7). For test isolation. */\nexport function resetAbbreviatedShaLength(): void {\n\tabbreviatedShaLength = 7;\n}\n\nexport function shortenRevision(\n\trev: string | undefined,\n\toptions?: {\n\t\tstrings?: { uncommitted?: string; uncommittedStaged?: string; working?: string };\n\t},\n): string {\n\tif (rev === deletedOrMissing) return '(deleted)';\n\tif (!rev) return options?.strings?.working ?? '';\n\tif (isUncommitted(rev)) {\n\t\treturn isUncommittedStaged(rev)\n\t\t\t? (options?.strings?.uncommittedStaged ?? 'Index')\n\t\t\t: (options?.strings?.uncommitted ?? 'Working Tree');\n\t}\n\tif (isRevisionRange(rev) || !isShaWithOptionalRevisionSuffix(rev)) return rev;\n\n\t// Don't allow shas to be shortened to less than 5 characters\n\tconst len = Math.max(5, getAbbreviatedShaLength());\n\n\t// If we have a suffix, append it\n\tconst match = shaShortenRegex.exec(rev);\n\tif (match != null) {\n\t\tconst [, rev, suffix] = match;\n\n\t\tif (suffix != null) {\n\t\t\treturn `${rev.substring(0, len)}${suffix}`;\n\t\t}\n\t}\n\n\treturn rev.substring(0, len);\n}\n\nexport function createRevisionRange(\n\tleft: string | undefined,\n\tright: string | undefined,\n\tnotation: GitRevisionRangeNotation,\n): GitRevisionRange {\n\treturn `${left ?? ''}${notation}${right ?? ''}`;\n}\n\nexport function getRevisionRangeParts(\n\trevRange: GitRevisionRange,\n): { left: string | undefined; right: string | undefined; notation: GitRevisionRangeNotation } | undefined {\n\tconst match = rangeRegex.exec(revRange);\n\tif (match == null) return undefined;\n\n\tconst [, left, notation, right] = match;\n\treturn {\n\t\tleft: left || undefined,\n\t\tright: right || undefined,\n\t\tnotation: notation as GitRevisionRangeNotation,\n\t};\n}\n\nexport function isRevisionRange(\n\trev: string | undefined,\n\trangeType: 'any' | 'qualified' | 'qualified-double-dot' | 'qualified-triple-dot' = 'any',\n): rev is GitRevisionRange {\n\tif (rev == null) return false;\n\n\tswitch (rangeType) {\n\t\tcase 'qualified':\n\t\t\treturn qualifiedRangeRegex.test(rev);\n\t\tcase 'qualified-double-dot':\n\t\t\treturn qualifiedDoubleDotRange.test(rev);\n\t\tcase 'qualified-triple-dot':\n\t\t\treturn qualifiedTripleDotRange.test(rev);\n\t\tdefault:\n\t\t\treturn rangeRegex.test(rev);\n\t}\n}\n\n//** Strips `origin/` from a reference or range, because we \"fake\" origin as the default remote */\nexport function stripOrigin<T extends string | GitRevisionRange | undefined>(ref: T): T {\n\treturn ref?.replace(/(?:^|(?<=..))origin\\//, '') as T;\n}\n\n/** Whether the file at `relativePath` doesn't exist at a resolved revision — nothing touched it yet, or its last change there deleted it or moved it away (a copy is reported instead of a rename when `diff.renames=copies`) */\nexport function isResolvedRevisionMissing(resolved: ResolvedRevision, relativePath: string): boolean {\n\treturn (\n\t\tresolved.sha === deletedOrMissing ||\n\t\tresolved.status === 'D' ||\n\t\t((resolved.status === 'R' || resolved.status === 'C') &&\n\t\t\tresolved.path != null &&\n\t\t\tresolved.path !== relativePath)\n\t);\n}\n"],"mappings":"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"}
@@ -201,6 +201,10 @@ export declare class GitHubApi {
201
201
  limit?: number;
202
202
  }): Promise<PagedResult<GitHubTag>>;
203
203
  resolveReference(token: GitHubTokenInfo, owner: string, repo: string, ref: string, path?: string): Promise<string | undefined>;
204
+ resolveReferenceForPath(token: GitHubTokenInfo, owner: string, repo: string, ref: string, path: string): Promise<{
205
+ sha: string;
206
+ exists: boolean;
207
+ } | undefined>;
204
208
  searchCommits(token: GitHubTokenInfo, query: string, options?: {
205
209
  cursor?: string;
206
210
  limit?: number;
@@ -1619,8 +1619,9 @@ var GitHubApi = class {
1619
1619
  }
1620
1620
  async resolveReference(token, owner, repo, ref, path) {
1621
1621
  const scope = getScopedLogger();
1622
+ if (path) return (await this.resolveReferenceForPath(token, owner, repo, ref, path))?.sha;
1622
1623
  try {
1623
- if (!path) return (await this.graphql(void 0, token, `query resolveReference(
1624
+ return (await this.graphql(void 0, token, `query resolveReference(
1624
1625
  $owner: String!
1625
1626
  $repo: String!
1626
1627
  $ref: String!
@@ -1635,11 +1636,20 @@ var GitHubApi = class {
1635
1636
  repo,
1636
1637
  ref
1637
1638
  }, scope))?.repository?.object?.oid ?? void 0;
1638
- return (await this.graphql(void 0, token, `query resolveReference(
1639
+ } catch (ex) {
1640
+ if (ex instanceof RequestNotFoundError) return void 0;
1641
+ throw this.handleException(ex, void 0, scope);
1642
+ }
1643
+ }
1644
+ async resolveReferenceForPath(token, owner, repo, ref, path) {
1645
+ const scope = getScopedLogger();
1646
+ try {
1647
+ const rsp = await this.graphql(void 0, token, `query resolveReferenceForPath(
1639
1648
  $owner: String!
1640
1649
  $repo: String!
1641
1650
  $ref: String!
1642
1651
  $path: String!
1652
+ $refPath: String!
1643
1653
  ) {
1644
1654
  repository(owner: $owner, name: $repo) {
1645
1655
  object(expression: $ref) {
@@ -1649,13 +1659,23 @@ var GitHubApi = class {
1649
1659
  }
1650
1660
  }
1651
1661
  }
1662
+ file: object(expression: $refPath) {
1663
+ oid
1664
+ }
1652
1665
  }
1653
1666
  }`, {
1654
1667
  owner,
1655
1668
  repo,
1656
1669
  ref,
1657
- path
1658
- }, scope))?.repository?.object?.history.nodes?.[0]?.oid ?? void 0;
1670
+ path,
1671
+ refPath: `${ref}:${path}`
1672
+ }, scope);
1673
+ const sha = rsp?.repository?.object?.history.nodes?.[0]?.oid;
1674
+ if (sha == null) return void 0;
1675
+ return {
1676
+ sha,
1677
+ exists: rsp?.repository?.file != null
1678
+ };
1659
1679
  } catch (ex) {
1660
1680
  if (ex instanceof RequestNotFoundError) return void 0;
1661
1681
  throw this.handleException(ex, void 0, scope);
@@ -3411,6 +3431,13 @@ __decorate([trace({ args: (token, owner, repo, ref, path) => ({
3411
3431
  ref,
3412
3432
  path
3413
3433
  }) })], GitHubApi.prototype, "resolveReference", null);
3434
+ __decorate([trace({ args: (token, owner, repo, ref, path) => ({
3435
+ token: `<token:${token.microHash}>`,
3436
+ owner,
3437
+ repo,
3438
+ ref,
3439
+ path
3440
+ }) })], GitHubApi.prototype, "resolveReferenceForPath", null);
3414
3441
  __decorate([trace({ args: (token, query) => ({
3415
3442
  token: `<token:${token.microHash}>`,
3416
3443
  query