@effected/github 0.6.1 → 0.8.0

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.
@@ -5,6 +5,47 @@ import { Context, Effect, Layer, Schema } from "effect";
5
5
 
6
6
  //#region src/GitHubRepository.ts
7
7
  /**
8
+ * A {@link RepositoryPatch} from a draft, dropping every explicitly-`undefined`
9
+ * field.
10
+ *
11
+ * @remarks
12
+ * The supported spelling for "apply only what was configured" — the natural
13
+ * shape for a sync action, and the one the checker cannot follow on its own.
14
+ * Without it a consumer under the recommended tsconfig is quietly pushed toward
15
+ * `as`, which is a real cost in a package whose stated design property is that
16
+ * the route is the key and there are no casts.
17
+ *
18
+ * Dropping the key rather than sending `undefined` is what the wire needs:
19
+ * `PATCH` treats an absent field as "leave it alone", while an explicit `null`
20
+ * or `undefined` is a value.
21
+ *
22
+ * A key-by-key loop still defeats TypeScript's correlation between two indexed
23
+ * accesses (`draft[key] = source[key]` over a union `key`), which no helper can
24
+ * fix — build the draft as a literal where you can.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { repositoryPatch } from "@effected/github";
29
+ *
30
+ * // `config.has_issues` is `boolean | undefined`; absent fields drop out.
31
+ * const patch = repositoryPatch({
32
+ * has_issues: config.has_issues,
33
+ * has_wiki: config.has_wiki,
34
+ * description: config.description,
35
+ * });
36
+ * ```
37
+ *
38
+ * @param draft - The fields to apply, any of which may be `undefined`.
39
+ * @returns A patch carrying only the fields that were actually set.
40
+ *
41
+ * @public
42
+ */
43
+ const repositoryPatch = (draft) => {
44
+ const out = {};
45
+ for (const [key, value] of Object.entries(draft)) if (value !== void 0) out[key] = value;
46
+ return out;
47
+ };
48
+ /**
8
49
  * Fields in the user-facing `security_and_analysis` block that GitHub accepts
9
50
  * as `{ status: "enabled" | "disabled" }`.
10
51
  *
@@ -234,4 +275,4 @@ const make = (client) => {
234
275
  };
235
276
 
236
277
  //#endregion
237
- export { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, transformSecurityAndAnalysis };
278
+ export { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, repositoryPatch, transformSecurityAndAnalysis };
package/README.md CHANGED
@@ -122,7 +122,7 @@ const program = Effect.gen(function* () {
122
122
 
123
123
  The existence check pages the issue's comments to the end and matches the marker in `upsert`'s exact spelling, so a comment either member writes stays findable by the other. It is a look-before-write: two runs racing on the same issue can both see no marker and both post, so treat the marker as the record rather than the check as a lock.
124
124
 
125
- Whether a run should comment at all usually turns on which issues a pull request closes, and that is a grammar rather than an API call. `IssueReferences` is that grammar as plain functions no service, no layer, nothing but strings in in the two dialects consumers actually write:
125
+ Whether a run should comment at all usually turns on which issues a pull request closes, and that is a grammar rather than an API call. That grammar now lives in [`@effected/github-references`](https://www.npmjs.com/package/@effected/github-references), a pure package with no octokit behind it; this package re-exports the two dialects it used to own so existing code keeps compiling:
126
126
 
127
127
  ```ts
128
128
  import { harvestIssueReferences, parseBareLineReference } from "@effected/github";
@@ -140,6 +140,8 @@ console.log(parseBareLineReference("closes #12 for real"));
140
140
 
141
141
  `harvestIssueReferences` reads the **inline-in-prose** dialect: one of the nine closing keywords (`CLOSING_KEYWORDS`) followed by whitespace and `#<number>`, anywhere in the text, no colon — the spelling GitHub itself scans a pull request body for. Duplicates come back as written, because whether `fixes #1, fixes #1` means one intent or two is the caller's question. `parseBareLineReference` reads the **bare-line** dialect, where the whole trimmed line is the reference and the colon is optional — the shape a generated references block writes, one per line. Cross-repo (`owner/repo#12`) and full-URL references are out of scope.
142
142
 
143
+ The re-export covers exactly six names — `CLOSING_KEYWORDS`, `ClosingKeyword`, `IssueReference`, `harvestIssueReferences`, `BareLineReference`, `parseBareLineReference` — and may be dropped at a later release. Import from `@effected/github-references` directly for new code; it also carries a third dialect this package does not re-export, the closing list (`Closes #247, #248 and #251`).
144
+
143
145
  ## Repository configuration
144
146
 
145
147
  Six services cover the half of a repository that is policy rather than content: `RepositorySecret`, `RepositoryVariable`, `Ruleset`, `DeploymentEnvironment`, `RepositorySecurity` and `CodeScanning`. They are shaped for a program applying the same configuration across a fleet, so every list read paginates to the end and a truncated page never becomes a wrong decision.
@@ -187,6 +189,19 @@ const program = Effect.gen(function* () {
187
189
  // GitHub would reject, which is what a person reading a dry run is checking for.
188
190
  ```
189
191
 
192
+ `updateSettings` takes octokit's own generated params, and those spell an optional field as `has_issues?: boolean` rather than `has_issues?: boolean | undefined` — so under `exactOptionalPropertyTypes` a `Partial<T>` built from your own settings schema does not assign to it at all. `repositoryPatch` is the supported way out, and it exists so the answer is never a cast:
193
+
194
+ ```ts
195
+ import { repositoryPatch } from "@effected/github";
196
+
197
+ declare const config: { has_issues?: boolean | undefined; description?: string | undefined };
198
+
199
+ const patch = repositoryPatch({ has_issues: config.has_issues, description: config.description });
200
+ // a RepositoryPatch carrying only the fields that were actually set
201
+ ```
202
+
203
+ Dropping the key is what the wire needs: `PATCH` reads an absent field as "leave it alone", while an explicit `null` is a value. `RepositoryPatchDraft` is the input type — the same fields, each allowed to be an explicit `undefined`. Build the draft as an object literal where you can: a key-by-key loop defeats TypeScript's correlation between two indexed accesses, which no helper can repair.
204
+
190
205
  `security_and_analysis` accepts both the bare `"enabled"` a human writes in a config file and the `{ status: "enabled" }` GitHub's own parameter type declares. A map touching neither GraphQL-only setting never reads the node id, so the common case stays one request. `ownerType` answers `"User"` or `"Organization"` for the repository in `Repo`, which is how a shared settings template drops the fields GitHub accepts only on an organization-owned repository before applying itself to a personal one.
191
206
 
192
207
  ## GitHub App authentication
@@ -266,6 +281,7 @@ const TestClient = GitHubClient.layerFixture(fixtures);
266
281
  - `GitHubClient` — the typed transport: `request`, `requestDecoded` (a mandatory-schema escape hatch for routes outside the generated map), `paginate` / `paginateStream`, `graphql`, and `rateLimit` (observation only — nothing here throttles on your behalf).
267
282
  - `Repo` / `RepoRef` — the `{ owner, repo }` coordinate, resolved per call through `R`, with `Repo.provide` for multi-repository programs.
268
283
  - `GitHubRepository` — the repository's settings as GitHub's own generated type, plus `defaultBranch`, `nodeId`, `ownerType` for gating organization-only fields, and `applySettings` reporting the keys it actually sent.
284
+ - `repositoryPatch` / `RepositoryPatchDraft` — build an `updateSettings` patch from fields that may be `undefined`, under `exactOptionalPropertyTypes`, without a cast.
269
285
  - `GitHubError` / `GitHubGraphQLError` — one error per transport, `kind`-routed with `hasKind` for `Effect.catchIf`.
270
286
  - `RetryPolicy` — the client's one retry policy: full-jitter backoff, server-advised delays honored up to a ceiling.
271
287
  - `GitHubApp` — App JWT signing, installation token minting/revocation, app and installation identity, and `clientLayer` for an App-authenticated `GitHubClient`.
@@ -273,7 +289,7 @@ const TestClient = GitHubClient.layerFixture(fixtures);
273
289
  - `CheckRun` — `withCheckRun` concludes on every exit path; `CheckRunOutput.truncated()` cuts rendered output to GitHub's byte limits.
274
290
  - `PullRequest` / `PullRequestComment` — upserts for both, `listFiles` answering with the same full `CommitFile` records a commit read returns, `headSha`/`baseSha` on `PullRequestInfo`, plus `CommentMarker` for finding a sticky comment again.
275
291
  - `GitHubIssue` — issues and their comments, including `commentOnce` for a marked comment that is posted exactly once and never edited, and `linkedIssues` for what a pull request closes.
276
- - `IssueReferences` — GitHub's nine closing keywords as pure functions: `harvestIssueReferences` for references inline in prose, `parseBareLineReference` for one-per-line generated ones.
292
+ - `harvestIssueReferences` / `parseBareLineReference` a compatibility re-export of the two closing-reference dialects that moved to `@effected/github-references`, with `CLOSING_KEYWORDS` and their result types.
277
293
  - `GitHubRelease` — releases and asset uploads, including the one route (`uploadAsset`, with the endpoint's optional display label) outside GitHub's generated endpoint map.
278
294
  - `RepositorySecret` / `RepositoryVariable` — repository and environment secrets and variables, with the sealed-box encryption GitHub's secrets API demands kept in one module nothing else imports.
279
295
  - `Ruleset` / `DeploymentEnvironment` / `RepositorySecurity` / `CodeScanning` — the rest of the configuration tier: rulesets matched by name and scope, idempotent environment writes, the three security toggles GitHub keeps off the repository endpoint, and CodeQL default setup with the language detection that gates it.
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { BareLineReference, CLOSING_KEYWORDS, ClosingKeyword, IssueReference, harvestIssueReferences, parseBareLineReference } from "@effected/github-references";
1
2
  import { Config, Context, Duration, Effect, Layer, Option, Redacted, Result, Schedule, Schema, Scope, Stream } from "effect";
2
3
  import { PaginatingEndpoints } from "@octokit/plugin-paginate-rest";
3
4
  import { Endpoints, RequestHeaders } from "@octokit/types";
@@ -2276,6 +2277,59 @@ type RepositorySettings = Data<"GET /repos/{owner}/{repo}">;
2276
2277
  * @public
2277
2278
  */
2278
2279
  type RepositoryPatch = Omit<Params<"PATCH /repos/{owner}/{repo}">, "owner" | "repo">;
2280
+ /**
2281
+ * A {@link RepositoryPatch} under construction, where an absent field may be
2282
+ * spelled as an explicit `undefined`.
2283
+ *
2284
+ * @remarks
2285
+ * The shape you actually have when you are applying only what a user
2286
+ * configured. Octokit's generated params spell an optional field as
2287
+ * `has_issues?: boolean`, **not** `has_issues?: boolean | undefined`, so under
2288
+ * `exactOptionalPropertyTypes` — on in this repo and in the silk tsconfig base
2289
+ * — a `Partial<T>` built from your own settings schema does not assign to
2290
+ * `RepositoryPatch` at all. This type does, and {@link repositoryPatch} turns
2291
+ * it into one.
2292
+ *
2293
+ * @public
2294
+ */
2295
+ type RepositoryPatchDraft = { readonly [K in keyof RepositoryPatch]?: RepositoryPatch[K] | undefined; };
2296
+ /**
2297
+ * A {@link RepositoryPatch} from a draft, dropping every explicitly-`undefined`
2298
+ * field.
2299
+ *
2300
+ * @remarks
2301
+ * The supported spelling for "apply only what was configured" — the natural
2302
+ * shape for a sync action, and the one the checker cannot follow on its own.
2303
+ * Without it a consumer under the recommended tsconfig is quietly pushed toward
2304
+ * `as`, which is a real cost in a package whose stated design property is that
2305
+ * the route is the key and there are no casts.
2306
+ *
2307
+ * Dropping the key rather than sending `undefined` is what the wire needs:
2308
+ * `PATCH` treats an absent field as "leave it alone", while an explicit `null`
2309
+ * or `undefined` is a value.
2310
+ *
2311
+ * A key-by-key loop still defeats TypeScript's correlation between two indexed
2312
+ * accesses (`draft[key] = source[key]` over a union `key`), which no helper can
2313
+ * fix — build the draft as a literal where you can.
2314
+ *
2315
+ * @example
2316
+ * ```ts
2317
+ * import { repositoryPatch } from "@effected/github";
2318
+ *
2319
+ * // `config.has_issues` is `boolean | undefined`; absent fields drop out.
2320
+ * const patch = repositoryPatch({
2321
+ * has_issues: config.has_issues,
2322
+ * has_wiki: config.has_wiki,
2323
+ * description: config.description,
2324
+ * });
2325
+ * ```
2326
+ *
2327
+ * @param draft - The fields to apply, any of which may be `undefined`.
2328
+ * @returns A patch carrying only the fields that were actually set.
2329
+ *
2330
+ * @public
2331
+ */
2332
+ declare const repositoryPatch: (draft: RepositoryPatchDraft) => RepositoryPatch;
2279
2333
  /**
2280
2334
  * Whether an account is a user or an organization.
2281
2335
  *
@@ -2549,108 +2603,6 @@ declare class GitTag extends GitTag_base {
2549
2603
  static readonly layerTest: (overrides?: Partial<GitTagShape>) => Layer.Layer<GitTag>;
2550
2604
  }
2551
2605
  //#endregion
2552
- //#region src/IssueReferences.d.ts
2553
- /**
2554
- * GitHub's closing-keyword issue-reference grammar, as pure functions.
2555
- *
2556
- * @remarks
2557
- * GitHub links an issue to a pull request when the PR's description carries
2558
- * `<keyword> #<number>` for one of nine documented keywords. Consumers speak
2559
- * that grammar in two distinct dialects, and this module models exactly those
2560
- * two — no service, no layer, nothing but strings in and values out:
2561
- *
2562
- * - **Inline-in-prose** ({@link harvestIssueReferences}): a reference may appear anywhere in
2563
- * running text — `"fixes #12 and closes #13"` — with mandatory whitespace
2564
- * and **no colon**, because that is the spelling GitHub itself scans PR
2565
- * bodies for. This is the dialect a release pipeline harvests from commit
2566
- * subjects and PR descriptions.
2567
- * - **Bare-line** ({@link parseBareLineReference}): the whole line, after trimming, *is*
2568
- * the reference — `"Closes: #12"` — with an **optional colon**, because a
2569
- * generated references region writes one reference per line and a colon
2570
- * reads better there. GitHub does not require the colon; the region format
2571
- * allows it, so the parser must too. The dialects differ because their
2572
- * producers do: prose is written by humans for GitHub's scanner, the region
2573
- * is written by tooling for humans.
2574
- *
2575
- * Deliberately out of scope this round: cross-repo references
2576
- * (`owner/repo#N`) and full-URL references
2577
- * (`https://github.com/owner/repo/issues/N`). Both are real GitHub spellings;
2578
- * neither dialect's consumers emit them yet, and guessing at their shape here
2579
- * would freeze an API nobody has driven.
2580
- */
2581
- /**
2582
- * The nine closing keywords GitHub documents, lowercased.
2583
- *
2584
- * @public
2585
- */
2586
- declare const CLOSING_KEYWORDS: readonly ["close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"];
2587
- /**
2588
- * One of the nine documented closing keywords, in canonical lowercase form.
2589
- *
2590
- * @public
2591
- */
2592
- type ClosingKeyword = (typeof CLOSING_KEYWORDS)[number];
2593
- /**
2594
- * One closing reference found in prose by {@link harvestIssueReferences}.
2595
- *
2596
- * @public
2597
- */
2598
- interface IssueReference {
2599
- /** The referenced issue number. */
2600
- readonly issueNumber: number;
2601
- /** The matched keyword, lowercased to its canonical form. */
2602
- readonly keyword: ClosingKeyword;
2603
- /** Offset of the first character of the whole match (`keyword` through digits). */
2604
- readonly start: number;
2605
- /** Offset one past the last character of the whole match. */
2606
- readonly end: number;
2607
- }
2608
- /**
2609
- * The closing reference a bare line carries, per {@link parseBareLineReference}.
2610
- *
2611
- * @remarks
2612
- * No offsets: in the bare-line dialect the whole line is the reference, so
2613
- * positions within it locate nothing a caller acts on.
2614
- *
2615
- * @public
2616
- */
2617
- interface BareLineReference {
2618
- /** The referenced issue number. */
2619
- readonly issueNumber: number;
2620
- /** The matched keyword, lowercased to its canonical form. */
2621
- readonly keyword: ClosingKeyword;
2622
- }
2623
- /**
2624
- * Every inline closing reference in `text`, in document order.
2625
- *
2626
- * @remarks
2627
- * The **inline-in-prose** dialect: case-insensitive `<keyword> #<number>`
2628
- * anywhere in the text, whitespace mandatory, colon not accepted — a colon
2629
- * spelling belongs to the bare-line dialect and {@link parseBareLineReference}.
2630
- * Duplicates are preserved: whether `fixes #1, fixes #1` means one reference
2631
- * or two is the caller's business, not a parser's.
2632
- *
2633
- * A match whose digits exceed `Number.MAX_SAFE_INTEGER` is skipped, not
2634
- * misparsed — see the module remarks for the scope boundary.
2635
- *
2636
- * @public
2637
- */
2638
- declare const harvestIssueReferences: (text: string) => ReadonlyArray<IssueReference>;
2639
- /**
2640
- * The reference a whole line carries, or `Option.none()`.
2641
- *
2642
- * @remarks
2643
- * The **bare-line** dialect: after trimming, the entire line must be
2644
- * `<keyword>[:] #<number>` — keyword case-insensitive, colon optional,
2645
- * whitespace before the `#` mandatory. Trailing prose, a missing keyword, or
2646
- * anything else at all is a rejection, never a partial parse; a line carries
2647
- * one reference or none. Digits past `Number.MAX_SAFE_INTEGER` reject too,
2648
- * for the same reason {@link harvestIssueReferences} skips them.
2649
- *
2650
- * @public
2651
- */
2652
- declare const parseBareLineReference: (line: string) => Option.Option<BareLineReference>;
2653
- //#endregion
2654
2606
  //#region src/PullRequest.d.ts
2655
2607
  /** How a pull request is merged. @public */
2656
2608
  declare const MergeMethod: Schema.Literals<readonly ["merge", "squash", "rebase"]>;
@@ -3380,5 +3332,5 @@ declare class WorkflowDispatch extends WorkflowDispatch_base {
3380
3332
  static readonly layerTest: (overrides?: Partial<WorkflowDispatchShape>) => Layer.Layer<WorkflowDispatch>;
3381
3333
  }
3382
3334
  //#endregion
3383
- export { Annotation, AnnotationLevel, type AppCredentials, AppIdentity, type AppliedSettings, ArtifactMetadata, type ArtifactMetadataShape, Attestation, AttestationListEntry, AttestationRecord, type AttestationShape, type BareLineReference, BotIdentity, type BranchOutcome, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, type CheckRunShape, type ClosingKeyword, CodeScanning, type CodeScanningSetup, type CodeScanningShape, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, type ConcludeCheckRun, DeploymentEnvironment, type DeploymentEnvironmentInfo, type DeploymentEnvironmentShape, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, type GitBranchShape, GitCommit, type GitCommitShape, GitHubApp, GitHubAppError, type GitHubAppOptions, type GitHubAppShape, GitHubClient, type GitHubClientOptions, type GitHubClientShape, GitHubCommit, type GitHubCommitShape, GitHubContent, type GitHubContentShape, GitHubError, GitHubErrorKind, type GitHubFixtures, GitHubGraphQLError, GitHubIssue, type GitHubIssueShape, GitHubRelease, type GitHubReleaseShape, GitHubRepository, type GitHubRepositoryShape, GitTag, type GitTagShape, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, type IssueReference, type LatestSemverOptions, LinkedIssue, MergeMethod, type OwnerType, PageOptions, PermissionGap, PermissionLevel, PermissionResult, type PollOptions, PullRequest, PullRequestComment, type PullRequestCommentShape, PullRequestInfo, type PullRequestShape, RateLimitSnapshot, type RecordedCall, ReleaseAsset, ReleaseInfo, Repo, RepoRef, type RepositoryPatch, RepositorySecret, type RepositorySecretShape, RepositorySecurity, type RepositorySecurityShape, type RepositorySettings, RepositoryVariable, type RepositoryVariableShape, type Data as RestData, type RequestExtras as RestExtras, type Item as RestItem, type PaginatingRoute as RestPaginatingRoute, type Params as RestParams, type Response as RestResponse, type Route as RestRoute, RetryPolicy, type RetryableFailure, Ruleset, type RulesetInfo, type RulesetPayload, type RulesetShape, SECURITY_ANALYSIS_STATUS_FIELDS, type SecretInfo, type SecretScope, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, type TokenRequest, type UpsertedPullRequest, type VariableInfo, type VersionFromTag, WorkflowDispatch, type WorkflowDispatchShape, type WorkflowInfo, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, transformSecurityAndAnalysis, versionFromTag };
3335
+ export { Annotation, AnnotationLevel, type AppCredentials, AppIdentity, type AppliedSettings, ArtifactMetadata, type ArtifactMetadataShape, Attestation, AttestationListEntry, AttestationRecord, type AttestationShape, type BareLineReference, BotIdentity, type BranchOutcome, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, type CheckRunShape, type ClosingKeyword, CodeScanning, type CodeScanningSetup, type CodeScanningShape, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, type ConcludeCheckRun, DeploymentEnvironment, type DeploymentEnvironmentInfo, type DeploymentEnvironmentShape, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, type GitBranchShape, GitCommit, type GitCommitShape, GitHubApp, GitHubAppError, type GitHubAppOptions, type GitHubAppShape, GitHubClient, type GitHubClientOptions, type GitHubClientShape, GitHubCommit, type GitHubCommitShape, GitHubContent, type GitHubContentShape, GitHubError, GitHubErrorKind, type GitHubFixtures, GitHubGraphQLError, GitHubIssue, type GitHubIssueShape, GitHubRelease, type GitHubReleaseShape, GitHubRepository, type GitHubRepositoryShape, GitTag, type GitTagShape, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, type IssueReference, type LatestSemverOptions, LinkedIssue, MergeMethod, type OwnerType, PageOptions, PermissionGap, PermissionLevel, PermissionResult, type PollOptions, PullRequest, PullRequestComment, type PullRequestCommentShape, PullRequestInfo, type PullRequestShape, RateLimitSnapshot, type RecordedCall, ReleaseAsset, ReleaseInfo, Repo, RepoRef, type RepositoryPatch, type RepositoryPatchDraft, RepositorySecret, type RepositorySecretShape, RepositorySecurity, type RepositorySecurityShape, type RepositorySettings, RepositoryVariable, type RepositoryVariableShape, type Data as RestData, type RequestExtras as RestExtras, type Item as RestItem, type PaginatingRoute as RestPaginatingRoute, type Params as RestParams, type Response as RestResponse, type Route as RestRoute, RetryPolicy, type RetryableFailure, Ruleset, type RulesetInfo, type RulesetPayload, type RulesetShape, SECURITY_ANALYSIS_STATUS_FIELDS, type SecretInfo, type SecretScope, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, type TokenRequest, type UpsertedPullRequest, type VariableInfo, type VersionFromTag, WorkflowDispatch, type WorkflowDispatchShape, type WorkflowInfo, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, repositoryPatch, transformSecurityAndAnalysis, versionFromTag };
3384
3336
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -16,9 +16,8 @@ import { GitHubContent } from "./GitHubContent.js";
16
16
  import { CommentMarker, CommentRecord, PullRequestComment } from "./PullRequestComment.js";
17
17
  import { CommentOnceResult, GitHubIssue, IssueInfo, LinkedIssue } from "./GitHubIssue.js";
18
18
  import { GitHubRelease, ReleaseAsset, ReleaseInfo } from "./GitHubRelease.js";
19
- import { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, transformSecurityAndAnalysis } from "./GitHubRepository.js";
19
+ import { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, repositoryPatch, transformSecurityAndAnalysis } from "./GitHubRepository.js";
20
20
  import { GitTag, SemverTag, TagRef, versionFromTag } from "./GitTag.js";
21
- import { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference } from "./IssueReferences.js";
22
21
  import { PageOptions } from "./Rest.js";
23
22
  import { MergeMethod, PullRequest, PullRequestInfo } from "./PullRequest.js";
24
23
  import { RepositorySecret } from "./RepositorySecret.js";
@@ -27,5 +26,6 @@ import { RepositoryVariable } from "./RepositoryVariable.js";
27
26
  import { Ruleset } from "./Ruleset.js";
28
27
  import { ExtraPermission, PermissionGap, PermissionLevel, PermissionResult, TokenPermissionError, TokenPermissions } from "./TokenPermissions.js";
29
28
  import { WorkflowDispatch, WorkflowRunStatus } from "./WorkflowDispatch.js";
29
+ import { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference } from "@effected/github-references";
30
30
 
31
- export { Annotation, AnnotationLevel, AppIdentity, ArtifactMetadata, Attestation, AttestationListEntry, AttestationRecord, BotIdentity, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CodeScanning, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, DeploymentEnvironment, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, GitCommit, GitHubApp, GitHubAppError, GitHubClient, GitHubCommit, GitHubContent, GitHubError, GitHubErrorKind, GitHubGraphQLError, GitHubIssue, GitHubRelease, GitHubRepository, GitTag, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, PullRequest, PullRequestComment, PullRequestInfo, RateLimitSnapshot, ReleaseAsset, ReleaseInfo, Repo, RepoRef, RepositorySecret, RepositorySecurity, RepositoryVariable, RetryPolicy, Ruleset, SECURITY_ANALYSIS_STATUS_FIELDS, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, WorkflowDispatch, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, transformSecurityAndAnalysis, versionFromTag };
31
+ export { Annotation, AnnotationLevel, AppIdentity, ArtifactMetadata, Attestation, AttestationListEntry, AttestationRecord, BotIdentity, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CodeScanning, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, DeploymentEnvironment, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, GitCommit, GitHubApp, GitHubAppError, GitHubClient, GitHubCommit, GitHubContent, GitHubError, GitHubErrorKind, GitHubGraphQLError, GitHubIssue, GitHubRelease, GitHubRepository, GitTag, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, PullRequest, PullRequestComment, PullRequestInfo, RateLimitSnapshot, ReleaseAsset, ReleaseInfo, Repo, RepoRef, RepositorySecret, RepositorySecurity, RepositoryVariable, RetryPolicy, Ruleset, SECURITY_ANALYSIS_STATUS_FIELDS, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, WorkflowDispatch, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, repositoryPatch, transformSecurityAndAnalysis, versionFromTag };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effected/github",
3
- "version": "0.6.1",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "Typed GitHub REST and GraphQL services over the octokit core request surface, with app auth and resource helpers.",
6
6
  "keywords": [
@@ -38,6 +38,7 @@
38
38
  "./package.json": "./package.json"
39
39
  },
40
40
  "dependencies": {
41
+ "@effected/github-references": "^0.1.0",
41
42
  "@effected/semver": "^0.5.0",
42
43
  "@octokit/core": "^7.0.6",
43
44
  "@octokit/plugin-paginate-rest": "^15.0.0",
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.58.12"
8
+ "packageVersion": "7.59.0"
9
9
  }
10
10
  ]
11
11
  }
@@ -1,126 +0,0 @@
1
- import { Option } from "effect";
2
-
3
- //#region src/IssueReferences.ts
4
- /**
5
- * GitHub's closing-keyword issue-reference grammar, as pure functions.
6
- *
7
- * @remarks
8
- * GitHub links an issue to a pull request when the PR's description carries
9
- * `<keyword> #<number>` for one of nine documented keywords. Consumers speak
10
- * that grammar in two distinct dialects, and this module models exactly those
11
- * two — no service, no layer, nothing but strings in and values out:
12
- *
13
- * - **Inline-in-prose** ({@link harvestIssueReferences}): a reference may appear anywhere in
14
- * running text — `"fixes #12 and closes #13"` — with mandatory whitespace
15
- * and **no colon**, because that is the spelling GitHub itself scans PR
16
- * bodies for. This is the dialect a release pipeline harvests from commit
17
- * subjects and PR descriptions.
18
- * - **Bare-line** ({@link parseBareLineReference}): the whole line, after trimming, *is*
19
- * the reference — `"Closes: #12"` — with an **optional colon**, because a
20
- * generated references region writes one reference per line and a colon
21
- * reads better there. GitHub does not require the colon; the region format
22
- * allows it, so the parser must too. The dialects differ because their
23
- * producers do: prose is written by humans for GitHub's scanner, the region
24
- * is written by tooling for humans.
25
- *
26
- * Deliberately out of scope this round: cross-repo references
27
- * (`owner/repo#N`) and full-URL references
28
- * (`https://github.com/owner/repo/issues/N`). Both are real GitHub spellings;
29
- * neither dialect's consumers emit them yet, and guessing at their shape here
30
- * would freeze an API nobody has driven.
31
- */
32
- /**
33
- * The nine closing keywords GitHub documents, lowercased.
34
- *
35
- * @public
36
- */
37
- const CLOSING_KEYWORDS = [
38
- "close",
39
- "closes",
40
- "closed",
41
- "fix",
42
- "fixes",
43
- "fixed",
44
- "resolve",
45
- "resolves",
46
- "resolved"
47
- ];
48
- /**
49
- * Both patterns derive from {@link CLOSING_KEYWORDS} so the constant and the
50
- * grammar cannot drift. Alternation order is safe: the regex engine backtracks
51
- * through alternatives, so `close` matching inside `closes` fails at the
52
- * mandatory `#`-introducer and retries the longer keyword.
53
- */
54
- const KEYWORDS = CLOSING_KEYWORDS.join("|");
55
- /** Inline-in-prose: mandatory whitespace, no colon. */
56
- const INLINE_PATTERN = new RegExp(`\\b(${KEYWORDS})\\s+#(\\d+)`, "gi");
57
- /**
58
- * Bare-line: optional colon, then mandatory same-line whitespace. `[ \t]`
59
- * rather than `\s`, so an embedded newline cannot smuggle two lines past a
60
- * parser whose contract is one.
61
- */
62
- const BARE_LINE_PATTERN = new RegExp(`^(${KEYWORDS}):?[ \\t]+#(\\d+)$`, "i");
63
- /**
64
- * `#<digits>` parsed to a number — or `undefined` when the digits exceed
65
- * `Number.MAX_SAFE_INTEGER`, because a silently rounded issue number is worse
66
- * than a skipped match. Callers skip such matches; they do not fail.
67
- */
68
- const safeIssueNumber = (digits) => {
69
- const value = Number(digits);
70
- return Number.isSafeInteger(value) ? value : void 0;
71
- };
72
- /**
73
- * Every inline closing reference in `text`, in document order.
74
- *
75
- * @remarks
76
- * The **inline-in-prose** dialect: case-insensitive `<keyword> #<number>`
77
- * anywhere in the text, whitespace mandatory, colon not accepted — a colon
78
- * spelling belongs to the bare-line dialect and {@link parseBareLineReference}.
79
- * Duplicates are preserved: whether `fixes #1, fixes #1` means one reference
80
- * or two is the caller's business, not a parser's.
81
- *
82
- * A match whose digits exceed `Number.MAX_SAFE_INTEGER` is skipped, not
83
- * misparsed — see the module remarks for the scope boundary.
84
- *
85
- * @public
86
- */
87
- const harvestIssueReferences = (text) => {
88
- const references = [];
89
- for (const match of text.matchAll(INLINE_PATTERN)) {
90
- const issueNumber = safeIssueNumber(match[2] ?? "");
91
- if (issueNumber === void 0) continue;
92
- references.push({
93
- issueNumber,
94
- keyword: (match[1] ?? "").toLowerCase(),
95
- start: match.index,
96
- end: match.index + match[0].length
97
- });
98
- }
99
- return references;
100
- };
101
- /**
102
- * The reference a whole line carries, or `Option.none()`.
103
- *
104
- * @remarks
105
- * The **bare-line** dialect: after trimming, the entire line must be
106
- * `<keyword>[:] #<number>` — keyword case-insensitive, colon optional,
107
- * whitespace before the `#` mandatory. Trailing prose, a missing keyword, or
108
- * anything else at all is a rejection, never a partial parse; a line carries
109
- * one reference or none. Digits past `Number.MAX_SAFE_INTEGER` reject too,
110
- * for the same reason {@link harvestIssueReferences} skips them.
111
- *
112
- * @public
113
- */
114
- const parseBareLineReference = (line) => {
115
- const match = BARE_LINE_PATTERN.exec(line.trim());
116
- if (match === null) return Option.none();
117
- const issueNumber = safeIssueNumber(match[2] ?? "");
118
- if (issueNumber === void 0) return Option.none();
119
- return Option.some({
120
- issueNumber,
121
- keyword: (match[1] ?? "").toLowerCase()
122
- });
123
- };
124
-
125
- //#endregion
126
- export { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference };