urtext 0.1.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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/analyze/blast-radius.d.ts +28 -0
- package/dist/analyze/blast-radius.js +163 -0
- package/dist/analyze/canonical.d.ts +27 -0
- package/dist/analyze/canonical.js +74 -0
- package/dist/analyze/citations.d.ts +256 -0
- package/dist/analyze/citations.js +945 -0
- package/dist/analyze/effects.d.ts +15 -0
- package/dist/analyze/effects.js +255 -0
- package/dist/analyze/fact.d.ts +42 -0
- package/dist/analyze/fact.js +46 -0
- package/dist/analyze/guards.d.ts +70 -0
- package/dist/analyze/guards.js +211 -0
- package/dist/analyze/index.d.ts +26 -0
- package/dist/analyze/index.js +52 -0
- package/dist/analyze/program.d.ts +15 -0
- package/dist/analyze/program.js +229 -0
- package/dist/analyze/surface.d.ts +48 -0
- package/dist/analyze/surface.js +396 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +12 -0
- package/dist/cli.d.ts +110 -0
- package/dist/cli.js +502 -0
- package/dist/extract/diff.d.ts +35 -0
- package/dist/extract/diff.js +116 -0
- package/dist/extract/git.d.ts +12 -0
- package/dist/extract/git.js +247 -0
- package/dist/extract/index.d.ts +4 -0
- package/dist/extract/index.js +57 -0
- package/dist/extract/intent.d.ts +64 -0
- package/dist/extract/intent.js +238 -0
- package/dist/extract/scope.d.ts +160 -0
- package/dist/extract/scope.js +284 -0
- package/dist/extract/symbols.d.ts +24 -0
- package/dist/extract/symbols.js +230 -0
- package/dist/interpret/client.d.ts +27 -0
- package/dist/interpret/client.js +80 -0
- package/dist/interpret/index.d.ts +41 -0
- package/dist/interpret/index.js +86 -0
- package/dist/interpret/prompt.d.ts +23 -0
- package/dist/interpret/prompt.js +128 -0
- package/dist/interpret/schema.d.ts +74 -0
- package/dist/interpret/schema.js +103 -0
- package/dist/report/conceal.d.ts +63 -0
- package/dist/report/conceal.js +129 -0
- package/dist/report/coverage.d.ts +43 -0
- package/dist/report/coverage.js +56 -0
- package/dist/report/html.d.ts +4 -0
- package/dist/report/html.js +634 -0
- package/dist/report/markdown.d.ts +2 -0
- package/dist/report/markdown.js +168 -0
- package/dist/report/model.d.ts +303 -0
- package/dist/report/model.js +289 -0
- package/dist/report/pdf.d.ts +2 -0
- package/dist/report/pdf.js +217 -0
- package/dist/report/terminal.d.ts +2 -0
- package/dist/report/terminal.js +206 -0
- package/dist/report/write.d.ts +105 -0
- package/dist/report/write.js +160 -0
- package/dist/score/index.d.ts +94 -0
- package/dist/score/index.js +572 -0
- package/dist/score/reach.d.ts +126 -0
- package/dist/score/reach.js +320 -0
- package/dist/score/reconcile.d.ts +52 -0
- package/dist/score/reconcile.js +208 -0
- package/dist/types.d.ts +221 -0
- package/dist/types.js +10 -0
- package/fonts/DejaVuSans-Bold.ttf +0 -0
- package/fonts/DejaVuSans-Oblique.ttf +0 -0
- package/fonts/DejaVuSans.ttf +0 -0
- package/fonts/DejaVuSansMono.ttf +0 -0
- package/fonts/LICENSE +187 -0
- package/package.json +44 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { type AnalysisContext, type Analyzer, type Changeset } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A repository-relative path followed by a line, or a line range. The path
|
|
4
|
+
* must contain at least one directory separator — see
|
|
5
|
+
* CITATION_GUARD_SEPARATOR in the design's false-positive guards for why a
|
|
6
|
+
* bare `Something.js:14` is not treated as a citation at all.
|
|
7
|
+
*
|
|
8
|
+
* Left to right: a lookbehind rejecting a preceding path character, so a
|
|
9
|
+
* match cannot start in the middle of a longer path; one or more `segment/`
|
|
10
|
+
* groups, which is what makes the separator mandatory; a final segment with
|
|
11
|
+
* a dot and an alphanumeric extension; a colon; a line number with no
|
|
12
|
+
* leading zero; optionally a hyphen and an end line; and a lookahead
|
|
13
|
+
* rejecting a trailing digit, letter, underscore, slash, or hyphen, so a
|
|
14
|
+
* citation is not matched inside a longer line number or a longer path.
|
|
15
|
+
* Capture groups: path, start line, end line or undefined.
|
|
16
|
+
*
|
|
17
|
+
* A trailing period is not rejected, so a citation ending a sentence is
|
|
18
|
+
* extracted like any other — see `test/analyze/citations.test.ts`,
|
|
19
|
+
* "extracts a citation a sentence's closing period touches, in both forms".
|
|
20
|
+
*/
|
|
21
|
+
export declare const LINE_CITATION: RegExp;
|
|
22
|
+
/**
|
|
23
|
+
* A backticked repository-relative path, then a quoted phrase — urtext's own
|
|
24
|
+
* comment-contract form, and the most checkable citation form in the
|
|
25
|
+
* repository, because the quoted text either appears in the named file or it
|
|
26
|
+
* does not. The same mandatory-separator path, inside backticks; an optional
|
|
27
|
+
* comma, semicolon, or colon; a short run of whitespace; then a straight or
|
|
28
|
+
* left curly double quote, the phrase, and a straight or right curly close.
|
|
29
|
+
* Capture groups: path, phrase.
|
|
30
|
+
*/
|
|
31
|
+
export declare const QUOTED_CITATION: RegExp;
|
|
32
|
+
/**
|
|
33
|
+
* The most code points a quoted phrase, or a stored was/now line, carries.
|
|
34
|
+
* Longer than this is a block quotation rather than a pointer.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MAX_QUOTE_CHARS = 240;
|
|
37
|
+
/** Appended to a was/now line the cap cut, so no line merely appears to end. */
|
|
38
|
+
export declare const CITATION_TRUNCATION_MARKER = "\u2026 [line truncated]";
|
|
39
|
+
/** Tracked files scanned as raw text, after masking. */
|
|
40
|
+
export declare const PROSE_EXTENSIONS: readonly [".md", ".markdown", ".txt"];
|
|
41
|
+
/**
|
|
42
|
+
* The pathspecs the candidate-file queries in this file's scan half pass to
|
|
43
|
+
* git. Narrower than `isTypeScriptFile` accepts — it also takes the
|
|
44
|
+
* module-explicit extensions, which no pathspec here names — so a citation
|
|
45
|
+
* written in one of those files is not checked at all. An under-report, the
|
|
46
|
+
* direction every approximation in this feature leans.
|
|
47
|
+
*/
|
|
48
|
+
export declare const CITATION_PATHSPECS: readonly ["*.md", "*.markdown", "*.txt", "*.ts", "*.tsx"];
|
|
49
|
+
export type CitationForm = "line" | "quote";
|
|
50
|
+
export interface Citation {
|
|
51
|
+
form: CitationForm;
|
|
52
|
+
/** The path exactly as the prose spelled it, before any resolution. */
|
|
53
|
+
path: string;
|
|
54
|
+
/** Form A only: the cited start line, and the end line for a range. */
|
|
55
|
+
line?: number;
|
|
56
|
+
endLine?: number;
|
|
57
|
+
/** Form B only: the quoted phrase, already normalized. */
|
|
58
|
+
quote?: string;
|
|
59
|
+
/** One-based line in the citing file where `path` sits. */
|
|
60
|
+
citingLine: number;
|
|
61
|
+
/** That line's text, trimmed, for the fact's anchor evidence. */
|
|
62
|
+
citingText: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Every whitespace run, newlines included, collapsed to a single space, then
|
|
66
|
+
* trimmed. Matching and comparison both run on normalized text, and the
|
|
67
|
+
* cited file is normalized identically before a containment test. Without
|
|
68
|
+
* this, every comment-contract citation in `src/` would fail: they wrap
|
|
69
|
+
* across continuation lines, so the phrase as written carries newlines and
|
|
70
|
+
* asterisks the cited file never had.
|
|
71
|
+
*/
|
|
72
|
+
export declare function normalizeText(text: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* CITATION_GUARD_FENCE. Spans from a line opening a fence through the next
|
|
75
|
+
* line closing that fence — same character, at least as long a run —
|
|
76
|
+
* inclusive, are blanked. A path and line inside a fence is sample output,
|
|
77
|
+
* and treating sample output as an assertion about the repository is the
|
|
78
|
+
* most common false positive available. An unclosed fence blanks to the end
|
|
79
|
+
* of the text: silence about a run of prose costs less than a finding built
|
|
80
|
+
* on a code block nobody closed. Indented blocks are deliberately not
|
|
81
|
+
* masked — they are indistinguishable from list continuations in this
|
|
82
|
+
* repository's prose, and the baseline gate already covers the illustrative
|
|
83
|
+
* ones. A blockquote prefix on the fence line is tolerated: a fence inside a
|
|
84
|
+
* quotation is still a fence, and the indent allowance alone cannot see past
|
|
85
|
+
* the marker. See `test/analyze/citations.test.ts`, "CITATION_GUARD_FENCE: a
|
|
86
|
+
* citation inside a fenced block is not one, and the same text outside it
|
|
87
|
+
* is" and "CITATION_GUARD_FENCE: a fenced block inside a blockquote is masked
|
|
88
|
+
* like any other".
|
|
89
|
+
*/
|
|
90
|
+
export declare function maskFences(text: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* CITATION_GUARD_URL. A link to another host is a link to another host, and
|
|
93
|
+
* its path-and-line tail says nothing about this repository. The regexes'
|
|
94
|
+
* lookbehind is a second line of defense, not a substitute: masking is what
|
|
95
|
+
* makes the intent explicit and testable.
|
|
96
|
+
*/
|
|
97
|
+
export declare function maskUrls(text: string): string;
|
|
98
|
+
export declare function isProseFile(path: string): boolean;
|
|
99
|
+
export declare function citationsInProse(text: string): Citation[];
|
|
100
|
+
/**
|
|
101
|
+
* Comments only. A path and line inside a string literal is usually a test
|
|
102
|
+
* fixture's expected output, and inside code it is not prose making a claim.
|
|
103
|
+
* Fences are not masked here — a fence is a prose construct — but URLs are,
|
|
104
|
+
* for the same reason they are in prose.
|
|
105
|
+
*/
|
|
106
|
+
export declare function citationsInComments(source: string, fileName: string): Citation[];
|
|
107
|
+
/** Every citation in one file, scanned the way that file's kind is scanned. */
|
|
108
|
+
export declare function citationsIn(path: string, text: string): Citation[];
|
|
109
|
+
/**
|
|
110
|
+
* The most citations one run checks, across both modes. Bounds a sweep of a
|
|
111
|
+
* repository whose prose cites code everywhere; the default mode is already
|
|
112
|
+
* bounded by the change and reaches this only on a very large diff. A cap
|
|
113
|
+
* that bites is disclosed — see `citationsCappedNote`.
|
|
114
|
+
*/
|
|
115
|
+
export declare const MAX_CITATIONS_CHECKED = 2000;
|
|
116
|
+
/**
|
|
117
|
+
* The most citing files one run opens. Bounds the blame calls, which are the
|
|
118
|
+
* expensive per-file work; the citation cap above bounds the per-citation
|
|
119
|
+
* work. Files are taken in path order so a capped run is deterministic.
|
|
120
|
+
*/
|
|
121
|
+
export declare const MAX_CITING_FILES = 320;
|
|
122
|
+
/**
|
|
123
|
+
* The most distinct (revision, cited file) pairs one run reads historically.
|
|
124
|
+
* A repository whose prose cites a hundred files from a hundred different
|
|
125
|
+
* baseline commits would otherwise pay a `git show` per pair with no bound
|
|
126
|
+
* at all; every citation past this is checked existence-only and said so.
|
|
127
|
+
*/
|
|
128
|
+
export declare const MAX_BASELINE_READS = 480;
|
|
129
|
+
/**
|
|
130
|
+
* The most basenames passed to one `git grep` invocation. Terms are chunked
|
|
131
|
+
* at this width and the results unioned, so unlike the caps above this one
|
|
132
|
+
* loses nothing and discloses nothing.
|
|
133
|
+
*/
|
|
134
|
+
export declare const MAX_GREP_TERMS = 96;
|
|
135
|
+
/**
|
|
136
|
+
* Pluralized inline in the style `review` in `../cli.ts` already uses, and
|
|
137
|
+
* phrased as reasons so they read alongside the existing warnings. They land
|
|
138
|
+
* in `warnings`, which becomes `ReportModel.notes`, which trips the "This
|
|
139
|
+
* review is partial." banner — correctly. A capped run genuinely did not
|
|
140
|
+
* check everything it was asked to.
|
|
141
|
+
*/
|
|
142
|
+
export declare function citingFilesCappedNote(scanned: number, found: number): string;
|
|
143
|
+
export declare function citationsCappedNote(checked: number, found: number): string;
|
|
144
|
+
/**
|
|
145
|
+
* No order clause, unlike the two caps above, and the difference is in what
|
|
146
|
+
* this sentence claims rather than in how its budget is spent. The budget is
|
|
147
|
+
* spent front to back like theirs — a citation is refused a historical read
|
|
148
|
+
* only once the distinct-pair allowance is gone, so the ones that degrade are
|
|
149
|
+
* the later ones in the same path order, minus any whose baseline pair had
|
|
150
|
+
* already been read. But this note states no fraction and no share of the
|
|
151
|
+
* repository: every citation it counts was checked, and the sentence says
|
|
152
|
+
* exactly how far that check went. There is no coverage claim here for an
|
|
153
|
+
* order to qualify, so the clause the caps carry would attach to a sentence
|
|
154
|
+
* that never said it had covered anything.
|
|
155
|
+
*/
|
|
156
|
+
export declare function baselineReadsCappedNote(unchecked: number): string;
|
|
157
|
+
/**
|
|
158
|
+
* Copy for a shallow repository, where blame answers but cannot be believed.
|
|
159
|
+
* Phrased as a skip rather than a partial check, because that is what it is.
|
|
160
|
+
*/
|
|
161
|
+
export declare function shallowRepositoryNote(): string;
|
|
162
|
+
/** Copy for citations whose history could not be read. */
|
|
163
|
+
export declare function blameUnavailableNote(count: number, reason: string): string;
|
|
164
|
+
export type RotKind = "missing_file" | "line_out_of_range" | "quote_absent" | "content_drift";
|
|
165
|
+
export interface CitationRot {
|
|
166
|
+
rot: RotKind;
|
|
167
|
+
citingFile: string;
|
|
168
|
+
citingLine: number;
|
|
169
|
+
citingText: string;
|
|
170
|
+
/** The resolved cited path, not the path as written. */
|
|
171
|
+
citedFile: string;
|
|
172
|
+
citedLine?: number;
|
|
173
|
+
/**
|
|
174
|
+
* The citation's end line, for a range. Absent on `content_drift`, whose
|
|
175
|
+
* `citedLine` is the one line that actually differs rather than the
|
|
176
|
+
* range's start: pairing this end with that start would print a span the
|
|
177
|
+
* prose never wrote. What the prose did write is carried whole in
|
|
178
|
+
* `writtenLine`/`writtenEndLine` below.
|
|
179
|
+
*/
|
|
180
|
+
citedEndLine?: number;
|
|
181
|
+
/**
|
|
182
|
+
* `content_drift` only: the citation exactly as the prose wrote it. Carried
|
|
183
|
+
* apart from `citedLine`, which on a drift names the one line whose content
|
|
184
|
+
* differs, because a drift finding has to say both things and must never
|
|
185
|
+
* mix them. The title and body name this pair — it is the string a reader
|
|
186
|
+
* searches their own document for, and the text they will edit — while the
|
|
187
|
+
* evidence points at the line that actually moved. Separate fields, so no
|
|
188
|
+
* sentence can compose a span out of one number from each.
|
|
189
|
+
*
|
|
190
|
+
* On the other three rot kinds `citedLine`/`citedEndLine` already are the
|
|
191
|
+
* citation as written, and these stay absent.
|
|
192
|
+
*/
|
|
193
|
+
writtenLine?: number;
|
|
194
|
+
writtenEndLine?: number;
|
|
195
|
+
quote?: string;
|
|
196
|
+
/** content_drift only: the first differing line, both sides, truncated. */
|
|
197
|
+
was?: string;
|
|
198
|
+
now?: string;
|
|
199
|
+
/** Abbreviated baseline commit. Absent means history could not be read. */
|
|
200
|
+
baseline?: string;
|
|
201
|
+
/** line_out_of_range only: the cited file's line count at this revision. */
|
|
202
|
+
lineCount?: number;
|
|
203
|
+
/** The cited line's current text, when the file and line exist now. */
|
|
204
|
+
citedText?: string;
|
|
205
|
+
/** True when the reviewed range touched `citedFile`. Proven, not inferred. */
|
|
206
|
+
citedTouched: boolean;
|
|
207
|
+
}
|
|
208
|
+
export interface CitationScanOptions {
|
|
209
|
+
/**
|
|
210
|
+
* Check every citation in the repository rather than only those pointing
|
|
211
|
+
* into files the reviewed range touched. Set by `--citations`.
|
|
212
|
+
*/
|
|
213
|
+
sweep?: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Called once per cap that bit and once for unreadable history, with the
|
|
216
|
+
* sentence the user is owed. An analyzer returns facts and nothing else, so
|
|
217
|
+
* this is the only channel a disclosure has; `review` in `../cli.ts` passes
|
|
218
|
+
* one that pushes into `warnings`. A caller that passes none gets the facts
|
|
219
|
+
* and no indication anything was skipped — the same contract, and the same
|
|
220
|
+
* hazard, as `runAnalyzers`'s `onFailure`.
|
|
221
|
+
*/
|
|
222
|
+
onNote?: (note: string) => void;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* The name the design gives this option bag where the analyzer takes it, and
|
|
226
|
+
* an alias rather than a second declaration on purpose: one field list cannot
|
|
227
|
+
* drift against itself, and the scan half of this module already documents
|
|
228
|
+
* every field above.
|
|
229
|
+
*/
|
|
230
|
+
export type CitationsOptions = CitationScanOptions;
|
|
231
|
+
export declare function parseBlame(out: string): Map<number, string>;
|
|
232
|
+
export declare function findCitationRot(changeset: Changeset, ctx: AnalysisContext, options?: CitationScanOptions): Promise<CitationRot[]>;
|
|
233
|
+
/**
|
|
234
|
+
* Returns its analyzer under a name it states outright, and that is
|
|
235
|
+
* load-bearing: `runAnalyzers` reports a failed analyzer by
|
|
236
|
+
* `analyzers[i].name` in a warning a user reads, and an arrow returned
|
|
237
|
+
* directly from a factory has no name at all, so a citation analyzer that
|
|
238
|
+
* threw would be disclosed as a numbered anonymous one.
|
|
239
|
+
*
|
|
240
|
+
* The other analyzers get their names for free, from NamedEvaluation of the
|
|
241
|
+
* variable declaration they are assigned to. That mechanism is not enough
|
|
242
|
+
* here. This binding sits one scope in and shadows the module-level
|
|
243
|
+
* singleton below, and a transform that renames shadowed symbols to keep
|
|
244
|
+
* every binding unique — esbuild, which is what runs this repository's tests
|
|
245
|
+
* — rewrites the binding, and the inferred name goes with it, turning the
|
|
246
|
+
* disclosed name into a near-miss of itself. So the name is written down
|
|
247
|
+
* rather than derived. See `test/analyze/citations-rot.test.ts`, "names
|
|
248
|
+
* itself when it throws, so the disclosure never says analyzer #N".
|
|
249
|
+
*/
|
|
250
|
+
export declare function makeCitationsAnalyzer(options?: CitationsOptions): Analyzer;
|
|
251
|
+
/**
|
|
252
|
+
* The default-mode instance, and the member of ANALYZERS. Also the identity
|
|
253
|
+
* `review` matches on when it swaps in a configured instance, so it must stay
|
|
254
|
+
* a single shared value rather than being reconstructed per call.
|
|
255
|
+
*/
|
|
256
|
+
export declare const citationsAnalyzer: Analyzer;
|