ttsc 0.26.2 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/cmd/graphbench/main.go +26 -16
- package/cmd/graphdump/main.go +37 -12
- package/cmd/graphdump/run_declares_the_capability_its_output_carries_test.go +137 -0
- package/cmd/graphdump/run_reports_an_unknown_flag_without_exiting_the_process_test.go +56 -0
- package/cmd/graphdump/run_reports_an_unloadable_project_without_printing_a_dump_test.go +46 -0
- package/cmd/ttsc/api_transform.go +28 -3
- package/cmd/ttscgraph/auxiliary_identity_state_tracks_retargets_not_source_contents_test.go +85 -0
- package/cmd/ttscgraph/disk_realpath_other.go +16 -0
- package/cmd/ttscgraph/disk_realpath_windows.go +56 -0
- package/cmd/ttscgraph/dump.go +43 -11
- package/cmd/ttscgraph/run_dump_claims_artifacts_only_when_it_asked_test.go +135 -0
- package/cmd/ttscgraph/run_dump_declares_the_capability_its_output_carries_test.go +96 -0
- package/cmd/ttscgraph/serve.go +357 -60
- package/cmd/ttscgraph/serve_adopts_a_republished_artifact_set_test.go +348 -0
- package/cmd/ttscgraph/serve_projects_an_artifact_no_source_owns_test.go +90 -0
- package/cmd/ttscgraph/serve_shards.go +31 -9
- package/driver/config_discovery.go +121 -0
- package/driver/emit_plugin.go +77 -11
- package/driver/graph.go +64 -11
- package/driver/input_observation.go +273 -0
- package/driver/input_observation_test.go +149 -0
- package/driver/plugins.go +506 -15
- package/driver/program.go +54 -1
- package/driver/resolution_candidates.go +13 -5
- package/driver/rewrite.go +45 -2
- package/driver/transform_dependencies.go +283 -0
- package/driver/transform_dependencies_declares_every_file_without_a_contributor_test.go +28 -0
- package/driver/transform_dependencies_drops_a_self_reported_dependency_test.go +21 -0
- package/driver/transform_dependencies_keys_a_reported_path_like_the_envelope_test.go +46 -0
- package/driver/transform_dependencies_requires_every_contributor_to_declare_test.go +38 -0
- package/driver/transform_dependencies_stays_silent_for_an_undeclared_contributor_test.go +23 -0
- package/driver/transform_dependencies_withdraws_completeness_after_an_unusable_dependency_test.go +37 -0
- package/internal/graph/artifacts.go +230 -0
- package/internal/graph/artifacts_index_what_a_plugin_published_test.go +154 -0
- package/internal/graph/artifacts_survive_a_partial_rebuild_test.go +89 -0
- package/internal/graph/build.go +35 -0
- package/internal/graph/build_releases_the_scratch_it_no_longer_reads_test.go +118 -0
- package/internal/graph/doc_refs_are_the_use_the_checker_already_counts_test.go +93 -0
- package/internal/graph/doc_refs_resolve_documentation_links_test.go +335 -0
- package/internal/graph/doc_tags.go +416 -0
- package/internal/graph/doc_tags_are_claimed_before_they_are_read_test.go +131 -0
- package/internal/graph/doc_tags_capture_every_unrecognized_tag_test.go +165 -0
- package/internal/graph/doc_tags_read_only_what_the_parser_attached_test.go +97 -0
- package/internal/graph/doc_tags_stop_at_the_external_boundary_test.go +59 -0
- package/internal/graph/doc_tags_survive_line_endings_and_repeated_blocks_test.go +146 -0
- package/internal/graph/dump.go +60 -13
- package/internal/graph/dump_checkout_paths_are_stable_test.go +2 -2
- package/internal/graph/dump_paths.go +2 -2
- package/internal/graph/dump_paths_are_portable_and_injective_test.go +1 -1
- package/internal/graph/edge_kinds_names_every_declared_kind_test.go +49 -0
- package/internal/graph/edges.go +1 -0
- package/internal/graph/graph.go +79 -4
- package/internal/graph/provenance.go +29 -2
- package/lib/TtscCompiler.d.ts +12 -11
- package/lib/TtscCompiler.js +44 -29
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/captureProcessOutput.js +2 -2
- package/lib/compiler/internal/captureProcessOutput.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +4 -3
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +9 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js +16 -4
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.js +3 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +1 -1
- package/lib/compiler/internal/runBuild.js +80 -34
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +2 -2
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +28 -0
- package/lib/compiler/internal/sharedHostHelpers.js +39 -0
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +12 -4
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.d.ts +3 -0
- package/lib/compiler/internal/transformProjectInMemory.js +239 -35
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/schema.js +12 -5
- package/lib/flags/schema.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/internal/createCanonicalTempDirectory.d.ts +17 -0
- package/lib/internal/createCanonicalTempDirectory.js +42 -0
- package/lib/internal/createCanonicalTempDirectory.js.map +1 -0
- package/lib/internal/projectInputPathIdentity.d.ts +3 -0
- package/lib/internal/projectInputPathIdentity.js +11 -5
- package/lib/internal/projectInputPathIdentity.js.map +1 -1
- package/lib/internal/resolveNodeBinary.d.ts +14 -0
- package/lib/internal/resolveNodeBinary.js +150 -0
- package/lib/internal/resolveNodeBinary.js.map +1 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.d.ts +15 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.js +61 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.js.map +1 -0
- package/lib/launcher/internal/prepareExecution.d.ts +3 -0
- package/lib/launcher/internal/prepareExecution.js +42 -14
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +25 -13
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +18 -3
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +2 -0
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +47 -3
- package/lib/launcher/internal/runtimeHooks.js +746 -64
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +62 -8
- package/lib/plugin/internal/buildSourcePlugin.js +754 -72
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/capabilityResolutionCache.d.ts +76 -0
- package/lib/plugin/internal/capabilityResolutionCache.js +224 -0
- package/lib/plugin/internal/capabilityResolutionCache.js.map +1 -0
- package/lib/plugin/internal/loadProjectPlugins.d.ts +17 -5
- package/lib/plugin/internal/loadProjectPlugins.js +1339 -77
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/resolveCapabilityPlugins.d.ts +55 -0
- package/lib/plugin/resolveCapabilityPlugins.js +118 -0
- package/lib/plugin/resolveCapabilityPlugins.js.map +1 -0
- package/lib/register.d.ts +1 -0
- package/lib/register.js +46 -0
- package/lib/register.js.map +1 -0
- package/lib/structures/ITtscCompilerContext.d.ts +6 -3
- package/lib/structures/ITtscCompilerTransformation.d.ts +38 -0
- package/lib/structures/ITtscPlugin.d.ts +33 -0
- package/package.json +16 -9
- package/shim/ast/parent.go +16 -3
- package/shim/checker/enums_gen.go +11 -0
- package/shim/checker/go.mod +9 -0
- package/shim/checker/go.sum +22 -0
- package/shim/checker/shim.go +78 -0
- package/shim/compiler/emithook.go +10 -0
- package/shim/compiler/incremental.go +45 -8
- package/src/TtscCompiler.ts +55 -33
- package/src/compiler/internal/captureProcessOutput.ts +3 -2
- package/src/compiler/internal/compileProjectInMemory.ts +4 -3
- package/src/compiler/internal/project/createNativeProjectContextArgs.ts +19 -4
- package/src/compiler/internal/resolveEmittedJavaScript.ts +6 -0
- package/src/compiler/internal/runBuild.ts +102 -39
- package/src/compiler/internal/runSingleFileEmit.ts +2 -2
- package/src/compiler/internal/sharedHostHelpers.ts +44 -0
- package/src/compiler/internal/startResidentTransform.ts +12 -3
- package/src/compiler/internal/transformProjectInMemory.ts +410 -39
- package/src/flags/schema.ts +12 -5
- package/src/index.ts +1 -0
- package/src/internal/createCanonicalTempDirectory.ts +53 -0
- package/src/internal/projectInputPathIdentity.ts +17 -4
- package/src/internal/resolveNodeBinary.ts +173 -0
- package/src/internal/resolveSafeCacheCleanupTargets.ts +85 -0
- package/src/launcher/internal/prepareExecution.ts +50 -14
- package/src/launcher/internal/runTtsc.ts +24 -13
- package/src/launcher/internal/runTtscserver.ts +18 -3
- package/src/launcher/internal/runTtsx.ts +2 -0
- package/src/launcher/internal/runtimeHooks.ts +934 -68
- package/src/plugin/internal/buildSourcePlugin.ts +984 -79
- package/src/plugin/internal/capabilityResolutionCache.ts +305 -0
- package/src/plugin/internal/loadProjectPlugins.ts +1718 -104
- package/src/plugin/resolveCapabilityPlugins.ts +171 -0
- package/src/register.ts +47 -0
- package/src/structures/ITtscCompilerContext.ts +6 -3
- package/src/structures/ITtscCompilerTransformation.ts +46 -0
- package/src/structures/ITtscPlugin.ts +36 -0
- package/tools/shim_audit/baseline.json +0 -2
- package/utility/host.go +18 -3
- package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +0 -5
- package/lib/internal/assertSafeExplicitCacheDirectory.js +0 -26
- package/lib/internal/assertSafeExplicitCacheDirectory.js.map +0 -1
- package/src/internal/assertSafeExplicitCacheDirectory.ts +0 -29
package/driver/plugins.go
CHANGED
|
@@ -5,7 +5,9 @@ import (
|
|
|
5
5
|
"fmt"
|
|
6
6
|
"os"
|
|
7
7
|
"path/filepath"
|
|
8
|
+
"sort"
|
|
8
9
|
"strings"
|
|
10
|
+
"sync"
|
|
9
11
|
)
|
|
10
12
|
|
|
11
13
|
// LinkedPluginsEnv is the environment variable ttsc sets to pass the JSON
|
|
@@ -27,6 +29,44 @@ const LinkedPluginsEnv = "TTSC_LINKED_PLUGINS_JSON"
|
|
|
27
29
|
// still receive it.
|
|
28
30
|
const PluginConfigDirEnv = "TTSC_PLUGIN_CONFIG_DIR"
|
|
29
31
|
|
|
32
|
+
// TsgoArgsEnv is the environment variable through which the ttsc launcher
|
|
33
|
+
// passes the tsgo CLI flags it did not consume itself (`--strict`,
|
|
34
|
+
// `--declaration`, the single-file lane's output containment, …) to a native
|
|
35
|
+
// sidecar. The value is a JSON array of argv tokens; an empty or absent value
|
|
36
|
+
// means nothing was forwarded.
|
|
37
|
+
//
|
|
38
|
+
// It rides the environment for the same reason PluginConfigDirEnv does, only
|
|
39
|
+
// with sharper consequences. The payload used to travel as a `--tsgo-args`
|
|
40
|
+
// flag, which #113 appended to a plugin protocol third-party hosts had already
|
|
41
|
+
// frozen. A Go `flag.FlagSet` created with `flag.ContinueOnError` treats an
|
|
42
|
+
// undeclared flag as fatal, so every sidecar built before #113 answered
|
|
43
|
+
// `flag provided but not defined: -tsgo-args` and exited 2 — including on
|
|
44
|
+
// `ttsc <file.ts>`, where the launcher forwards its own output-containment
|
|
45
|
+
// flags and the user passed nothing at all (issue #1188). An unknown
|
|
46
|
+
// environment variable is inert to every host; an unknown flag is fatal to all
|
|
47
|
+
// of them. ttsc's own hosts still accept `--tsgo-args` so an older launcher
|
|
48
|
+
// paired with a newer host keeps working.
|
|
49
|
+
const TsgoArgsEnv = "TTSC_TSGO_ARGS"
|
|
50
|
+
|
|
51
|
+
// TsgoArgsFromEnv decodes the forwarded tsgo argv the launcher published in
|
|
52
|
+
// TsgoArgsEnv. An absent or whitespace-only value yields a nil slice and no
|
|
53
|
+
// error, so a host can call this unconditionally.
|
|
54
|
+
//
|
|
55
|
+
// Hosts that also declare a `--tsgo-args` flag should prefer the explicit flag
|
|
56
|
+
// value and fall back to this; LoadProgram already does that for every
|
|
57
|
+
// driver-based host.
|
|
58
|
+
func TsgoArgsFromEnv() ([]string, error) {
|
|
59
|
+
raw := strings.TrimSpace(os.Getenv(TsgoArgsEnv))
|
|
60
|
+
if raw == "" {
|
|
61
|
+
return nil, nil
|
|
62
|
+
}
|
|
63
|
+
var args []string
|
|
64
|
+
if err := json.Unmarshal([]byte(raw), &args); err != nil {
|
|
65
|
+
return nil, fmt.Errorf("ttsc driver: invalid %s: %w", TsgoArgsEnv, err)
|
|
66
|
+
}
|
|
67
|
+
return args, nil
|
|
68
|
+
}
|
|
69
|
+
|
|
30
70
|
// PluginConfigBaseDir returns the directory where a plugin anchors its
|
|
31
71
|
// config-file discovery walk and resolves relative "configFile" paths.
|
|
32
72
|
// The explicit PluginConfigDirEnv channel wins when set; otherwise the
|
|
@@ -60,6 +100,182 @@ type PluginContext struct {
|
|
|
60
100
|
Cwd string
|
|
61
101
|
Entry PluginEntry
|
|
62
102
|
Tsconfig string
|
|
103
|
+
|
|
104
|
+
reportHostInput func(string)
|
|
105
|
+
reportHostInputHash func(string, *string)
|
|
106
|
+
reportHostInputHashUnknown func(string)
|
|
107
|
+
reportHostInputRealpath func(string, *string)
|
|
108
|
+
reportHostInputRealpathUnknown func(string)
|
|
109
|
+
reportFileDependency func(string, string)
|
|
110
|
+
reportFileDependencyRejected func(string)
|
|
111
|
+
reportFileComplete func(string)
|
|
112
|
+
reportEveryFileComplete func()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ReportHostInputHash declares the exact file state consumed by a native
|
|
116
|
+
// plugin. hash is a lowercase SHA-256 digest for an observed file and nil for
|
|
117
|
+
// a missing candidate. Conflicting observations are retained as host inputs
|
|
118
|
+
// but omitted from PluginHostInputHashes, forcing persistent adapters to
|
|
119
|
+
// decline narrow reuse without failing the transform.
|
|
120
|
+
func (ctx PluginContext) ReportHostInputHash(file string, hash *string) {
|
|
121
|
+
if ctx.reportHostInputHash == nil || strings.TrimSpace(file) == "" {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
if !filepath.IsAbs(file) {
|
|
125
|
+
file = filepath.Join(ctx.Cwd, file)
|
|
126
|
+
}
|
|
127
|
+
file = filepath.Clean(file)
|
|
128
|
+
if hash != nil && !isLowerSHA256(*hash) {
|
|
129
|
+
if ctx.reportHostInputHashUnknown != nil {
|
|
130
|
+
ctx.reportHostInputHashUnknown(file)
|
|
131
|
+
} else if ctx.reportHostInput != nil {
|
|
132
|
+
ctx.reportHostInput(file)
|
|
133
|
+
}
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
ctx.reportHostInputHash(file, hash)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ReportHostInputRealpath declares the physical path resolved while a native
|
|
140
|
+
// plugin consumed file. realpath is absolute for an observed path and nil for
|
|
141
|
+
// a missing candidate. Conflicting observations remain host inputs but are
|
|
142
|
+
// omitted from PluginHostInputRealpaths so adapters cannot attach an earlier
|
|
143
|
+
// result to a retargeted symlink or junction.
|
|
144
|
+
func (ctx PluginContext) ReportHostInputRealpath(file string, realpath *string) {
|
|
145
|
+
if ctx.reportHostInputRealpath == nil || strings.TrimSpace(file) == "" {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
if !filepath.IsAbs(file) {
|
|
149
|
+
file = filepath.Join(ctx.Cwd, file)
|
|
150
|
+
}
|
|
151
|
+
file = filepath.Clean(file)
|
|
152
|
+
if realpath != nil {
|
|
153
|
+
if strings.TrimSpace(*realpath) == "" || !filepath.IsAbs(*realpath) {
|
|
154
|
+
if ctx.reportHostInputRealpathUnknown != nil {
|
|
155
|
+
ctx.reportHostInputRealpathUnknown(file)
|
|
156
|
+
} else if ctx.reportHostInput != nil {
|
|
157
|
+
ctx.reportHostInput(file)
|
|
158
|
+
}
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
resolved := filepath.Clean(*realpath)
|
|
162
|
+
realpath = &resolved
|
|
163
|
+
}
|
|
164
|
+
ctx.reportHostInputRealpath(file, realpath)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
func isLowerSHA256(value string) bool {
|
|
168
|
+
if len(value) != 64 {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
for _, char := range value {
|
|
172
|
+
if (char < '0' || char > '9') && (char < 'a' || char > 'f') {
|
|
173
|
+
return false
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return true
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ReportHostInput declares an absolute file whose content or presence was
|
|
180
|
+
// consumed while the native plugin evaluated configuration. Native transform
|
|
181
|
+
// envelopes expose the generation-wide union so persistent hosts can invalidate
|
|
182
|
+
// without re-evaluating plugin config on the JavaScript side.
|
|
183
|
+
func (ctx PluginContext) ReportHostInput(file string) {
|
|
184
|
+
if ctx.reportHostInput == nil || strings.TrimSpace(file) == "" {
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
if !filepath.IsAbs(file) {
|
|
188
|
+
file = filepath.Join(ctx.Cwd, file)
|
|
189
|
+
}
|
|
190
|
+
ctx.reportHostInput(filepath.Clean(file))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ReportFileDependency declares one file whose content influenced this
|
|
194
|
+
// plugin's contribution to the transformed file file. Both are resolved
|
|
195
|
+
// against the plugin's cwd and keyed like every other envelope section, so a
|
|
196
|
+
// plugin reports the program's own file names and the host joins the sections
|
|
197
|
+
// by key.
|
|
198
|
+
//
|
|
199
|
+
// Reporting alone only widens what a consumer invalidates on; it is
|
|
200
|
+
// ReportFileDependenciesComplete that turns the reported set into the file's
|
|
201
|
+
// whole input set.
|
|
202
|
+
//
|
|
203
|
+
// A dependency this cannot resolve to a key is not silently forgotten: it
|
|
204
|
+
// withdraws this plugin's completeness claim for that file, because a complete
|
|
205
|
+
// list missing a member is exactly what serves stale output. The plugin's other
|
|
206
|
+
// files keep theirs.
|
|
207
|
+
func (ctx PluginContext) ReportFileDependency(file string, dependency string) {
|
|
208
|
+
if ctx.reportFileDependency == nil {
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
target, ok := ctx.transformKey(file)
|
|
212
|
+
if !ok {
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
input, ok := ctx.transformKey(dependency)
|
|
216
|
+
if !ok {
|
|
217
|
+
if ctx.reportFileDependencyRejected != nil {
|
|
218
|
+
ctx.reportFileDependencyRejected(target)
|
|
219
|
+
}
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
ctx.reportFileDependency(target, input)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ReportFileDependenciesComplete declares that everything this plugin's
|
|
226
|
+
// contribution to file consumed, beyond file's own text and the universal
|
|
227
|
+
// compiler-option chain, was reported through ReportFileDependency — possibly
|
|
228
|
+
// nothing at all.
|
|
229
|
+
//
|
|
230
|
+
// The declaration is per (plugin, file), the way the protocol's completeness
|
|
231
|
+
// contract defines it: the host lists a file in dependenciesComplete only when
|
|
232
|
+
// every plugin that can contribute to it declared it, because a consumer cannot
|
|
233
|
+
// attribute one plugin's entries back to it.
|
|
234
|
+
func (ctx PluginContext) ReportFileDependenciesComplete(file string) {
|
|
235
|
+
if ctx.reportFileComplete == nil {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
target, ok := ctx.transformKey(file)
|
|
239
|
+
if !ok {
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
ctx.reportFileComplete(target)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ReportDependenciesComplete makes the same declaration for every file in the
|
|
246
|
+
// program at once: this plugin's contribution to any transformed file is a
|
|
247
|
+
// function of that file's own text, whatever it reported for that file, its
|
|
248
|
+
// reported host inputs, and the compiler options.
|
|
249
|
+
//
|
|
250
|
+
// That is the honest claim of a syntactic transform — one that decides from the
|
|
251
|
+
// file in front of it and its own configuration rather than from the type
|
|
252
|
+
// system — and it is the only form available to a hook that never sees the
|
|
253
|
+
// program, such as SourcePreamble.
|
|
254
|
+
func (ctx PluginContext) ReportDependenciesComplete() {
|
|
255
|
+
if ctx.reportEveryFileComplete == nil {
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
ctx.reportEveryFileComplete()
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// transformKey resolves one plugin-reported path to the key convention every
|
|
262
|
+
// envelope section uses. A plugin reports the spellings its host handed it
|
|
263
|
+
// (absolute program file names, or paths relative to the plugin's cwd), and
|
|
264
|
+
// the compiler's own file names are slash-normalized on every platform, so
|
|
265
|
+
// both sides must pass through TransformOutputKey to meet.
|
|
266
|
+
//
|
|
267
|
+
// Separators and the project prefix reconcile, but the suffix keeps the case
|
|
268
|
+
// the caller wrote: report the program's own spelling of a file rather than a
|
|
269
|
+
// re-cased one, or the key will not match on a case-insensitive filesystem and
|
|
270
|
+
// the declaration is dropped.
|
|
271
|
+
func (ctx PluginContext) transformKey(file string) (string, bool) {
|
|
272
|
+
if strings.TrimSpace(file) == "" {
|
|
273
|
+
return "", false
|
|
274
|
+
}
|
|
275
|
+
if !filepath.IsAbs(file) {
|
|
276
|
+
file = filepath.Join(ctx.Cwd, file)
|
|
277
|
+
}
|
|
278
|
+
return TransformOutputKey(ctx.Cwd, filepath.Clean(file)), true
|
|
63
279
|
}
|
|
64
280
|
|
|
65
281
|
// SourcePreamblePlugin can inject source text before TypeScript-Go parses the
|
|
@@ -90,9 +306,245 @@ type EmitTransformPlugin interface {
|
|
|
90
306
|
}
|
|
91
307
|
|
|
92
308
|
type linkedPluginState struct {
|
|
93
|
-
cwd
|
|
94
|
-
|
|
95
|
-
|
|
309
|
+
cwd string
|
|
310
|
+
declarations *pluginFileDeclarations
|
|
311
|
+
entries []PluginEntry
|
|
312
|
+
inputs *pluginHostInputScopes
|
|
313
|
+
tsconfig string
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// pluginHostInputScopes keeps one observation set per plugin hook. A hash from
|
|
317
|
+
// one hook cannot prove another hook's same-file dependency when that hook only
|
|
318
|
+
// reported the path, while ReportHostInput followed by ReportHostInputHash in
|
|
319
|
+
// one hook remains one complete observation.
|
|
320
|
+
type pluginHostInputScopes struct {
|
|
321
|
+
mu sync.Mutex
|
|
322
|
+
scopes []*pluginHostInputs
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
type pluginHostInputs struct {
|
|
326
|
+
files map[string]struct{}
|
|
327
|
+
hashes map[string]pluginHostInputHash
|
|
328
|
+
realpaths map[string]pluginHostInputHash
|
|
329
|
+
mu sync.Mutex
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
type pluginHostInputHash struct {
|
|
333
|
+
hash *string
|
|
334
|
+
known bool
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
func newPluginHostInputScopes() *pluginHostInputScopes {
|
|
338
|
+
return &pluginHostInputScopes{}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
func newPluginHostInputs() *pluginHostInputs {
|
|
342
|
+
return &pluginHostInputs{
|
|
343
|
+
files: map[string]struct{}{},
|
|
344
|
+
hashes: map[string]pluginHostInputHash{},
|
|
345
|
+
realpaths: map[string]pluginHostInputHash{},
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
func (inputs *pluginHostInputScopes) newScope() *pluginHostInputs {
|
|
350
|
+
scope := newPluginHostInputs()
|
|
351
|
+
if inputs == nil {
|
|
352
|
+
return scope
|
|
353
|
+
}
|
|
354
|
+
inputs.mu.Lock()
|
|
355
|
+
inputs.scopes = append(inputs.scopes, scope)
|
|
356
|
+
inputs.mu.Unlock()
|
|
357
|
+
return scope
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
func (inputs *pluginHostInputScopes) snapshot() []*pluginHostInputs {
|
|
361
|
+
if inputs == nil {
|
|
362
|
+
return nil
|
|
363
|
+
}
|
|
364
|
+
inputs.mu.Lock()
|
|
365
|
+
defer inputs.mu.Unlock()
|
|
366
|
+
return append([]*pluginHostInputs(nil), inputs.scopes...)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
func (inputs *pluginHostInputs) addHash(file string, hash *string) {
|
|
370
|
+
if inputs == nil {
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
inputs.mu.Lock()
|
|
374
|
+
defer inputs.mu.Unlock()
|
|
375
|
+
inputs.files[file] = struct{}{}
|
|
376
|
+
previous, exists := inputs.hashes[file]
|
|
377
|
+
if !exists {
|
|
378
|
+
inputs.hashes[file] = pluginHostInputHash{hash: cloneStringPointer(hash), known: true}
|
|
379
|
+
return
|
|
380
|
+
}
|
|
381
|
+
if !previous.known || !sameStringPointer(previous.hash, hash) {
|
|
382
|
+
inputs.hashes[file] = pluginHostInputHash{known: false}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
func (inputs *pluginHostInputs) invalidateHash(file string) {
|
|
387
|
+
if inputs == nil {
|
|
388
|
+
return
|
|
389
|
+
}
|
|
390
|
+
inputs.mu.Lock()
|
|
391
|
+
defer inputs.mu.Unlock()
|
|
392
|
+
inputs.files[file] = struct{}{}
|
|
393
|
+
inputs.hashes[file] = pluginHostInputHash{known: false}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
func (inputs *pluginHostInputs) addRealpath(file string, realpath *string) {
|
|
397
|
+
if inputs == nil {
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
inputs.mu.Lock()
|
|
401
|
+
defer inputs.mu.Unlock()
|
|
402
|
+
inputs.files[file] = struct{}{}
|
|
403
|
+
previous, exists := inputs.realpaths[file]
|
|
404
|
+
if !exists {
|
|
405
|
+
inputs.realpaths[file] = pluginHostInputHash{hash: cloneStringPointer(realpath), known: true}
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
if !previous.known || !sameStringPointer(previous.hash, realpath) {
|
|
409
|
+
inputs.realpaths[file] = pluginHostInputHash{known: false}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
func (inputs *pluginHostInputs) invalidateRealpath(file string) {
|
|
414
|
+
if inputs == nil {
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
inputs.mu.Lock()
|
|
418
|
+
defer inputs.mu.Unlock()
|
|
419
|
+
inputs.files[file] = struct{}{}
|
|
420
|
+
inputs.realpaths[file] = pluginHostInputHash{known: false}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
func cloneStringPointer(value *string) *string {
|
|
424
|
+
if value == nil {
|
|
425
|
+
return nil
|
|
426
|
+
}
|
|
427
|
+
cloned := *value
|
|
428
|
+
return &cloned
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
func sameStringPointer(left, right *string) bool {
|
|
432
|
+
if left == nil || right == nil {
|
|
433
|
+
return left == nil && right == nil
|
|
434
|
+
}
|
|
435
|
+
return *left == *right
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
func (inputs *pluginHostInputs) add(file string) {
|
|
439
|
+
if inputs == nil {
|
|
440
|
+
return
|
|
441
|
+
}
|
|
442
|
+
inputs.mu.Lock()
|
|
443
|
+
inputs.files[file] = struct{}{}
|
|
444
|
+
inputs.mu.Unlock()
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
func (inputs *pluginHostInputs) snapshot() (map[string]struct{}, map[string]pluginHostInputHash, map[string]pluginHostInputHash) {
|
|
448
|
+
if inputs == nil {
|
|
449
|
+
return nil, nil, nil
|
|
450
|
+
}
|
|
451
|
+
inputs.mu.Lock()
|
|
452
|
+
defer inputs.mu.Unlock()
|
|
453
|
+
files := make(map[string]struct{}, len(inputs.files))
|
|
454
|
+
for file := range inputs.files {
|
|
455
|
+
files[file] = struct{}{}
|
|
456
|
+
}
|
|
457
|
+
hashes := make(map[string]pluginHostInputHash, len(inputs.hashes))
|
|
458
|
+
for file, observation := range inputs.hashes {
|
|
459
|
+
hashes[file] = pluginHostInputHash{
|
|
460
|
+
hash: cloneStringPointer(observation.hash),
|
|
461
|
+
known: observation.known,
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
realpaths := make(map[string]pluginHostInputHash, len(inputs.realpaths))
|
|
465
|
+
for file, observation := range inputs.realpaths {
|
|
466
|
+
realpaths[file] = pluginHostInputHash{
|
|
467
|
+
hash: cloneStringPointer(observation.hash),
|
|
468
|
+
known: observation.known,
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return files, hashes, realpaths
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
func (inputs *pluginHostInputScopes) list() []string {
|
|
475
|
+
union := map[string]struct{}{}
|
|
476
|
+
for _, scope := range inputs.snapshot() {
|
|
477
|
+
files, _, _ := scope.snapshot()
|
|
478
|
+
for file := range files {
|
|
479
|
+
union[file] = struct{}{}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
files := make([]string, 0, len(union))
|
|
483
|
+
for file := range union {
|
|
484
|
+
files = append(files, file)
|
|
485
|
+
}
|
|
486
|
+
sort.Strings(files)
|
|
487
|
+
return files
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
func (inputs *pluginHostInputScopes) hashList() map[string]*string {
|
|
491
|
+
combined := map[string]pluginHostInputHash{}
|
|
492
|
+
for _, scope := range inputs.snapshot() {
|
|
493
|
+
files, hashes, _ := scope.snapshot()
|
|
494
|
+
for file := range files {
|
|
495
|
+
observation, exists := hashes[file]
|
|
496
|
+
if !exists || !observation.known {
|
|
497
|
+
combined[file] = pluginHostInputHash{known: false}
|
|
498
|
+
continue
|
|
499
|
+
}
|
|
500
|
+
previous, exists := combined[file]
|
|
501
|
+
if !exists {
|
|
502
|
+
combined[file] = observation
|
|
503
|
+
} else if !previous.known || !sameStringPointer(previous.hash, observation.hash) {
|
|
504
|
+
combined[file] = pluginHostInputHash{known: false}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
hashes := map[string]*string{}
|
|
509
|
+
for file, observation := range combined {
|
|
510
|
+
if observation.known {
|
|
511
|
+
hashes[file] = cloneStringPointer(observation.hash)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if len(hashes) == 0 {
|
|
515
|
+
return nil
|
|
516
|
+
}
|
|
517
|
+
return hashes
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
func (inputs *pluginHostInputScopes) realpathList() map[string]*string {
|
|
521
|
+
combined := map[string]pluginHostInputHash{}
|
|
522
|
+
for _, scope := range inputs.snapshot() {
|
|
523
|
+
files, _, realpaths := scope.snapshot()
|
|
524
|
+
for file := range files {
|
|
525
|
+
observation, exists := realpaths[file]
|
|
526
|
+
if !exists || !observation.known {
|
|
527
|
+
combined[file] = pluginHostInputHash{known: false}
|
|
528
|
+
continue
|
|
529
|
+
}
|
|
530
|
+
previous, exists := combined[file]
|
|
531
|
+
if !exists {
|
|
532
|
+
combined[file] = observation
|
|
533
|
+
} else if !previous.known || !sameStringPointer(previous.hash, observation.hash) {
|
|
534
|
+
combined[file] = pluginHostInputHash{known: false}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
realpaths := map[string]*string{}
|
|
539
|
+
for file, observation := range combined {
|
|
540
|
+
if observation.known {
|
|
541
|
+
realpaths[file] = cloneStringPointer(observation.hash)
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if len(realpaths) == 0 {
|
|
545
|
+
return nil
|
|
546
|
+
}
|
|
547
|
+
return realpaths
|
|
96
548
|
}
|
|
97
549
|
|
|
98
550
|
var pluginRegistry []any
|
|
@@ -113,16 +565,23 @@ func RegisterPlugin(plugin any) {
|
|
|
113
565
|
func loadLinkedPluginState(cwd, tsconfigPath string) (linkedPluginState, error) {
|
|
114
566
|
input := strings.TrimSpace(os.Getenv(LinkedPluginsEnv))
|
|
115
567
|
if input == "" {
|
|
116
|
-
return linkedPluginState{
|
|
568
|
+
return linkedPluginState{
|
|
569
|
+
cwd: cwd,
|
|
570
|
+
declarations: newPluginFileDeclarations(),
|
|
571
|
+
inputs: newPluginHostInputScopes(),
|
|
572
|
+
tsconfig: tsconfigPath,
|
|
573
|
+
}, nil
|
|
117
574
|
}
|
|
118
575
|
var entries []PluginEntry
|
|
119
576
|
if err := json.Unmarshal([]byte(input), &entries); err != nil {
|
|
120
577
|
return linkedPluginState{}, fmt.Errorf("ttsc driver: invalid %s: %w", LinkedPluginsEnv, err)
|
|
121
578
|
}
|
|
122
579
|
return linkedPluginState{
|
|
123
|
-
cwd:
|
|
124
|
-
|
|
125
|
-
|
|
580
|
+
cwd: cwd,
|
|
581
|
+
declarations: newPluginFileDeclarations(),
|
|
582
|
+
entries: entries,
|
|
583
|
+
inputs: newPluginHostInputScopes(),
|
|
584
|
+
tsconfig: tsconfigPath,
|
|
126
585
|
}, nil
|
|
127
586
|
}
|
|
128
587
|
|
|
@@ -140,7 +599,7 @@ func (state linkedPluginState) sourcePreamble() (string, error) {
|
|
|
140
599
|
if !ok {
|
|
141
600
|
continue
|
|
142
601
|
}
|
|
143
|
-
text, err := preamble.SourcePreamble(state.
|
|
602
|
+
text, err := preamble.SourcePreamble(state.contextAt(index, entry))
|
|
144
603
|
if err != nil {
|
|
145
604
|
return "", err
|
|
146
605
|
}
|
|
@@ -161,7 +620,7 @@ func (state linkedPluginState) apply(prog *Program) error {
|
|
|
161
620
|
if !ok {
|
|
162
621
|
continue
|
|
163
622
|
}
|
|
164
|
-
if err := transform.ApplyProgram(prog, state.
|
|
623
|
+
if err := transform.ApplyProgram(prog, state.contextAt(index, entry)); err != nil {
|
|
165
624
|
return err
|
|
166
625
|
}
|
|
167
626
|
}
|
|
@@ -195,7 +654,7 @@ func (state linkedPluginState) emitTransforms() ([]PluginTransform, error) {
|
|
|
195
654
|
if !ok {
|
|
196
655
|
continue
|
|
197
656
|
}
|
|
198
|
-
transform, err := emitter.EmitTransform(state.
|
|
657
|
+
transform, err := emitter.EmitTransform(state.contextAt(index, entry))
|
|
199
658
|
if err != nil {
|
|
200
659
|
return nil, err
|
|
201
660
|
}
|
|
@@ -216,11 +675,43 @@ func registeredPlugin(index int) (any, bool) {
|
|
|
216
675
|
return pluginRegistry[index], true
|
|
217
676
|
}
|
|
218
677
|
|
|
219
|
-
//
|
|
220
|
-
|
|
678
|
+
// contextAt builds the PluginContext the driver passes to one plugin hook.
|
|
679
|
+
//
|
|
680
|
+
// Host-input observations are scoped per hook, because a hash one hook reported
|
|
681
|
+
// cannot prove another hook's dependency on the same path. Dependency
|
|
682
|
+
// declarations are scoped per plugin instead: completeness is a claim about
|
|
683
|
+
// everything one plugin contributes to a file, so the claims of its preamble
|
|
684
|
+
// and program hooks are the same plugin's claim and must not be attributed
|
|
685
|
+
// separately.
|
|
686
|
+
func (state linkedPluginState) contextAt(index int, entry PluginEntry) PluginContext {
|
|
687
|
+
inputs := state.inputs.newScope()
|
|
688
|
+
declaration := state.declarations.forPlugin(index)
|
|
221
689
|
return PluginContext{
|
|
222
|
-
Cwd:
|
|
223
|
-
Entry:
|
|
224
|
-
Tsconfig:
|
|
690
|
+
Cwd: state.cwd,
|
|
691
|
+
Entry: entry,
|
|
692
|
+
Tsconfig: state.tsconfig,
|
|
693
|
+
reportHostInput: inputs.add,
|
|
694
|
+
reportHostInputHash: inputs.addHash,
|
|
695
|
+
reportHostInputHashUnknown: inputs.invalidateHash,
|
|
696
|
+
reportHostInputRealpath: inputs.addRealpath,
|
|
697
|
+
reportHostInputRealpathUnknown: inputs.invalidateRealpath,
|
|
698
|
+
reportFileDependency: declaration.addDependency,
|
|
699
|
+
reportFileDependencyRejected: declaration.rejectDependency,
|
|
700
|
+
reportFileComplete: declaration.addComplete,
|
|
701
|
+
reportEveryFileComplete: declaration.completeEveryFile,
|
|
225
702
|
}
|
|
226
703
|
}
|
|
704
|
+
|
|
705
|
+
// hostInputs returns the exact native configuration inputs reported in this
|
|
706
|
+
// generation.
|
|
707
|
+
func (state linkedPluginState) hostInputs() []string {
|
|
708
|
+
return state.inputs.list()
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
func (state linkedPluginState) hostInputHashes() map[string]*string {
|
|
712
|
+
return state.inputs.hashList()
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
func (state linkedPluginState) hostInputRealpaths() map[string]*string {
|
|
716
|
+
return state.inputs.realpathList()
|
|
717
|
+
}
|
package/driver/program.go
CHANGED
|
@@ -197,6 +197,7 @@ type Program struct {
|
|
|
197
197
|
checkerRelease func()
|
|
198
198
|
Host shimcompiler.CompilerHost
|
|
199
199
|
FS vfs.FS
|
|
200
|
+
inputObserver *inputObservationFS
|
|
200
201
|
SourcePreamble string
|
|
201
202
|
plugins linkedPluginState
|
|
202
203
|
pluginsApplied bool
|
|
@@ -263,6 +264,23 @@ func ParseTSConfig(fs vfs.FS, cwd, tsconfigPath string, host shimcompiler.Compil
|
|
|
263
264
|
return parsed, nil, nil
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// resolveTsgoArgs picks the forwarded tsgo argv for this load: the caller's
|
|
268
|
+
// explicit LoadProgramOptions.TsgoArgs when it has one, otherwise whatever the
|
|
269
|
+
// launcher published in TsgoArgsEnv.
|
|
270
|
+
//
|
|
271
|
+
// The explicit value wins so a host that declares its own `--tsgo-args` flag
|
|
272
|
+
// (cmd/ttsc, the utility host, @ttsc/lint) keeps deciding for itself, and an
|
|
273
|
+
// embedder that deliberately passes an empty argv is not overridden by an
|
|
274
|
+
// environment variable an ancestor ttsc process happened to set. The fallback
|
|
275
|
+
// is what carries the payload into a third-party sidecar whose flag set does
|
|
276
|
+
// not declare `--tsgo-args` at all — see TsgoArgsEnv and issue #1188.
|
|
277
|
+
func resolveTsgoArgs(explicit []string) ([]string, error) {
|
|
278
|
+
if len(explicit) > 0 {
|
|
279
|
+
return explicit, nil
|
|
280
|
+
}
|
|
281
|
+
return TsgoArgsFromEnv()
|
|
282
|
+
}
|
|
283
|
+
|
|
266
284
|
// parseTsgoArgs runs forwarded tsgo CLI flags through TypeScript-Go's own
|
|
267
285
|
// command-line parser, yielding a CompilerOptions overlay ParseTSConfig merges
|
|
268
286
|
// over the tsconfig. This is how a plugin build — which constructs its Program
|
|
@@ -357,6 +375,8 @@ func LoadProgram(cwd, tsconfigPath string, options LoadProgramOptions) (*Program
|
|
|
357
375
|
if fs == nil {
|
|
358
376
|
fs = DefaultFS()
|
|
359
377
|
}
|
|
378
|
+
inputObserver := newInputObservationFS(fs)
|
|
379
|
+
fs = inputObserver
|
|
360
380
|
if options.SourcePreamble != "" {
|
|
361
381
|
fs = sourcePreambleFS{
|
|
362
382
|
FS: fs,
|
|
@@ -365,7 +385,11 @@ func LoadProgram(cwd, tsconfigPath string, options LoadProgramOptions) (*Program
|
|
|
365
385
|
}
|
|
366
386
|
host := DefaultHost(cwd, fs)
|
|
367
387
|
|
|
368
|
-
|
|
388
|
+
tsgoArgs, err := resolveTsgoArgs(options.TsgoArgs)
|
|
389
|
+
if err != nil {
|
|
390
|
+
return nil, nil, err
|
|
391
|
+
}
|
|
392
|
+
cliOptions, cliDiags, err := parseTsgoArgs(tsgoArgs, host)
|
|
369
393
|
if err != nil {
|
|
370
394
|
return nil, nil, err
|
|
371
395
|
}
|
|
@@ -401,6 +425,7 @@ func LoadProgram(cwd, tsconfigPath string, options LoadProgramOptions) (*Program
|
|
|
401
425
|
checkerRelease: done,
|
|
402
426
|
Host: host,
|
|
403
427
|
FS: fs,
|
|
428
|
+
inputObserver: inputObserver,
|
|
404
429
|
SourcePreamble: options.SourcePreamble,
|
|
405
430
|
}
|
|
406
431
|
prog.plugins = pluginState
|
|
@@ -563,6 +588,34 @@ func (p *Program) HasLinkedProgramPlugins() bool {
|
|
|
563
588
|
return p != nil && p.plugins.hasProgramPlugins()
|
|
564
589
|
}
|
|
565
590
|
|
|
591
|
+
// PluginHostInputs returns the generation-wide native configuration files
|
|
592
|
+
// reported by linked plugins while this Program was loaded or transformed.
|
|
593
|
+
func (p *Program) PluginHostInputs() []string {
|
|
594
|
+
if p == nil {
|
|
595
|
+
return nil
|
|
596
|
+
}
|
|
597
|
+
return p.plugins.hostInputs()
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// PluginHostInputHashes returns evaluation-time fingerprints for the subset of
|
|
601
|
+
// native host inputs whose exact state plugins reported without conflict.
|
|
602
|
+
func (p *Program) PluginHostInputHashes() map[string]*string {
|
|
603
|
+
if p == nil {
|
|
604
|
+
return nil
|
|
605
|
+
}
|
|
606
|
+
return p.plugins.hostInputHashes()
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// PluginHostInputRealpaths returns evaluation-time physical identities for the
|
|
610
|
+
// subset of native host inputs whose symlink or junction target was observed
|
|
611
|
+
// without conflict.
|
|
612
|
+
func (p *Program) PluginHostInputRealpaths() map[string]*string {
|
|
613
|
+
if p == nil {
|
|
614
|
+
return nil
|
|
615
|
+
}
|
|
616
|
+
return p.plugins.hostInputRealpaths()
|
|
617
|
+
}
|
|
618
|
+
|
|
566
619
|
// Diagnostics returns project diagnostics that must block compilation or
|
|
567
620
|
// runtime execution before any JavaScript is emitted or evaluated.
|
|
568
621
|
func (p *Program) Diagnostics() []Diagnostic {
|