@ttsc/evidence 0.29.0 → 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/ITtscEvidenceGraphTypeScriptReference.d.ts +18 -6
- package/lib/typings/TtscEvidenceGraphTypeScriptSymbol.d.ts +11 -12
- package/native/config.go +12 -35
- 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 +38 -8
- package/native/imports.go +21 -8
- package/native/inputs.go +13 -4
- package/native/loader.go +170 -23
- package/native/model.go +10 -3
- package/native/rooted_typescript.go +116 -0
- package/native/typescript.go +30 -11
- package/native/typescript_cache.go +5 -4
- package/package.json +5 -5
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
package evidence
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"sort"
|
|
5
|
+
|
|
6
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// Diagnostic inspection never creates an obligation. It distinguishes a
|
|
10
|
+
// declaration the collector intentionally withheld from a misspelled address.
|
|
11
|
+
func diagnoseFileLinkTarget(loader *typeScriptLoader, module string, segments []string, where string) string {
|
|
12
|
+
inventory := loader.inventory(module)
|
|
13
|
+
if inventory == nil {
|
|
14
|
+
return "Unreadable TypeScript evidence target" + where + ": " + loader.failure(module) + ". Restore the configured source file."
|
|
15
|
+
}
|
|
16
|
+
resolver := newTypeScriptExportResolver(loader, []string{module})
|
|
17
|
+
if len(resolver.lookup(module, segments, false)) != 0 {
|
|
18
|
+
return "Unselected TypeScript evidence target" + where + ": the declaration exists but this reference's files or symbol selection does not admit it. Select its symbol kind or cite a selected declaration."
|
|
19
|
+
}
|
|
20
|
+
exports := resolver.accessor(module, segments, nil, false, false)
|
|
21
|
+
sort.SliceStable(exports, func(left, right int) bool { return len(exports[left].Address) > len(exports[right].Address) })
|
|
22
|
+
for _, exported := range exports {
|
|
23
|
+
if exported.Local == "" {
|
|
24
|
+
namespace := formatFileAccessor(exported.Address)
|
|
25
|
+
if len(exported.Address) == len(segments) {
|
|
26
|
+
return "Unsupported TypeScript evidence target" + where + ": '" + namespace + "' is a module namespace, not a declared evidence unit. Cite a supported declaration inside it."
|
|
27
|
+
}
|
|
28
|
+
return "Missing TypeScript evidence export" + where + ": the module namespace '" + namespace + "' exports no declaration named '" + segments[len(exported.Address)] + "'. Correct the name inside that namespace."
|
|
29
|
+
}
|
|
30
|
+
if len(exported.Address) > len(segments) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
if encodeTypeScriptIdentity(exported.Address) != encodeTypeScriptIdentity(segments[:len(exported.Address)]) {
|
|
34
|
+
continue
|
|
35
|
+
}
|
|
36
|
+
source := loader.inventory(exported.Path)
|
|
37
|
+
if source == nil || source.Source == nil {
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
local := exported.Local
|
|
41
|
+
// Inventories use public local aliases, while the AST uses bindings.
|
|
42
|
+
for _, entry := range source.Exports {
|
|
43
|
+
if entry.Specifier == "" && entry.Public == local && entry.Local != "" {
|
|
44
|
+
local = entry.Local
|
|
45
|
+
break
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
tail := append([]string{local}, segments[len(exported.Address):]...)
|
|
49
|
+
if exported.TypeOnly {
|
|
50
|
+
identity := append([]string{exported.Local}, segments[len(exported.Address):]...)
|
|
51
|
+
for _, unit := range source.Units {
|
|
52
|
+
if unit.ValueSpace && !unit.TypeSpace && encodeTypeScriptIdentity(unit.Identity) == encodeTypeScriptIdentity(identity) {
|
|
53
|
+
return "Type-only TypeScript evidence target" + where + ": this export exposes no value through which the member can be addressed. Use a public value export or cite its type."
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if cause := inspectUnavailableDeclaration(source.Source.Statements, tail); cause != "" {
|
|
58
|
+
return "Unsupported TypeScript evidence target" + where + ": " + cause + ". Cite a supported public declaration."
|
|
59
|
+
}
|
|
60
|
+
if len(segments) > len(exported.Address) {
|
|
61
|
+
return "Missing TypeScript evidence member" + where + ": the exported declaration has no addressable member '" + formatFileAccessor(segments[len(exported.Address):]) + "'. Correct the member name and use '.prototype' for an instance member."
|
|
62
|
+
}
|
|
63
|
+
return "Unsupported TypeScript evidence declaration" + where + ": the export is not a supported type, function, or property unit. Cite a supported declaration."
|
|
64
|
+
}
|
|
65
|
+
if inventory.Source != nil && inventory.Source.Statements != nil {
|
|
66
|
+
for _, statement := range inventory.Source.Statements.Nodes {
|
|
67
|
+
if statement == nil {
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
for _, declared := range topLevelDeclaredNames(statement) {
|
|
71
|
+
if declared.Name == segments[0] {
|
|
72
|
+
return "Unexported TypeScript evidence declaration" + where + ": '" + segments[0] + "' is a local binding, not a public export of this module. Use its public alias or default export."
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if cause := inspectUnavailableDeclaration(inventory.Source.Statements, segments); cause != "" {
|
|
78
|
+
return "Unsupported TypeScript evidence target" + where + ": " + cause + ". Export a supported declaration or correct the target."
|
|
79
|
+
}
|
|
80
|
+
return "Missing TypeScript evidence export" + where + ": the module exports no declaration named '" + segments[0] + "'. Use its public export name or correct the file."
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func inspectUnavailableDeclaration(statements *shimast.NodeList, segments []string) string {
|
|
84
|
+
if statements == nil || len(segments) == 0 {
|
|
85
|
+
return ""
|
|
86
|
+
}
|
|
87
|
+
for _, statement := range statements.Nodes {
|
|
88
|
+
if statement == nil {
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
if typeScriptDeclarationName(statement) != segments[0] {
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
if len(segments) == 1 {
|
|
95
|
+
if !isSyntacticallyExported(statement) {
|
|
96
|
+
return "the declaration is not exported"
|
|
97
|
+
}
|
|
98
|
+
return "the declaration form is not supported by the evidence unit model"
|
|
99
|
+
}
|
|
100
|
+
tail := segments[1:]
|
|
101
|
+
var members *shimast.NodeList
|
|
102
|
+
class := statement.Kind == shimast.KindClassDeclaration
|
|
103
|
+
switch statement.Kind {
|
|
104
|
+
case shimast.KindClassDeclaration:
|
|
105
|
+
members = statement.AsClassDeclaration().Members
|
|
106
|
+
case shimast.KindInterfaceDeclaration:
|
|
107
|
+
members = statement.AsInterfaceDeclaration().Members
|
|
108
|
+
case shimast.KindTypeAliasDeclaration:
|
|
109
|
+
node := statement.AsTypeAliasDeclaration().Type
|
|
110
|
+
if node != nil && node.Kind == shimast.KindTypeLiteral {
|
|
111
|
+
members = node.AsTypeLiteralNode().Members
|
|
112
|
+
}
|
|
113
|
+
case shimast.KindModuleDeclaration:
|
|
114
|
+
body := statement.AsModuleDeclaration().Body
|
|
115
|
+
if body != nil && body.Kind == shimast.KindModuleBlock {
|
|
116
|
+
return inspectUnavailableDeclaration(body.AsModuleBlock().Statements, tail)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
instance := class && len(tail) > 1 && tail[0] == "prototype"
|
|
120
|
+
if instance {
|
|
121
|
+
tail = tail[1:]
|
|
122
|
+
}
|
|
123
|
+
if members == nil || len(tail) != 1 {
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
for _, member := range members.Nodes {
|
|
127
|
+
if member != nil && member.Kind == shimast.KindConstructor && instance {
|
|
128
|
+
for _, parameter := range member.Parameters() {
|
|
129
|
+
if parameter != nil && isParameterProperty(parameter) && declarationName(parameter.Name()) == tail[0] && !isPublicClassMember(parameter) {
|
|
130
|
+
return "the member is private or protected"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if member == nil || member.Name() == nil {
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
name := member.Name()
|
|
138
|
+
if name.Kind != shimast.KindIdentifier && name.Kind != shimast.KindPrivateIdentifier && name.Kind != shimast.KindStringLiteral && name.Kind != shimast.KindNumericLiteral {
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
if name.Text() != tail[0] {
|
|
142
|
+
continue
|
|
143
|
+
}
|
|
144
|
+
if class {
|
|
145
|
+
static := shimast.GetCombinedModifierFlags(member)&shimast.ModifierFlagsStatic != 0
|
|
146
|
+
if static == instance {
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
if !isPublicClassMember(member) || name.Kind == shimast.KindPrivateIdentifier {
|
|
150
|
+
return "the member is private or protected"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if member.Kind == shimast.KindGetAccessor || member.Kind == shimast.KindSetAccessor || member.ModifierFlags()&shimast.ModifierFlagsAccessor != 0 {
|
|
154
|
+
return "accessors are not evidence units"
|
|
155
|
+
}
|
|
156
|
+
return "the member is not exposed as a supported public evidence unit"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return ""
|
|
160
|
+
}
|
package/native/fingerprint.go
CHANGED
|
@@ -161,12 +161,12 @@ func (index *scopeIndex) compute(rootID string) string {
|
|
|
161
161
|
if len(scope) == 0 {
|
|
162
162
|
return ""
|
|
163
163
|
}
|
|
164
|
-
// Ordered by
|
|
164
|
+
// Ordered by identity rather than by walk order, so the value does not depend
|
|
165
165
|
// on which file the loader happened to read first, and by symbol as well
|
|
166
166
|
// because two same-titled Markdown headings answer to one anchor.
|
|
167
167
|
sort.Slice(scope, func(left int, right int) bool {
|
|
168
|
-
if scope[left]
|
|
169
|
-
return scope[left]
|
|
168
|
+
if fingerprintIdentity(scope[left]) != fingerprintIdentity(scope[right]) {
|
|
169
|
+
return fingerprintIdentity(scope[left]) < fingerprintIdentity(scope[right])
|
|
170
170
|
}
|
|
171
171
|
if scope[left].Symbol != scope[right].Symbol {
|
|
172
172
|
return scope[left].Symbol < scope[right].Symbol
|
|
@@ -178,7 +178,7 @@ func (index *scopeIndex) compute(rootID string) string {
|
|
|
178
178
|
// NUL separates the fields because a target may contain any printable
|
|
179
179
|
// character, and a joined pair that can be re-split ambiguously lets two
|
|
180
180
|
// different scopes compose one digest.
|
|
181
|
-
composite.Write([]byte(unit
|
|
181
|
+
composite.Write([]byte(fingerprintIdentity(unit)))
|
|
182
182
|
composite.Write([]byte{0})
|
|
183
183
|
composite.Write([]byte(unit.Symbol))
|
|
184
184
|
composite.Write([]byte{0})
|
|
@@ -188,6 +188,35 @@ func (index *scopeIndex) compute(rootID string) string {
|
|
|
188
188
|
return presentedFingerprint(hex.EncodeToString(composite.Sum(nil)))
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
func fingerprintIdentity(unit *evidenceUnit) string {
|
|
192
|
+
if unit.Type == artifactTypeScript {
|
|
193
|
+
return unit.ID
|
|
194
|
+
}
|
|
195
|
+
return unit.Target
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// A code review fingerprints the declaring inventory, before any public alias
|
|
199
|
+
// or type-only edge projects its surface. Selection controls permission and
|
|
200
|
+
// coverage; it cannot make one citation require multiple content fingerprints.
|
|
201
|
+
func referenceReviewScopes(reference referenceState, loader *typeScriptLoader) *scopeIndex {
|
|
202
|
+
units := append(append([]*evidenceUnit{}, reference.Population...), reference.Hidden...)
|
|
203
|
+
if reference.Spec.Type != artifactTypeScript {
|
|
204
|
+
return newScopeIndex(units)
|
|
205
|
+
}
|
|
206
|
+
seen := map[string]bool{}
|
|
207
|
+
canonical := []*evidenceUnit{}
|
|
208
|
+
for _, unit := range units {
|
|
209
|
+
if seen[unit.Path] {
|
|
210
|
+
continue
|
|
211
|
+
}
|
|
212
|
+
seen[unit.Path] = true
|
|
213
|
+
if inventory := loader.inventory(unit.Path); inventory != nil {
|
|
214
|
+
canonical = append(canonical, inventory.Units...)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return newScopeIndex(canonical)
|
|
218
|
+
}
|
|
219
|
+
|
|
191
220
|
// scopeContribution is what one unit adds to its scope's composite.
|
|
192
221
|
//
|
|
193
222
|
// A withdrawn unit contributes the tag that withdrew it. That is what makes a
|
package/native/graph.go
CHANGED
|
@@ -378,6 +378,12 @@ func materializeClaimStates(
|
|
|
378
378
|
continue
|
|
379
379
|
}
|
|
380
380
|
if reference.Type == artifactTypeScript {
|
|
381
|
+
if reference.Rooted {
|
|
382
|
+
rootedState, rootedProblems := materializeRootedTypeScriptReference(claim, reference, loader)
|
|
383
|
+
problems = problems.add(severity, rootedProblems...)
|
|
384
|
+
state.References = append(state.References, rootedState)
|
|
385
|
+
continue
|
|
386
|
+
}
|
|
381
387
|
localState, localProblems := materializeLocalTypeScriptReference(
|
|
382
388
|
claim,
|
|
383
389
|
reference,
|
|
@@ -607,6 +613,7 @@ func evaluateEvidenceGraph(
|
|
|
607
613
|
sort.Strings(declarationIDs)
|
|
608
614
|
|
|
609
615
|
resolved := map[string]string{}
|
|
616
|
+
fileLinks := indexFileLinkClaims(states, loader)
|
|
610
617
|
for _, id := range declarationIDs {
|
|
611
618
|
severity := ownerSeverity(owners[id])
|
|
612
619
|
declaration := declarations[id]
|
|
@@ -618,12 +625,23 @@ func evaluateEvidenceGraph(
|
|
|
618
625
|
)
|
|
619
626
|
continue
|
|
620
627
|
}
|
|
628
|
+
if isFileLinkTarget(declaration.Target) {
|
|
629
|
+
unitID, problem := resolveFileLinkDeclaration(declaration, owners[id], loader, fileLinks, context)
|
|
630
|
+
if problem != "" {
|
|
631
|
+
problems = problems.add(severity, problem)
|
|
632
|
+
} else {
|
|
633
|
+
resolved[id] = unitID
|
|
634
|
+
}
|
|
635
|
+
continue
|
|
636
|
+
}
|
|
621
637
|
if isInlineLinkTarget(declaration.Target) {
|
|
622
638
|
unitID, problem := resolveInlineLinkDeclaration(
|
|
623
639
|
declaration,
|
|
624
640
|
loader,
|
|
625
641
|
scopedTargets,
|
|
626
642
|
scopedHidden,
|
|
643
|
+
fileLinks,
|
|
644
|
+
states,
|
|
627
645
|
context,
|
|
628
646
|
)
|
|
629
647
|
if problem != "" {
|
|
@@ -655,7 +673,7 @@ func evaluateEvidenceGraph(
|
|
|
655
673
|
if len(addressable) == 0 && len(code) != 0 {
|
|
656
674
|
problems = problems.add(
|
|
657
675
|
severity,
|
|
658
|
-
"Code evidence target '"+declaration.Target+"' at "+declaration.location()+" for "+context+":
|
|
676
|
+
"Code evidence target '"+declaration.Target+"' at "+declaration.location()+" for "+context+": an unqualified symbol has no module identity in this artifact. In Markdown, write '@link <file.ts>#<Accessor> <reason>' using a path relative to this document. Otherwise move the citation to a TypeScript claim.",
|
|
659
677
|
)
|
|
660
678
|
continue
|
|
661
679
|
}
|
|
@@ -935,12 +953,7 @@ func evaluateEvidenceGraph(
|
|
|
935
953
|
// Withdrawn units are absent from Population by construction, and
|
|
936
954
|
// the scope composite still needs their identities so a member
|
|
937
955
|
// leaving the public surface moves the fingerprint.
|
|
938
|
-
reviewScopes =
|
|
939
|
-
append(
|
|
940
|
-
append([]*evidenceUnit{}, reference.Population...),
|
|
941
|
-
reference.Hidden...,
|
|
942
|
-
),
|
|
943
|
-
)
|
|
956
|
+
reviewScopes = referenceReviewScopes(reference, loader)
|
|
944
957
|
}
|
|
945
958
|
if reviewLedgerForClaim == nil {
|
|
946
959
|
reviewLedgerForClaim = newReviewLedger(state.Reviews)
|
|
@@ -1448,6 +1461,7 @@ func materializeEntryReference(
|
|
|
1448
1461
|
state.Units = population.Units
|
|
1449
1462
|
state.Hidden = population.Hidden
|
|
1450
1463
|
state.Published = population.Published
|
|
1464
|
+
state.Code = population.Code
|
|
1451
1465
|
if failure := loader.failure(entry); failure != "" {
|
|
1452
1466
|
state.Healthy = false
|
|
1453
1467
|
return state, []string{
|
|
@@ -1539,6 +1553,7 @@ func materializeLocalTypeScriptReference(
|
|
|
1539
1553
|
state.Units = population.Units
|
|
1540
1554
|
state.Hidden = population.Hidden
|
|
1541
1555
|
state.Published = population.Published
|
|
1556
|
+
state.Code = population.Code
|
|
1542
1557
|
applyTraversedScopes(&state, population.Reached)
|
|
1543
1558
|
if !state.Healthy {
|
|
1544
1559
|
return state, nil
|
|
@@ -1624,6 +1639,7 @@ func materializePackageGlobReference(
|
|
|
1624
1639
|
state.Units = population.Units
|
|
1625
1640
|
state.Hidden = population.Hidden
|
|
1626
1641
|
state.Published = population.Published
|
|
1642
|
+
state.Code = population.Code
|
|
1627
1643
|
applyTraversedScopes(&state, population.Reached)
|
|
1628
1644
|
if !state.Healthy {
|
|
1629
1645
|
return state, problems
|
|
@@ -1691,6 +1707,8 @@ func resolveInlineLinkDeclaration(
|
|
|
1691
1707
|
loader *typeScriptLoader,
|
|
1692
1708
|
scopedTargets map[scopedTargetKey]map[string]*evidenceUnit,
|
|
1693
1709
|
scopedHidden map[scopedTargetKey]*evidenceUnit,
|
|
1710
|
+
fileLinks map[int]*fileLinkClaimIndex,
|
|
1711
|
+
states []claimState,
|
|
1694
1712
|
context string,
|
|
1695
1713
|
) (string, string) {
|
|
1696
1714
|
target := inlineLinkTarget(declaration.Target)
|
|
@@ -1721,7 +1739,19 @@ func resolveInlineLinkDeclaration(
|
|
|
1721
1739
|
return "", "Incomplete evidence target '" + displayTarget(declaration.Target) + "' at " + declaration.location() + " for " + context + ": a namespace import names a module rather than a unit. Name a symbol inside '" + binding.Specifier + "' that the named reference selects."
|
|
1722
1740
|
}
|
|
1723
1741
|
name := strings.Join(remaining, ".")
|
|
1724
|
-
|
|
1742
|
+
identity, _ := loader.moduleIdentity(resolvedPath)
|
|
1743
|
+
candidates, hidden := queryFileLinkClaims(fileLinks, states, identity, remaining, true)
|
|
1744
|
+
for id, unit := range scopedTargets[scopedTargetKey{path: resolvedPath, target: name}] {
|
|
1745
|
+
candidates[id] = unit
|
|
1746
|
+
}
|
|
1747
|
+
if len(candidates) == 0 && len(hidden) != 0 {
|
|
1748
|
+
ids := make([]string, 0, len(hidden))
|
|
1749
|
+
for id := range hidden {
|
|
1750
|
+
ids = append(ids, id)
|
|
1751
|
+
}
|
|
1752
|
+
sort.Strings(ids)
|
|
1753
|
+
return "", hiddenTargetProblem(declaration, hidden[ids[0]], context)
|
|
1754
|
+
}
|
|
1725
1755
|
switch len(candidates) {
|
|
1726
1756
|
case 0:
|
|
1727
1757
|
if hidden := scopedHidden[scopedTargetKey{
|
package/native/imports.go
CHANGED
|
@@ -19,6 +19,7 @@ type importBinding struct {
|
|
|
19
19
|
Specifier string
|
|
20
20
|
Imported string
|
|
21
21
|
Namespace bool
|
|
22
|
+
TypeOnly bool
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
// collectImportBindings indexes a file's imports by the local name each binds.
|
|
@@ -52,6 +53,7 @@ func collectImportBindings(file *shimast.SourceFile) map[string]importBinding {
|
|
|
52
53
|
Local: name,
|
|
53
54
|
Specifier: specifier,
|
|
54
55
|
Imported: "default",
|
|
56
|
+
TypeOnly: clause.IsTypeOnly(),
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
if clause.NamedBindings == nil {
|
|
@@ -64,6 +66,7 @@ func collectImportBindings(file *shimast.SourceFile) map[string]importBinding {
|
|
|
64
66
|
Local: name,
|
|
65
67
|
Specifier: specifier,
|
|
66
68
|
Namespace: true,
|
|
69
|
+
TypeOnly: clause.IsTypeOnly(),
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
case shimast.KindNamedImports:
|
|
@@ -91,6 +94,7 @@ func collectImportBindings(file *shimast.SourceFile) map[string]importBinding {
|
|
|
91
94
|
Local: local,
|
|
92
95
|
Specifier: specifier,
|
|
93
96
|
Imported: imported,
|
|
97
|
+
TypeOnly: clause.IsTypeOnly() || specifierNode.IsTypeOnly,
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
}
|
|
@@ -124,19 +128,28 @@ var typeScriptModuleExtensions = []string{
|
|
|
124
128
|
// must spell its sibling as `./x.js`, so refusing to map it back would make the
|
|
125
129
|
// correct import form unresolvable.
|
|
126
130
|
func moduleCandidates(base string) []string {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
if isTypeScriptPath(base) {
|
|
132
|
+
return []string{base}
|
|
133
|
+
}
|
|
134
|
+
substitutions := map[string][]string{
|
|
135
|
+
".js": {".ts", ".tsx", ".d.ts"},
|
|
136
|
+
".mjs": {".mts", ".d.mts"},
|
|
137
|
+
".cjs": {".cts", ".d.cts"},
|
|
138
|
+
}
|
|
139
|
+
if extensions, emitted := substitutions[path.Ext(base)]; emitted {
|
|
140
|
+
stripped := strings.TrimSuffix(base, path.Ext(base))
|
|
141
|
+
candidates := make([]string, 0, len(extensions))
|
|
142
|
+
for _, extension := range extensions {
|
|
143
|
+
candidates = append(candidates, stripped+extension)
|
|
133
144
|
}
|
|
145
|
+
return candidates
|
|
134
146
|
}
|
|
147
|
+
candidates := []string{}
|
|
135
148
|
for _, extension := range typeScriptModuleExtensions {
|
|
136
|
-
candidates = append(candidates,
|
|
149
|
+
candidates = append(candidates, base+extension)
|
|
137
150
|
}
|
|
138
151
|
for _, extension := range typeScriptModuleExtensions {
|
|
139
|
-
candidates = append(candidates, path.Join(
|
|
152
|
+
candidates = append(candidates, path.Join(base, "index"+extension))
|
|
140
153
|
}
|
|
141
154
|
return candidates
|
|
142
155
|
}
|
package/native/inputs.go
CHANGED
|
@@ -35,10 +35,8 @@ func (graphRule) ProjectInputs(ctx *rule.ProjectInputContext) []rule.ProjectInpu
|
|
|
35
35
|
// graphProjectInputs collects the external dependency of every configured
|
|
36
36
|
// obligation.
|
|
37
37
|
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
// watches, so declaring them again would ask for a second watcher on a file
|
|
41
|
-
// that already has one.
|
|
38
|
+
// Program sources are already watched. Rooted TypeScript references additionally
|
|
39
|
+
// declare the directory containing their disk-loaded export closure.
|
|
42
40
|
func graphProjectInputs(config graphConfig) []rule.ProjectInput {
|
|
43
41
|
config = enabledGraphConfig(config)
|
|
44
42
|
inputs := []rule.ProjectInput{}
|
|
@@ -49,6 +47,17 @@ func graphProjectInputs(config graphConfig) []rule.ProjectInput {
|
|
|
49
47
|
}
|
|
50
48
|
for _, reference := range claim.References {
|
|
51
49
|
switch reference.Type {
|
|
50
|
+
case artifactTypeScript:
|
|
51
|
+
if reference.Rooted {
|
|
52
|
+
// Export traversal can reach a module outside the entry globs, and
|
|
53
|
+
// this pre-Program protocol cannot discover that closure. The root
|
|
54
|
+
// is its explicit boundary, including future files and repairs.
|
|
55
|
+
pattern := "**"
|
|
56
|
+
if reference.Root != "" {
|
|
57
|
+
pattern = strings.TrimSuffix(reference.Root, "/") + "/**"
|
|
58
|
+
}
|
|
59
|
+
inputs = append(inputs, rule.ProjectInput{Kind: rule.ProjectInputGlob, Pattern: pattern})
|
|
60
|
+
}
|
|
52
61
|
case artifactMarkdown, artifactPrisma:
|
|
53
62
|
inputs = append(inputs, globInputs(reference.Root, reference.Files)...)
|
|
54
63
|
case artifactSwagger:
|