okf-kit 0.10.0 → 0.12.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/CHANGELOG.md +149 -0
- package/README.md +61 -3
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -1
- package/dist/rules/sources-fresh.d.ts +11 -4
- package/dist/rules/sources-fresh.js +421 -57
- package/dist/rules/sources-fresh.js.map +1 -1
- package/dist/types.d.ts +27 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,155 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.12.0] - 2026-09-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Adds a pinned fixture-repository regression test for the documented
|
|
15
|
+
two-branch squash-merge decision procedure, including every stale branch
|
|
16
|
+
state's re-verify-and-re-stamp rescue.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- `sources-fresh` under a `--repo-root` naming a SUBDIRECTORY of the
|
|
21
|
+
repository: both re-stamp rescues read the doc's committed value with
|
|
22
|
+
`git show <rev>:<path>`, and git resolves that path against the
|
|
23
|
+
repository's top level, never the cwd, while the rule's own doc path is
|
|
24
|
+
relative to the passed root. Spelled bare, the read failed (every rescue
|
|
25
|
+
collapsed to a `staleness not assessable` notice: a locally re-stamped
|
|
26
|
+
doc, or a doc re-stamped in the same commit as its source, no longer read
|
|
27
|
+
clean) or, with a same-named doc at the top level, read THAT doc's stamp
|
|
28
|
+
in the subdirectory doc's place (a dirty-but-not-re-stamped doc could
|
|
29
|
+
read clean, a false green). The same frame mismatch made the committed
|
|
30
|
+
rescue's rename-aware `git diff-tree` lookup never match the doc, so a
|
|
31
|
+
doc created in the co-commit read `not assessable` instead of clean. All
|
|
32
|
+
three sites now go through one helper that respells the path in the
|
|
33
|
+
top-level frame via `git rev-parse --show-prefix` (read at most once per
|
|
34
|
+
run and shared with `--dirty-as-now`'s dirty-path matching, which
|
|
35
|
+
already used it), so a subdirectory root now judges exactly as the top
|
|
36
|
+
level does. Cost with the flag off: one extra `git rev-parse` per run on
|
|
37
|
+
the re-stamp path, none per doc; a top-level `--repo-root` is otherwise
|
|
38
|
+
byte-identical to before. The README's "prefer the top level" limitation
|
|
39
|
+
paragraph is gone. (task agent-dx 266d64d3)
|
|
40
|
+
- `--dirty-as-now`'s shared virtual-commit instant is now pinned: the clock
|
|
41
|
+
is read exactly once per `check` run through an injectable `ctx.now`
|
|
42
|
+
(default `Date.now`), and a test asserts both the read count and that
|
|
43
|
+
every dirty path in both rules cites the identical instant, so a
|
|
44
|
+
per-call re-read can no longer slip in unnoticed. Also adds an
|
|
45
|
+
ignored-only new-directory control for the `--untracked-files=all`
|
|
46
|
+
status read, and trims `src/rules/sources-fresh.ts`'s comments to the
|
|
47
|
+
invariants and their reasons.
|
|
48
|
+
|
|
49
|
+
## [0.11.0] - 2026-09-12
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- `check` gets `--dirty-as-now`: an opt-in flag under which every
|
|
54
|
+
uncommitted change (modified, staged, or untracked per `git status
|
|
55
|
+
--porcelain --untracked-files=all`) is modeled as though it landed in
|
|
56
|
+
ONE virtual commit made
|
|
57
|
+
right now, applied at a single shared choke point
|
|
58
|
+
(`commitEpochWithDirtyAsNow` in `src/rules/sources-fresh.ts`) so both
|
|
59
|
+
`sources-fresh` (a dirty `sources` path's epoch) AND `sources-fresh-future`
|
|
60
|
+
(a dirty DOC's own epoch) read the identical virtual instant, rather than
|
|
61
|
+
each rule -- or each path kind -- getting its own patch. Closes a gap
|
|
62
|
+
surfaced by the 2026-09-11 review-method dogfood (agent-dx PR #236): a
|
|
63
|
+
test file four OKF docs list as a source was edited, a pre-commit `check`
|
|
64
|
+
run reported 0 warnings because the source's last commit still predated
|
|
65
|
+
every doc's `timestamp`, and CI's strict freshness guard then failed once
|
|
66
|
+
the commit landed and gave the source a new, later commit time. Omit the
|
|
67
|
+
flag and both rules are unchanged; see the README's "Uncommitted edits
|
|
68
|
+
(`--dirty-as-now`)" section for the recommended pre-commit invocation and
|
|
69
|
+
the exact parity matrix (six working-tree states, each reproduced
|
|
70
|
+
through the built CLI with `--strict` exit codes, including the one
|
|
71
|
+
shape inherent to the model where a clean local run does NOT imply a
|
|
72
|
+
clean CI run: a source edit committed alone while its doc re-stamp stays
|
|
73
|
+
uncommitted). Carries a working-tree
|
|
74
|
+
analogue of `sources-fresh`'s own co-commit re-stamp rescue, evaluated
|
|
75
|
+
against that same virtual commit: a doc re-stamped locally (uncommitted,
|
|
76
|
+
on-disk `timestamp` differing -- in EITHER direction -- from the value
|
|
77
|
+
committed at `HEAD`; an untracked doc counts as re-stamped too) rescues a
|
|
78
|
+
dirty source exactly like a real re-stamp landing in the same commit
|
|
79
|
+
does, so the README's recommended `--dirty-as-now --strict` pre-commit
|
|
80
|
+
gate can actually be made green by following its own remedy (re-stamp,
|
|
81
|
+
then commit) while the source stays uncommitted. Reads the work tree's
|
|
82
|
+
dirty paths once per `check` run (`git --no-optional-locks status
|
|
83
|
+
--porcelain=v2 -z --untracked-files=all`), not once per unique source
|
|
84
|
+
path, and normalizes a `./`-prefixed or `/`-suffixed path spelling
|
|
85
|
+
before matching it against that dirty-paths set, so any spelling of the
|
|
86
|
+
same source or doc path matches consistently. `--untracked-files=all` is
|
|
87
|
+
load-bearing, not decoration: git's default untracked mode collapses a
|
|
88
|
+
brand-new directory into a single `? newdir/` record and never names the
|
|
89
|
+
files inside it, so a source or doc inside one matched nothing and the
|
|
90
|
+
flag reported `untracked by git` (exit 0) for content a plain `check`
|
|
91
|
+
reported STALE (exit 1) the moment it was committed -- the exact
|
|
92
|
+
divergence the flag exists to close. A `sources` entry spelled `.`/`./`
|
|
93
|
+
(the repo root) is matched by containment rather than by lookup, since
|
|
94
|
+
`git status` never reports the root as an entry; a `--repo-root` naming
|
|
95
|
+
a SUBDIRECTORY of the repository is handled by rebasing the queried path
|
|
96
|
+
onto the repository top level (`git rev-parse --show-prefix`, the run's
|
|
97
|
+
second and last extra git process) instead of silently matching nothing.
|
|
98
|
+
When git cannot be read at all (`status` failing, its output past the
|
|
99
|
+
16 MiB `MAX_GIT_OUTPUT_BYTES` cap, git missing), the run emits one
|
|
100
|
+
bundle-level notice -- "`--dirty-as-now` not applied: git status could
|
|
101
|
+
not be read, judging by committed history only" -- rather than falling
|
|
102
|
+
back to committed history in a silence indistinguishable from a clean
|
|
103
|
+
tree. Distinguishes a genuinely untracked doc (no entry
|
|
104
|
+
for it at `HEAD` at all) from a real git failure reading an existing
|
|
105
|
+
`HEAD` blob when deciding whether a dirty doc's own re-stamp counts,
|
|
106
|
+
falling through to the ordinary not-assessable notice in the latter
|
|
107
|
+
case rather than guessing.
|
|
108
|
+
|
|
109
|
+
### Documented
|
|
110
|
+
|
|
111
|
+
- Decision (task agent-dx 27c4f709): the anchored, path-less continuation
|
|
112
|
+
form the `orchestrator-workflow` package's dogfood bundle writes
|
|
113
|
+
(`` `:N-M#"anchor"` ``) is declared bundle-local, not ported into
|
|
114
|
+
`CONT_COLON_RE`/`SHORT_FORM_COLON_RE`. See the README's "Citation
|
|
115
|
+
resolution (citations-resolve)" section for the who-pays and the port
|
|
116
|
+
trigger.
|
|
117
|
+
- Decision, kept option (a): the rule stays as-is; two loosening
|
|
118
|
+
alternatives were considered and rejected. The README's "Staleness
|
|
119
|
+
(sources-fresh)" section now documents the two-branch squash-merge
|
|
120
|
+
interaction as the rule's own three-step decision procedure (the
|
|
121
|
+
doc-last-commit lookup under git's default history simplification, the
|
|
122
|
+
epoch gate, and the value-level re-stamp check) instead of an
|
|
123
|
+
enumeration of merge shapes, plus the one consequence that follows for
|
|
124
|
+
any branch merging a squash-carrying trunk. The two rejected
|
|
125
|
+
alternatives: (b) a source counts fresh whenever the doc's last commit
|
|
126
|
+
merely postdates it, with no re-stamp required -- readers pay, because
|
|
127
|
+
any merge or unrelated doc touch would silence real drift; (c) compare
|
|
128
|
+
against the doc's own last commit rather than the frontmatter stamp when
|
|
129
|
+
they disagree -- readers pay, because the stamp stops being the
|
|
130
|
+
verification claim. Under the kept option (a), branch authors pay
|
|
131
|
+
instead: one re-verify-and-re-stamp commit after merging a
|
|
132
|
+
squash-carrying trunk (or after changing a source past a trunk squash
|
|
133
|
+
the doc's history resolved through), the recipe now in the README.
|
|
134
|
+
Reproduced with a fixture repo (the trunk and eight branch variants:
|
|
135
|
+
doc untouched, B1; doc untouched with a second source changed after the
|
|
136
|
+
squash, B3; own-older-stamp kept wholesale before the squash, B2, and
|
|
137
|
+
after it, B2late, discriminating the epoch gate from the re-stamp
|
|
138
|
+
check; own-older-stamp with a mixed conflict resolution that changes
|
|
139
|
+
the stamp value, B2a, or does not, B2b; and both re-verify-and-re-stamp
|
|
140
|
+
recipe follow-ups, B2r and B3r) before writing the decision text, then
|
|
141
|
+
checked the procedure's own prediction against all eight plus the
|
|
142
|
+
trunk; no rule change. No fleet pin bump needed (no rule/behavior
|
|
143
|
+
change).
|
|
144
|
+
- Concrete case that motivated this decision: in the `agent-grounding`
|
|
145
|
+
repo, `docs/okf/grounding-stack-overview.md` read STALE after merging
|
|
146
|
+
master (batch-42 task branch `f31ad37f`'s squash-merged re-stamp) into a
|
|
147
|
+
second, longer-lived task branch (`d341afd5`), which carried its own
|
|
148
|
+
older stamp of the same doc; the batch-42 orchestrator run (pandora
|
|
149
|
+
workspace) recorded the resolution as decision D-015, exactly the
|
|
150
|
+
re-verify-and-re-stamp commit this README section now generalizes as
|
|
151
|
+
the recipe.
|
|
152
|
+
|
|
153
|
+
### Security
|
|
154
|
+
|
|
155
|
+
- devDependencies: vitest and @vitest/mocker 4.1.6 -> 4.1.11
|
|
156
|
+
(GHSA-82fw-gwwq-j7x9), lockfile only, no runtime dependency changed
|
|
157
|
+
(CVE sweep 2026-09-11, agent-dx PR #235).
|
|
158
|
+
|
|
10
159
|
## [0.10.0] - 2026-09-06
|
|
11
160
|
|
|
12
161
|
### Added
|
package/README.md
CHANGED
|
@@ -34,6 +34,10 @@ okf-kit check path/to/bundle --strict
|
|
|
34
34
|
|
|
35
35
|
# narrow sources-fresh-future's default 10-minute clock-skew allowance
|
|
36
36
|
okf-kit check path/to/bundle --future-skew-minutes 2
|
|
37
|
+
|
|
38
|
+
# pre-commit: treat an uncommitted source edit as happening now, so this run
|
|
39
|
+
# reports the same staleness CI will report once you commit
|
|
40
|
+
okf-kit check path/to/bundle --dirty-as-now
|
|
37
41
|
```
|
|
38
42
|
|
|
39
43
|
## Scaffold a bundle (`init`)
|
|
@@ -72,7 +76,7 @@ Every template doc except `benchmark-template.md` ships with `sources: [path/to/
|
|
|
72
76
|
| `links-resolve` | error | Markdown links to other `.md` files in the bundle must resolve to a real file. Relative targets resolve against the containing file's directory; targets starting with `/` resolve against the bundle root. A relative target that climbs out of the bundle directory (`../outside.md`) and still resolves on disk is accepted; the rule checks resolution, not containment. |
|
|
73
77
|
| `no-absolute-links` | warning | Link targets should not start with `/`. GitHub resolves a leading slash against the repository root, not the bundle root, so an absolute link 404s once the bundle is viewed outside its own repository. Use a same-directory relative link instead. |
|
|
74
78
|
| `sources-shape` | error | Frontmatter `sources`, when present, must be a non-empty array of non-empty strings. With a repo root (explicit or auto-detected), each listed path (file or directory) must also exist under it. |
|
|
75
|
-
| `sources-fresh` | warning / notice | For docs with a `sources` list and a repo root, flags a source path whose last git commit is newer than both the doc's `timestamp` and the doc file's own last re-stamping commit (re-stamp decided by comparing frontmatter `timestamp` values across that commit's first-parent boundary). See "Staleness (sources-fresh)" below. |
|
|
79
|
+
| `sources-fresh` | warning / notice | For docs with a `sources` list and a repo root, flags a source path whose last git commit is newer than both the doc's `timestamp` and the doc file's own last re-stamping commit (re-stamp decided by comparing frontmatter `timestamp` values across that commit's first-parent boundary). With `--dirty-as-now`, a source with an uncommitted change is judged as of right now instead of its last commit. See "Staleness (sources-fresh)" below. |
|
|
76
80
|
| `sources-fresh-future` | warning | For the same docs as `sources-fresh`, flags a `timestamp` later than the doc file's own last commit by more than a clock-skew allowance (default 10 minutes, `--future-skew-minutes`). Catches a local wall-clock time mistakenly written with a `Z`/UTC suffix. See "Staleness (sources-fresh)" below. |
|
|
77
81
|
| `citations-resolve` | warning / notice | For docs with a repo root, flags a `` `path:N`/`path:N-M` `` citation (and its `` `:N` ``/`` -`M` ``/`` (`N`) `` continuations, and bare paragraph-bound short forms `:N-M`/`(N-M)`) whose target file is missing, whose range is inverted or exceeds the file, or whose start line is blank or (for a non-markdown target) only a closing brace. A full citation may also carry an optional `#anchor` (e.g. `` `CHANGELOG.md:50-144#0.24.0` ``), checked against the target's own structure/content instead of just its line numbers. A backtick-delimited `` `path:#heading` `` citation (`.md` targets only) resolves to a whole Markdown section instead of a line range, immune to every line-number shift above it; see "Heading-section citations" below. A short-form citation's range into a test file is also checked for a describe/it block boundary. `--require-anchors` opts into five additional checks; see "Anchor strictness (opt-in, `--require-anchors`)" below. See "Citation resolution (citations-resolve)" below. |
|
|
78
82
|
| `prose-line-references` | (opt-in, `--prose-line-references`) warning / notice | Off by default. Flags a prose-embedded line reference outside `citations-resolve`'s own backtick grammar (`line N`, `lines N-M`, `lines N to M`) that is drifted, unresolvable, or ambiguous once bound to the nearest named file. `--prose-line-references-strict` additionally flags every such reference as a formatting policy violation. See "Prose line references (opt-in, `--prose-line-references`)" below. |
|
|
@@ -107,8 +111,60 @@ Known limitation: a `git log` call that fails for a reason other than "no histor
|
|
|
107
111
|
|
|
108
112
|
Known limitation: the doc-commit comparison suppresses staleness for every source older than the doc file's last re-stamping commit, not only for sources from the same commit -- provided that commit is the one that rewrote the stamp. For a multi-source doc that means a re-stamp silences drift on every source changed before it, even ones that specific re-stamp did not itself verify. The frontmatter `timestamp` still governs sources changed after the doc's last commit. Also note: the check only looks at WHETHER the `timestamp` value changed, never at whether the new value is itself correct -- a hand-typed or deliberately backdated stamp still counts as a re-stamp (`sources-fresh-future` is the rule that catches an implausible value). "Changed" means the parsed frontmatter VALUE changed: a rewrite to the same instant in another representation (`...00Z` to `...00.000Z`) still counts as a re-stamp, since the raw string differs even though it names the same instant, while adding or removing quotes around an otherwise-unchanged value does NOT count, since YAML parsing already normalizes those away before the comparison ever sees them. And the comparison is against the FIRST parent only: a merge that takes the doc wholesale from its second parent is judged against the first-parent baseline, which is the baseline the pull request under review is measured against anyway.
|
|
109
113
|
|
|
114
|
+
**Two-branch squash interaction:** the rule follows one decision procedure, never a catalog of merge shapes, and the procedure is what to read a squash-merge scenario against, not a list of named cases:
|
|
115
|
+
|
|
116
|
+
1. **The doc's last commit.** `git log -1 -- <doc>` under git's default history simplification: a merge whose result for the doc path is identical to one of its parents is skipped, and the walk continues on that side to the real content-changing commit instead; only a merge that changed the doc against every parent is itself returned. The epoch lookup and the re-stamp check below both start from this same resolved commit.
|
|
117
|
+
2. **The epoch gate.** A source whose own last commit is at or before the resolved doc commit is judged by step 3; a source committed after the resolved doc commit skips step 3 and is judged by the frontmatter `timestamp` alone: STALE whenever the source change also postdates that stamp (the normal case, since nothing the doc showed as of its last commit could reflect a change that had not happened yet), fresh in the rare case that the stamp itself is later than the source change, because the frontmatter comparison is the first thing the rule evaluates.
|
|
118
|
+
3. **The re-stamp check (`restampedByOwnLastCommit`).** Compare the resolved commit's parsed frontmatter `timestamp` VALUE against its value in that SAME commit's first parent (rename-aware); a difference, or the doc being created there, counts as re-stamped.
|
|
119
|
+
|
|
120
|
+
One sentence for the outcome: a source reads fresh when its own last commit is at or before the doc's resolved last commit and that commit re-stamped the value, or when the source's own last commit is at or before the frontmatter `timestamp`; every other assessable case is STALE (the notice outcomes in the table above are neither fresh nor STALE).
|
|
121
|
+
|
|
122
|
+
The one consequence that follows for a branch merging a trunk carrying a squash: the squash re-dates every source it touched to the merge instant, and steps 1-3 can only ever see the MERGING branch's own resolved doc commit, never the trunk's route to that squash. So after such a merge, a clean verdict is not evidence the branch's doc was verified against the re-dated source (the known limitation above already says a re-stamp silences drift on sources it never itself checked, and step 3 only asks whether the value moved, never what it verified); a STALE verdict means the branch's resolved doc commit is older than the re-dated source, or newer but carrying no re-stamp of its own. Which of the two the rule reports depends only on where the branch's resolved doc commit falls relative to the squash (steps 1 and 2), never on who edited what:
|
|
123
|
+
|
|
124
|
+
| Branch shape | Doc commit the lookup resolves to | Verdict | Why |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| B never touched the doc | The trunk's squash commit (the merge is skipped: its doc content matches the trunk's) | Fresh for a source at/before the squash; STALE for a source B itself changes after the squash and after the stamp | The squash's own re-stamp (step 3) only covers sources the epoch gate lets reach it (step 2); a later change on B's own branch fails that gate |
|
|
127
|
+
| B carries its own older doc edit and keeps it through the merge | B's own doc-edit commit (the merge is skipped: its doc content matches B's pre-merge copy) | STALE when the edit predates the squash; fresh when it postdates the squash and changed the stamp value (the re-stamp exception); STALE when it postdates the squash but left the stamp alone | Step 3 only asks whether B's edit changed the value against its OWN first parent, never what the edit verified; an edit that lands after the squash and differs from its own prior value passes the gate and reads re-stamped regardless |
|
|
128
|
+
|
|
129
|
+
**Recipe:** after merging a trunk that carries a squash into any branch whose bundle declares the sources that squash re-dated, re-verify each such doc against its current `sources` and bump its `timestamp` in one dedicated commit, whatever `sources-fresh` currently reports for it -- the same recipe as the Authoring guidance below, just triggered by the merge. Seen in practice on a long-lived second branch after a squash-merged re-stamp landed on the trunk; see the CHANGELOG for the concrete case.
|
|
130
|
+
|
|
110
131
|
**Authoring guidance:** when you re-verify a doc against its sources, bump its frontmatter `timestamp` (and add a line to the bundle's `log.md`) so `sources-fresh` reflects that the doc is current again.
|
|
111
132
|
|
|
133
|
+
### Uncommitted edits (`--dirty-as-now`)
|
|
134
|
+
|
|
135
|
+
`sources-fresh` and `sources-fresh-future` normally judge every path by its last GIT COMMIT time, so a source or doc you have edited but not yet committed still reads by whatever it looked like at its last commit -- often still "fresh" relative to an already-stale doc `timestamp`. Once you commit, that same path gets a brand-new commit time, and CI's freshness guard (typically run in strict mode) can fail on a doc your local, pre-commit `check` run reported as clean. `--dirty-as-now` closes that gap by modeling every uncommitted change -- modified, staged, or untracked, i.e. anything `git status --porcelain --untracked-files=all` reports -- as though it landed in ONE VIRTUAL COMMIT made right now: a dirty `sources` path's epoch becomes now, and a dirty DOC's OWN epoch becomes now too, both read from the exact same shared instant so two dirty paths in one `check` run never disagree about what "now" was. Both rules read a dirty path's epoch this same way -- there is exactly one place in the code that applies the substitution, not a separate patch per rule -- so a pre-commit run reports the same verdict CI will report once the commit lands, for either rule. It has no effect on a path with no uncommitted change (judged exactly as before), and it is entirely opt-in: omit it and both rules are byte-for-byte unchanged. One consequence worth calling out: an untracked source's ordinary `untracked by git, staleness unknown` notice (see the table above) becomes a STALE warning under this flag instead, since an untracked path is itself an uncommitted change; symmetrically, an untracked DOC -- which `sources-fresh-future` otherwise leaves unassessed entirely (see that rule's table above) -- gets a real `sources-fresh-future` verdict too, since its virtual epoch is now a real "now" to compare its `timestamp` against. Both hold for a file inside a BRAND-NEW untracked directory as well, which is why the status read passes `--untracked-files=all`: git's default untracked mode reports a new directory as one single `? newdir/` record and never names the files in it, so a source or doc inside one used to be invisible to this flag (reported merely `untracked by git`, exit 0) right up until the commit that made it STALE in CI. The cost of `--untracked-files=all` is a longer status output in a work tree carrying many untracked, non-ignored files; if it ever exceeds the internal 16 MiB git-output cap, the run reports the not-applied notice below rather than pretending the tree is clean.
|
|
136
|
+
|
|
137
|
+
Three smaller behaviors worth knowing. A `sources` entry spelled `.` or `./` (the repo root itself) is dirty whenever ANY path in the work tree is dirty -- it is matched by containment, since `git status` never reports the root as an entry of its own. `--repo-root` may name a SUBDIRECTORY of the repository: `git status` reports dirty paths relative to the repository's top level, and `git show <rev>:<path>` reads a blob by a top-level-relative path too, so the rule respells every path it hands to either (via `git rev-parse --show-prefix`, read once per run) before matching a dirty path or reading a doc's committed value; dirty-path detection and both re-stamp rescues (the working-tree one here and the committed co-commit one above) then behave under a subdirectory root exactly as under the top level, and a same-named doc at the top level is never read in the subdirectory doc's place. And if git cannot be read at all (`status` failing, output past the cap, git missing), `check` emits one bundle-level `sources-fresh` notice reading "`--dirty-as-now` not applied: git status could not be read, judging by committed history only", and both rules fall back to committed history; the flag never reports a silent all-clear it did not actually verify.
|
|
138
|
+
|
|
139
|
+
The flag also carries a working-tree analogue of the doc-commit re-stamp rescue described above, evaluated against that same virtual commit: a doc re-stamped LOCALLY (its on-disk frontmatter `timestamp` value differs from the value committed at `HEAD` -- a change in EITHER direction, including a backwards move, counts -- and the doc file itself is dirty; an untracked doc counts as re-stamped too, the working-tree equivalent of "the doc being created there") rescues a dirty source exactly like a real re-stamp landing in the same commit does. Without this, bumping a doc's `timestamp` locally and re-running `check --dirty-as-now` could still report STALE, purely because a few seconds pass between writing the new timestamp and running the check -- defeating the point of the recommended invocation below. A doc that is dirty for some OTHER reason (a body edit that leaves the `timestamp` value unchanged) is not rescued: that case still reports STALE, same as before. Reading the doc's committed value distinguishes a genuinely untracked doc (no entry for it at `HEAD` at all -- always a re-stamp) from a real git failure reading an EXISTING `HEAD` blob (a corrupt object, an unreadable blob): only the former is treated as "created"; the latter falls through to the ordinary `staleness not assessable` notice instead of being silently guessed either way.
|
|
140
|
+
|
|
141
|
+
**Recommended pre-commit invocation**, matching the "re-verify, bump `timestamp`, then commit" discipline above -- run this on the working tree BEFORE committing an edit to any file a bundle lists as a `sources` entry, so a doc that needs re-stamping is caught before the commit that would otherwise make it stale in CI:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
okf-kit check path/to/bundle --dirty-as-now --strict
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
If it reports a doc STALE, re-verify that doc against its current `sources` and bump its `timestamp` in the same commit as the source edit (or its own dedicated commit), THEN commit -- exactly the measure-after-commit discipline described above, just checked before the commit exists rather than after CI runs.
|
|
148
|
+
|
|
149
|
+
**What this actually produces for the recipe above, reproduced through the built CLI (source committed, doc committed with a matching `timestamp`, then):**
|
|
150
|
+
|
|
151
|
+
| Working-tree state | `check --dirty-as-now --strict` |
|
|
152
|
+
|---|---|
|
|
153
|
+
| Source edited, doc re-stamped on disk to now (a few seconds to a minute after writing the stamp) | exit 0, clean -- neither `sources-fresh` nor `sources-fresh-future` fires |
|
|
154
|
+
| Source edited, doc left alone (not re-stamped) | exit 1, `sources-fresh` STALE |
|
|
155
|
+
| Source edit and doc re-stamp committed TOGETHER, flag OFF | exit 0, clean (the committed-history co-commit rescue, unaffected by this flag) |
|
|
156
|
+
| Doc dirty for an unrelated reason (a body edit, `timestamp` value unchanged), source edited | exit 1, `sources-fresh` STALE -- not rescued |
|
|
157
|
+
| Doc re-stamped on disk to a value BEFORE the one committed at `HEAD` (a backwards move), source edited | exit 0, clean -- still counts as a re-stamp (see above) |
|
|
158
|
+
| Source edit committed ALONE, the doc's re-stamp left uncommitted in the working tree | exit 0, clean locally -- but CI is RED (`sources-fresh` STALE) until that re-stamp is committed too |
|
|
159
|
+
|
|
160
|
+
That last row is the one shape where a clean local run does NOT imply a clean CI run, and it is inherent to the model rather than a gap to be fixed: the flag judges the content in YOUR WORKING TREE, while CI judges only what you actually pushed. Commit the source edit without its doc re-stamp and CI sees a source newer than the doc's committed `timestamp`, exactly as it should. The remedy is the one this section already recommends: commit the re-stamp, in the same commit as the source edit or its own.
|
|
161
|
+
|
|
162
|
+
What "matches CI" actually means here: `--dirty-as-now` makes a local run compute the same `sources-fresh`/`sources-fresh-future` VERDICT (fresh, STALE, or not-assessable) that a post-commit `check` run would compute for the same content -- it says nothing about whether a given CI setup turns that verdict into a failed build, and nothing about warning classes outside these two rules. Whether it does depends entirely on how that CI wires up `okf-kit check`: this package's own CI runs it two different ways for the same bundle -- `.github/workflows/okf-staleness.yml` calls `check` warn-only (findings surface in the job summary and as annotations, but the job never fails on them), while `.github/workflows/ci.yml`'s freshness guard step runs `check --require-anchors` and then filters the JSON report through `jq` for `sources-fresh`/`sources-fresh-future` findings, only failing the build on THOSE. `--strict` is broader than either: it fails on every warning-severity finding from EVERY rule (including ones this flag says nothing about, like `citations-resolve`), so a locally-strict, CI-clean bundle is not a contradiction -- it means the CI in question does not block on every warning class `--strict` does. Read the target repo's actual CI wiring before treating `--dirty-as-now --strict` as equivalent to "will this pass CI".
|
|
163
|
+
|
|
164
|
+
`--dirty-as-now` ships in the same `okf-kit` release as everything else in this CHANGELOG entry; a CI step that installs a PINNED `okf-kit` version (as both workflows above do) only gains the flag once that pin is bumped to a release that includes it.
|
|
165
|
+
|
|
166
|
+
**Known limitations, stated rather than hidden.** Ignored files (`.gitignore`) are deliberately NOT treated as dirty here (`git status` is run without `--ignored`): an ignored source keeps its ordinary `untracked by git, staleness unknown` notice rather than becoming newly dirty under this flag. A source living inside a dirty SUBMODULE is likewise not detected as dirty: `git status` reports a submodule with uncommitted changes as one single record for the submodule's own path, not per file inside it, and this flag's path-matching does not currently descend into that report to find the individual dirty files a `sources` entry might name.
|
|
167
|
+
|
|
112
168
|
### Future-dated timestamps (`sources-fresh-future`)
|
|
113
169
|
|
|
114
170
|
`sources-fresh` catches a `timestamp` that is too OLD relative to a source's last commit. `sources-fresh-future` catches the opposite mistake: a `timestamp` that is too NEW relative to the doc file's OWN last commit -- in practice, almost always a local wall-clock time hand-written with a trailing `Z` (or another UTC marker) it does not actually have, rather than a genuine future date. It never looks at `sources` commit times at all, only at the doc file's own git history, so it has nothing to say about whether any source is stale; the two rules are complementary, not overlapping, and are assessed over the same population of docs (a validly-shaped `sources` list and a repo root available, exactly like `sources-fresh` above).
|
|
@@ -118,7 +174,7 @@ Known limitation: the doc-commit comparison suppresses staleness for every sourc
|
|
|
118
174
|
| The doc's `timestamp` is later than the doc file's own last commit by more than the skew allowance | warning | `FUTURE-DATED: doc timestamp <iso> is after the doc's own last commit <iso> (skew allowance <n>s)` |
|
|
119
175
|
| The doc's `timestamp` is at or within the skew allowance of the doc file's own last commit | (nothing) | fresh: an ordinary write-then-commit gap, not a mistake |
|
|
120
176
|
| The doc's `timestamp` string has no `Z`/UTC designator or numeric offset (e.g. `2026-01-01T00:00:00`, no offset) | notice | future-dated check skipped: timestamp has no UTC designator (`Z`) or numeric offset, can't be compared reliably across timezones |
|
|
121
|
-
| The doc has no git history yet (uncommitted) | (nothing) | unknown, not flagged: there is no real commit time to compare against |
|
|
177
|
+
| The doc has no git history yet (uncommitted) | (nothing) | unknown, not flagged: there is no real commit time to compare against -- UNLESS `--dirty-as-now` is passed, in which case a dirty (including untracked) doc gets a real verdict against the shared virtual-commit "now" instant instead (see "Uncommitted edits" below) |
|
|
122
178
|
| The doc's `timestamp` is missing or not a parseable date | (nothing) | left to `sources-fresh`'s own notice, not duplicated here |
|
|
123
179
|
| No repo root available (see auto-detection above) | (nothing) | left to `sources-fresh`'s single bundle-level notice, not duplicated here |
|
|
124
180
|
|
|
@@ -180,6 +236,8 @@ Anchors are checked only once the base checks above (blank-start-line, closing-b
|
|
|
180
236
|
|
|
181
237
|
**Continuation citations.** Once a sentence states a full `path:N` citation, prose commonly repeats just the line (or range) for a later reference in the same sentence: `` `:N` ``/`` `:N-M` `` (bare colon-prefixed), `` -`M` ``/`` –`M` `` (hyphen- or en-dash-led, the tail of a split range like `` `path:N`-`M` ``), or `` (`N`) `` (parenthesized). Each resolves against the nearest preceding citation in the same doc that resolved to a real file; a continuation right after an unresolved, ambiguous, or out-of-scope citation is silently skipped, not misattributed to an earlier, unrelated file. A heading-section citation (see above) carries no line number and is never a continuation's target: it never sets or clears which citation a later continuation resolves against.
|
|
182
238
|
|
|
239
|
+
**Anchored path-less continuation form: not recognised (bundle-local).** The `orchestrator-workflow` package's own dogfood bundle writes a backtick-wrapped, path-less continuation with a content anchor, e.g. `` `:913-923#"..."` ``, distinct from the two forms above. `CONT_COLON_RE` needs its closing backtick immediately after the digit range, so a trailing `#"anchor"` before the backtick never matches it; `SHORT_FORM_COLON_RE` excludes any match immediately preceded by a backtick and otherwise requires a serial-connective prefix, neither of which this form carries. So this rule sees the form as nothing at all, not merely as unresolved. Recognising it (an opt-in rule, or folding it into this one) would move the cost to okf-kit's maintainers: the rule itself, an allowlist/anchor-geometry contract as public API, and a fleet-wide pin bump on every fix. Declaring it bundle-local instead leaves the cost where it already sits: only the `orchestrator-workflow` package's own `test/docs-consistency.test.ts` guard checks the form, and every other fleet bundle that might someday write it stays unguarded until it grows the same check by hand. Port trigger, restated from the orchestrator-workflow CHANGELOG's "Citation-sibling-drift guard, okf-kit-porting decision" entry: a second fleet bundle observed carrying real sibling-citation drift in a review pass (not merely plausible in the abstract) reopens the port decision. A fleet count at the time of this decision found the live form only in that one bundle (`docs/okf/model-preselection.md`, 4 occurrences); other apparent hits were historical prose in a `log.md` narrating a re-point, not live citations.
|
|
240
|
+
|
|
183
241
|
**Short-form citations.** Distinct from a continuation above: a *bare* (no backtick, no file name at all) colon-range `:N-M`, e.g. `:580-588` in running prose. A short-form citation binds to **the last full `path:N-M` citation named earlier in the same paragraph** -- not the nearest preceding citation anywhere in the doc (that is what a continuation does); a paragraph boundary is a blank (empty or whitespace-only) line. A short-form citation with no full citation earlier in its own paragraph is reported `short-form-unbound`, not silently skipped. Only a range is recognised, never a bare single number (`:5`): a bare number is too easily an unrelated enumeration marker (e.g. a numbered list item) to detect mechanically without a large false-positive cost. A resolved short-form citation gets every check a full citation gets, plus the test-file/Markdown block-boundary check above (`test-range-*` / `markdown-range-boundary-bracket-or-fence`).
|
|
184
242
|
|
|
185
243
|
**Serial-connective gate, and why the paren form is not collected at all.** Three earlier rounds each tried to separate a real short-form citation from ordinary prose that merely contains an N-M-shaped number pair ("the window (2026-2027)", "follow steps (2-4)", "three engineers (1-3)") by deciding from the range's *values*: an inverted-pair check, a span cap plus a year/well-known-port plausibility gate, then a containment-or-adjacency check against the paragraph's last full citation. All three were eventually defeated by the same class of false positive, because every real paren-form citation this rule was ever built against has the identical shape `<English word> (N-M)` as ordinary prose -- there is no lexical signal that tells them apart. The bare parenthesized form `(N-M)` is therefore not collected as a short-form citation candidate at all; measured against this repo's own dogfood bundle, dropping it changed nothing (39 findings / 17 warnings / 22 notices, identical with and without it).
|
|
@@ -262,7 +320,7 @@ This is advisory: don't fail the build on warnings unless you pass `--strict`. U
|
|
|
262
320
|
with:
|
|
263
321
|
fetch-depth: 0
|
|
264
322
|
- name: OKF bundle check
|
|
265
|
-
run: npx okf-kit@0.
|
|
323
|
+
run: npx okf-kit@0.12.0 check path/to/bundle
|
|
266
324
|
```
|
|
267
325
|
|
|
268
326
|
Pin the version: an unpinned `npx okf-kit` picks up new rules on their release day, which turns an unrelated PR red.
|
package/dist/cli.d.ts
CHANGED
|
@@ -40,6 +40,18 @@ export interface CheckOptions {
|
|
|
40
40
|
* `ctx.freshnessFutureSkewSeconds`.
|
|
41
41
|
*/
|
|
42
42
|
futureSkewMinutes?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Opt-in for `sources-fresh` AND `sources-fresh-future`: model every
|
|
45
|
+
* uncommitted change (modified, staged, or untracked) as though it
|
|
46
|
+
* landed in ONE virtual commit made right now, instead of at its last
|
|
47
|
+
* real commit. Both a dirty `sources` path and a dirty DOC read their
|
|
48
|
+
* commit time from that same shared instant, so a pre-commit run reports
|
|
49
|
+
* the verdict CI will report once the commit lands -- for either rule.
|
|
50
|
+
* Stored on `ctx.dirtyAsNow`; see its jsdoc in `src/types.ts` (the
|
|
51
|
+
* canonical description of the model) and the README's "Uncommitted
|
|
52
|
+
* edits (`--dirty-as-now`)" section.
|
|
53
|
+
*/
|
|
54
|
+
dirtyAsNow?: boolean;
|
|
43
55
|
/** Test-only override for git access; production code shells out to the real `git` binary. */
|
|
44
56
|
runGit?: RunGit;
|
|
45
57
|
}
|
package/dist/cli.js
CHANGED
|
@@ -36,6 +36,9 @@ export function runCheck(bundleDir, options = {}) {
|
|
|
36
36
|
if (options.futureSkewMinutes !== undefined) {
|
|
37
37
|
ctx.freshnessFutureSkewSeconds = Math.round(options.futureSkewMinutes * 60);
|
|
38
38
|
}
|
|
39
|
+
if (options.dirtyAsNow) {
|
|
40
|
+
ctx.dirtyAsNow = true;
|
|
41
|
+
}
|
|
39
42
|
const findings = allRules.flatMap((rule) => rule.run(ctx));
|
|
40
43
|
const summary = summarize(findings);
|
|
41
44
|
const exitCode = summary.errors > 0 || (Boolean(options.strict) && summary.warnings > 0)
|
|
@@ -72,6 +75,9 @@ program
|
|
|
72
75
|
"the remedy to lift it into a backtick citation or a symbol name (ignored unless --prose-line-references is also passed)")
|
|
73
76
|
.option("--future-skew-minutes <n>", "sources-fresh-future: clock-skew allowance in minutes before a doc `timestamp` later than " +
|
|
74
77
|
"the doc's own last commit is flagged as future-dated (default 10)")
|
|
78
|
+
.option("--dirty-as-now", "sources-fresh + sources-fresh-future: model every uncommitted change (modified, staged, or " +
|
|
79
|
+
"untracked) -- a `sources` path and the doc itself alike -- as one virtual commit made right " +
|
|
80
|
+
"now, so a pre-commit run matches what CI reports after the commit lands (opt-in, see README)")
|
|
75
81
|
.exitOverride()
|
|
76
82
|
.action((bundleDir, opts) => {
|
|
77
83
|
try {
|
|
@@ -95,6 +101,7 @@ program
|
|
|
95
101
|
proseLineReferences: opts.proseLineReferences,
|
|
96
102
|
proseLineReferencesStrict: opts.proseLineReferencesStrict,
|
|
97
103
|
futureSkewMinutes,
|
|
104
|
+
dirtyAsNow: opts.dirtyAsNow,
|
|
98
105
|
});
|
|
99
106
|
const output = opts.json
|
|
100
107
|
? renderJson(result.bundleDir, result.findings)
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,CAAC;AA8DtB,MAAM,UAAU,QAAQ,CACtB,SAAiB,EACjB,UAAwB,EAAE;IAE1B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACvE,MAAM,IAAI,UAAU,CAAC,oCAAoC,SAAS,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,0EAA0E;IAC1E,0EAA0E;IAC1E,0EAA0E;IAC1E,qEAAqE;IACrE,oEAAoE;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ;QAC/B,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;QAChC,CAAC,CAAC,cAAc,CAAC,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,UAAU,CAAC,iBAAiB,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,GAAG,CAAC,cAAc,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,mBAAmB,IAAI,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;QAChC,GAAG,CAAC,mBAAmB,GAAG;YACxB,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC;SACnD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC5C,GAAG,CAAC,0BAA0B,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,QAAQ,GACZ,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,CAAC,CAAC;IACR,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,2EAA2E;AAC3E,uEAAuE;AACvE,2EAA2E;AAC3E,sEAAsE;AACtE,2EAA2E;AAC3E,8BAA8B;AAC9B,OAAO,CAAC,YAAY,EAAE,CAAC;AAEvB,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,qCAAqC,CAAC;KAClD,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;AAE1B,OAAO;KACJ,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CACL,wBAAwB,EACxB,2FAA2F;IACzF,sFAAsF,CACzF;KACA,MAAM,CAAC,YAAY,EAAE,yBAAyB,CAAC;KAC/C,MAAM,CAAC,cAAc,EAAE,8CAA8C,CAAC;KACtE,MAAM,CACL,mBAAmB,EACnB,4FAA4F;IAC1F,mFAAmF,CACtF;KACA,MAAM,CACL,uCAAuC,EACvC,gFAAgF;IAC9E,0CAA0C,CAC7C;KACA,MAAM,CACL,yBAAyB,EACzB,wFAAwF;IACtF,wGAAwG,CAC3G;KACA,MAAM,CACL,gCAAgC,EAChC,4FAA4F;IAC1F,yHAAyH,CAC5H;KACA,MAAM,CACL,2BAA2B,EAC3B,4FAA4F;IAC1F,mEAAmE,CACtE;KACA,MAAM,CACL,gBAAgB,EAChB,6FAA6F;IAC3F,8FAA8F;IAC9F,8FAA8F,CACjG;KACA,YAAY,EAAE;KACd,MAAM,CACL,CACE,SAAiB,EACjB,IAUC,EACD,EAAE;IACF,IAAI,CAAC;QACH,IAAI,iBAAqC,CAAC;QAC1C,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAC9C,iEAAiE;YACjE,8DAA8D;YAC9D,gEAAgE;YAChE,MAAM,CAAC,GAAG,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,UAAU,CAClB,8DAA8D,IAAI,CAAC,iBAAiB,IAAI,CACzF,CAAC;YACJ,CAAC;YACD,iBAAiB,GAAG,CAAC,CAAC;QACxB,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE;YACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,yBAAyB,EAAE,IAAI,CAAC,yBAAyB;YACzD,iBAAiB;YACjB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI;YACtB,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC;YAC/C,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CACF,CAAC;AAEJ,OAAO;KACJ,OAAO,CAAC,YAAY,CAAC;KACrB,WAAW,CACV,yEAAyE,CAC1E;KACA,MAAM,CACL,aAAa,EACb,oGAAoG,CACrG;KACA,YAAY,EAAE;KACd,MAAM,CAAC,CAAC,GAAuB,EAAE,IAAyB,EAAE,EAAE;IAC7D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,0EAA0E;AAC1E,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,0EAA0E;AAC1E,2EAA2E;AAC3E,+BAA+B;AAC/B,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,yBAAyB;IACzB,mBAAmB;CACpB,CAAC,CAAC;AAEH,2EAA2E;AAC3E,4EAA4E;AAC5E,uEAAuE;AACvE,wEAAwE;AACxE,qBAAqB;AACrB,wEAAwE;AACxE,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;IAC7B,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAEvD,IAAI,YAAY,EAAE,CAAC;IACjB,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;YAClC,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC;YACD,iEAAiE;YACjE,qEAAqE;YACrE,uEAAuE;YACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CACjE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAyB,CAAC;QACrD,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"}
|
|
@@ -29,9 +29,16 @@ export declare const sourcesFreshRule: Rule;
|
|
|
29
29
|
* rather than duplicating it) and no valid `timestamp` (`sources-fresh`
|
|
30
30
|
* already reports that per-doc notice, so this rule silently skips such a
|
|
31
31
|
* doc rather than reporting it twice). An uncommitted doc (no own commit
|
|
32
|
-
* yet) is likewise "unknown, not flagged": there is no real
|
|
33
|
-
* compare the timestamp against, and flagging every
|
|
34
|
-
* not-yet-committed doc as "future-dated" would be a false
|
|
35
|
-
* every fresh draft.
|
|
32
|
+
* yet) is likewise "unknown, not flagged" by DEFAULT: there is no real
|
|
33
|
+
* commit time to compare the timestamp against, and flagging every
|
|
34
|
+
* hand-authored, not-yet-committed doc as "future-dated" would be a false
|
|
35
|
+
* positive on every fresh draft. Under `--dirty-as-now` (`ctx.dirtyAsNow`),
|
|
36
|
+
* this changes: `getDocCommitEpochShared` below substitutes the shared
|
|
37
|
+
* virtual-commit "now" instant for ANY dirty doc's epoch (untracked
|
|
38
|
+
* included -- see `commitEpochWithDirtyAsNow`), so a dirty doc DOES get a
|
|
39
|
+
* real comparison here, exactly the working-tree parity `--dirty-as-now`
|
|
40
|
+
* exists for: a `timestamp` re-stamped to "now" reads fresh (within the
|
|
41
|
+
* skew allowance), while one still carrying an implausible future value
|
|
42
|
+
* gets caught before the commit that would otherwise make it so in CI.
|
|
36
43
|
*/
|
|
37
44
|
export declare const sourcesFreshFutureRule: Rule;
|
|
@@ -39,17 +39,39 @@ export const sourcesFreshRule = {
|
|
|
39
39
|
}
|
|
40
40
|
const repoRoot = ctx.repoRoot;
|
|
41
41
|
const git = ctx.runGit ?? defaultRunGit;
|
|
42
|
+
// `--dirty-as-now` asked for, but git could not tell us what is dirty
|
|
43
|
+
// (a `status` past RunGit's output cap, a `rev-parse` failure, git
|
|
44
|
+
// missing): every path below then falls through to committed history,
|
|
45
|
+
// which is the RIGHT fallback but the WRONG silence -- "the flag found
|
|
46
|
+
// nothing dirty" and "the flag never ran" produce the identical empty
|
|
47
|
+
// finding list. Say so once, bundle-level, in the same style as the
|
|
48
|
+
// "not inside a git work tree" notice above (and, like that one,
|
|
49
|
+
// emitted only here: `sources-fresh-future` shares the same degraded
|
|
50
|
+
// state and relies on this single notice instead of duplicating it).
|
|
51
|
+
if (ctx.dirtyAsNow && getDirtyStateShared(ctx, git, repoRoot) === null) {
|
|
52
|
+
findings.push({
|
|
53
|
+
ruleId: RULE_ID,
|
|
54
|
+
severity: "notice",
|
|
55
|
+
file: "",
|
|
56
|
+
message: "`--dirty-as-now` not applied: git status could not be read, judging by committed history only",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
42
59
|
// One git call per unique source path across all docs, even though a
|
|
43
60
|
// STALE/untracked finding is reported per (doc, path) below.
|
|
44
61
|
const commitEpochCache = new Map();
|
|
45
|
-
|
|
62
|
+
// `--dirty-as-now`: every dirty path's "commit epoch" is the SAME
|
|
63
|
+
// virtual-commit instant, shared (by `ctx` identity) with
|
|
64
|
+
// `sources-fresh-future`'s doc-epoch lookup below -- see
|
|
65
|
+
// `commitEpochWithDirtyAsNow`'s doc comment for why this lives in one
|
|
66
|
+
// place instead of being reimplemented per rule.
|
|
67
|
+
const commitEpochFor = (source) => commitEpochWithDirtyAsNow(ctx, git, repoRoot, source, () => {
|
|
46
68
|
const cached = commitEpochCache.get(source);
|
|
47
69
|
if (cached !== undefined)
|
|
48
70
|
return cached;
|
|
49
71
|
const epoch = getLastCommitEpoch(git, repoRoot, source);
|
|
50
72
|
commitEpochCache.set(source, epoch);
|
|
51
73
|
return epoch;
|
|
52
|
-
};
|
|
74
|
+
});
|
|
53
75
|
for (const { doc, sources } of docsWithSources) {
|
|
54
76
|
const timestampEpoch = getTimestampEpoch(doc.frontmatter.parsed);
|
|
55
77
|
if (timestampEpoch === undefined) {
|
|
@@ -72,23 +94,47 @@ export const sourcesFreshRule = {
|
|
|
72
94
|
// rules don't each spawn their own `git log` for the same doc in one
|
|
73
95
|
// `check` run.
|
|
74
96
|
//
|
|
75
|
-
// GIT PROCESS BUDGET
|
|
76
|
-
// `git log -1 --format=%ct` epoch lookup
|
|
77
|
-
// the re-stamp path (`git log -1 --format=%H%n%P`,
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
97
|
+
// GIT PROCESS BUDGET per doc per `check` run, `--dirty-as-now` OFF: 1
|
|
98
|
+
// (the shared `git log -1 --format=%ct` epoch lookup) + at most 4 on
|
|
99
|
+
// the re-stamp path (`git log -1 --format=%H%n%P`, `git diff-tree`,
|
|
100
|
+
// two `git show`s), i.e. AT MOST 5 regardless of how many sources the
|
|
101
|
+
// doc declares, since both lookups are memoized per doc. Plus one `git
|
|
102
|
+
// log` per UNIQUE source path across the bundle (commitEpochCache),
|
|
103
|
+
// and, per RUN rather than per doc, at most one `git rev-parse
|
|
104
|
+
// --show-prefix` (getShowPrefixShared, spent the first time any
|
|
105
|
+
// re-stamp lookup needs the top-level path frame) and at most one
|
|
106
|
+
// `git rev-parse --is-shallow-repository` (isShallowRepoShared).
|
|
107
|
+
// Pinned by "spends at most five git processes per doc" in
|
|
108
|
+
// test/sources-fresh.test.ts.
|
|
109
|
+
//
|
|
110
|
+
// With `--dirty-as-now` ON, add one `git status` per run (the
|
|
111
|
+
// show-prefix read above is shared with it, see readDirtyState) plus,
|
|
112
|
+
// PER DOC, at most one `git ls-tree` and one `git show`, spent only
|
|
113
|
+
// when that doc is itself dirty AND some source of its reads stale.
|
|
88
114
|
const repoRelDocPath = toRepoRelDocPath(repoRoot, ctx.bundleDir, doc);
|
|
89
115
|
const docCommitEpochFor = () => getDocCommitEpochShared(ctx, git, repoRoot, repoRelDocPath);
|
|
116
|
+
const showPrefixFor = () => getShowPrefixShared(ctx, git, repoRoot);
|
|
117
|
+
// The single decision point for "did the doc's last commit, real or
|
|
118
|
+
// virtual, actually re-stamp it". A dirty doc (under `--dirty-as-now`)
|
|
119
|
+
// is judged by its WORKING-TREE value against the value committed at
|
|
120
|
+
// HEAD, the virtual commit's implicit first parent
|
|
121
|
+
// (`dirtyDocRestampVerdict`); any other doc is judged against its real
|
|
122
|
+
// last commit's first parent (`restampedByOwnLastCommit`). Because
|
|
123
|
+
// `docCommitEpochFor` already reports a dirty doc's epoch as "now"
|
|
124
|
+
// (`commitEpochWithDirtyAsNow`), the ordinary `docCommitEpoch >=
|
|
125
|
+
// commitEpoch` gate below fires for a dirty doc exactly as for a real
|
|
126
|
+
// co-commit, so ONE verdict function is picked here rather than two
|
|
127
|
+
// mechanisms answering overlapping questions.
|
|
90
128
|
let restampMemo;
|
|
91
|
-
const restampFor = () =>
|
|
129
|
+
const restampFor = () => {
|
|
130
|
+
if (restampMemo !== undefined)
|
|
131
|
+
return restampMemo;
|
|
132
|
+
restampMemo =
|
|
133
|
+
ctx.dirtyAsNow && isDirtyForShared(ctx, git, repoRoot, repoRelDocPath)
|
|
134
|
+
? dirtyDocRestampVerdict(git, repoRoot, repoRelDocPath, getTimestampIdentity(doc.frontmatter.parsed), showPrefixFor)
|
|
135
|
+
: restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, () => isShallowRepoShared(ctx, git, repoRoot), showPrefixFor);
|
|
136
|
+
return restampMemo;
|
|
137
|
+
};
|
|
92
138
|
// At most one "not assessable" notice per doc, however many of its
|
|
93
139
|
// sources hit the unanswerable re-stamp question.
|
|
94
140
|
let notAssessableReported = false;
|
|
@@ -108,14 +154,16 @@ export const sourcesFreshRule = {
|
|
|
108
154
|
continue;
|
|
109
155
|
}
|
|
110
156
|
let isStale = commitEpoch > timestampEpoch;
|
|
111
|
-
// Doc committed at/after the source, AND that commit actually
|
|
112
|
-
// re-stamped it: not stale (see comment above). A doc without git
|
|
113
|
-
// history (null epoch, e.g. uncommitted) keeps the frontmatter-only
|
|
114
|
-
// comparison. When git cannot answer the re-stamp question at all,
|
|
115
|
-
// the doc is reported as not assessable rather than being guessed
|
|
116
|
-
// either way: calling it STALE would turn a git hiccup into a red
|
|
117
|
-
// build, and calling it fresh would be a silent pass.
|
|
118
157
|
if (isStale) {
|
|
158
|
+
// Doc committed (or, under `--dirty-as-now`, virtually committed
|
|
159
|
+
// right now) at/after the source, AND that commit actually
|
|
160
|
+
// re-stamped it: not stale (see comment above). A doc without git
|
|
161
|
+
// history (null epoch, e.g. uncommitted and clean, no dirty
|
|
162
|
+
// status at all) keeps the frontmatter-only comparison. When git
|
|
163
|
+
// cannot answer the re-stamp question at all, the doc is reported
|
|
164
|
+
// as not assessable rather than being guessed either way: calling
|
|
165
|
+
// it STALE would turn a git hiccup into a red build, and calling
|
|
166
|
+
// it fresh would be a silent pass.
|
|
119
167
|
const docCommitEpoch = docCommitEpochFor();
|
|
120
168
|
if (docCommitEpoch !== null && docCommitEpoch >= commitEpoch) {
|
|
121
169
|
const verdict = restampFor();
|
|
@@ -173,10 +221,17 @@ export const sourcesFreshRule = {
|
|
|
173
221
|
* rather than duplicating it) and no valid `timestamp` (`sources-fresh`
|
|
174
222
|
* already reports that per-doc notice, so this rule silently skips such a
|
|
175
223
|
* doc rather than reporting it twice). An uncommitted doc (no own commit
|
|
176
|
-
* yet) is likewise "unknown, not flagged": there is no real
|
|
177
|
-
* compare the timestamp against, and flagging every
|
|
178
|
-
* not-yet-committed doc as "future-dated" would be a false
|
|
179
|
-
* every fresh draft.
|
|
224
|
+
* yet) is likewise "unknown, not flagged" by DEFAULT: there is no real
|
|
225
|
+
* commit time to compare the timestamp against, and flagging every
|
|
226
|
+
* hand-authored, not-yet-committed doc as "future-dated" would be a false
|
|
227
|
+
* positive on every fresh draft. Under `--dirty-as-now` (`ctx.dirtyAsNow`),
|
|
228
|
+
* this changes: `getDocCommitEpochShared` below substitutes the shared
|
|
229
|
+
* virtual-commit "now" instant for ANY dirty doc's epoch (untracked
|
|
230
|
+
* included -- see `commitEpochWithDirtyAsNow`), so a dirty doc DOES get a
|
|
231
|
+
* real comparison here, exactly the working-tree parity `--dirty-as-now`
|
|
232
|
+
* exists for: a `timestamp` re-stamped to "now" reads fresh (within the
|
|
233
|
+
* skew allowance), while one still carrying an implausible future value
|
|
234
|
+
* gets caught before the commit that would otherwise make it so in CI.
|
|
180
235
|
*/
|
|
181
236
|
export const sourcesFreshFutureRule = {
|
|
182
237
|
id: FUTURE_RULE_ID,
|
|
@@ -267,33 +322,333 @@ function getLastCommitEpoch(git, repoRoot, source) {
|
|
|
267
322
|
const epoch = Number.parseInt(out, 10);
|
|
268
323
|
return Number.isNaN(epoch) ? null : epoch;
|
|
269
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* The full SET of top-level-relative paths `git status` reports as dirty
|
|
327
|
+
* (modified, staged, or untracked) across the WHOLE work tree, read via a
|
|
328
|
+
* SINGLE `status` process per `check` run (never per source or per doc).
|
|
329
|
+
* Used only behind `--dirty-as-now`: a dirty path has no "last commit" yet
|
|
330
|
+
* that reflects its current content, so `sources-fresh` substitutes the
|
|
331
|
+
* current time for it instead of `getLastCommitEpoch`'s necessarily stale
|
|
332
|
+
* answer.
|
|
333
|
+
*
|
|
334
|
+
* `--no-optional-locks`: a read-only check (often a hook or CI step) must
|
|
335
|
+
* not rewrite the index as a side effect. No `--ignored`: an ignored
|
|
336
|
+
* source keeps its "untracked by git, staleness unknown" notice.
|
|
337
|
+
*
|
|
338
|
+
* `--untracked-files=all` is load-bearing. Under git's default untracked
|
|
339
|
+
* mode a brand-new directory collapses into ONE `? newdir/` record and the
|
|
340
|
+
* files inside it are never listed, while the matcher (`isDirtyForShared`)
|
|
341
|
+
* matches a queried path that IS an entry or is an ANCESTOR of one -- so a
|
|
342
|
+
* source or doc INSIDE a new directory matched nothing and silently kept
|
|
343
|
+
* its committed-history verdict, the local/CI divergence this flag exists
|
|
344
|
+
* to remove. The cost is one record per untracked file; a status past
|
|
345
|
+
* RunGit's 16 MiB cap resolves to null like any other git failure and is
|
|
346
|
+
* reported, never treated as "nothing is dirty".
|
|
347
|
+
*
|
|
348
|
+
* `--porcelain=v2 -z` rather than v1: RunGit `.trim()`s every output, and a
|
|
349
|
+
* v1 line for an unstaged-only change starts with a LITERAL SPACE (` M
|
|
350
|
+
* path`), so as the first line its leading field byte would be eaten and
|
|
351
|
+
* the path mis-cut. Every v2 record starts with a non-whitespace kind
|
|
352
|
+
* byte, and NUL delimiting keeps a path with a space, tab or non-ASCII
|
|
353
|
+
* byte intact. Record shapes (fixed fields are read positionally, never
|
|
354
|
+
* re-split by content): `? path`; `1 XY sub mH mI mW hH hI path` (8 fixed
|
|
355
|
+
* fields); `2 XY sub mH mI mW hH hI score path\0origPath` (9 fixed fields,
|
|
356
|
+
* origPath is the FOLLOWING token; both sides of a rename count as dirty);
|
|
357
|
+
* `u XY sub m1 m2 m3 mW h1 h2 h3 path` (10 fixed fields).
|
|
358
|
+
*
|
|
359
|
+
* A failed git call (either one) makes the WHOLE state null: every path
|
|
360
|
+
* then keeps its ordinary commit-epoch verdict, and the rule surfaces that
|
|
361
|
+
* once as the bundle-level "`--dirty-as-now` not applied" notice, since
|
|
362
|
+
* "the flag silently did nothing" and "nothing was dirty" are otherwise
|
|
363
|
+
* indistinguishable to a reader of an empty finding list.
|
|
364
|
+
*/
|
|
365
|
+
function readDirtyState(ctx, git, repoRoot) {
|
|
366
|
+
const prefix = getShowPrefixShared(ctx, git, repoRoot);
|
|
367
|
+
if (prefix === null)
|
|
368
|
+
return null;
|
|
369
|
+
const out = git([
|
|
370
|
+
"--no-optional-locks",
|
|
371
|
+
"status",
|
|
372
|
+
"--porcelain=v2",
|
|
373
|
+
"-z",
|
|
374
|
+
"--untracked-files=all",
|
|
375
|
+
], repoRoot);
|
|
376
|
+
if (out === null)
|
|
377
|
+
return null;
|
|
378
|
+
const paths = new Set();
|
|
379
|
+
// `-z` NUL-terminates every record, including the last -- RunGit's
|
|
380
|
+
// `.trim()` does not strip NUL, so splitting always leaves one empty
|
|
381
|
+
// trailing token.
|
|
382
|
+
const tokens = out.split("\0").filter((t) => t !== "");
|
|
383
|
+
let i = 0;
|
|
384
|
+
while (i < tokens.length) {
|
|
385
|
+
const token = tokens[i];
|
|
386
|
+
const kind = token[0];
|
|
387
|
+
if (kind === "?") {
|
|
388
|
+
paths.add(normalizeRelPath(token.slice(2)));
|
|
389
|
+
i += 1;
|
|
390
|
+
}
|
|
391
|
+
else if (kind === "1") {
|
|
392
|
+
paths.add(normalizeRelPath(token.split(" ").slice(8).join(" ")));
|
|
393
|
+
i += 1;
|
|
394
|
+
}
|
|
395
|
+
else if (kind === "2") {
|
|
396
|
+
paths.add(normalizeRelPath(token.split(" ").slice(9).join(" ")));
|
|
397
|
+
const origPath = tokens[i + 1];
|
|
398
|
+
if (origPath !== undefined)
|
|
399
|
+
paths.add(normalizeRelPath(origPath));
|
|
400
|
+
i += 2;
|
|
401
|
+
}
|
|
402
|
+
else if (kind === "u") {
|
|
403
|
+
paths.add(normalizeRelPath(token.split(" ").slice(10).join(" ")));
|
|
404
|
+
i += 1;
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// An unrecognized record kind (should not occur without --ignored,
|
|
408
|
+
// which is never passed): skip rather than mis-parse it as a path.
|
|
409
|
+
i += 1;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return { prefix, paths };
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Canonicalizes a repo-relative path spelling before it is used as a dirty
|
|
416
|
+
* lookup key or matched against one: strips a leading `./` and a trailing
|
|
417
|
+
* `/`, converts backslashes, and collapses `.`/`..` segments and duplicate
|
|
418
|
+
* slashes via `path.posix.normalize`. `git status` always reports canonical
|
|
419
|
+
* forward-slash paths, but a frontmatter-authored `sources` entry is under
|
|
420
|
+
* no such obligation: `./srcdir` and `srcdir/` name the same directory
|
|
421
|
+
* `srcdir` does and MUST match the same dirty entries (a raw `srcdir/`
|
|
422
|
+
* would build a self-defeating `srcdir//` prefix, a raw `./srcdir` never
|
|
423
|
+
* matches at all). Applied on BOTH sides of every dirty-path comparison in
|
|
424
|
+
* this file.
|
|
425
|
+
*
|
|
426
|
+
* `.`, `./` and the empty string all normalize to `.`, the root directory
|
|
427
|
+
* itself: a legal `sources` spelling but never a `git status` entry, so
|
|
428
|
+
* `isDirtyForShared` answers it by containment instead of by lookup.
|
|
429
|
+
*/
|
|
430
|
+
function normalizeRelPath(relPath) {
|
|
431
|
+
let p = relPath.replace(/\\/g, "/");
|
|
432
|
+
while (p.startsWith("./"))
|
|
433
|
+
p = p.slice(2);
|
|
434
|
+
p = path.posix.normalize(p);
|
|
435
|
+
while (p.length > 1 && p.endsWith("/"))
|
|
436
|
+
p = p.slice(0, -1);
|
|
437
|
+
return p;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Per-run cache (keyed by `BundleContext`, same pattern as
|
|
441
|
+
* `docCommitEpochCache` below) of `readDirtyState`'s answer, so the WHOLE
|
|
442
|
+
* `check` run -- both rules, every doc, every source -- spends at most one
|
|
443
|
+
* `git status` (plus one `git rev-parse --show-prefix`) process, not one
|
|
444
|
+
* per rule. A cached `null` (the git read failed) is a real cached answer,
|
|
445
|
+
* hence the `.has` check rather than a truthiness test: a failed read is
|
|
446
|
+
* not retried per source.
|
|
447
|
+
*/
|
|
448
|
+
const dirtyStateCache = new WeakMap();
|
|
449
|
+
function getDirtyStateShared(ctx, git, repoRoot) {
|
|
450
|
+
if (dirtyStateCache.has(ctx))
|
|
451
|
+
return dirtyStateCache.get(ctx) ?? null;
|
|
452
|
+
const state = readDirtyState(ctx, git, repoRoot);
|
|
453
|
+
dirtyStateCache.set(ctx, state);
|
|
454
|
+
return state;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Whether `relPath` (a `sources` entry OR a doc's own path relative to
|
|
458
|
+
* `ctx.repoRoot`, in any spelling `normalizeRelPath` accepts) is dirty per
|
|
459
|
+
* `git status`. The queried path is first respelled in the top-level frame
|
|
460
|
+
* every reported entry uses (`toTopLevelPath`; a no-op when `--repo-root`
|
|
461
|
+
* IS the top level). A dirty FILE then matches by exact normalized path; a
|
|
462
|
+
* dirty DIRECTORY source matches if any reported path lives under it (a
|
|
463
|
+
* `/`-terminated prefix, so `srcdirX/x.ts` never matches `srcdir`). `.`
|
|
464
|
+
* names the root directory itself, which `git status` never reports as an
|
|
465
|
+
* entry, so it is matched by containment: any dirty path at all.
|
|
466
|
+
*
|
|
467
|
+
* A failed state read (`null`) is "nothing is dirty": every path keeps its
|
|
468
|
+
* ordinary commit-epoch verdict, and the rule reports the failure once at
|
|
469
|
+
* bundle level (see `readDirtyState`).
|
|
470
|
+
*/
|
|
471
|
+
function isDirtyForShared(ctx, git, repoRoot, relPath) {
|
|
472
|
+
const state = getDirtyStateShared(ctx, git, repoRoot);
|
|
473
|
+
if (state === null)
|
|
474
|
+
return false;
|
|
475
|
+
const { paths } = state;
|
|
476
|
+
const normalized = normalizeRelPath(toTopLevelPath(state.prefix, relPath));
|
|
477
|
+
if (normalized === ".")
|
|
478
|
+
return paths.size > 0;
|
|
479
|
+
if (paths.has(normalized))
|
|
480
|
+
return true;
|
|
481
|
+
const prefix = `${normalized}/`;
|
|
482
|
+
for (const p of paths) {
|
|
483
|
+
if (p.startsWith(prefix))
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Per-run cache (keyed by `BundleContext`) of the SINGLE "now" instant
|
|
490
|
+
* `--dirty-as-now` substitutes for every dirty path's commit epoch, across
|
|
491
|
+
* BOTH rules and every doc/source they assess: one `check` run models every
|
|
492
|
+
* dirty path as landing in the same virtual commit.
|
|
493
|
+
*
|
|
494
|
+
* THE CACHE IS THE GUARANTEE, not the order the callers happen to run in:
|
|
495
|
+
* the rescue gate is an INEQUALITY (`docCommitEpoch >= commitEpoch`) whose
|
|
496
|
+
* two sides are BOTH this value when a dirty doc is paired with a dirty
|
|
497
|
+
* source, and reading the clock afresh per side would let a second boundary
|
|
498
|
+
* between the two reads flip it into a silent, unreproducible STALE
|
|
499
|
+
* depending on which side asked first. The clock is read exactly ONCE per
|
|
500
|
+
* run (`ctx.now`, defaulting to `Date.now`, injectable so a test can pin
|
|
501
|
+
* that count); every caller wanting "now" goes through this accessor.
|
|
502
|
+
*/
|
|
503
|
+
const nowEpochCache = new WeakMap();
|
|
504
|
+
function getNowEpochShared(ctx) {
|
|
505
|
+
let epoch = nowEpochCache.get(ctx);
|
|
506
|
+
if (epoch === undefined) {
|
|
507
|
+
epoch = Math.floor((ctx.now ?? Date.now)() / 1000);
|
|
508
|
+
nowEpochCache.set(ctx, epoch);
|
|
509
|
+
}
|
|
510
|
+
return epoch;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Per-run cache of `git rev-parse --show-prefix` for `repoRoot`: `""` when
|
|
514
|
+
* `repoRoot` IS the repository's top level, otherwise its path relative to
|
|
515
|
+
* the top level with a trailing slash (`sub/`, `a/b/`); `null` when git
|
|
516
|
+
* could not answer. Read at most once per run, and by everything in this
|
|
517
|
+
* file that has to speak in the TOP-LEVEL path frame.
|
|
518
|
+
*
|
|
519
|
+
* THE INVARIANT: every path this file receives is relative to `repoRoot`,
|
|
520
|
+
* but `git status` entries, `git diff-tree --name-status` entries and the
|
|
521
|
+
* `<rev>:<path>` blob spelling `git show` takes are all top-level-relative
|
|
522
|
+
* (a bare `<rev>:<path>` is NOT resolved against the cwd). The two frames
|
|
523
|
+
* coincide only when `--repo-root` names the top level. Under a
|
|
524
|
+
* `--repo-root` naming a SUBDIRECTORY, a root-relative path used in the
|
|
525
|
+
* top-level frame either matches nothing (a blob read fails, a dirty path
|
|
526
|
+
* never matches) or, worse, reads a SAME-NAMED file at the top level in
|
|
527
|
+
* the doc's place and judges the doc by a stranger's stamp. So every
|
|
528
|
+
* cross-frame step goes through `toTopLevelPath` with this prefix, never
|
|
529
|
+
* a bare path.
|
|
530
|
+
*/
|
|
531
|
+
const showPrefixCache = new WeakMap();
|
|
532
|
+
function getShowPrefixShared(ctx, git, repoRoot) {
|
|
533
|
+
if (showPrefixCache.has(ctx))
|
|
534
|
+
return showPrefixCache.get(ctx) ?? null;
|
|
535
|
+
// `""` (this IS the top level) is a valid answer; only an outright
|
|
536
|
+
// failure is null.
|
|
537
|
+
const raw = git(["rev-parse", "--show-prefix"], repoRoot);
|
|
538
|
+
const prefix = raw === null ? null : raw === "" ? "" : `${normalizeRelPath(raw)}/`;
|
|
539
|
+
showPrefixCache.set(ctx, prefix);
|
|
540
|
+
return prefix;
|
|
541
|
+
}
|
|
542
|
+
/** `rootRelPath` (relative to `repoRoot`) respelled in the top-level frame `showPrefix` (from `getShowPrefixShared`) describes. */
|
|
543
|
+
function toTopLevelPath(showPrefix, rootRelPath) {
|
|
544
|
+
return `${showPrefix}${rootRelPath}`;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* THE one place a blob is read: `git show <rev>:<topLevelPath>`. The path
|
|
548
|
+
* MUST already be in the top-level frame (`toTopLevelPath`), see
|
|
549
|
+
* `getShowPrefixShared`. Null on any git failure, "no such path at that
|
|
550
|
+
* rev" included.
|
|
551
|
+
*/
|
|
552
|
+
function showBlob(git, repoRoot, rev, topLevelPath) {
|
|
553
|
+
return git(["show", `${rev}:${topLevelPath}`], repoRoot);
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* THE single choke point where `--dirty-as-now`'s virtual-commit model is
|
|
557
|
+
* applied: a dirty `relPath` (source or doc, see `isDirtyForShared`) is
|
|
558
|
+
* judged as committed at the shared "now" instant (`getNowEpochShared`)
|
|
559
|
+
* instead of consulting `actualEpoch` at all; anything else -- the flag
|
|
560
|
+
* off, or `relPath` not dirty -- defers to `actualEpoch` (typically a
|
|
561
|
+
* memoized real `git log` lookup), byte-identical to pre-flag behavior.
|
|
562
|
+
* Every commit-epoch read in this file that is meant to honor
|
|
563
|
+
* `--dirty-as-now` MUST go through this function (directly, or via
|
|
564
|
+
* `getDocCommitEpochShared` below, which is itself built on it) rather
|
|
565
|
+
* than re-implementing the dirty check inline, so a source's epoch and a
|
|
566
|
+
* doc's own epoch are always read the same way, by both rules.
|
|
567
|
+
*/
|
|
568
|
+
function commitEpochWithDirtyAsNow(ctx, git, repoRoot, relPath, actualEpoch) {
|
|
569
|
+
if (ctx.dirtyAsNow && isDirtyForShared(ctx, git, repoRoot, relPath)) {
|
|
570
|
+
return getNowEpochShared(ctx);
|
|
571
|
+
}
|
|
572
|
+
return actualEpoch();
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* `--dirty-as-now` only: the verdict for "did the doc's OWN uncommitted
|
|
576
|
+
* working-tree state re-stamp it" -- the virtual-commit analogue of
|
|
577
|
+
* `restampedByOwnLastCommit`'s co-commit check, used in its place (see
|
|
578
|
+
* `restampFor` in the rule above) whenever the doc itself is dirty. The
|
|
579
|
+
* virtual commit's implicit "first parent" is simply HEAD, so this compares
|
|
580
|
+
* the doc's CURRENT (working-tree) parsed `timestamp` identity -- already
|
|
581
|
+
* read from disk by the caller, since `BundleDoc` always reflects the
|
|
582
|
+
* working tree, dirty or not -- against the value committed at HEAD for the
|
|
583
|
+
* same path. Any change of value, in EITHER direction (including a
|
|
584
|
+
* backwards re-stamp), counts as re-stamped, mirroring the committed
|
|
585
|
+
* rescue's "changed, not corrected" semantics documented on
|
|
586
|
+
* `restampedByOwnLastCommit` below.
|
|
587
|
+
*
|
|
588
|
+
* Distinguishes a genuinely untracked/new doc (no entry for this path at
|
|
589
|
+
* HEAD at all -- `git ls-tree HEAD -- <path>` succeeds with EMPTY output,
|
|
590
|
+
* never a git failure) from a real git failure reading an EXISTING HEAD
|
|
591
|
+
* blob (`git show` itself failing -- a corrupt object, an unreadable blob):
|
|
592
|
+
* the former counts as "restamped" (there is no prior committed value to
|
|
593
|
+
* compare against, so its whole content, stamp included, is new -- the
|
|
594
|
+
* working-tree equivalent of "the doc being created there"); the latter is
|
|
595
|
+
* `unknown`, falling through to the rule's existing not-assessable notice
|
|
596
|
+
* rather than being silently treated the same as "created". `git ls-tree`
|
|
597
|
+
* itself failing (an unborn HEAD, git unavailable) is likewise `unknown`.
|
|
598
|
+
*/
|
|
599
|
+
function dirtyDocRestampVerdict(git, repoRoot, repoRelDocPath, onDiskTimestamp, showPrefix) {
|
|
600
|
+
// A pathspec (`--`), cwd-relative: stays in the root-relative frame.
|
|
601
|
+
const treeEntry = git(["ls-tree", "-z", "HEAD", "--", repoRelDocPath], repoRoot);
|
|
602
|
+
if (treeEntry === null)
|
|
603
|
+
return "unknown";
|
|
604
|
+
if (treeEntry === "")
|
|
605
|
+
return "restamped";
|
|
606
|
+
const prefix = showPrefix();
|
|
607
|
+
if (prefix === null)
|
|
608
|
+
return "unknown";
|
|
609
|
+
const committed = showBlob(git, repoRoot, "HEAD", toTopLevelPath(prefix, repoRelDocPath));
|
|
610
|
+
if (committed === null)
|
|
611
|
+
return "unknown";
|
|
612
|
+
const committedStamp = getTimestampIdentity(parseFrontmatter(committed).frontmatter.parsed);
|
|
613
|
+
return committedStamp !== onDiskTimestamp ? "restamped" : "not-restamped";
|
|
614
|
+
}
|
|
270
615
|
function epochToIso(epochSeconds) {
|
|
271
616
|
return new Date(epochSeconds * 1000).toISOString();
|
|
272
617
|
}
|
|
273
618
|
/**
|
|
274
|
-
* Per-run cache of a doc's own last-commit epoch, keyed by
|
|
275
|
-
* `BundleContext` instance so `sources-fresh`'s doc-commit comparison
|
|
276
|
-
* `sources-fresh-future`'s timestamp comparison -- both need the
|
|
277
|
-
* (repoRoot, doc path) `getLastCommitEpoch` lookup for every doc
|
|
278
|
-
* `check` invocation -- share one `git log` process per doc instead
|
|
279
|
-
* rule spawning its own. Safe to key on the context object itself:
|
|
280
|
-
* `BundleContext` is built per `runCheck`/`loadBundle` call, so
|
|
281
|
-
* reuses a stale cache entry across invocations, and the WeakMap
|
|
282
|
-
* cache be garbage-collected with the context once a run is done.
|
|
619
|
+
* Per-run cache of a doc's own REAL (committed) last-commit epoch, keyed by
|
|
620
|
+
* the `BundleContext` instance so `sources-fresh`'s doc-commit comparison
|
|
621
|
+
* and `sources-fresh-future`'s timestamp comparison -- both need the
|
|
622
|
+
* IDENTICAL (repoRoot, doc path) `getLastCommitEpoch` lookup for every doc
|
|
623
|
+
* in one `check` invocation -- share one `git log` process per doc instead
|
|
624
|
+
* of each rule spawning its own. Safe to key on the context object itself:
|
|
625
|
+
* a fresh `BundleContext` is built per `runCheck`/`loadBundle` call, so
|
|
626
|
+
* nothing reuses a stale cache entry across invocations, and the WeakMap
|
|
627
|
+
* lets the cache be garbage-collected with the context once a run is done.
|
|
628
|
+
*
|
|
629
|
+
* `getDocCommitEpochShared` below is the single place BOTH rules read a
|
|
630
|
+
* doc's commit epoch from, and it is itself built on
|
|
631
|
+
* `commitEpochWithDirtyAsNow`: under `--dirty-as-now`, a dirty doc's epoch
|
|
632
|
+
* is the shared virtual "now" instant instead of this real cache's answer,
|
|
633
|
+
* so `sources-fresh`'s co-commit rescue and `sources-fresh-future`'s
|
|
634
|
+
* timestamp comparison always see the identical (real-or-virtual) epoch
|
|
635
|
+
* for the same doc in the same `check` run.
|
|
283
636
|
*/
|
|
284
637
|
const docCommitEpochCache = new WeakMap();
|
|
285
638
|
function getDocCommitEpochShared(ctx, git, repoRoot, repoRelDocPath) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
639
|
+
return commitEpochWithDirtyAsNow(ctx, git, repoRoot, repoRelDocPath, () => {
|
|
640
|
+
let cache = docCommitEpochCache.get(ctx);
|
|
641
|
+
if (!cache) {
|
|
642
|
+
cache = new Map();
|
|
643
|
+
docCommitEpochCache.set(ctx, cache);
|
|
644
|
+
}
|
|
645
|
+
const cached = cache.get(repoRelDocPath);
|
|
646
|
+
if (cached !== undefined)
|
|
647
|
+
return cached;
|
|
648
|
+
const epoch = getLastCommitEpoch(git, repoRoot, repoRelDocPath);
|
|
649
|
+
cache.set(repoRelDocPath, epoch);
|
|
650
|
+
return epoch;
|
|
651
|
+
});
|
|
297
652
|
}
|
|
298
653
|
/**
|
|
299
654
|
* Per-run cache (keyed by `BundleContext`, same pattern as
|
|
@@ -370,7 +725,7 @@ function isShallowRepoShared(ctx, git, repoRoot) {
|
|
|
370
725
|
* (skipped for a root commit), and 2 blob reads (skipped when the doc was
|
|
371
726
|
* created there). See the GIT PROCESS BUDGET comment in the rule above.
|
|
372
727
|
*/
|
|
373
|
-
function restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, isShallowRepo) {
|
|
728
|
+
function restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, isShallowRepo, showPrefix) {
|
|
374
729
|
// %H then %P on its own line: the doc's last commit and its parent list in
|
|
375
730
|
// ONE process. Default history simplification is exactly what this needs
|
|
376
731
|
// for a single path: a merge whose result for that path differs from every
|
|
@@ -397,15 +752,22 @@ function restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, isShallowRepo)
|
|
|
397
752
|
return isShallowRepo() ? "unknown-shallow-root" : "restamped";
|
|
398
753
|
}
|
|
399
754
|
const firstParent = parents[0];
|
|
400
|
-
|
|
755
|
+
// From here on everything git reports or takes is in the top-level frame
|
|
756
|
+
// (see getShowPrefixShared): the diff-tree entries previousPathIn matches
|
|
757
|
+
// against, and both `<rev>:<path>` blob reads.
|
|
758
|
+
const prefix = showPrefix();
|
|
759
|
+
if (prefix === null)
|
|
760
|
+
return "unknown";
|
|
761
|
+
const topLevelDocPath = toTopLevelPath(prefix, repoRelDocPath);
|
|
762
|
+
const previous = previousPathIn(git, repoRoot, firstParent, sha, topLevelDocPath);
|
|
401
763
|
if (previous.kind === "unknown")
|
|
402
764
|
return "unknown";
|
|
403
765
|
if (previous.kind === "created")
|
|
404
766
|
return "restamped";
|
|
405
|
-
const current = git
|
|
767
|
+
const current = showBlob(git, repoRoot, sha, topLevelDocPath);
|
|
406
768
|
if (current === null)
|
|
407
769
|
return "unknown";
|
|
408
|
-
const before = git
|
|
770
|
+
const before = showBlob(git, repoRoot, firstParent, previous.path);
|
|
409
771
|
if (before === null)
|
|
410
772
|
return "unknown";
|
|
411
773
|
const currentStamp = getTimestampIdentity(parseFrontmatter(current).frontmatter.parsed);
|
|
@@ -418,6 +780,8 @@ function restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, isShallowRepo)
|
|
|
418
780
|
* Where the doc lived in `parentSha`, so its previous revision can be read
|
|
419
781
|
* by that path: the same path (`same`), a different one it was renamed from
|
|
420
782
|
* (`renamed`), or nowhere at all because that commit created it (`created`).
|
|
783
|
+
* `topLevelDocPath` and every returned path are in the top-level frame,
|
|
784
|
+
* the one `diff-tree --name-status` reports in (see getShowPrefixShared).
|
|
421
785
|
*
|
|
422
786
|
* Runs `git diff-tree` WITHOUT a pathspec on purpose. A pathspec is applied
|
|
423
787
|
* BEFORE rename detection, so `git diff-tree -M --name-status <parent> <sha>
|
|
@@ -438,7 +802,7 @@ function restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, isShallowRepo)
|
|
|
438
802
|
* `--name-status` output C-QUOTES any path containing a non-ASCII byte
|
|
439
803
|
* (`core.quotePath` defaults to true) as a double-quoted string with octal
|
|
440
804
|
* escapes (e.g. `"bundle/\303\266lt.md"` for `bundle/ölt.md`), so a plain
|
|
441
|
-
* `
|
|
805
|
+
* `topLevelDocPath` never string-equals that quoted form and a non-ASCII doc
|
|
442
806
|
* falls through every branch below to the `same` fallback, which returns
|
|
443
807
|
* the doc's real (unquoted) CURRENT path unchanged. When that commit was
|
|
444
808
|
* actually a rename or creation, the doc was NOT at that path in the first
|
|
@@ -451,7 +815,7 @@ function restampedByOwnLastCommit(git, repoRoot, repoRelDocPath, isShallowRepo)
|
|
|
451
815
|
* override this rule would otherwise have to remember on every git
|
|
452
816
|
* invocation touching a path, not just this one).
|
|
453
817
|
*/
|
|
454
|
-
function previousPathIn(git, repoRoot, parentSha, sha,
|
|
818
|
+
function previousPathIn(git, repoRoot, parentSha, sha, topLevelDocPath) {
|
|
455
819
|
const nameStatus = git([
|
|
456
820
|
"diff-tree",
|
|
457
821
|
"-r",
|
|
@@ -481,19 +845,19 @@ function previousPathIn(git, repoRoot, parentSha, sha, repoRelDocPath) {
|
|
|
481
845
|
const oldPath = tokens[i + 1];
|
|
482
846
|
const newPath = tokens[i + 2];
|
|
483
847
|
i += 3;
|
|
484
|
-
if (newPath ===
|
|
848
|
+
if (newPath === topLevelDocPath) {
|
|
485
849
|
return { kind: "renamed", path: oldPath };
|
|
486
850
|
}
|
|
487
851
|
continue;
|
|
488
852
|
}
|
|
489
853
|
const p = tokens[i + 1];
|
|
490
854
|
i += 2;
|
|
491
|
-
if (p !==
|
|
855
|
+
if (p !== topLevelDocPath)
|
|
492
856
|
continue;
|
|
493
857
|
if (status.startsWith("A"))
|
|
494
858
|
return { kind: "created" };
|
|
495
|
-
return { kind: "same", path:
|
|
859
|
+
return { kind: "same", path: topLevelDocPath };
|
|
496
860
|
}
|
|
497
|
-
return { kind: "same", path:
|
|
861
|
+
return { kind: "same", path: topLevelDocPath };
|
|
498
862
|
}
|
|
499
863
|
//# sourceMappingURL=sources-fresh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sources-fresh.js","sourceRoot":"","sources":["../../src/rules/sources-fresh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,GACjB,MAAM,YAAY,CAAC;AASpB,MAAM,OAAO,GAAG,eAAe,CAAC;AAChC,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAS;IACpC,EAAE,EAAE,OAAO;IACX,WAAW,EACT,6vBAA6vB;IAC/vB,GAAG,CAAC,GAAG;QACL,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,MAAM,eAAe,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC;QAElD,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAClB,sEAAsE;YACtE,mEAAmE;YACnE,qEAAqE;YACrE,oEAAoE;YACpE,mEAAmE;YACnE,oEAAoE;YACpE,oBAAoB;YACpB,QAAQ,CAAC,IAAI,CAAC;gBACZ,MAAM,EAAE,OAAO;gBACf,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,EAAE;gBACR,OAAO,EAAE,+CAA+C;aACzD,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC;QAExC,qEAAqE;QACrE,6DAA6D;QAC7D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAyB,CAAC;QAC1D,MAAM,cAAc,GAAG,CAAC,MAAc,EAAiB,EAAE;YACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,MAAM,CAAC;YACxC,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;YACxD,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;QAEF,KAAK,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,eAAe,EAAE,CAAC;YAC/C,MAAM,cAAc,GAAG,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACjE,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBACjC,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,OAAO;oBACf,QAAQ,EAAE,QAAQ;oBAClB,IAAI,EAAE,GAAG,CAAC,OAAO;oBACjB,OAAO,EAAE,8CAA8C;iBACxD,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,sEAAsE;YACtE,qEAAqE;YACrE,qEAAqE;YACrE,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,mEAAmE;YACnE,mEAAmE;YACnE,qEAAqE;YACrE,eAAe;YACf,EAAE;YACF,8DAA8D;YAC9D,sEAAsE;YACtE,yEAAyE;YACzE,kEAAkE;YAClE,qEAAqE;YACrE,kEAAkE;YAClE,kEAAkE;YAClE,8DAA8D;YAC9D,iDAAiD;YACjD,6DAA6D;YAC7D,gEAAgE;YAChE,kEAAkE;YAClE,kDAAkD;YAClD,MAAM,cAAc,GAAG,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACtE,MAAM,iBAAiB,GAAG,GAAkB,EAAE,CAC5C,uBAAuB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC9D,IAAI,WAAuC,CAAC;YAC5C,MAAM,UAAU,GAAG,GAAmB,EAAE,CACtC,CAAC,WAAW,KAAK,wBAAwB,CACvC,GAAG,EACH,QAAQ,EACR,cAAc,EACd,GAAG,EAAE,CAAC,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAC9C,CAAC,CAAC;YACL,mEAAmE;YACnE,kDAAkD;YAClD,IAAI,qBAAqB,GAAG,KAAK,CAAC;YAElC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,mEAAmE;gBACnE,oCAAoC;gBACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAAE,SAAS;gBAE1D,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;gBAC3C,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;oBACzB,QAAQ,CAAC,IAAI,CAAC;wBACZ,MAAM,EAAE,OAAO;wBACf,QAAQ,EAAE,QAAQ;wBAClB,IAAI,EAAE,GAAG,CAAC,OAAO;wBACjB,OAAO,EAAE,0CAA0C,MAAM,IAAI;qBAC9D,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;gBAED,IAAI,OAAO,GAAG,WAAW,GAAG,cAAc,CAAC;gBAE3C,8DAA8D;gBAC9D,kEAAkE;gBAClE,oEAAoE;gBACpE,mEAAmE;gBACnE,kEAAkE;gBAClE,kEAAkE;gBAClE,sDAAsD;gBACtD,IAAI,OAAO,EAAE,CAAC;oBACZ,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;oBAC3C,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,IAAI,WAAW,EAAE,CAAC;wBAC7D,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;wBAC7B,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;4BAC5B,OAAO,GAAG,KAAK,CAAC;wBAClB,CAAC;6BAAM,IACL,OAAO,KAAK,SAAS;4BACrB,OAAO,KAAK,sBAAsB,EAClC,CAAC;4BACD,IAAI,CAAC,qBAAqB,EAAE,CAAC;gCAC3B,qBAAqB,GAAG,IAAI,CAAC;gCAC7B,QAAQ,CAAC,IAAI,CAAC;oCACZ,MAAM,EAAE,OAAO;oCACf,QAAQ,EAAE,QAAQ;oCAClB,IAAI,EAAE,GAAG,CAAC,OAAO;oCACjB,OAAO,EACL,OAAO,KAAK,sBAAsB;wCAChC,CAAC,CAAC,gQAAgQ;wCAClQ,CAAC,CAAC,gHAAgH;iCACvH,CAAC,CAAC;4BACL,CAAC;4BACD,SAAS;wBACX,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,IAAI,OAAO,EAAE,CAAC;oBACZ,QAAQ,CAAC,IAAI,CAAC;wBACZ,MAAM,EAAE,OAAO;wBACf,QAAQ,EAAE,SAAS;wBACnB,IAAI,EAAE,GAAG,CAAC,OAAO;wBACjB,OAAO,EAAE,YAAY,MAAM,cAAc,UAAU,CAAC,WAAW,CAAC,wBAAwB,UAAU,CAAC,cAAc,CAAC,EAAE;qBACrH,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAS;IAC1C,EAAE,EAAE,cAAc;IAClB,WAAW,EACT,ylBAAylB;IAC3lB,GAAG,CAAC,GAAG;QACL,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,MAAM,eAAe,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClD,IAAI,CAAC,GAAG,CAAC,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAEnC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC;QACxC,MAAM,WAAW,GACf,GAAG,CAAC,0BAA0B,IAAI,2BAA2B,CAAC;QAEhE,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,eAAe,EAAE,CAAC;YACtC,MAAM,cAAc,GAAG,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACjE,IAAI,cAAc,KAAK,SAAS;gBAAE,SAAS;YAE3C,qEAAqE;YACrE,iEAAiE;YACjE,4DAA4D;YAC5D,oEAAoE;YACpE,8DAA8D;YAC9D,6DAA6D;YAC7D,kEAAkE;YAClE,qEAAqE;YACrE,gBAAgB;YAChB,MAAM,YAAY,GAAG,qBAAqB,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACnE,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,EAAE,CAAC;gBAClE,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,cAAc;oBACtB,QAAQ,EAAE,QAAQ;oBAClB,IAAI,EAAE,GAAG,CAAC,OAAO;oBACjB,OAAO,EACL,kIAAkI;iBACrI,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,MAAM,cAAc,GAAG,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACtE,MAAM,cAAc,GAAG,uBAAuB,CAC5C,GAAG,EACH,GAAG,EACH,QAAQ,EACR,cAAc,CACf,CAAC;YACF,IAAI,cAAc,KAAK,IAAI;gBAAE,SAAS;YAEtC,IAAI,cAAc,GAAG,cAAc,GAAG,WAAW,EAAE,CAAC;gBAClD,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,cAAc;oBACtB,QAAQ,EAAE,SAAS;oBACnB,IAAI,EAAE,GAAG,CAAC,OAAO;oBACjB,OAAO,EAAE,+BAA+B,UAAU,CAAC,cAAc,CAAC,uCAAuC,UAAU,CAAC,cAAc,CAAC,oBAAoB,WAAW,IAAI;iBACvK,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF;;;;;GAKG;AACH,SAAS,kBAAkB,CACzB,GAAkB;IAElB,OAAO,GAAG,CAAC,IAAI;SACZ,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;SACzE,MAAM,CACL,CAAC,KAAK,EAAkD,EAAE,CACxD,KAAK,CAAC,OAAO,KAAK,SAAS,CAC9B,CAAC;AACN,CAAC;AAED,yGAAyG;AACzG,SAAS,gBAAgB,CACvB,QAAgB,EAChB,SAAiB,EACjB,GAAc;IAEd,OAAO,IAAI;SACR,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;SACrD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,kBAAkB,CACzB,GAAW,EACX,QAAgB,EAChB,MAAc;IAEd,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvE,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5C,CAAC;AAED,SAAS,UAAU,CAAC,YAAoB;IACtC,OAAO,IAAI,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AACrD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,mBAAmB,GAAG,IAAI,OAAO,EAGpC,CAAC;AAEJ,SAAS,uBAAuB,CAC9B,GAAkB,EAClB,GAAW,EACX,QAAgB,EAChB,cAAsB;IAEtB,IAAI,KAAK,GAAG,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;QAClB,mBAAmB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IAChE,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,gBAAgB,GAAG,IAAI,OAAO,EAA0B,CAAC;AAE/D,SAAS,mBAAmB,CAC1B,GAAkB,EAClB,GAAW,EACX,QAAgB;IAEhB,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,yBAAyB,CAAC,EAAE,QAAQ,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,MAAM,CAAC;IAC9D,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACrC,OAAO,SAAS,CAAC;AACnB,CAAC;AAkBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,SAAS,wBAAwB,CAC/B,GAAW,EACX,QAAgB,EAChB,cAAsB,EACtB,aAA4B;IAE5B,2EAA2E;IAC3E,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,IAAI,GAAG,GAAG,CACd,CAAC,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,CAAC,EACtD,QAAQ,CACT,CAAC;IACF,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,OAAO,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACtE,oEAAoE;IACpE,wEAAwE;IACxE,uEAAuE;IACvE,oEAAoE;IACpE,uEAAuE;IACvE,2EAA2E;IAC3E,kEAAkE;IAClE,yEAAyE;IACzE,gEAAgE;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,aAAa,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,WAAW,CAAC;IAChE,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE/B,MAAM,QAAQ,GAAG,cAAc,CAC7B,GAAG,EACH,QAAQ,EACR,WAAW,EACX,GAAG,EACH,cAAc,CACf,CAAC;IACF,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAClD,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAEpD,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,cAAc,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IACpE,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACvC,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,WAAW,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC1E,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAEtC,MAAM,YAAY,GAAG,oBAAoB,CACvC,gBAAgB,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAC7C,CAAC;IACF,MAAM,WAAW,GAAG,oBAAoB,CACtC,gBAAgB,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,CAC5C,CAAC;IACF,0EAA0E;IAC1E,oEAAoE;IACpE,OAAO,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC;AACtE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,SAAS,cAAc,CACrB,GAAW,EACX,QAAgB,EAChB,SAAiB,EACjB,GAAW,EACX,cAAsB;IAKtB,MAAM,UAAU,GAAG,GAAG,CACpB;QACE,WAAW;QACX,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,eAAe;QACf,gBAAgB;QAChB,SAAS;QACT,GAAG;KACJ,EACD,QAAQ,CACT,CAAC;IACF,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAEpD,wEAAwE;IACxE,wEAAwE;IACxE,wEAAwE;IACxE,uEAAuE;IACvE,sEAAsE;IACtE,yEAAyE;IACzE,uEAAuE;IACvE,yEAAyE;IACzE,gDAAgD;IAChD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9B,CAAC,IAAI,CAAC,CAAC;YACP,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;gBAC/B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC5C,CAAC;YACD,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,CAAC,IAAI,CAAC,CAAC;QACP,IAAI,CAAC,KAAK,cAAc;YAAE,SAAS;QACnC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACvD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AAChD,CAAC"}
|
|
1
|
+
{"version":3,"file":"sources-fresh.js","sourceRoot":"","sources":["../../src/rules/sources-fresh.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -79,6 +79,33 @@ export interface BundleContext {
|
|
|
79
79
|
* was not passed, in which case the rule applies its own default.
|
|
80
80
|
*/
|
|
81
81
|
freshnessFutureSkewSeconds?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Opt-in for `sources-fresh` AND `sources-fresh-future` (see
|
|
84
|
+
* `--dirty-as-now` in `src/cli.ts`): every uncommitted change (modified,
|
|
85
|
+
* staged, or untracked per `git status --porcelain --untracked-files=all`) is modeled as though
|
|
86
|
+
* it landed in ONE virtual commit made right now, instead of at its last
|
|
87
|
+
* real commit's time. That virtual-commit epoch is the SINGLE place both
|
|
88
|
+
* rules read a dirty path's "commit time" from (see
|
|
89
|
+
* `getDocCommitEpochShared`/`commitEpochFor` in
|
|
90
|
+
* `src/rules/sources-fresh.ts`): a dirty `sources` path's epoch becomes
|
|
91
|
+
* now (`sources-fresh`'s base comparison), and a dirty DOC's own epoch
|
|
92
|
+
* becomes now too (both `sources-fresh`'s co-commit rescue and
|
|
93
|
+
* `sources-fresh-future`'s timestamp comparison read that same virtual
|
|
94
|
+
* epoch). Closes the gap between a pre-commit `check` run (which sees
|
|
95
|
+
* only committed history) and CI's post-commit run (which sees the new
|
|
96
|
+
* commit time) for content edited but not yet committed. Undefined (the
|
|
97
|
+
* default) leaves both rules looking only at committed history,
|
|
98
|
+
* byte-identical to behavior before this option existed.
|
|
99
|
+
*/
|
|
100
|
+
dirtyAsNow?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Clock for `--dirty-as-now`'s virtual-commit instant, in milliseconds
|
|
103
|
+
* since the epoch like `Date.now` (the default when undefined). Read
|
|
104
|
+
* exactly ONCE per `check` run (`getNowEpochShared` in
|
|
105
|
+
* `src/rules/sources-fresh.ts`); injectable so a test can pin that count
|
|
106
|
+
* and the shared value rather than racing the wall clock.
|
|
107
|
+
*/
|
|
108
|
+
now?: () => number;
|
|
82
109
|
}
|
|
83
110
|
export interface Rule {
|
|
84
111
|
id: string;
|