@ttsc/evidence 0.25.0 → 0.26.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/README.md +24 -6
- package/lib/index.d.ts +7 -2
- package/lib/index.js +7 -2
- package/lib/internal/canonicalDigest.d.ts +1 -0
- package/lib/internal/canonicalDigest.js +97 -0
- package/lib/internal/loadPrismaModels.js +9 -2
- package/lib/internal/loadSwaggerOperations.js +96 -5
- package/lib/structures/ITtscEvidenceGraphReferenceBase.d.ts +48 -0
- package/lib/structures/ITtscEvidenceGraphTypeScriptClaim.d.ts +3 -3
- package/lib/structures/ITtscEvidenceGraphTypeScriptReference.d.ts +4 -4
- package/lib/typings/ITtscLintContributorRules.d.ts +23 -0
- package/lib/typings/TtscEvidenceGraphTypeScriptSymbol.d.ts +64 -29
- package/native/comments.go +162 -0
- package/native/config.go +2 -0
- package/native/declaration.go +213 -0
- package/native/documented.go +12 -12
- package/native/exports.go +64 -7
- package/native/fingerprint.go +351 -0
- package/native/graph.go +252 -16
- package/native/markdown.go +263 -0
- package/native/model.go +179 -1
- package/native/prisma.go +59 -3
- package/native/prisma_cache.go +7 -0
- package/native/review.go +355 -0
- package/native/swagger.go +8 -0
- package/native/typescript.go +697 -64
- package/native/unreadable.go +155 -0
- package/package.json +3 -3
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
package evidence
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"sort"
|
|
5
|
+
"strings"
|
|
6
|
+
|
|
7
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// attachedCommentEnds indexes, by end offset, where each attached documentation
|
|
11
|
+
// block's own text begins.
|
|
12
|
+
//
|
|
13
|
+
// The end is what identifies a comment: the parser stops reading one exactly
|
|
14
|
+
// where the scanner does. A block's reported start is not, because it is a full
|
|
15
|
+
// start, and a full start reaches back to the previous token and swallows every
|
|
16
|
+
// blank line and every comment between. Testing containment against that made
|
|
17
|
+
// the reporter answer differently depending on what followed a tag, so a
|
|
18
|
+
// citation in a `//` comment was reported above an undocumented declaration and
|
|
19
|
+
// silent above a documented one, which is the shape an author is most likely to
|
|
20
|
+
// write in a codebase that documents its exports.
|
|
21
|
+
type attachedCommentEnds map[int]int
|
|
22
|
+
|
|
23
|
+
// holds reports whether a comment is one the parser handed to a node.
|
|
24
|
+
func (ends attachedCommentEnds) holds(start int, end int) bool {
|
|
25
|
+
attachedStart, taken := ends[end]
|
|
26
|
+
return taken && attachedStart <= start
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// reportUnreadableTypeScriptTags records every tag written in a comment the
|
|
30
|
+
// parser attached to no declaration.
|
|
31
|
+
//
|
|
32
|
+
// The graph reads tags only from the blocks a node reports, which is what keeps
|
|
33
|
+
// a citation, the host it lands on, and the exclusion that must cut it out of a
|
|
34
|
+
// digest all naming the same position. A comment the parser attached to nothing
|
|
35
|
+
// is outside that agreement: no node reports it, so the tag in it reaches no
|
|
36
|
+
// host and is not excluded from anything either.
|
|
37
|
+
//
|
|
38
|
+
// Discarding it silently is the failure this rule exists to remove. The comment
|
|
39
|
+
// is real, the file keeps it, and an author reading the source sees a citation
|
|
40
|
+
// that does nothing while the coverage diagnostic that follows names the
|
|
41
|
+
// reference and suggests writing the citation they already wrote.
|
|
42
|
+
//
|
|
43
|
+
// The shapes are ordinary rather than exotic. TypeScript attaches no
|
|
44
|
+
// documentation to a binding element, so a block between the braces of a
|
|
45
|
+
// destructuring pattern is read by nobody; a `//` comment is not documentation
|
|
46
|
+
// at all, which is one keystroke from a block that is; and a documented
|
|
47
|
+
// declaration an author commented out keeps a citation that now proves nothing.
|
|
48
|
+
func reportUnreadableTypeScriptTags(
|
|
49
|
+
file *shimast.SourceFile,
|
|
50
|
+
location string,
|
|
51
|
+
attached attachedCommentEnds,
|
|
52
|
+
inventory *artifactInventory,
|
|
53
|
+
) {
|
|
54
|
+
if file == nil || inventory == nil {
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
content := file.Text()
|
|
58
|
+
forEachComment(file, func(_ shimast.Kind, start int, end int) {
|
|
59
|
+
if start < 0 || end > len(content) || start >= end {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
if attached.holds(start, end) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
body := readableCommentBody(content[start:end])
|
|
66
|
+
baseLine := lineAt(content, start)
|
|
67
|
+
for _, parsed := range parseDeclarations(body) {
|
|
68
|
+
inventory.Unreadable = append(inventory.Unreadable, unreadableTagProblem(
|
|
69
|
+
"@"+string(parsed.Tag),
|
|
70
|
+
location,
|
|
71
|
+
baseLine+parsed.LineOffset,
|
|
72
|
+
))
|
|
73
|
+
}
|
|
74
|
+
for _, review := range parseReviews(body) {
|
|
75
|
+
inventory.Unreadable = append(inventory.Unreadable, unreadableTagProblem(
|
|
76
|
+
review.marker(),
|
|
77
|
+
location,
|
|
78
|
+
baseLine+review.LineOffset,
|
|
79
|
+
))
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// unreadableTagProblem names the position and the moves that fix it, which is
|
|
85
|
+
// the whole value of reporting a tag nothing can read.
|
|
86
|
+
//
|
|
87
|
+
// Two moves rather than one, because the tag reaches nothing for two different
|
|
88
|
+
// reasons. A citation an author meant to keep belongs in a documentation block
|
|
89
|
+
// on a declaration; one left behind in code that is commented out belongs
|
|
90
|
+
// nowhere, and naming only the first would send that author to move a tag they
|
|
91
|
+
// should be deleting.
|
|
92
|
+
func unreadableTagProblem(tag string, location string, line int) string {
|
|
93
|
+
return "Unreadable " + tag + " at " + location + ":" + decimal(line) +
|
|
94
|
+
": the parser attaches this comment to no declaration, so nothing reads the tag." +
|
|
95
|
+
" Move it into a documentation block written directly above the declaration it answers for," +
|
|
96
|
+
" or delete it with the code it was written against." +
|
|
97
|
+
untrueTagWarning
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// readableCommentBody strips the syntax a comment opens with, so a line that
|
|
101
|
+
// carries a tag is recognized by the same reader every other comment goes
|
|
102
|
+
// through.
|
|
103
|
+
//
|
|
104
|
+
// The declaration parser removes `/**`, `/*`, and a leading `*`, because those
|
|
105
|
+
// are the shapes a readable block takes. It does not remove a run of slashes,
|
|
106
|
+
// and it must not learn to: a documentation block's line never opens that way,
|
|
107
|
+
// and teaching the shared parser to accept one would let a `//` line inside a
|
|
108
|
+
// block declare something the graph then reads from an unreadable position.
|
|
109
|
+
//
|
|
110
|
+
// Every run of two or more slashes comes off, so a tag buried behind a third or
|
|
111
|
+
// a fourth is answered like one behind two. They are unreadable for one reason
|
|
112
|
+
// and by one keystroke, and answering only some of them split one comment
|
|
113
|
+
// against itself: the review parser removes `///` and the declaration parser
|
|
114
|
+
// does not, so `/// @evidenceReview` was reported while the `/// @evidence`
|
|
115
|
+
// beside it stayed silent.
|
|
116
|
+
func readableCommentBody(comment string) string {
|
|
117
|
+
lines := strings.Split(comment, "\n")
|
|
118
|
+
for index, line := range lines {
|
|
119
|
+
trimmed := strings.TrimSpace(line)
|
|
120
|
+
if !strings.HasPrefix(trimmed, "//") {
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
lines[index] = strings.TrimSpace(strings.TrimLeft(trimmed, "/"))
|
|
124
|
+
}
|
|
125
|
+
return strings.Join(lines, "\n")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// unreadableTypeScriptTags collects every unreadable tag the scanned TypeScript
|
|
129
|
+
// populations found.
|
|
130
|
+
//
|
|
131
|
+
// One file reached through two configured roots is two inventories of the same
|
|
132
|
+
// text, so the same comment is found twice. The graph's own reporter sorts and
|
|
133
|
+
// drops exact duplicates, which is what collapses them; this only has to gather
|
|
134
|
+
// them in a defined order so its input does not depend on map iteration.
|
|
135
|
+
//
|
|
136
|
+
// Only a file some configured glob selects is reported. A base is a directory
|
|
137
|
+
// and a population is a glob inside it, so a file is scanned whenever it sits
|
|
138
|
+
// under a declared root and belongs to a population only if the glob takes it.
|
|
139
|
+
// Reporting every scanned file made the rule answer for source it does not
|
|
140
|
+
// govern: a stray tag in a consumer's `node_modules` failed their build, naming
|
|
141
|
+
// a repair in a file they did not write.
|
|
142
|
+
func unreadableTypeScriptTags(
|
|
143
|
+
inventories map[string]*artifactInventory,
|
|
144
|
+
governed map[string]bool,
|
|
145
|
+
) []string {
|
|
146
|
+
reported := []string{}
|
|
147
|
+
for address, inventory := range inventories {
|
|
148
|
+
if inventory == nil || !governed[address] {
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
reported = append(reported, inventory.Unreadable...)
|
|
152
|
+
}
|
|
153
|
+
sort.Strings(reported)
|
|
154
|
+
return reported
|
|
155
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/evidence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Evidence-graph lint contributor for @ttsc/lint: declare provenance with a JSDoc @evidence tag and fail the build when it is missing or dangling.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"@types/node": "^25.3.0",
|
|
49
49
|
"rimraf": "^6.1.2",
|
|
50
50
|
"typescript": "^7.0.2",
|
|
51
|
-
"@ttsc/lint": "0.
|
|
52
|
-
"ttsc": "0.
|
|
51
|
+
"@ttsc/lint": "0.26.0",
|
|
52
|
+
"ttsc": "0.26.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@prisma/prisma-schema-wasm": "7.10.0-2.d0368e25c88e68caa4d283b5f2d88d1b76ed9356",
|