@rmartz/merge-safety 0.14.0 → 0.16.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.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,367 @@
1
+ /**
2
+ * Breaking-change detection over a PR's **own** unified diff (#53).
3
+ *
4
+ * Until now `prIsBreaking` was read entirely from the PR title's `!` marker or a
5
+ * `breaking change` label an LLM turn applies (`/review` Step 5 in the coordinator,
6
+ * which shells to `breaking-change.py check-diff`). That made a *required,
7
+ * merge-gating* check depend on a non-deterministic producer, and it failed in the
8
+ * **permissive** direction: no `/review` run, or a reviewer who misread the diff,
9
+ * and the PR was evaluated as non-breaking. These detectors are pure functions over
10
+ * a diff, so the check derives the fact itself; the title `!` marker is the only
11
+ * declared input alongside it — the label is never read.
12
+ *
13
+ * Ported from `claude/scripts/breaking_change.py` in `rmartz/dotfiles`
14
+ * (`has_major_version_bump` / `has_sensitive_package_bump` /
15
+ * `has_material_test_changes`). Each returns the *specific* packages or files that
16
+ * tripped it rather than a bare boolean, so the check-run can name them — the same
17
+ * "one computation, two views" shape the base-commit and file-overlap facts use.
18
+ *
19
+ * Deliberately NOT ported: `add_breaking_marker` / `remove_breaking_marker` /
20
+ * `reconcile_breaking_title`, which rewrite the PR *title* inside the squash-merge
21
+ * transaction (with the release-please exemption). Detection moves here; stamping
22
+ * stays in `merge-pr.py`, at a moment a PR-event action cannot reach.
23
+ */
24
+ /** The kinds of breaking signal a PR's own diff can carry. */
25
+ declare const BREAKING_DIFF_KINDS: readonly ["major-version-bump", "sensitive-package-bump", "material-test-changes"];
26
+ type BreakingDiffKind = (typeof BREAKING_DIFF_KINDS)[number];
27
+ /** One fired detector, with the packages / files that tripped it. */
28
+ interface BreakingDiffSignal {
29
+ kind: BreakingDiffKind;
30
+ /** The specific package names or file paths, surfaced in the check-run reason. */
31
+ detail: string[];
32
+ }
33
+
34
+ /**
35
+ * Reason presentation for the merge-safety check-run — how a verdict's facts are
36
+ * rendered as the human-readable lines the check-run output carries.
37
+ *
38
+ * Split from `merge-safety.ts` (the verdict *logic*) so each stays under its
39
+ * `max-lines` cap as axes accumulate (#53 added the diff-derived breaking
40
+ * signals). Presentation is a genuinely separate concern —
41
+ * nothing here decides anything, it only formats.
42
+ */
43
+
44
+ /** A base commit surfaced in a reason so the report names *which* commit triggered it. */
45
+ interface BaseCommit {
46
+ /** The full commit SHA (rendered abbreviated in the report). */
47
+ sha: string;
48
+ /** The commit subject (first line of its message). */
49
+ subject: string;
50
+ }
51
+
52
+ /**
53
+ * Base-health classification — "is the base branch's own CI failing?", the
54
+ * PR-independent axis of the merge-safety verdict.
55
+ *
56
+ * Extracted from `merge-safety.ts` when the self-derived breaking-change signal
57
+ * (#53) pushed that file past its 480-line cap. It is a genuinely separate
58
+ * concern: every other clause of the verdict reads *this PR* against *its base*,
59
+ * while these functions read only the base tip's check-runs and know nothing
60
+ * about any PR. Pure — the network boundary stays in the bin's probes.
61
+ */
62
+ /**
63
+ * A base-tip check-run reduced to what base-health classification needs: its name
64
+ * (matched against the base branch's required status checks), its conclusion, and
65
+ * the slug of the producing GitHub App (used by the fallback heuristic to tell a
66
+ * GitHub Actions CI run from an external deploy integration).
67
+ */
68
+ interface BaseCheckRun {
69
+ /** The check-run name (e.g. the workflow / job name), matched to a required context. */
70
+ name: string;
71
+ /** The check-run conclusion, or `null` while still in progress. */
72
+ conclusion: string | null;
73
+ /** The producing GitHub App's slug (e.g. `github-actions`, `vercel`), or `null`. */
74
+ appSlug: string | null;
75
+ }
76
+
77
+ /**
78
+ * Merge-safety predicate — "is this PR safe to merge *as it stands*, or must it
79
+ * first be brought current against its base branch and re-run through CI?"
80
+ *
81
+ * This is the coordinator's `_pr_needs_branch_update` decision, lifted into a
82
+ * pure, side-effect-free function so it can be shared by two callers: PR Shepherd
83
+ * (which merges) and the `merge-safety` GitHub check (which *surfaces* the
84
+ * verdict as a required status so it's visible on the PR and can gate auto-merge).
85
+ * It knows nothing about posting, check-runs, or PR Shepherd's gate labels — it
86
+ * maps gathered *facts* to a verdict, and the caller owns the emission channel.
87
+ *
88
+ * The rule (a PR **must be brought current** when it is not already current AND):
89
+ * 1. a **breaking** commit landed on the base since the PR's merge-base **and the
90
+ * PR is not a (non-breaking) `docs` PR**, OR
91
+ * 2. a **CI** commit landed on the base since merge-base — `ci`-typed, or one
92
+ * that changed `.github/workflows/**` / `.github/actions/**` (#67) — (the
93
+ * coordinator rebases in-flight PRs past CI changes, by prefix or path), OR
94
+ * 3. the PR is **itself** a breaking change **and the base has moved by more than
95
+ * `docs` commits alone**, OR
96
+ * 4. the PR is **itself** a CI change (`ci`-typed, or its diff touches those
97
+ * paths) **and is not a hotfix** — a CI
98
+ * guard is only as good as the base it last ran against, so a CI PR that was
99
+ * clean when it was opened must be re-tested against the current base to
100
+ * catch a pattern the guard protects against that has regressed on the base
101
+ * since (the symmetric partner to clause 2's base-side detection). The
102
+ * `hotfix` label exempts *this* clause — a CI fix for a base whose own CI is
103
+ * red can be caught in a bind (base health blocks it unless it is a hotfix,
104
+ * and being forced current may itself be impossible or pointless while the
105
+ * base is broken), so `hotfix` frees it here just as it frees the base-health
106
+ * axis. The exemption is deliberately *this-PR-is-itself-CI*-only: it does
107
+ * not touch clause 3 (`prIsBreaking`) or the base-side clauses (1, 2, 5),
108
+ * which guard against real incompatibilities a hotfix must still rebase past,
109
+ * OR
110
+ * 5. the PR's changed files **intersect** the files changed on the base since
111
+ * merge-base.
112
+ *
113
+ * The `docs` carve-outs on clauses 1 and 3 (a breaking and a docs change interact
114
+ * only through a shared file; CI changes get no such carve-out) are explained in
115
+ * `staleness.ts`, which evaluates clauses 1–5.
116
+ *
117
+ * Clause 5 is a *narrowing* guard, not a widening one: it only ever forces more
118
+ * PRs current. Git can merge two disjoint-looking diffs cleanly and still produce
119
+ * invalid code (an earlier PR deletes a symbol this PR still references), so any
120
+ * file-level overlap forces a rebase + re-CI to catch the semantic conflict a
121
+ * clean textual merge hides.
122
+ *
123
+ * A hard git **conflict** is a separate axis from staleness — GitHub blocks such
124
+ * a merge regardless — but the verdict folds it in so a single check answers "is
125
+ * it safe to merge right now?", with a distinct label for visibility.
126
+ *
127
+ * **Base health** is a third, PR-independent axis: when the base branch's own CI
128
+ * is failing, merging anything but a fix onto it only compounds a broken base, so
129
+ * a PR is held **unless it is a hotfix** (the `hotfix` label is the escape hatch
130
+ * that lets the fix for broken main through). "Failing CI" is read expansively —
131
+ * any failing GitHub Actions run on the base counts — but a failing *deploy* does
132
+ * not: a red deploy under green Actions is likelier an external/environmental
133
+ * fault no code change can fix, so it must not wedge the whole merge queue.
134
+ *
135
+ * **The breaking verdict reads the title and the diff, never a label** (#82).
136
+ * `prIsBreaking` is the PR title's `!` marker or a breaking signal in the PR's own
137
+ * diff (`breaking-diff.ts`, #53). Whether a PR *should* carry `!` — the
138
+ * `breaking change` label, a dependency major bump, a linter bump's `ci` type — is
139
+ * title policy, enforced by pr-policy's title check; this check only consumes the
140
+ * resulting title and never reads or writes a label for it.
141
+ */
142
+
143
+ /** Labels the check drives on a PR. Structural (`as const`) per repo convention. */
144
+ declare const MERGE_SAFETY_LABELS: readonly ["update required", "merge conflict"];
145
+ type MergeSafetyLabel = (typeof MERGE_SAFETY_LABELS)[number];
146
+ /**
147
+ * The gathered facts a merge-safety verdict is computed from. The `*SinceMergeBase`
148
+ * / `fileOverlap` booleans drive the verdict; the parallel `baseBreakingCommits` /
149
+ * `baseCiCommits` / `overlappingFiles` detail lists name *which* base commits and
150
+ * files triggered each, so the report can surface the specifics. Each boolean is
151
+ * exactly `list.length > 0` — the gatherer derives it from the list.
152
+ */
153
+ interface MergeSafetyFacts {
154
+ /** The PR's merge-base is the current base-branch tip — nothing is stale. */
155
+ isCurrent: boolean;
156
+ /** A breaking commit landed on the base since the PR's merge-base. */
157
+ baseBreakingSinceMergeBase: boolean;
158
+ /** A CI commit (`ci`-typed, or touching a CI path) landed on the base since merge-base. */
159
+ baseCiSinceMergeBase: boolean;
160
+ /** The PR is itself a breaking change: its title's `!` marker or a diff-derived signal. */
161
+ prIsBreaking: boolean;
162
+ /**
163
+ * The PR title is a `docs:` / `docs(scope):` conventional commit. A non-breaking
164
+ * docs PR is exempt from the base-breaking clause (a breaking base change only
165
+ * forces it current through a shared file, via `fileOverlap`).
166
+ */
167
+ prIsDocs: boolean;
168
+ /**
169
+ * The base moved since merge-base, and **every** commit it moved by is
170
+ * `docs`-typed. Exempts the `prIsBreaking` clause: a breaking PR behind only docs
171
+ * commits need not be brought current unless the files overlap.
172
+ */
173
+ baseOnlyDocsSinceMergeBase: boolean;
174
+ /**
175
+ * The PR is itself a CI change: title `ci:` / `ci(scope):`, or its own diff
176
+ * changes `.github/workflows/**` / `.github/actions/**` (#67).
177
+ */
178
+ prIsCi: boolean;
179
+ /** The PR's changed files intersect the base's changed files since merge-base. */
180
+ fileOverlap: boolean;
181
+ /** Git reports the PR as conflicting (`mergeable === 'CONFLICTING'`). */
182
+ hasConflict: boolean;
183
+ /** The base branch tip has at least one failing GitHub Actions CI check. */
184
+ baseCiFailing: boolean;
185
+ /**
186
+ * The PR carries the `hotfix` label, exempting it from the base-CI-failing axis
187
+ * *and* from the `prIsCi` update-required clause (a hotfix CI fix for a red base
188
+ * is not forced current). It does not exempt `prIsBreaking` or the base-side
189
+ * clauses.
190
+ */
191
+ prIsHotfix: boolean;
192
+ /** The base commits since merge-base whose message marks a breaking change. */
193
+ baseBreakingCommits: readonly BaseCommit[];
194
+ /** The CI base commits (`ci`-typed, or touching a CI path) since merge-base. */
195
+ baseCiCommits: readonly BaseCommit[];
196
+ /** The PR's changed files that also changed on the base since merge-base. */
197
+ overlappingFiles: readonly string[];
198
+ /** The names of the failing base CI checks, surfaced in the base-health reason. */
199
+ failingBaseChecks: readonly string[];
200
+ /**
201
+ * The breaking signals the PR's **own diff** carries (#53) — a dependency major
202
+ * bump, a CI-sensitive linter/formatter version change, or material changes to
203
+ * existing tests. These feed `prIsBreaking` alongside the title marker, so a PR
204
+ * that changes something risky is re-tested against a moved base even when its
205
+ * title is unmarked.
206
+ */
207
+ prBreakingDiffSignals: readonly BreakingDiffSignal[];
208
+ }
209
+ /**
210
+ * `pending` is posted as an incomplete (`in_progress`) check-run: it blocks the
211
+ * merge like `failure` but renders as a yellow dot, not a red ✗ (#58).
212
+ */
213
+ type MergeSafetyConclusion = 'success' | 'failure' | 'pending';
214
+ interface MergeSafetyDecision {
215
+ /**
216
+ * The check-run conclusion: `success` iff safe to merge as-is; `pending` when the
217
+ * only problem is staleness, which a branch update clears; otherwise `failure`.
218
+ */
219
+ conclusion: MergeSafetyConclusion;
220
+ /** The PR must be brought current before merge (the staleness axis). */
221
+ needsUpdate: boolean;
222
+ /** The PR has a hard git conflict (the mergeability axis). */
223
+ hasConflict: boolean;
224
+ /** Blocked because the base's CI is failing and this PR is not a hotfix (the base-health axis). */
225
+ baseUnhealthy: boolean;
226
+ /**
227
+ * Short state phrase for the check-run title — the verdict at a glance. One of
228
+ * `No update required` / `Update required` / `Merge conflict` / `Base CI
229
+ * failing` / `Could not evaluate`. The check-run
230
+ * *name* stays the stable `merge-safety` (so branch
231
+ * protection can match it); this varies with the outcome instead.
232
+ */
233
+ title: string;
234
+ /** Ordered most→least severe, human-readable — the check-run output detail. */
235
+ reasons: string[];
236
+ /** One-line check-run summary. */
237
+ summary: string;
238
+ /**
239
+ * Labels the check drives.
240
+ *
241
+ * `add` / `remove` are **reconciled**: the check owns `update required` and
242
+ * `merge conflict` outright, adding the ones that apply and removing the rest.
243
+ */
244
+ labels: {
245
+ add: MergeSafetyLabel[];
246
+ remove: MergeSafetyLabel[];
247
+ };
248
+ }
249
+ /**
250
+ * Map gathered {@link MergeSafetyFacts} to a {@link MergeSafetyDecision}. Pure:
251
+ * the same facts always yield the same verdict. A PR that is already current is
252
+ * always safe on the staleness axis — a stale trigger can only matter when the
253
+ * PR is behind — so the update clauses are gated on `!isCurrent`.
254
+ */
255
+ declare function evaluateMergeSafety(facts: MergeSafetyFacts): MergeSafetyDecision;
256
+ /**
257
+ * The verdict for a PR whose facts could not be gathered (bad merge-base, a git
258
+ * command that failed, an unreadable PR). Fail-safe: `failure`, so a consumer
259
+ * that trusts the verdict treats an ungatherable PR as unsafe rather than green.
260
+ * `needsUpdate` / `hasConflict` stay `false` because they are genuinely unknown —
261
+ * the `failure` conclusion is what carries the safety, not a fabricated axis. No
262
+ * labels are proposed: an ungatherable state is not evidence for adding or
263
+ * removing either label.
264
+ */
265
+ declare function errorMergeSafetyDecision(message: string): MergeSafetyDecision;
266
+
267
+ /** Runs a `git` argv and yields stdout, or `null` on non-zero exit / failure. */
268
+ type GitRunner = (args: string[]) => Promise<string | null>;
269
+ /**
270
+ * Fetches the base branch tip's check-runs (deduped to the latest per name) so
271
+ * base-health can be judged. Injected like {@link GitRunner} so the assembly logic
272
+ * stays testable with a fake and the network boundary lives in the bin. Soft-fails
273
+ * to `[]` (an unreadable base is treated as *not* failing) so a transient `gh`
274
+ * error never wedges the whole merge queue on a base-health false positive.
275
+ */
276
+ type BaseChecksProbe = (baseSha: string) => Promise<readonly BaseCheckRun[]>;
277
+ /**
278
+ * Fetches the base branch's **required status check** contexts — the set base-health
279
+ * scopes failures to (#40). Returns `null` when protection can't be read (transient
280
+ * `gh` error, no ruleset, missing scope); a `null` or empty set means base-health
281
+ * reports no failure, so a probe hiccup never wedges the merge queue. Injected like
282
+ * {@link BaseChecksProbe}, with the network boundary in the bin.
283
+ */
284
+ type RequiredChecksProbe = (baseBranch: string) => Promise<readonly string[] | null>;
285
+ /** The real `git` runner, bounded and rooted at `cwd`. */
286
+ declare function makeGitRunner(cwd?: string): GitRunner;
287
+ /** PR metadata the gatherer needs beyond what git derives (from `gh pr view --json`). */
288
+ interface PrMergeMeta {
289
+ headSha: string;
290
+ title: string;
291
+ labels: readonly string[];
292
+ /** `gh`'s `mergeable`: `MERGEABLE` | `CONFLICTING` | `UNKNOWN`. */
293
+ mergeable: string;
294
+ }
295
+ interface GatherOptions {
296
+ /** Base branch ref to compare against (default `origin/main`). */
297
+ baseRef?: string;
298
+ git: GitRunner;
299
+ /** Probe for the base tip's check-runs, used to judge base health. */
300
+ baseChecks: BaseChecksProbe;
301
+ /** Probe for the base branch's required status checks, scoping base health (#40). */
302
+ requiredChecks: RequiredChecksProbe;
303
+ }
304
+ /**
305
+ * Assemble {@link MergeSafetyFacts} for one PR. Throws when the merge-base or base
306
+ * tip can't be resolved — the caller must treat an ungatherable PR as unsafe
307
+ * (fail the check) rather than let a stale green through.
308
+ */
309
+ declare function gatherMergeSafetyFacts(meta: PrMergeMeta, { baseRef, git, baseChecks, requiredChecks }: GatherOptions): Promise<MergeSafetyFacts>;
310
+
311
+ /**
312
+ * The API-backed fact source: a {@link GitRunner} that answers the `git` queries
313
+ * {@link gatherMergeSafetyFacts} makes from the GitHub REST API instead of a local
314
+ * checkout, so merge-safety can run where there is no `git` binary (a hosted
315
+ * GitHub App's serverless function). The git-backed runner stays the default; this
316
+ * one is opt-in through the same `git` injection point.
317
+ *
318
+ * Every query maps onto two compares and, for CI-path detection, one commit read
319
+ * per base commit:
320
+ * - `compare/{head}...{tip}` — the merge base, the base commits since it, and the
321
+ * base-side changed files;
322
+ * - `compare/{tip}...{head}` — the PR-side changed files and their patches;
323
+ * - `commits/{sha}` — each base commit's own files, for the CI-path signal.
324
+ *
325
+ * The compare API truncates silently (250 commits, 300 files) and omits `patch`
326
+ * for oversized files. Each of those **fails closed** by throwing, so the caller
327
+ * reports `Could not evaluate` rather than a verdict built on partial data.
328
+ */
329
+
330
+ /**
331
+ * A GitHub REST `GET` for a path relative to the API root (e.g.
332
+ * `repos/o/r/compare/a...b`), yielding the parsed JSON body, or `null` when the
333
+ * read fails. A caller that wants a transient error to abort the run (rather than
334
+ * fail the check) may throw instead; the error propagates unchanged.
335
+ */
336
+ type GitHubApiGet = (path: string) => Promise<unknown>;
337
+ interface ApiGitRunnerOptions {
338
+ /** `owner/repo` the PR and its base live in. */
339
+ repo: string;
340
+ api: GitHubApiGet;
341
+ /** Concurrent `commits/{sha}` reads during CI-path detection (default 8). */
342
+ concurrency?: number;
343
+ }
344
+ /** The compare API's caps: past these its lists are silently truncated. */
345
+ declare const COMPARE_MAX_COMMITS = 250;
346
+ declare const COMPARE_MAX_FILES = 300;
347
+ /** A commit read lists at most this many files without pagination. */
348
+ declare const COMMIT_MAX_FILES = 300;
349
+ /**
350
+ * A {@link GitRunner} backed by the GitHub REST API rather than a checkout. It
351
+ * answers exactly the queries {@link gatherMergeSafetyFacts} makes and throws on
352
+ * any other, so a new git query added there fails closed until it is mapped here.
353
+ * Comparisons are cached for the runner's lifetime, so create one per evaluation.
354
+ */
355
+ declare function makeApiGitRunner({ repo, api, concurrency }: ApiGitRunnerOptions): GitRunner;
356
+
1
357
  /**
2
358
  * @rmartz/merge-safety — public entry point.
3
359
  *
4
360
  * Encodes the package's stable public contract: the `merge-safety` check-run
5
361
  * name and the CLI command surface. The evaluate/invalidate implementation
6
362
  * (`merge-safety.ts` + `merge-safety-facts.ts` and the `merge-safety` bin)
7
- * lives alongside it; this module is intentionally the narrow, frozen surface
8
- * consumers and the reusable workflow depend on.
363
+ * lives alongside it. The check-run name and command surface below are frozen;
364
+ * the re-exported library surface lets a consumer run the verdict in-process.
9
365
  */
10
366
  /**
11
367
  * The name of the check-run merge-safety posts for each PR.
@@ -18,6 +374,7 @@
18
374
  * docs/check-run-contract.md.
19
375
  */
20
376
  declare const MERGE_SAFETY_CHECK_NAME = "merge-safety";
377
+
21
378
  /**
22
379
  * The two operations the `merge-safety` CLI dispatches:
23
380
  * - `evaluate` — gather base-currency + breaking-change + conflict facts for one
@@ -32,4 +389,4 @@ type MergeSafetyCommand = (typeof MERGE_SAFETY_COMMANDS)[number];
32
389
  /** Type guard for the CLI command surface. */
33
390
  declare function isMergeSafetyCommand(value: string | undefined): value is MergeSafetyCommand;
34
391
 
35
- export { MERGE_SAFETY_CHECK_NAME, MERGE_SAFETY_COMMANDS, type MergeSafetyCommand, isMergeSafetyCommand };
392
+ export { type ApiGitRunnerOptions, type BaseCheckRun, type BaseChecksProbe, COMMIT_MAX_FILES, COMPARE_MAX_COMMITS, COMPARE_MAX_FILES, type GatherOptions, type GitHubApiGet, type GitRunner, MERGE_SAFETY_CHECK_NAME, MERGE_SAFETY_COMMANDS, type MergeSafetyCommand, type MergeSafetyDecision, type MergeSafetyFacts, type PrMergeMeta, type RequiredChecksProbe, errorMergeSafetyDecision, evaluateMergeSafety, gatherMergeSafetyFacts, isMergeSafetyCommand, makeApiGitRunner, makeGitRunner };
package/dist/index.js CHANGED
@@ -1,10 +1,26 @@
1
1
  import {
2
+ COMMIT_MAX_FILES,
3
+ COMPARE_MAX_COMMITS,
4
+ COMPARE_MAX_FILES,
2
5
  MERGE_SAFETY_CHECK_NAME,
3
6
  MERGE_SAFETY_COMMANDS,
4
- isMergeSafetyCommand
5
- } from "./chunk-ITPKHZGC.js";
7
+ errorMergeSafetyDecision,
8
+ evaluateMergeSafety,
9
+ gatherMergeSafetyFacts,
10
+ isMergeSafetyCommand,
11
+ makeApiGitRunner,
12
+ makeGitRunner
13
+ } from "./chunk-2QWRQ4Q5.js";
6
14
  export {
15
+ COMMIT_MAX_FILES,
16
+ COMPARE_MAX_COMMITS,
17
+ COMPARE_MAX_FILES,
7
18
  MERGE_SAFETY_CHECK_NAME,
8
19
  MERGE_SAFETY_COMMANDS,
9
- isMergeSafetyCommand
20
+ errorMergeSafetyDecision,
21
+ evaluateMergeSafety,
22
+ gatherMergeSafetyFacts,
23
+ isMergeSafetyCommand,
24
+ makeApiGitRunner,
25
+ makeGitRunner
10
26
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmartz/merge-safety",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "The pre-auto-merge safety verdict for a PR (base-currency, breaking-change, and conflict facts), posted as the `merge-safety` check-run and distributed through the `rmartz/merge-safety-action` composite action kept current by Dependabot.",
5
5
  "keywords": [
6
6
  "ci",
@@ -1,12 +0,0 @@
1
- // src/index.ts
2
- var MERGE_SAFETY_CHECK_NAME = "merge-safety";
3
- var MERGE_SAFETY_COMMANDS = ["evaluate", "invalidate"];
4
- function isMergeSafetyCommand(value) {
5
- return value !== void 0 && MERGE_SAFETY_COMMANDS.includes(value);
6
- }
7
-
8
- export {
9
- MERGE_SAFETY_CHECK_NAME,
10
- MERGE_SAFETY_COMMANDS,
11
- isMergeSafetyCommand
12
- };