typia 14.0.0 → 14.0.2
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/internal/_createStandardSchema.d.ts +1 -2
- package/lib/internal/_createStandardSchema.js.map +1 -1
- package/lib/internal/_createStandardSchema.mjs.map +1 -1
- package/lib/module.d.ts +1 -2
- package/lib/module.js.map +1 -1
- package/lib/module.mjs.map +1 -1
- package/lib/re-exports.d.ts +1 -1
- package/lib/re-exports.js.map +1 -1
- package/lib/transformers/NoTransformConfigurationError.js +19 -4
- package/lib/transformers/NoTransformConfigurationError.js.map +1 -1
- package/lib/transformers/NoTransformConfigurationError.mjs +12 -6
- package/lib/transformers/NoTransformConfigurationError.mjs.map +1 -1
- package/native/cmd/ttsc-typia/create_assert_error_factory_arity_test.go +5 -2
- package/native/cmd/ttsc-typia/dependency_collector_virtual_scheme_test.go +52 -0
- package/native/cmd/ttsc-typia/json_schema_nonsensible_intersection_diagnostic_test.go +80 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_argument_transform_test.go +177 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_barrel_transform_test.go +115 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_inference_transform_test.go +285 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_shape_transform_test.go +117 -0
- package/native/cmd/ttsc-typia/project_dependencies_callee_untransformed_barrel_transform_test.go +121 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_diagnostic_transform_test.go +116 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_envelope_transform_test.go +115 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_inferred_type_transform_test.go +127 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_replaced_library_transform_test.go +153 -0
- package/native/cmd/ttsc-typia/project_dependencies_complete_untouched_reprint_transform_test.go +155 -0
- package/native/cmd/ttsc-typia/project_dependencies_computed_key_transform_test.go +218 -0
- package/native/cmd/ttsc-typia/project_dependencies_custom_lib_name_transform_test.go +6 -5
- package/native/cmd/ttsc-typia/project_dependencies_enum_member_value_transform_test.go +131 -0
- package/native/cmd/ttsc-typia/project_dependencies_inferred_declaration_transform_test.go +159 -0
- package/native/cmd/ttsc-typia/project_dependencies_jsdoc_typedef_transform_test.go +134 -0
- package/native/cmd/ttsc-typia/project_dependencies_named_tuple_member_transform_test.go +123 -0
- package/native/cmd/ttsc-typia/project_dependencies_qualified_barrel_transform_test.go +141 -0
- package/native/cmd/ttsc-typia/project_dependencies_type_parameter_default_transform_test.go +127 -0
- package/native/cmd/ttsc-typia/transform.go +193 -19
- package/native/core/schemas/metadata/MetadataDependency.go +613 -30
- package/native/transform/CallExpressionTransformer.go +16 -1
- package/package.json +4 -5
- package/src/internal/_createStandardSchema.ts +1 -2
- package/src/module.ts +6 -2
- package/src/re-exports.ts +13 -0
- package/src/transformers/NoTransformConfigurationError.ts +19 -4
|
@@ -22,16 +22,61 @@ import (
|
|
|
22
22
|
// modes register none).
|
|
23
23
|
var metadataDependency_listeners sync.Map
|
|
24
24
|
|
|
25
|
+
// MetadataDependency_IListener is what a registered host receives while one
|
|
26
|
+
// file is transformed. `File` is the report; `Unbounded` is the admission that
|
|
27
|
+
// the report cannot be the whole story.
|
|
28
|
+
type MetadataDependency_IListener struct {
|
|
29
|
+
// File receives each consulted declaration file name.
|
|
30
|
+
File func(fileName string)
|
|
31
|
+
// Callee receives a declaration file name reached while deciding WHICH
|
|
32
|
+
// declaration a call resolves to, rather than what a consulted type is built
|
|
33
|
+
// from.
|
|
34
|
+
//
|
|
35
|
+
// The two differ on default libraries alone, and only once the libraries are
|
|
36
|
+
// real files (`libReplacement`, `noembed`). A replacement really can change a
|
|
37
|
+
// generated validator, so the type channel withholds the file that consulted
|
|
38
|
+
// one. It can never change which declaration a call resolves to: typia
|
|
39
|
+
// recognizes its own calls by a path ending in `/typia/lib/<file>.d.ts` or
|
|
40
|
+
// `/typia/src/<file>.ts`, and a file the compiler classifies as a default
|
|
41
|
+
// library satisfies neither, whatever its path on disk. Withholding there
|
|
42
|
+
// costs a file its declaration for calling `table.get(...)` and, under
|
|
43
|
+
// `noembed`, for calling anything at all (samchon/typia#2361).
|
|
44
|
+
//
|
|
45
|
+
// A host that does not distinguish them may leave this nil; the registry
|
|
46
|
+
// falls back to File.
|
|
47
|
+
Callee func(fileName string)
|
|
48
|
+
// Unbounded reports that the analysis consulted something no file list can
|
|
49
|
+
// bound: a declaration whose type this package can only read from an
|
|
50
|
+
// inferred position, or a callee whose identity is decided by an expression
|
|
51
|
+
// that names nothing.
|
|
52
|
+
//
|
|
53
|
+
// A host that only widens invalidation may ignore it, because an unreported
|
|
54
|
+
// file is still watched through the reference closure. A host that narrows to
|
|
55
|
+
// the reported list cannot: it has to leave the file out of that narrowing,
|
|
56
|
+
// since the list it would vouch for is missing an input nobody can enumerate.
|
|
57
|
+
Unbounded func()
|
|
58
|
+
}
|
|
59
|
+
|
|
25
60
|
// MetadataDependency_listen registers the listener that receives every
|
|
26
61
|
// consulted declaration file name resolved through `checker`. The caller owns
|
|
27
62
|
// attribution (which transformed file the touches belong to) and filtering.
|
|
28
|
-
func MetadataDependency_listen(checker *nativechecker.Checker, listener
|
|
29
|
-
if checker == nil || listener == nil {
|
|
63
|
+
func MetadataDependency_listen(checker *nativechecker.Checker, listener MetadataDependency_IListener) {
|
|
64
|
+
if checker == nil || listener.File == nil {
|
|
30
65
|
return
|
|
31
66
|
}
|
|
67
|
+
if listener.Callee == nil {
|
|
68
|
+
listener.Callee = listener.File
|
|
69
|
+
}
|
|
32
70
|
metadataDependency_listeners.Store(checker, listener)
|
|
33
71
|
}
|
|
34
72
|
|
|
73
|
+
// MetadataDependency_unbounded raises the admission from outside this package.
|
|
74
|
+
// The transform raises it for a typia call that takes its validated type from
|
|
75
|
+
// the value argument, which no written type node bounds.
|
|
76
|
+
func MetadataDependency_unbounded(checker *nativechecker.Checker) {
|
|
77
|
+
metadataDependency_listener(checker).unbounded()
|
|
78
|
+
}
|
|
79
|
+
|
|
35
80
|
// MetadataDependency_release removes the listener registered for `checker`.
|
|
36
81
|
func MetadataDependency_release(checker *nativechecker.Checker) {
|
|
37
82
|
if checker == nil {
|
|
@@ -43,7 +88,7 @@ func MetadataDependency_release(checker *nativechecker.Checker) {
|
|
|
43
88
|
// MetadataDependency_active reports whether a listener is registered for
|
|
44
89
|
// `checker`, so analysis code can skip walks performed only for collection.
|
|
45
90
|
func MetadataDependency_active(checker *nativechecker.Checker) bool {
|
|
46
|
-
return metadataDependency_listener(checker)
|
|
91
|
+
return metadataDependency_listener(checker).active()
|
|
47
92
|
}
|
|
48
93
|
|
|
49
94
|
// MetadataDependency_touchType reports the declaration files of a consulted
|
|
@@ -54,7 +99,7 @@ func MetadataDependency_touchType(checker *nativechecker.Checker, typ *nativeche
|
|
|
54
99
|
return
|
|
55
100
|
}
|
|
56
101
|
listener := metadataDependency_listener(checker)
|
|
57
|
-
if listener ==
|
|
102
|
+
if listener.active() == false {
|
|
58
103
|
return
|
|
59
104
|
}
|
|
60
105
|
visited := map[*nativeast.Symbol]bool{}
|
|
@@ -66,7 +111,7 @@ func MetadataDependency_touchType(checker *nativechecker.Checker, typ *nativeche
|
|
|
66
111
|
// symbol (e.g. an object property or a heritage target).
|
|
67
112
|
func MetadataDependency_touchSymbol(checker *nativechecker.Checker, symbol *nativeast.Symbol) {
|
|
68
113
|
listener := metadataDependency_listener(checker)
|
|
69
|
-
if listener ==
|
|
114
|
+
if listener.active() == false {
|
|
70
115
|
return
|
|
71
116
|
}
|
|
72
117
|
metadataDependency_touchVisited(checker, listener, symbol, map[*nativeast.Symbol]bool{})
|
|
@@ -80,36 +125,235 @@ func MetadataDependency_touchSymbol(checker *nativechecker.Checker, symbol *nati
|
|
|
80
125
|
// symbol — so only the written reference can register the alias' own file.
|
|
81
126
|
func MetadataDependency_touchTypeNode(checker *nativechecker.Checker, node *nativeast.Node) {
|
|
82
127
|
listener := metadataDependency_listener(checker)
|
|
83
|
-
if listener ==
|
|
128
|
+
if listener.active() == false || node == nil {
|
|
84
129
|
return
|
|
85
130
|
}
|
|
86
131
|
metadataDependency_walkNode(checker, listener, node, map[*nativeast.Symbol]bool{})
|
|
87
132
|
}
|
|
88
133
|
|
|
89
|
-
|
|
134
|
+
// MetadataDependency_touchCallee reports the files that decide WHICH
|
|
135
|
+
// declaration a call expression's callee names.
|
|
136
|
+
//
|
|
137
|
+
// typia recognizes its own call sites by the source file that declares the
|
|
138
|
+
// resolved signature, so every module an import or re-export chain passes
|
|
139
|
+
// through chooses whether a call is rewritten at all. Re-pointing a barrel from
|
|
140
|
+
// `export { is } from "./local"` to `export { is } from "typia"` turns an
|
|
141
|
+
// untouched file into a generated validator, and the reverse turns a validator
|
|
142
|
+
// back into a plain call. The type-graph touches cannot see either: they report
|
|
143
|
+
// what the validated type is, never what selected the callee.
|
|
144
|
+
//
|
|
145
|
+
// This runs for every call expression the transformer examines rather than only
|
|
146
|
+
// for recognized typia calls, because a call that is not typia's today is
|
|
147
|
+
// exactly the one an edit to one of those files makes typia's tomorrow. A
|
|
148
|
+
// callee whose identity no name in it decides raises the unbounded admission.
|
|
149
|
+
func MetadataDependency_touchCallee(checker *nativechecker.Checker, callee *nativeast.Node) {
|
|
150
|
+
listener := metadataDependency_listener(checker)
|
|
151
|
+
if listener.active() == false || callee == nil {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
if metadataDependency_walkCallee(checker, listener, callee, false) == false {
|
|
155
|
+
listener.unbounded()
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// metadataDependency_walkCallee reports every name written in a callee and
|
|
160
|
+
// answers whether those names decide which declaration the call resolves to.
|
|
161
|
+
//
|
|
162
|
+
// Two shapes are treated specially, and both are about where a call's identity
|
|
163
|
+
// actually comes from:
|
|
164
|
+
//
|
|
165
|
+
// - A nested call contributes its own callee AND the names it is applied to,
|
|
166
|
+
// but only the callee decides boundedness. Every indirection a caller writes
|
|
167
|
+
// -- a factory, a barrel, a namespace alias, a local binding -- sits on the
|
|
168
|
+
// callee chain, while a generic pass-through carries identity through the
|
|
169
|
+
// argument instead (`pick(ns).is<T>(x)`), so both are reported;
|
|
170
|
+
// metadataDependency_touchApplied says why the applied walk's answer is
|
|
171
|
+
// dropped. Reporting the names is not the whole answer there:
|
|
172
|
+
// metadataDependency_calleeBounded says why a callable reached inside a
|
|
173
|
+
// nested call must also write its return type. What stays given up is an
|
|
174
|
+
// overload selected by an argument's TYPE, or by a borrowed VALUE, since no
|
|
175
|
+
// written name on the chain carries either.
|
|
176
|
+
// - A function literal is where the walk stops. Written directly in callee
|
|
177
|
+
// position it is the most bounded declaration there is: the call resolves to
|
|
178
|
+
// the literal itself, in this very file, and its body is nobody's input.
|
|
179
|
+
// Reached through a nested call (`(() => is)()<T>(x)`) it is the opposite:
|
|
180
|
+
// the identity is whatever its body returns, and no set of files describes
|
|
181
|
+
// that, so the walk reports unbounded instead of guessing.
|
|
182
|
+
//
|
|
183
|
+
// Every other expression composes sub-expressions, so its children are walked
|
|
184
|
+
// and each name in them reported.
|
|
185
|
+
func metadataDependency_walkCallee(
|
|
186
|
+
checker *nativechecker.Checker,
|
|
187
|
+
listener MetadataDependency_IListener,
|
|
188
|
+
node *nativeast.Node,
|
|
189
|
+
nested bool,
|
|
190
|
+
) bool {
|
|
191
|
+
if node == nil {
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
switch node.Kind {
|
|
195
|
+
case nativeast.KindArrowFunction,
|
|
196
|
+
nativeast.KindFunctionExpression,
|
|
197
|
+
nativeast.KindFunctionDeclaration,
|
|
198
|
+
nativeast.KindClassExpression,
|
|
199
|
+
nativeast.KindClassDeclaration,
|
|
200
|
+
nativeast.KindMethodDeclaration,
|
|
201
|
+
nativeast.KindGetAccessor,
|
|
202
|
+
nativeast.KindSetAccessor,
|
|
203
|
+
nativeast.KindConstructor:
|
|
204
|
+
return nested == false
|
|
205
|
+
case nativeast.KindCallExpression,
|
|
206
|
+
nativeast.KindNewExpression:
|
|
207
|
+
metadataDependency_touchApplied(checker, listener, node.Arguments())
|
|
208
|
+
return metadataDependency_walkCallee(checker, listener, node.Expression(), true)
|
|
209
|
+
case nativeast.KindTaggedTemplateExpression:
|
|
210
|
+
tagged := node.AsTaggedTemplateExpression()
|
|
211
|
+
metadataDependency_touchApplied(checker, listener, []*nativeast.Node{tagged.Template})
|
|
212
|
+
return metadataDependency_walkCallee(checker, listener, tagged.Tag, true)
|
|
213
|
+
case nativeast.KindIdentifier,
|
|
214
|
+
nativeast.KindPrivateIdentifier,
|
|
215
|
+
nativeast.KindThisKeyword,
|
|
216
|
+
nativeast.KindSuperKeyword,
|
|
217
|
+
nativeast.KindPropertyAccessExpression,
|
|
218
|
+
nativeast.KindElementAccessExpression,
|
|
219
|
+
nativeast.KindQualifiedName:
|
|
220
|
+
// The whole access resolves to the member the call names; walking on to its
|
|
221
|
+
// qualifier reports whatever selected the object that publishes it, and a
|
|
222
|
+
// module other than the caller may declare that (`helpers.is`).
|
|
223
|
+
metadataDependency_touchDeclarations(checker, listener, node, nested)
|
|
224
|
+
}
|
|
225
|
+
bounded := true
|
|
226
|
+
node.ForEachChild(func(child *nativeast.Node) bool {
|
|
227
|
+
if metadataDependency_walkCallee(checker, listener, child, nested) == false {
|
|
228
|
+
bounded = false
|
|
229
|
+
}
|
|
230
|
+
return false
|
|
231
|
+
})
|
|
232
|
+
return bounded
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// metadataDependency_touchApplied reports the names a nested call is applied to,
|
|
236
|
+
// without letting their shape decide the caller's boundedness.
|
|
237
|
+
//
|
|
238
|
+
// A generic pass-through carries a callee's identity through what it is applied
|
|
239
|
+
// to, not through its own name: `pick(ns).is<T>(x)` resolves to typia's `is`
|
|
240
|
+
// because `ns` holds the typia namespace, so the file declaring `ns` chooses
|
|
241
|
+
// whether this call is rewritten at all -- and the callee chain alone never
|
|
242
|
+
// names it. Reproduced: `main.ts` was declared complete reporting only `foo.ts`
|
|
243
|
+
// and `pick.ts` (samchon/typia#2357).
|
|
244
|
+
//
|
|
245
|
+
// The walk's answer is deliberately dropped rather than combined. An argument's
|
|
246
|
+
// shape is not the caller's identity: a function literal handed to
|
|
247
|
+
// `arr.map(...).filter(...)` would otherwise withhold every file that chains an
|
|
248
|
+
// array method, for a body that decides nothing about which `filter` this is.
|
|
249
|
+
// Dropping it also keeps the walk's own boundary -- it stops at a function
|
|
250
|
+
// literal instead of descending -- so no file is charged with the identifiers
|
|
251
|
+
// inside a callback.
|
|
252
|
+
//
|
|
253
|
+
// What stays unreported is the same boundary the callee chain already states: an
|
|
254
|
+
// argument that is itself computed (`pick(getNs())`) names its own callee and no
|
|
255
|
+
// further. That one no longer over-declares, because the callee it names is a
|
|
256
|
+
// callable whose inferred return type withholds the caller
|
|
257
|
+
// (metadataDependency_calleeBounded); an overload selected by an argument's
|
|
258
|
+
// TYPE, or by a borrowed VALUE, is still decided by something no written name
|
|
259
|
+
// carries.
|
|
260
|
+
func metadataDependency_touchApplied(
|
|
261
|
+
checker *nativechecker.Checker,
|
|
262
|
+
listener MetadataDependency_IListener,
|
|
263
|
+
applied []*nativeast.Node,
|
|
264
|
+
) {
|
|
265
|
+
for _, node := range applied {
|
|
266
|
+
metadataDependency_walkCallee(checker, listener, node, true)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// metadataDependency_touchDeclarations reports one written reference's own
|
|
271
|
+
// declaring files, following alias hops but without walking the type surface of
|
|
272
|
+
// what it names. The caller asks which declaration a name selects, not what
|
|
273
|
+
// that declaration's type is built from; the type graph reports the latter
|
|
274
|
+
// where it is actually consulted.
|
|
275
|
+
//
|
|
276
|
+
// `nested` says the reference sits inside a nested call, and there the question
|
|
277
|
+
// changes. The outermost callee's identity IS the declaration this resolves to,
|
|
278
|
+
// whose file is reported on the line above, so how that declaration was written
|
|
279
|
+
// cannot matter. One call in, the identity is the inner call's RETURN TYPE, and
|
|
280
|
+
// an unbounded declaration -- `const getNs = () => ns`, `const FLAG = RAW` --
|
|
281
|
+
// carries it from a file no written name on this chain reaches. Reporting the
|
|
282
|
+
// names without admitting that declared three shapes complete while an edit to
|
|
283
|
+
// an unreported file deleted the generated validator outright
|
|
284
|
+
// (samchon/typia#2360).
|
|
285
|
+
func metadataDependency_touchDeclarations(
|
|
286
|
+
checker *nativechecker.Checker,
|
|
287
|
+
listener MetadataDependency_IListener,
|
|
288
|
+
reference *nativeast.Node,
|
|
289
|
+
nested bool,
|
|
290
|
+
) {
|
|
90
291
|
if checker == nil {
|
|
91
|
-
return
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
symbol := checker.GetSymbolAtLocation(reference)
|
|
295
|
+
if symbol == nil {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
// Everything this function reaches was reached to decide which declaration a
|
|
299
|
+
// name selects, so all of it belongs to the identity channel -- the alias hops
|
|
300
|
+
// as much as the terminus.
|
|
301
|
+
report := listener.Callee
|
|
302
|
+
if symbol.Flags&nativeast.SymbolFlagsAlias != 0 {
|
|
303
|
+
metadataDependency_touchPath(checker, listener, symbol, report)
|
|
304
|
+
if resolved := nativechecker.Checker_getAliasedSymbol(checker, symbol); resolved != nil {
|
|
305
|
+
symbol = resolved
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
for _, declaration := range symbol.Declarations {
|
|
309
|
+
if src := nativeast.GetSourceFileOfNode(declaration); src != nil {
|
|
310
|
+
report(src.FileName())
|
|
311
|
+
}
|
|
312
|
+
if nested && metadataDependency_calleeBounded(declaration) == false {
|
|
313
|
+
listener.unbounded()
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
func metadataDependency_listener(checker *nativechecker.Checker) MetadataDependency_IListener {
|
|
319
|
+
if checker == nil {
|
|
320
|
+
return MetadataDependency_IListener{}
|
|
92
321
|
}
|
|
93
322
|
value, ok := metadataDependency_listeners.Load(checker)
|
|
94
323
|
if ok == false {
|
|
95
|
-
return
|
|
324
|
+
return MetadataDependency_IListener{}
|
|
96
325
|
}
|
|
97
|
-
listener, ok := value.(
|
|
326
|
+
listener, ok := value.(MetadataDependency_IListener)
|
|
98
327
|
if ok == false {
|
|
99
|
-
return
|
|
328
|
+
return MetadataDependency_IListener{}
|
|
100
329
|
}
|
|
101
330
|
return listener
|
|
102
331
|
}
|
|
103
332
|
|
|
333
|
+
// active reports whether a host is collecting through this listener.
|
|
334
|
+
func (listener MetadataDependency_IListener) active() bool {
|
|
335
|
+
return listener.File != nil
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// unbounded raises the admission when the registered host asked for it, so
|
|
339
|
+
// every call site can report unconditionally instead of guarding twice.
|
|
340
|
+
func (listener MetadataDependency_IListener) unbounded() {
|
|
341
|
+
if listener.Unbounded != nil {
|
|
342
|
+
listener.Unbounded()
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
104
346
|
// metadataDependency_touchVisited reports the symbol's declaration files and
|
|
105
347
|
// walks the type references written inside declarations that carry type
|
|
106
348
|
// annotations (aliases, properties, methods, parameters, index signatures), so
|
|
107
349
|
// checker-collapsed references — an alias of an intrinsic consumed through a
|
|
108
|
-
// property or another alias — still register their declaring files.
|
|
109
|
-
//
|
|
350
|
+
// property or another alias — still register their declaring files. A
|
|
351
|
+
// declaration whose type is not written on it raises the unbounded admission
|
|
352
|
+
// instead. `visited` guards alias cycles and bounds repeated work within one
|
|
353
|
+
// touch.
|
|
110
354
|
func metadataDependency_touchVisited(
|
|
111
355
|
checker *nativechecker.Checker,
|
|
112
|
-
listener
|
|
356
|
+
listener MetadataDependency_IListener,
|
|
113
357
|
symbol *nativeast.Symbol,
|
|
114
358
|
visited map[*nativeast.Symbol]bool,
|
|
115
359
|
) {
|
|
@@ -122,25 +366,309 @@ func metadataDependency_touchVisited(
|
|
|
122
366
|
continue
|
|
123
367
|
}
|
|
124
368
|
if src := nativeast.GetSourceFileOfNode(declaration); src != nil {
|
|
125
|
-
listener(src.FileName())
|
|
369
|
+
listener.File(src.FileName())
|
|
126
370
|
}
|
|
371
|
+
if metadataDependency_bounded(declaration) == false {
|
|
372
|
+
listener.unbounded()
|
|
373
|
+
}
|
|
374
|
+
metadataDependency_touchName(checker, listener, declaration, visited)
|
|
127
375
|
for _, surface := range metadataDependency_typeSurface(declaration) {
|
|
128
376
|
metadataDependency_walkNode(checker, listener, surface, visited)
|
|
129
377
|
}
|
|
130
378
|
}
|
|
131
379
|
}
|
|
132
380
|
|
|
381
|
+
// metadataDependency_touchName reports the files that decide a member's KEY
|
|
382
|
+
// when the key is computed.
|
|
383
|
+
//
|
|
384
|
+
// A validator indexes the property by name — `interface Doc { [Kind.A]: number
|
|
385
|
+
// }` emits `input.alpha` — so the enum member's value is read into the output
|
|
386
|
+
// exactly the way an `enum` member's own value is, and it is written in
|
|
387
|
+
// whatever file declares it. The declaration's written type says nothing about
|
|
388
|
+
// it, and neither does the type graph: the resolved key is an interned string
|
|
389
|
+
// literal with no symbol to follow. Renaming `Kind.A` therefore changed the
|
|
390
|
+
// generated validator with no reported edge for a bundler cache to invalidate
|
|
391
|
+
// (samchon/typia#2126, samchon/typia#2357).
|
|
392
|
+
//
|
|
393
|
+
// Only a computed name needs this. An identifier or string-literal member name
|
|
394
|
+
// is written on the declaration itself, and its file is already reported.
|
|
395
|
+
func metadataDependency_touchName(
|
|
396
|
+
checker *nativechecker.Checker,
|
|
397
|
+
listener MetadataDependency_IListener,
|
|
398
|
+
declaration *nativeast.Node,
|
|
399
|
+
visited map[*nativeast.Symbol]bool,
|
|
400
|
+
) {
|
|
401
|
+
name := declaration.Name()
|
|
402
|
+
if name == nil || name.Kind != nativeast.KindComputedPropertyName {
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
metadataDependency_walkName(checker, listener, name.Expression(), visited)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// metadataDependency_walkName reports the declarations a computed key's
|
|
409
|
+
// expression names, and admits when nothing written bounds it.
|
|
410
|
+
//
|
|
411
|
+
// A literal key needs no report: `["alpha"]` is written here, so no other file
|
|
412
|
+
// decides it. Every other shape is a reference, and resolving it through
|
|
413
|
+
// metadataDependency_touchVisited is what makes the report transitive: the
|
|
414
|
+
// symbol's own declaration is reported, its alias path registers the barrel it
|
|
415
|
+
// traveled, and metadataDependency_bounded answers whether that declaration
|
|
416
|
+
// fixes the value or borrows it — `const KEY = "gamma"` is bounded while `const
|
|
417
|
+
// KEY = other.VALUE` is not, exactly as for an enum member.
|
|
418
|
+
//
|
|
419
|
+
// The qualifier is walked as well as the whole reference. `Kind.A` resolves
|
|
420
|
+
// straight to the enum member, which reports the file declaring it but not the
|
|
421
|
+
// modules the reference traveled to select `Kind`; those are what a re-pointed
|
|
422
|
+
// barrel changes.
|
|
423
|
+
//
|
|
424
|
+
// Every other expression raises the unbounded admission rather than a guess: a
|
|
425
|
+
// call or a substituted template takes its value from evaluation, which no file
|
|
426
|
+
// list bounds. Only the kinds a property enumeration actually delivers are
|
|
427
|
+
// named: a string, no-substitution template, or numeric literal key, a bare
|
|
428
|
+
// name, and a property access each declare a property, while a parenthesized
|
|
429
|
+
// reference, a bigint literal, and an element access declare none at all -- so
|
|
430
|
+
// the walk never sees those, and refusing to vouch for a shape nobody has
|
|
431
|
+
// exhibited costs nothing.
|
|
432
|
+
func metadataDependency_walkName(
|
|
433
|
+
checker *nativechecker.Checker,
|
|
434
|
+
listener MetadataDependency_IListener,
|
|
435
|
+
expression *nativeast.Node,
|
|
436
|
+
visited map[*nativeast.Symbol]bool,
|
|
437
|
+
) {
|
|
438
|
+
if expression == nil {
|
|
439
|
+
listener.unbounded()
|
|
440
|
+
return
|
|
441
|
+
}
|
|
442
|
+
switch expression.Kind {
|
|
443
|
+
case nativeast.KindStringLiteral,
|
|
444
|
+
nativeast.KindNoSubstitutionTemplateLiteral,
|
|
445
|
+
nativeast.KindNumericLiteral:
|
|
446
|
+
return
|
|
447
|
+
case nativeast.KindIdentifier,
|
|
448
|
+
nativeast.KindPropertyAccessExpression:
|
|
449
|
+
// A reference the checker cannot resolve takes the fall-through below
|
|
450
|
+
// rather than an exit of its own. Nothing reaches it: a name resolving to
|
|
451
|
+
// no symbol declares no property symbol either -- the member becomes a
|
|
452
|
+
// dynamic key instead -- and this walk only ever runs on a declaration the
|
|
453
|
+
// property enumeration already handed over.
|
|
454
|
+
if symbol := metadataDependency_resolve(checker, listener, expression); symbol != nil {
|
|
455
|
+
metadataDependency_touchVisited(checker, listener, symbol, visited)
|
|
456
|
+
metadataDependency_touchQualifier(checker, listener, expression, visited)
|
|
457
|
+
return
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
listener.unbounded()
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// metadataDependency_calleeBounded reports whether a declaration reached inside
|
|
464
|
+
// a nested call pins the identity of what that call RETURNS.
|
|
465
|
+
//
|
|
466
|
+
// A nested call's identity is its return type, so the question here is only
|
|
467
|
+
// ever asked of callables -- and of a variable whose initializer is one, which
|
|
468
|
+
// is the same declaration spelled differently. A callable pins the identity
|
|
469
|
+
// when its return type is written; when it is inferred, the identity comes from
|
|
470
|
+
// whatever the body happens to return, which lives in a file no name on the
|
|
471
|
+
// callee chain reaches. `const getNs = () => ns` and `function getNs() { return
|
|
472
|
+
// ns; }` are that shape, and both declared their caller complete while an edit
|
|
473
|
+
// to the unreported `ns.ts` deleted the generated validator outright
|
|
474
|
+
// (samchon/typia#2360).
|
|
475
|
+
//
|
|
476
|
+
// Everything else stays bounded on purpose, and metadataDependency_bounded is
|
|
477
|
+
// deliberately NOT consulted here. It answers a different question -- whether a
|
|
478
|
+
// declaration's TYPE is written where the type walk can read it -- and it calls
|
|
479
|
+
// `const ns = typia` unbounded for want of an annotation. On this channel that
|
|
480
|
+
// declaration is fine: the walk writes the name `ns`, so `ns.ts` is reported
|
|
481
|
+
// and an edit to it invalidates the caller. Withholding on it would take back
|
|
482
|
+
// samchon/typia#2357, whose whole point is that such a caller stays declared.
|
|
483
|
+
//
|
|
484
|
+
// What that leaves open is an overload selected by a borrowed VALUE (`const
|
|
485
|
+
// FLAG = RAW; sel(FLAG).is<T>(x)`): `flag.ts` is reported, `rawflag.ts` is not,
|
|
486
|
+
// and the two are structurally indistinguishable from the pair above.
|
|
487
|
+
// Separating them needs the initializer chain followed and reported, not a
|
|
488
|
+
// boundedness answer.
|
|
489
|
+
func metadataDependency_calleeBounded(declaration *nativeast.Node) bool {
|
|
490
|
+
if metadataDependency_calleeCallable(declaration) {
|
|
491
|
+
return declaration.Type() != nil
|
|
492
|
+
}
|
|
493
|
+
if declaration.Kind == nativeast.KindVariableDeclaration {
|
|
494
|
+
if initializer := declaration.Initializer(); initializer != nil &&
|
|
495
|
+
metadataDependency_calleeCallable(initializer) {
|
|
496
|
+
return declaration.Type() != nil || initializer.Type() != nil
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return true
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// metadataDependency_calleeCallable reports whether a node is a callable whose
|
|
503
|
+
// written return type would pin what a call on it produces.
|
|
504
|
+
//
|
|
505
|
+
// A construct signature is absent on purpose: `new X()` returns `X`, and the
|
|
506
|
+
// class is the declaration the walk already reports.
|
|
507
|
+
func metadataDependency_calleeCallable(node *nativeast.Node) bool {
|
|
508
|
+
switch node.Kind {
|
|
509
|
+
case nativeast.KindFunctionDeclaration,
|
|
510
|
+
nativeast.KindFunctionExpression,
|
|
511
|
+
nativeast.KindArrowFunction,
|
|
512
|
+
nativeast.KindMethodDeclaration,
|
|
513
|
+
nativeast.KindMethodSignature,
|
|
514
|
+
nativeast.KindCallSignature,
|
|
515
|
+
nativeast.KindFunctionType,
|
|
516
|
+
nativeast.KindGetAccessor:
|
|
517
|
+
return true
|
|
518
|
+
}
|
|
519
|
+
return false
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// metadataDependency_bounded reports whether a declaration's type is written
|
|
523
|
+
// where this walk can read it. A declaration that fails it raises the unbounded
|
|
524
|
+
// admission, which costs the file being transformed its completeness
|
|
525
|
+
// declaration and nothing else.
|
|
526
|
+
//
|
|
527
|
+
// The answer is NO for every kind this switch does not name, and that direction
|
|
528
|
+
// is the whole point. Under-reporting a file is safe -- it keeps the host-owned
|
|
529
|
+
// reference closure -- while declaring a file whose inputs were not enumerated
|
|
530
|
+
// serves a stale validator, so a declaration kind nobody thought about has to
|
|
531
|
+
// cost narrowing rather than correctness.
|
|
532
|
+
//
|
|
533
|
+
// What makes a kind bounded is that its type is either written on it, surfaced
|
|
534
|
+
// by metadataDependency_typeSurface, or absent entirely (a module, an alias
|
|
535
|
+
// hop, an enum's own declaration). What makes one unbounded is inference: an
|
|
536
|
+
// object-literal member and a destructured binding take their type from an
|
|
537
|
+
// expression, and so does a property, parameter, or variable with no
|
|
538
|
+
// annotation. Following that means following type inference over arbitrary
|
|
539
|
+
// expressions -- a call's return type, an overload's selection, a conditional's
|
|
540
|
+
// branches, a contextually typed parameter -- which is the same problem a typia
|
|
541
|
+
// call with no written type argument has, and it gets the same answer
|
|
542
|
+
// (samchon/typia#2126, samchon/typia#2357).
|
|
543
|
+
//
|
|
544
|
+
// Only kinds an input actually reaches are named. A tuple element and a JSDoc
|
|
545
|
+
// `@property` / `@param` tag are not: each is reached through the written node
|
|
546
|
+
// that spells it -- the alias or literal spelling the tuple, the typedef owning
|
|
547
|
+
// the tag -- which metadataDependency_walkNode descends whole, so no property
|
|
548
|
+
// enumeration ever hands one of them here. Naming them changed no envelope in
|
|
549
|
+
// either direction, which is the only evidence that settles it;
|
|
550
|
+
// TestProjectDependenciesNamedTupleMemberTransform and
|
|
551
|
+
// TestProjectDependenciesJsDocTypedefTransform are the fixtures that measured
|
|
552
|
+
// it and would fail if either kind started arriving.
|
|
553
|
+
func metadataDependency_bounded(declaration *nativeast.Node) bool {
|
|
554
|
+
switch declaration.Kind {
|
|
555
|
+
case nativeast.KindTypeAliasDeclaration,
|
|
556
|
+
nativeast.KindJSTypeAliasDeclaration,
|
|
557
|
+
nativeast.KindInterfaceDeclaration,
|
|
558
|
+
nativeast.KindClassDeclaration,
|
|
559
|
+
nativeast.KindClassExpression,
|
|
560
|
+
nativeast.KindTypeLiteral,
|
|
561
|
+
nativeast.KindMappedType,
|
|
562
|
+
nativeast.KindTypeParameter,
|
|
563
|
+
nativeast.KindEnumDeclaration:
|
|
564
|
+
// Structural declarations: metadataDependency_typeSurface hands their
|
|
565
|
+
// written types to the walk, and their members surface individually.
|
|
566
|
+
return true
|
|
567
|
+
case nativeast.KindMethodSignature,
|
|
568
|
+
nativeast.KindMethodDeclaration,
|
|
569
|
+
nativeast.KindGetAccessor,
|
|
570
|
+
nativeast.KindSetAccessor,
|
|
571
|
+
nativeast.KindIndexSignature,
|
|
572
|
+
nativeast.KindCallSignature,
|
|
573
|
+
nativeast.KindConstructSignature,
|
|
574
|
+
nativeast.KindFunctionType,
|
|
575
|
+
nativeast.KindConstructorType,
|
|
576
|
+
nativeast.KindFunctionDeclaration,
|
|
577
|
+
nativeast.KindFunctionExpression,
|
|
578
|
+
nativeast.KindArrowFunction,
|
|
579
|
+
nativeast.KindConstructor,
|
|
580
|
+
nativeast.KindClassStaticBlockDeclaration:
|
|
581
|
+
// Callables. An analysis emits one as `typeof x === "function"` and reads
|
|
582
|
+
// no part of its signature, which is the contract
|
|
583
|
+
// TestProjectDependenciesSignatureAliasTransform states, so an inferred
|
|
584
|
+
// return type is not an input either.
|
|
585
|
+
return true
|
|
586
|
+
case nativeast.KindSourceFile,
|
|
587
|
+
nativeast.KindModuleDeclaration,
|
|
588
|
+
nativeast.KindNamespaceExportDeclaration,
|
|
589
|
+
nativeast.KindImportDeclaration,
|
|
590
|
+
nativeast.KindImportClause,
|
|
591
|
+
nativeast.KindImportSpecifier,
|
|
592
|
+
nativeast.KindImportEqualsDeclaration,
|
|
593
|
+
nativeast.KindNamespaceImport,
|
|
594
|
+
nativeast.KindNamespaceExport,
|
|
595
|
+
nativeast.KindExportDeclaration,
|
|
596
|
+
nativeast.KindExportSpecifier,
|
|
597
|
+
nativeast.KindExportAssignment:
|
|
598
|
+
// Modules and alias hops carry no type of their own; the hop itself is
|
|
599
|
+
// reported by metadataDependency_touchPath and the terminus is resolved
|
|
600
|
+
// separately.
|
|
601
|
+
return true
|
|
602
|
+
case nativeast.KindPropertySignature,
|
|
603
|
+
nativeast.KindPropertyDeclaration,
|
|
604
|
+
nativeast.KindParameter,
|
|
605
|
+
nativeast.KindVariableDeclaration:
|
|
606
|
+
return declaration.Type() != nil || metadataDependency_literal(declaration.Initializer())
|
|
607
|
+
case nativeast.KindEnumMember,
|
|
608
|
+
nativeast.KindPropertyAssignment:
|
|
609
|
+
// An enum member's value is read straight into the generated validator, and
|
|
610
|
+
// an object-literal member's type is its initializer. Both are written here
|
|
611
|
+
// when the initializer is a literal or, for an auto-numbered enum member,
|
|
612
|
+
// absent; anything else names a value some other file may declare.
|
|
613
|
+
initializer := declaration.Initializer()
|
|
614
|
+
return initializer == nil || metadataDependency_literal(initializer)
|
|
615
|
+
}
|
|
616
|
+
return false
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// metadataDependency_literal reports an initializer that fixes a declaration's
|
|
620
|
+
// type inside the declaration itself, so no other file can decide it.
|
|
621
|
+
func metadataDependency_literal(initializer *nativeast.Node) bool {
|
|
622
|
+
if initializer == nil {
|
|
623
|
+
return false
|
|
624
|
+
}
|
|
625
|
+
switch initializer.Kind {
|
|
626
|
+
case nativeast.KindNumericLiteral,
|
|
627
|
+
nativeast.KindBigIntLiteral,
|
|
628
|
+
nativeast.KindStringLiteral,
|
|
629
|
+
nativeast.KindNoSubstitutionTemplateLiteral,
|
|
630
|
+
nativeast.KindRegularExpressionLiteral,
|
|
631
|
+
nativeast.KindTrueKeyword,
|
|
632
|
+
nativeast.KindFalseKeyword,
|
|
633
|
+
nativeast.KindNullKeyword:
|
|
634
|
+
return true
|
|
635
|
+
case nativeast.KindParenthesizedExpression:
|
|
636
|
+
return metadataDependency_literal(initializer.Expression())
|
|
637
|
+
case nativeast.KindPrefixUnaryExpression:
|
|
638
|
+
// `-1` is how a negative number is written, and TypeScript reads the sign
|
|
639
|
+
// and the literal as one constant. Only the numeric operators qualify: `!x`
|
|
640
|
+
// and `~x` say nothing about where x came from.
|
|
641
|
+
unary := initializer.AsPrefixUnaryExpression()
|
|
642
|
+
switch unary.Operator {
|
|
643
|
+
case nativeast.KindMinusToken, nativeast.KindPlusToken:
|
|
644
|
+
switch unary.Operand.Kind {
|
|
645
|
+
case nativeast.KindNumericLiteral, nativeast.KindBigIntLiteral:
|
|
646
|
+
return true
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return false
|
|
651
|
+
}
|
|
652
|
+
|
|
133
653
|
// metadataDependency_typeSurface selects the WRITTEN type nodes of a
|
|
134
|
-
// declaration: the whole node for a `type` alias
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
654
|
+
// declaration: the whole node for a `type` alias, a mapped type, or a type
|
|
655
|
+
// parameter (constraint and default included), the type parameters and index
|
|
656
|
+
// signatures of an interface or class, the annotation for properties,
|
|
657
|
+
// parameters, and variables, and parameter types + return type for methods,
|
|
658
|
+
// accessors, and index signatures. Bodies and initializers are excluded — a
|
|
659
|
+
// reference appearing only there is not part of the type the analysis consulted,
|
|
660
|
+
// and a declaration that has only an initializer to go on is reported unbounded
|
|
661
|
+
// by metadataDependency_bounded rather than guessed at.
|
|
662
|
+
//
|
|
663
|
+
// Interface, class, and type-literal declarations contribute only their index
|
|
664
|
+
// signatures: every other member surfaces individually through property
|
|
665
|
+
// enumeration.
|
|
141
666
|
func metadataDependency_typeSurface(declaration *nativeast.Node) []*nativeast.Node {
|
|
142
667
|
switch declaration.Kind {
|
|
143
|
-
case nativeast.KindTypeAliasDeclaration
|
|
668
|
+
case nativeast.KindTypeAliasDeclaration,
|
|
669
|
+
nativeast.KindJSTypeAliasDeclaration,
|
|
670
|
+
nativeast.KindMappedType,
|
|
671
|
+
nativeast.KindTypeParameter:
|
|
144
672
|
return []*nativeast.Node{declaration}
|
|
145
673
|
case nativeast.KindInterfaceDeclaration,
|
|
146
674
|
nativeast.KindClassDeclaration,
|
|
@@ -155,6 +683,18 @@ func metadataDependency_typeSurface(declaration *nativeast.Node) []*nativeast.No
|
|
|
155
683
|
// bundler cache to invalidate (samchon/typia#2126). Members are surfaced
|
|
156
684
|
// through this same selector, which keeps an index signature's own body-
|
|
157
685
|
// free key/value contract as the boundary.
|
|
686
|
+
//
|
|
687
|
+
// A call or construct signature is symbol-less in the same way and is
|
|
688
|
+
// deliberately NOT surfaced: the analysis emits a callable as `typeof x ===
|
|
689
|
+
// "function"` and never reads its parameter or return types, so registering
|
|
690
|
+
// them would invalidate consumers on edits that cannot change the output.
|
|
691
|
+
// TestProjectDependenciesSignatureAliasTransform is that boundary.
|
|
692
|
+
// A type parameter is not surfaced from here even though the declaration
|
|
693
|
+
// owns the list: a parameter the members use is reached through the member
|
|
694
|
+
// that uses it, and one no member uses is not consulted at all, so appending
|
|
695
|
+
// the list would report an alias behind an unused default. The parameter's
|
|
696
|
+
// own declaration carries its constraint and default, and this same selector
|
|
697
|
+
// surfaces those when the walk arrives there.
|
|
158
698
|
output := []*nativeast.Node{}
|
|
159
699
|
for _, member := range declaration.Members() {
|
|
160
700
|
if member == nil || member.Kind != nativeast.KindIndexSignature {
|
|
@@ -165,7 +705,8 @@ func metadataDependency_typeSurface(declaration *nativeast.Node) []*nativeast.No
|
|
|
165
705
|
return output
|
|
166
706
|
case nativeast.KindPropertySignature,
|
|
167
707
|
nativeast.KindPropertyDeclaration,
|
|
168
|
-
nativeast.KindParameter
|
|
708
|
+
nativeast.KindParameter,
|
|
709
|
+
nativeast.KindVariableDeclaration:
|
|
169
710
|
if annotation := declaration.Type(); annotation != nil {
|
|
170
711
|
return []*nativeast.Node{annotation}
|
|
171
712
|
}
|
|
@@ -199,7 +740,7 @@ func metadataDependency_typeSurface(declaration *nativeast.Node) []*nativeast.No
|
|
|
199
740
|
// which in turn walks type-alias declarations transitively.
|
|
200
741
|
func metadataDependency_walkNode(
|
|
201
742
|
checker *nativechecker.Checker,
|
|
202
|
-
listener
|
|
743
|
+
listener MetadataDependency_IListener,
|
|
203
744
|
node *nativeast.Node,
|
|
204
745
|
visited map[*nativeast.Symbol]bool,
|
|
205
746
|
) {
|
|
@@ -227,6 +768,7 @@ func metadataDependency_walkNode(
|
|
|
227
768
|
}
|
|
228
769
|
if name != nil {
|
|
229
770
|
metadataDependency_touchVisited(checker, listener, metadataDependency_resolve(checker, listener, name), visited)
|
|
771
|
+
metadataDependency_touchQualifier(checker, listener, name, visited)
|
|
230
772
|
}
|
|
231
773
|
node.ForEachChild(func(child *nativeast.Node) bool {
|
|
232
774
|
metadataDependency_walkNode(checker, listener, child, visited)
|
|
@@ -234,6 +776,44 @@ func metadataDependency_walkNode(
|
|
|
234
776
|
})
|
|
235
777
|
}
|
|
236
778
|
|
|
779
|
+
// metadataDependency_touchQualifier resolves every prefix of a qualified
|
|
780
|
+
// reference, so the modules that SELECTED the namespace half are reported too.
|
|
781
|
+
//
|
|
782
|
+
// The checker answers a qualified name with its terminus: `Kind.A` hands back
|
|
783
|
+
// the enum member, which is not an alias, so metadataDependency_resolve finds no
|
|
784
|
+
// path to walk and the barrel between the caller and the enum goes unreported --
|
|
785
|
+
// while `Kind` alone would have been an alias and reported it. Re-pointing
|
|
786
|
+
// `export { Kind } from "./kind"` at another enum changes the constant the
|
|
787
|
+
// validator compares against, so that barrel is an input like any other
|
|
788
|
+
// (samchon/typia#2126, samchon/typia#2357).
|
|
789
|
+
//
|
|
790
|
+
// Each prefix is resolved the same way the terminus is, which keeps a nested
|
|
791
|
+
// qualification (`outer.inner.Type`) reported hop by hop and costs nothing for a
|
|
792
|
+
// bare name, whose prefix chain is empty.
|
|
793
|
+
func metadataDependency_touchQualifier(
|
|
794
|
+
checker *nativechecker.Checker,
|
|
795
|
+
listener MetadataDependency_IListener,
|
|
796
|
+
name *nativeast.Node,
|
|
797
|
+
visited map[*nativeast.Symbol]bool,
|
|
798
|
+
) {
|
|
799
|
+
for qualifier := metadataDependency_left(name); qualifier != nil; qualifier = metadataDependency_left(qualifier) {
|
|
800
|
+
metadataDependency_touchVisited(checker, listener, metadataDependency_resolve(checker, listener, qualifier), visited)
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// metadataDependency_left returns the namespace half of a qualified reference,
|
|
805
|
+
// in either the type spelling (`A.B`) or the value spelling (`a.b`), and nil for
|
|
806
|
+
// a bare name that qualifies nothing.
|
|
807
|
+
func metadataDependency_left(node *nativeast.Node) *nativeast.Node {
|
|
808
|
+
switch node.Kind {
|
|
809
|
+
case nativeast.KindQualifiedName:
|
|
810
|
+
return node.AsQualifiedName().Left
|
|
811
|
+
case nativeast.KindPropertyAccessExpression:
|
|
812
|
+
return node.Expression()
|
|
813
|
+
}
|
|
814
|
+
return nil
|
|
815
|
+
}
|
|
816
|
+
|
|
237
817
|
// metadataDependency_resolve resolves a written reference name to its final
|
|
238
818
|
// symbol, following import aliases so the touched declarations are the real
|
|
239
819
|
// declaring files rather than the local import specifier. Every module the
|
|
@@ -241,7 +821,7 @@ func metadataDependency_walkNode(
|
|
|
241
821
|
// SELECT which declaration the terminus is (see metadataDependency_touchPath).
|
|
242
822
|
func metadataDependency_resolve(
|
|
243
823
|
checker *nativechecker.Checker,
|
|
244
|
-
listener
|
|
824
|
+
listener MetadataDependency_IListener,
|
|
245
825
|
name *nativeast.Node,
|
|
246
826
|
) *nativeast.Symbol {
|
|
247
827
|
if checker == nil || name == nil {
|
|
@@ -252,7 +832,9 @@ func metadataDependency_resolve(
|
|
|
252
832
|
return nil
|
|
253
833
|
}
|
|
254
834
|
if symbol.Flags&nativeast.SymbolFlagsAlias != 0 {
|
|
255
|
-
|
|
835
|
+
// The type walk: a hop reached here was reached because a consulted type is
|
|
836
|
+
// built from what it publishes, so it reports on the consultation channel.
|
|
837
|
+
metadataDependency_touchPath(checker, listener, symbol, listener.File)
|
|
256
838
|
if resolved := nativechecker.Checker_getAliasedSymbol(checker, symbol); resolved != nil {
|
|
257
839
|
symbol = resolved
|
|
258
840
|
}
|
|
@@ -275,8 +857,9 @@ func metadataDependency_resolve(
|
|
|
275
857
|
// barrel's exports, keeping unrelated siblings out of the envelope.
|
|
276
858
|
func metadataDependency_touchPath(
|
|
277
859
|
checker *nativechecker.Checker,
|
|
278
|
-
listener
|
|
860
|
+
listener MetadataDependency_IListener,
|
|
279
861
|
symbol *nativeast.Symbol,
|
|
862
|
+
report func(fileName string),
|
|
280
863
|
) {
|
|
281
864
|
visited := map[*nativeast.Symbol]bool{}
|
|
282
865
|
for symbol != nil && symbol.Flags&nativeast.SymbolFlagsAlias != 0 && visited[symbol] == false {
|
|
@@ -287,7 +870,7 @@ func metadataDependency_touchPath(
|
|
|
287
870
|
}
|
|
288
871
|
// The file that WRITES this hop (the barrel's own `export ... from` line).
|
|
289
872
|
if src := nativeast.GetSourceFileOfNode(declaration); src != nil {
|
|
290
|
-
|
|
873
|
+
report(src.FileName())
|
|
291
874
|
}
|
|
292
875
|
specifier := metadataDependency_moduleSpecifier(declaration)
|
|
293
876
|
if specifier == nil {
|
|
@@ -308,7 +891,7 @@ func metadataDependency_touchPath(
|
|
|
308
891
|
}
|
|
309
892
|
for _, moduleDeclaration := range module.Declarations {
|
|
310
893
|
if src := nativeast.GetSourceFileOfNode(moduleDeclaration); src != nil {
|
|
311
|
-
|
|
894
|
+
report(src.FileName())
|
|
312
895
|
}
|
|
313
896
|
}
|
|
314
897
|
symbol = metadataDependency_exported(module, declaration)
|