@ttsc/evidence 0.28.6 → 0.30.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/lib/structures/ITtscEvidenceGraphClaimBase.d.ts +7 -0
- package/lib/structures/ITtscEvidenceGraphReferenceBase.d.ts +7 -0
- package/lib/structures/ITtscEvidenceGraphTypeScriptReference.d.ts +18 -6
- package/lib/typings/TtscEvidenceGraphTypeScriptSymbol.d.ts +11 -12
- package/native/config.go +43 -47
- package/native/declaration.go +50 -1
- package/native/default_exports.go +62 -0
- package/native/export_resolution.go +275 -0
- package/native/exports.go +62 -144
- package/native/file_link.go +370 -0
- package/native/file_link_diagnostics.go +160 -0
- package/native/fingerprint.go +33 -4
- package/native/graph.go +119 -79
- package/native/imports.go +21 -8
- package/native/inputs.go +13 -4
- package/native/loader.go +170 -23
- package/native/markdown.go +17 -11
- package/native/model.go +16 -4
- package/native/prisma.go +33 -26
- package/native/prisma_cache.go +16 -4
- package/native/rooted_typescript.go +116 -0
- package/native/severity.go +156 -0
- package/native/swagger.go +23 -16
- package/native/typescript.go +33 -14
- package/native/typescript_cache.go +5 -4
- package/native/unreadable.go +5 -6
- package/package.json +6 -6
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
package evidence
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"io/fs"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"sort"
|
|
8
|
+
"strings"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// A rooted reference selects entries from disk and follows their exports only
|
|
12
|
+
// inside its declared root. Ordinary imports do not expand the population.
|
|
13
|
+
func materializeRootedTypeScriptReference(claim claimSpec, reference referenceSpec, loader *typeScriptLoader) (referenceState, []string) {
|
|
14
|
+
state := referenceState{Spec: reference, Healthy: false, UnitsByScope: map[string][]*evidenceUnit{}}
|
|
15
|
+
context := claimLabel(claim) + " " + referenceLabel(reference)
|
|
16
|
+
base := reference.Base
|
|
17
|
+
if info, err := os.Stat(base.Absolute); err != nil || !info.IsDir() {
|
|
18
|
+
cause := "the path names a file"
|
|
19
|
+
if err != nil {
|
|
20
|
+
cause = causeText(err)
|
|
21
|
+
}
|
|
22
|
+
return state, []string{context + " could not read TypeScript reference root '" + populationRootLabel(base) + "': " + cause + ". Select an existing readable directory containing the reference files."}
|
|
23
|
+
}
|
|
24
|
+
from, resolved := resolvedBaseDirectory(base)
|
|
25
|
+
if !resolved {
|
|
26
|
+
return state, []string{unresolvedBaseProblem(base, artifactTypeScript)}
|
|
27
|
+
}
|
|
28
|
+
from, resolved = physicalTypeScriptPath(from)
|
|
29
|
+
if !resolved {
|
|
30
|
+
return state, []string{unresolvedBaseProblem(base, artifactTypeScript)}
|
|
31
|
+
}
|
|
32
|
+
entries := map[string]bool{}
|
|
33
|
+
problems := []string{}
|
|
34
|
+
err := filepath.WalkDir(from, func(current string, entry fs.DirEntry, walkErr error) error {
|
|
35
|
+
if walkErr != nil {
|
|
36
|
+
return walkErr
|
|
37
|
+
}
|
|
38
|
+
relative, err := filepath.Rel(from, current)
|
|
39
|
+
if err != nil {
|
|
40
|
+
return err
|
|
41
|
+
}
|
|
42
|
+
relative = filepath.ToSlash(relative)
|
|
43
|
+
if entry.IsDir() {
|
|
44
|
+
if relative != "." && (entry.Name() == "node_modules" || !reference.Files.couldMatchDescendant(relative)) {
|
|
45
|
+
return filepath.SkipDir
|
|
46
|
+
}
|
|
47
|
+
return nil
|
|
48
|
+
}
|
|
49
|
+
if isTypeScriptPath(relative) && reference.Files.matches(relative) {
|
|
50
|
+
entries[loader.projectPath(base.display(relative))] = true
|
|
51
|
+
}
|
|
52
|
+
return nil
|
|
53
|
+
})
|
|
54
|
+
if err != nil {
|
|
55
|
+
problems = append(problems, context+" could not list TypeScript root '"+populationRootLabel(base)+"': "+causeText(err)+". Restore filesystem access before evaluating coverage.")
|
|
56
|
+
}
|
|
57
|
+
// An open Program snapshot can precede its first save. It is authoritative
|
|
58
|
+
// on the same terms as an edited file that already exists on disk.
|
|
59
|
+
for module := range loader.program {
|
|
60
|
+
identity, resolved := loader.moduleIdentity(module)
|
|
61
|
+
if !resolved {
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
relative, ok := relativeProjectPath(from, resolveProjectPath(loader.identityRoot, identity))
|
|
65
|
+
if ok && reference.Files.matches(relative) {
|
|
66
|
+
entries[loader.projectPath(base.display(relative))] = true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for entry := range entries {
|
|
70
|
+
state.Paths = append(state.Paths, entry)
|
|
71
|
+
}
|
|
72
|
+
sort.Strings(state.Paths)
|
|
73
|
+
confined := *loader
|
|
74
|
+
confined.boundary = &base
|
|
75
|
+
confined.resolved = map[string]string{}
|
|
76
|
+
confined.failures = map[string]string{}
|
|
77
|
+
population := materializeEntryUnits(&confined, state.Paths, reference.Symbols)
|
|
78
|
+
state.Units, state.Hidden, state.Published = population.Units, population.Hidden, population.Published
|
|
79
|
+
state.Code = population.Code
|
|
80
|
+
applyTraversedScopes(&state, population.Reached)
|
|
81
|
+
failed := []string{}
|
|
82
|
+
for module := range confined.failures {
|
|
83
|
+
failed = append(failed, module)
|
|
84
|
+
}
|
|
85
|
+
sort.Strings(failed)
|
|
86
|
+
for _, module := range failed {
|
|
87
|
+
problems = append(problems, context+" could not load TypeScript module '"+module+"': "+confined.failures[module]+". Repair the export or explicitly select a root containing its implementation.")
|
|
88
|
+
}
|
|
89
|
+
state.Healthy = len(problems) == 0
|
|
90
|
+
if !state.Healthy {
|
|
91
|
+
return state, problems
|
|
92
|
+
}
|
|
93
|
+
if len(state.Paths) == 0 {
|
|
94
|
+
return state, []string{context + " matched no typescript files for " + describePopulation(base, reference.Files) + ". Correct the configured root and files."}
|
|
95
|
+
}
|
|
96
|
+
if len(state.Units) == 0 {
|
|
97
|
+
return state, []string{context + " found no selected evidence units (" + reference.Symbols.names() + "). Select symbol kinds present in its exported declarations."}
|
|
98
|
+
}
|
|
99
|
+
return state, nil
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func (loader *typeScriptLoader) withinBoundary(module string) bool {
|
|
103
|
+
if loader.boundary == nil {
|
|
104
|
+
return true
|
|
105
|
+
}
|
|
106
|
+
base, baseOK := loader.moduleIdentity(loader.boundary.Absolute)
|
|
107
|
+
source, sourceOK := loader.moduleIdentity(module)
|
|
108
|
+
if !baseOK || !sourceOK {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
relative, ok := relativeProjectPath(resolveProjectPath(loader.identityRoot, base), resolveProjectPath(loader.identityRoot, source))
|
|
112
|
+
if !ok || strings.Contains("/"+relative+"/", "/node_modules/") {
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
return true
|
|
116
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
package evidence
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"sort"
|
|
6
|
+
|
|
7
|
+
"github.com/samchon/ttsc/packages/lint/rule"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func decodeGraphSeverity(raw json.RawMessage, path string) (*rule.Severity, []string) {
|
|
11
|
+
if len(raw) == 0 {
|
|
12
|
+
return nil, nil
|
|
13
|
+
}
|
|
14
|
+
var severity rule.Severity
|
|
15
|
+
var value any
|
|
16
|
+
if err := json.Unmarshal(raw, &value); err != nil {
|
|
17
|
+
return nil, []string{"Invalid evidence/graph configuration at " + path + ": expected a lint severity value."}
|
|
18
|
+
}
|
|
19
|
+
switch value {
|
|
20
|
+
case "off", float64(0):
|
|
21
|
+
severity = rule.SeverityOff
|
|
22
|
+
case "warning", "warn", float64(1):
|
|
23
|
+
severity = rule.SeverityWarn
|
|
24
|
+
case "error", float64(2):
|
|
25
|
+
severity = rule.SeverityError
|
|
26
|
+
default:
|
|
27
|
+
return nil, []string{"Invalid evidence/graph configuration at " + path + ": expected 'off', 'warning', 'warn', 'error', 0, 1, or 2; omit severity or use undefined to inherit the enclosing level."}
|
|
28
|
+
}
|
|
29
|
+
return &severity, nil
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Resolve inheritance once, before populations are loaded. A nil severity is
|
|
33
|
+
// unset; an explicit zero disables its population.
|
|
34
|
+
func resolveGraphSeverities(config *graphConfig, severity rule.Severity) {
|
|
35
|
+
for i := range config.Claims {
|
|
36
|
+
claim := &config.Claims[i]
|
|
37
|
+
claim.Level = severity
|
|
38
|
+
if claim.Severity != nil {
|
|
39
|
+
claim.Level = *claim.Severity
|
|
40
|
+
}
|
|
41
|
+
for j := range claim.References {
|
|
42
|
+
reference := &claim.References[j]
|
|
43
|
+
reference.Level = claim.Level
|
|
44
|
+
if reference.Severity != nil {
|
|
45
|
+
reference.Level = *reference.Severity
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type graphDiagnostic struct {
|
|
52
|
+
Message string
|
|
53
|
+
Severity rule.Severity
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type graphDiagnostics []graphDiagnostic
|
|
57
|
+
|
|
58
|
+
func (problems graphDiagnostics) add(severity rule.Severity, messages ...string) graphDiagnostics {
|
|
59
|
+
for _, message := range messages {
|
|
60
|
+
problems = append(problems, graphDiagnostic{Message: message, Severity: severity})
|
|
61
|
+
}
|
|
62
|
+
return problems
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func (problems graphDiagnostics) report(ctx *rule.ProjectContext) {
|
|
66
|
+
levels := map[string]rule.Severity{}
|
|
67
|
+
for _, problem := range problems {
|
|
68
|
+
levels[problem.Message] = max(levels[problem.Message], problem.Severity)
|
|
69
|
+
}
|
|
70
|
+
messages := make([]string, 0, len(levels))
|
|
71
|
+
for message := range levels {
|
|
72
|
+
messages = append(messages, message)
|
|
73
|
+
}
|
|
74
|
+
sort.Strings(messages)
|
|
75
|
+
for _, message := range messages {
|
|
76
|
+
ctx.ReportSeverity(levels[message], message)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// A shared source problem belongs to every population that reads it. Keep the
|
|
81
|
+
// strongest owning level without pooling independent coverage obligations.
|
|
82
|
+
func populationSeverity(config graphConfig, kind artifactKind, base populationBase, path string, symbol string, descendants bool) rule.Severity {
|
|
83
|
+
var severity rule.Severity
|
|
84
|
+
matches := func(candidate populationBase, files globSet, symbols symbolSet) bool {
|
|
85
|
+
return candidate.Absolute == base.Absolute &&
|
|
86
|
+
(path == "" || files.matches(path) || descendants && files.couldMatchDescendant(path)) &&
|
|
87
|
+
(symbol == "*" || symbols.contains(symbol))
|
|
88
|
+
}
|
|
89
|
+
for _, claim := range config.Claims {
|
|
90
|
+
if claim.Type == kind && matches(claim.Base, claim.Files, claim.Symbols) {
|
|
91
|
+
severity = max(severity, claim.Level)
|
|
92
|
+
}
|
|
93
|
+
for _, reference := range claim.References {
|
|
94
|
+
if reference.Type == kind && reference.Package == "" && matches(reference.Base, reference.Files, reference.Symbols) {
|
|
95
|
+
severity = max(severity, reference.Level)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return severity
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func artifactSeverity(config graphConfig, kind artifactKind) rule.Severity {
|
|
103
|
+
var severity rule.Severity
|
|
104
|
+
for _, claim := range config.Claims {
|
|
105
|
+
if claim.Type == kind {
|
|
106
|
+
severity = max(severity, claim.Level)
|
|
107
|
+
}
|
|
108
|
+
for _, reference := range claim.References {
|
|
109
|
+
if reference.Type == kind {
|
|
110
|
+
severity = max(severity, reference.Level)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return severity
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
func swaggerSeverity(config graphConfig, source string) rule.Severity {
|
|
118
|
+
var severity rule.Severity
|
|
119
|
+
for _, claim := range config.Claims {
|
|
120
|
+
for _, reference := range claim.References {
|
|
121
|
+
if reference.Type == artifactSwagger && reference.Source == source {
|
|
122
|
+
severity = max(severity, reference.Level)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return severity
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func ownerSeverity(owners []claimState) rule.Severity {
|
|
130
|
+
var severity rule.Severity
|
|
131
|
+
for _, owner := range owners {
|
|
132
|
+
severity = max(severity, owner.Spec.Level)
|
|
133
|
+
}
|
|
134
|
+
return severity
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
func inventorySeverity(config graphConfig, kind artifactKind, address string, symbol string) rule.Severity {
|
|
138
|
+
var severity rule.Severity
|
|
139
|
+
for _, base := range configuredBases(config, kind) {
|
|
140
|
+
if relative, ok := base.relativeOf(address); ok {
|
|
141
|
+
severity = max(severity, populationSeverity(config, kind, base, relative, symbol, false))
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return severity
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Empty or failed populations contribute no file to the shared Prisma parse.
|
|
148
|
+
func prismaSetSeverity(config graphConfig, inventories map[string]*artifactInventory) rule.Severity {
|
|
149
|
+
var severity rule.Severity
|
|
150
|
+
for address, inventory := range inventories {
|
|
151
|
+
if inventory != nil && inventory.FailureBase == "" {
|
|
152
|
+
severity = max(severity, inventorySeverity(config, artifactPrisma, address, "*"))
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return severity
|
|
156
|
+
}
|
package/native/swagger.go
CHANGED
|
@@ -11,6 +11,8 @@ import (
|
|
|
11
11
|
"sort"
|
|
12
12
|
"strings"
|
|
13
13
|
"time"
|
|
14
|
+
|
|
15
|
+
"github.com/samchon/ttsc/packages/lint/rule"
|
|
14
16
|
)
|
|
15
17
|
|
|
16
18
|
const swaggerBridgeTimeout = 60 * time.Second
|
|
@@ -94,7 +96,7 @@ type swaggerOperation struct {
|
|
|
94
96
|
func loadSwaggerInventories(
|
|
95
97
|
root string,
|
|
96
98
|
config graphConfig,
|
|
97
|
-
) (map[string]*artifactInventory,
|
|
99
|
+
) (map[string]*artifactInventory, graphDiagnostics) {
|
|
98
100
|
sources := configuredSwaggerSources(config)
|
|
99
101
|
inventories := map[string]*artifactInventory{}
|
|
100
102
|
for _, source := range sources {
|
|
@@ -114,15 +116,16 @@ func loadSwaggerInventories(
|
|
|
114
116
|
// TypeScript keystroke that triggers a rebuild.
|
|
115
117
|
digests := swaggerContentDigests(root, sources)
|
|
116
118
|
pending := []string{}
|
|
117
|
-
problems :=
|
|
119
|
+
problems := graphDiagnostics{}
|
|
120
|
+
severity := artifactSeverity(config, artifactSwagger)
|
|
118
121
|
for _, source := range sources {
|
|
119
122
|
outcome, hit := lookupSwaggerDocument(source, digests[source])
|
|
120
123
|
if !hit {
|
|
121
124
|
pending = append(pending, source)
|
|
122
125
|
continue
|
|
123
126
|
}
|
|
124
|
-
problems =
|
|
125
|
-
|
|
127
|
+
problems = problems.add(
|
|
128
|
+
swaggerSeverity(config, source),
|
|
126
129
|
swaggerUnitsFromOutcome(source, inventories[source], outcome)...,
|
|
127
130
|
)
|
|
128
131
|
}
|
|
@@ -140,30 +143,34 @@ func loadSwaggerInventories(
|
|
|
140
143
|
inventoryProblem{Symbol: "operation", Message: message},
|
|
141
144
|
)
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
var pendingSeverity rule.Severity
|
|
147
|
+
for _, source := range pending {
|
|
148
|
+
pendingSeverity = max(pendingSeverity, swaggerSeverity(config, source))
|
|
149
|
+
}
|
|
150
|
+
return inventories, problems.add(pendingSeverity, message)
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
seen := map[string]bool{}
|
|
147
154
|
for _, document := range result.Documents {
|
|
148
155
|
inventory := inventories[document.Source]
|
|
149
156
|
if inventory == nil {
|
|
150
|
-
problems =
|
|
151
|
-
|
|
157
|
+
problems = problems.add(
|
|
158
|
+
severity,
|
|
152
159
|
"Evidence graph Swagger normalizer returned an unconfigured source '"+displaySwaggerSource(document.Source)+"'. Reinstall @ttsc/evidence; the native and JavaScript bridge contracts disagree.",
|
|
153
160
|
)
|
|
154
161
|
continue
|
|
155
162
|
}
|
|
156
163
|
if seen[document.Source] {
|
|
157
|
-
problems =
|
|
158
|
-
|
|
164
|
+
problems = problems.add(
|
|
165
|
+
swaggerSeverity(config, document.Source),
|
|
159
166
|
"Evidence graph Swagger normalizer returned source '"+displaySwaggerSource(document.Source)+"' more than once. Reinstall @ttsc/evidence; the native and JavaScript bridge contracts disagree.",
|
|
160
167
|
)
|
|
161
168
|
continue
|
|
162
169
|
}
|
|
163
170
|
seen[document.Source] = true
|
|
164
171
|
outcome := swaggerDocumentOutcome{Operations: document.Operations}
|
|
165
|
-
problems =
|
|
166
|
-
|
|
172
|
+
problems = problems.add(
|
|
173
|
+
swaggerSeverity(config, document.Source),
|
|
167
174
|
swaggerUnitsFromOutcome(document.Source, inventory, outcome)...,
|
|
168
175
|
)
|
|
169
176
|
rememberSwaggerDocument(document.Source, document.Digest, outcome)
|
|
@@ -171,8 +178,8 @@ func loadSwaggerInventories(
|
|
|
171
178
|
for _, problem := range result.Problems {
|
|
172
179
|
inventory := inventories[problem.Source]
|
|
173
180
|
if inventory == nil {
|
|
174
|
-
problems =
|
|
175
|
-
|
|
181
|
+
problems = problems.add(
|
|
182
|
+
severity,
|
|
176
183
|
"Evidence graph Swagger normalizer rejected an unconfigured source '"+displaySwaggerSource(problem.Source)+"'. Reinstall @ttsc/evidence; the native and JavaScript bridge contracts disagree.",
|
|
177
184
|
)
|
|
178
185
|
continue
|
|
@@ -182,8 +189,8 @@ func loadSwaggerInventories(
|
|
|
182
189
|
Rejected: true,
|
|
183
190
|
Problem: problem.Message,
|
|
184
191
|
}
|
|
185
|
-
problems =
|
|
186
|
-
|
|
192
|
+
problems = problems.add(
|
|
193
|
+
swaggerSeverity(config, problem.Source),
|
|
187
194
|
swaggerUnitsFromOutcome(problem.Source, inventory, outcome)...,
|
|
188
195
|
)
|
|
189
196
|
rememberSwaggerDocument(problem.Source, problem.Digest, outcome)
|
|
@@ -198,7 +205,7 @@ func loadSwaggerInventories(
|
|
|
198
205
|
inventories[source].Problems,
|
|
199
206
|
inventoryProblem{Symbol: "operation", Message: message},
|
|
200
207
|
)
|
|
201
|
-
problems =
|
|
208
|
+
problems = problems.add(swaggerSeverity(config, source), message)
|
|
202
209
|
}
|
|
203
210
|
return inventories, problems
|
|
204
211
|
}
|
package/native/typescript.go
CHANGED
|
@@ -71,16 +71,13 @@ func extendTypeScriptInventories(
|
|
|
71
71
|
// three kinds converge: health alone now decides that the claim stays active,
|
|
72
72
|
// and the population it names is the one the author has to repair.
|
|
73
73
|
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
// refused a `root` outright, so every reference base of this kind is the default
|
|
77
|
-
// one, which this pass leaves alone: `baseDirectoryProblem` returns on it, and
|
|
78
|
-
// the resolver question below is asked only of a root someone declared.
|
|
74
|
+
// Check passes claim populations here. Rooted references validate their disk
|
|
75
|
+
// directories after claim activation in materializeRootedTypeScriptReference.
|
|
79
76
|
func typeScriptBaseProblems(
|
|
80
77
|
config graphConfig,
|
|
81
78
|
inventories map[string]*artifactInventory,
|
|
82
|
-
)
|
|
83
|
-
problems :=
|
|
79
|
+
) graphDiagnostics {
|
|
80
|
+
problems := graphDiagnostics{}
|
|
84
81
|
for _, base := range configuredBases(config, artifactTypeScript) {
|
|
85
82
|
problem := baseDirectoryProblem(base, artifactTypeScript)
|
|
86
83
|
// The stat accepts a chain of links the resolver will not finish, and this
|
|
@@ -111,7 +108,7 @@ func typeScriptBaseProblems(
|
|
|
111
108
|
continue
|
|
112
109
|
}
|
|
113
110
|
recordPopulationFailure(inventories, artifactTypeScript, base)
|
|
114
|
-
problems =
|
|
111
|
+
problems = problems.add(populationSeverity(config, artifactTypeScript, base, "", "*", false), problem)
|
|
115
112
|
}
|
|
116
113
|
return problems
|
|
117
114
|
}
|
|
@@ -245,6 +242,7 @@ func scanTypeScriptInventoryAt(
|
|
|
245
242
|
file *shimast.SourceFile,
|
|
246
243
|
) *artifactInventory {
|
|
247
244
|
inventory := &artifactInventory{
|
|
245
|
+
Source: file,
|
|
248
246
|
Address: address.Key,
|
|
249
247
|
Path: address.Display,
|
|
250
248
|
Type: artifactTypeScript,
|
|
@@ -528,7 +526,7 @@ func collectTypeScriptStatements(
|
|
|
528
526
|
if typeOnlyProjection {
|
|
529
527
|
continue
|
|
530
528
|
}
|
|
531
|
-
name :=
|
|
529
|
+
name := typeScriptDeclarationName(statement)
|
|
532
530
|
if name == "" {
|
|
533
531
|
continue
|
|
534
532
|
}
|
|
@@ -583,7 +581,7 @@ func collectTypeScriptStatements(
|
|
|
583
581
|
addTypeScriptHost(supportedHosts, statement, symbol)
|
|
584
582
|
}
|
|
585
583
|
case shimast.KindClassDeclaration:
|
|
586
|
-
name :=
|
|
584
|
+
name := typeScriptDeclarationName(statement)
|
|
587
585
|
if name == "" {
|
|
588
586
|
continue
|
|
589
587
|
}
|
|
@@ -1377,7 +1375,7 @@ func collectHiddenDeclarationNames(
|
|
|
1377
1375
|
if statement == nil {
|
|
1378
1376
|
continue
|
|
1379
1377
|
}
|
|
1380
|
-
name :=
|
|
1378
|
+
name := typeScriptDeclarationName(statement)
|
|
1381
1379
|
if name == "" {
|
|
1382
1380
|
continue
|
|
1383
1381
|
}
|
|
@@ -1701,6 +1699,12 @@ func walkTypeScriptNode(node *shimast.Node, visit func(*shimast.Node)) {
|
|
|
1701
1699
|
type exportedName struct {
|
|
1702
1700
|
Public string
|
|
1703
1701
|
TypeOnly bool
|
|
1702
|
+
// IdentityOnly materializes a default's local declaration without
|
|
1703
|
+
// publishing its binding as a named export.
|
|
1704
|
+
IdentityOnly bool
|
|
1705
|
+
// ValueIdentity retains the value side needed by a default alias while
|
|
1706
|
+
// TypeOnly still describes this named export's public restriction.
|
|
1707
|
+
ValueIdentity bool
|
|
1704
1708
|
}
|
|
1705
1709
|
|
|
1706
1710
|
func collectLocalExportNames(
|
|
@@ -1748,6 +1752,21 @@ func collectLocalExportNames(
|
|
|
1748
1752
|
})
|
|
1749
1753
|
}
|
|
1750
1754
|
}
|
|
1755
|
+
for local, binding := range collectDefaultExportBindings(statements) {
|
|
1756
|
+
if len(exports[local]) == 0 {
|
|
1757
|
+
binding.IdentityOnly = true
|
|
1758
|
+
exports[local] = []exportedName{binding}
|
|
1759
|
+
} else if !binding.TypeOnly {
|
|
1760
|
+
selected := 0
|
|
1761
|
+
for index, name := range exports[local] {
|
|
1762
|
+
current := exports[local][selected]
|
|
1763
|
+
if current.TypeOnly && !name.TypeOnly || current.TypeOnly == name.TypeOnly && name.Public < current.Public {
|
|
1764
|
+
selected = index
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
exports[local][selected].ValueIdentity = true
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1751
1770
|
return exports
|
|
1752
1771
|
}
|
|
1753
1772
|
|
|
@@ -1787,6 +1806,9 @@ func publicTypeScriptExports(
|
|
|
1787
1806
|
names[local] = exportedName{Public: local}
|
|
1788
1807
|
}
|
|
1789
1808
|
for _, exported := range exports[local] {
|
|
1809
|
+
if exported.ValueIdentity {
|
|
1810
|
+
exported.TypeOnly = false
|
|
1811
|
+
}
|
|
1790
1812
|
if exported.TypeOnly && !allowTypeOnly {
|
|
1791
1813
|
continue
|
|
1792
1814
|
}
|
|
@@ -1820,9 +1842,6 @@ func declarationName(node *shimast.Node) string {
|
|
|
1820
1842
|
shimast.KindStringLiteral,
|
|
1821
1843
|
shimast.KindNumericLiteral:
|
|
1822
1844
|
name := node.Text()
|
|
1823
|
-
if containsWhitespace(name) {
|
|
1824
|
-
return ""
|
|
1825
|
-
}
|
|
1826
1845
|
return name
|
|
1827
1846
|
default:
|
|
1828
1847
|
return ""
|
|
@@ -29,11 +29,12 @@ import (
|
|
|
29
29
|
// depend on the hit.
|
|
30
30
|
var typeScriptInventories = newTypeScriptInventoryCache()
|
|
31
31
|
|
|
32
|
-
// typeScriptInventoryKey identifies one scan.
|
|
33
|
-
//
|
|
34
|
-
//
|
|
32
|
+
// typeScriptInventoryKey identifies one scan. Both the unit address and display
|
|
33
|
+
// path belong to its result. Root aliases can share unit IDs while a file has
|
|
34
|
+
// different project-relative paths; reusing the old path can read another file.
|
|
35
35
|
type typeScriptInventoryKey struct {
|
|
36
36
|
address string
|
|
37
|
+
display string
|
|
37
38
|
file *shimast.SourceFile
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -69,7 +70,7 @@ func (cache *typeScriptInventoryCache) scan(
|
|
|
69
70
|
if cache == nil || file == nil {
|
|
70
71
|
return scanTypeScriptInventoryAt(address, file)
|
|
71
72
|
}
|
|
72
|
-
key := typeScriptInventoryKey{address: address.Key, file: file}
|
|
73
|
+
key := typeScriptInventoryKey{address: address.Key, display: address.Display, file: file}
|
|
73
74
|
cache.mutex.Lock()
|
|
74
75
|
if inventory, hit := cache.live[key]; hit {
|
|
75
76
|
cache.mutex.Unlock()
|
package/native/unreadable.go
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package evidence
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
"sort"
|
|
5
4
|
"strings"
|
|
6
5
|
|
|
7
6
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
@@ -142,14 +141,14 @@ func readableCommentBody(comment string) string {
|
|
|
142
141
|
func unreadableTypeScriptTags(
|
|
143
142
|
inventories map[string]*artifactInventory,
|
|
144
143
|
governed map[string]bool,
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
config graphConfig,
|
|
145
|
+
) graphDiagnostics {
|
|
146
|
+
reported := graphDiagnostics{}
|
|
147
147
|
for address, inventory := range inventories {
|
|
148
|
-
if inventory == nil || !governed[address] {
|
|
148
|
+
if inventory == nil || len(inventory.Unreadable) == 0 || !governed[address] {
|
|
149
149
|
continue
|
|
150
150
|
}
|
|
151
|
-
reported =
|
|
151
|
+
reported = reported.add(inventorySeverity(config, artifactTypeScript, address, "*"), inventory.Unreadable...)
|
|
152
152
|
}
|
|
153
|
-
sort.Strings(reported)
|
|
154
153
|
return reported
|
|
155
154
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/evidence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.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": {
|
|
@@ -42,19 +42,19 @@
|
|
|
42
42
|
"url": "https://github.com/samchon/ttsc/issues"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@ttsc/lint": "
|
|
45
|
+
"@ttsc/lint": ">0.28.6"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
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.30.0",
|
|
52
|
+
"ttsc": "0.30.0"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@prisma/prisma-schema-wasm": "7.10.0-2.d0368e25c88e68caa4d283b5f2d88d1b76ed9356",
|
|
56
|
-
"@typia/interface": "14.0.
|
|
57
|
-
"@typia/utils": "14.0.
|
|
56
|
+
"@typia/interface": "^14.0.6",
|
|
57
|
+
"@typia/utils": "^14.0.6",
|
|
58
58
|
"yaml": "^2.9.0"
|
|
59
59
|
},
|
|
60
60
|
"homepage": "https://ttsc.dev",
|