ttsc 0.19.3 → 0.20.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 +7 -5
- package/cmd/graphdump/main.go +2 -4
- package/cmd/ttsc/filter.go +12 -4
- package/cmd/ttsc/filter_resolves_flag_names_case_insensitively_test.go +53 -0
- package/cmd/ttsc/flags_gen.go +3 -3
- package/cmd/ttscgraph/dump.go +5 -7
- package/cmd/ttscgraph/run_dump_emits_only_checker_verified_member_relations_test.go +118 -0
- package/cmd/ttscgraph/serve.go +58 -308
- package/cmd/ttscgraph/serve_session_keeps_base_url_fallback_unchanged_test.go +49 -0
- package/cmd/ttscgraph/serve_session_keeps_esm_directory_candidate_unchanged_test.go +61 -0
- package/cmd/ttscgraph/serve_session_keeps_exports_blocked_file_candidates_unchanged_test.go +64 -0
- package/cmd/ttscgraph/serve_session_keeps_inactive_conditional_export_unchanged_test.go +66 -0
- package/cmd/ttscgraph/serve_session_keeps_lower_priority_module_candidate_unchanged_test.go +67 -0
- package/cmd/ttscgraph/serve_session_keeps_lower_priority_paths_pattern_unchanged_test.go +58 -0
- package/cmd/ttscgraph/serve_session_keeps_nonlongest_root_dirs_candidate_unchanged_test.go +54 -0
- package/cmd/ttscgraph/serve_session_reloads_commonjs_package_entry_for_esm_test.go +50 -0
- package/cmd/ttscgraph/serve_session_reloads_module_suffix_candidate_test.go +41 -0
- package/cmd/ttscgraph/serve_session_reloads_superseding_module_candidates_test.go +216 -0
- package/cmd/ttscgraph/serve_session_retries_failed_dump_test.go +103 -0
- package/driver/graph.go +12 -6
- package/driver/lsp.go +30 -0
- package/driver/program.go +37 -1
- package/driver/resolution_candidates.go +819 -0
- package/driver/windowsjunction/windowsjunction.go +40 -0
- package/go.mod +2 -0
- package/internal/graph/build.go +45 -11
- package/internal/graph/dump.go +276 -100
- package/internal/graph/dump_checkout_paths_are_stable_test.go +210 -0
- package/internal/graph/dump_diagnostics_ride_the_generation_that_built_it_test.go +9 -3
- package/internal/graph/dump_paths.go +172 -0
- package/internal/graph/dump_paths_are_portable_and_injective_test.go +93 -0
- package/internal/graph/dump_uses_ecma_line_terminators_test.go +87 -0
- package/internal/graph/duplicate_variable_object_members_keep_first_declaration_test.go +61 -0
- package/internal/graph/edges.go +208 -0
- package/internal/graph/graph.go +143 -5
- package/internal/graph/line_model.go +122 -0
- package/internal/graph/member_relation_edges_follow_checker_validity_test.go +85 -0
- package/internal/graph/member_relation_edges_preserve_checker_boundaries_test.go +191 -0
- package/internal/graph/member_relation_edges_reject_checker_invalid_pairs_test.go +119 -0
- package/internal/graph/node_ids_preserve_hash_bearing_components_test.go +41 -0
- package/internal/graph/node_modifiers_emit_union_strings_test.go +4 -1
- package/internal/graph/object_literal_members_ride_on_the_snapshot_test.go +192 -0
- package/internal/graph/object_member_signatures_preserve_literal_whitespace_test.go +67 -0
- package/internal/graph/object_members.go +229 -0
- package/internal/graph/provenance.go +88 -30
- package/internal/graph/source_texts_cover_every_resident_program_source_test.go +73 -0
- package/internal/graphsymbols/position_helpers_follow_ecma_line_terminators_test.go +66 -0
- package/internal/graphsymbols/provider.go +26 -91
- package/internal/lspserver/lsp_clean_didopen_refreshes_compiler_state_test.go +144 -0
- package/internal/lspserver/lsp_completion.go +109 -0
- package/internal/lspserver/lsp_completion_gate_never_refuses_a_matching_line_test.go +50 -0
- package/internal/lspserver/lsp_completion_hints_longest_trigger_wins_test.go +149 -0
- package/internal/lspserver/lsp_completion_hints_nearest_trigger_wins_test.go +37 -0
- package/internal/lspserver/lsp_completion_merges_into_upstream_response_test.go +149 -0
- package/internal/lspserver/lsp_completion_nearest_hint_replaces_nearest_filter_test.go +43 -0
- package/internal/lspserver/lsp_completion_preserves_completion_list_extensions_test.go +99 -0
- package/internal/lspserver/lsp_completion_refuses_hints_inside_a_string_literal_test.go +69 -0
- package/internal/lspserver/lsp_completion_replaces_full_filter_in_rank_order_test.go +85 -0
- package/internal/lspserver/lsp_completion_request.go +455 -0
- package/internal/lspserver/lsp_completion_scope.go +530 -0
- package/internal/lspserver/lsp_completion_scope_bench_test.go +41 -0
- package/internal/lspserver/lsp_completion_scope_classifies_regex_statement_and_operator_boundaries_test.go +39 -0
- package/internal/lspserver/lsp_completion_scope_ignores_jsdoc_bytes_in_literals_test.go +108 -0
- package/internal/lspserver/lsp_completion_scope_refuses_regex_hints_test.go +52 -0
- package/internal/lspserver/lsp_completion_trigger_uses_last_rune_test.go +24 -0
- package/internal/lspserver/lsp_deleted_watched_file_withdraws_plugin_diagnostics_test.go +110 -0
- package/internal/lspserver/lsp_didsave_keeps_the_incremental_changed_uri_path_test.go +78 -0
- package/internal/lspserver/lsp_hints_absence_is_not_an_error_test.go +46 -0
- package/internal/lspserver/lsp_hints_refresh_coalesces_concurrent_requests_test.go +82 -0
- package/internal/lspserver/lsp_hints_refresh_ignores_a_superseded_generation_test.go +40 -0
- package/internal/lspserver/lsp_hints_refresh_keeps_each_producer_isolated_test.go +64 -0
- package/internal/lspserver/lsp_hints_refresh_replaces_the_session_snapshot_test.go +66 -0
- package/internal/lspserver/lsp_hints_refresh_scheduled_by_editor_events_test.go +90 -0
- package/internal/lspserver/lsp_hints_refresh_serves_completion_while_running_test.go +91 -0
- package/internal/lspserver/lsp_index_byte_from_bounds_its_search_start_test.go +38 -0
- package/internal/lspserver/lsp_initialize_constrains_position_encoding_to_utf16_test.go +205 -0
- package/internal/lspserver/lsp_late_completion_trigger_is_reported_once_test.go +105 -0
- package/internal/lspserver/lsp_native_completion_hints_decode_flat_lint_wire_test.go +66 -0
- package/internal/lspserver/lsp_native_completion_hints_grouped_compatibility_boundary_test.go +60 -0
- package/internal/lspserver/lsp_native_plugin_source.go +315 -2
- package/internal/lspserver/lsp_native_resident.go +304 -0
- package/internal/lspserver/lsp_plugin.go +85 -8
- package/internal/lspserver/lsp_plugin_completion_resolve_stays_local_test.go +82 -0
- package/internal/lspserver/lsp_position_conversions_span_astral_and_combining_runes_test.go +119 -0
- package/internal/lspserver/lsp_proxy.go +601 -9
- package/internal/lspserver/lsp_refresh.go +70 -0
- package/internal/lspserver/lsp_resident_falls_back_when_serve_unsupported_test.go +43 -0
- package/internal/lspserver/lsp_resident_maps_verb_args_test.go +34 -0
- package/internal/lspserver/lsp_server.go +13 -1
- package/internal/lspserver/lsp_watched_file_changes_reach_compiler_caches_test.go +172 -0
- package/lib/TtscCompiler.d.ts +3 -1
- package/lib/TtscCompiler.js +5 -1
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/TtscService.d.ts +13 -3
- package/lib/TtscService.js +6 -6
- package/lib/TtscService.js.map +1 -1
- package/lib/compiler/internal/project/readConfigJson.d.ts +30 -0
- package/lib/compiler/internal/project/readConfigJson.js +208 -0
- package/lib/compiler/internal/project/readConfigJson.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.js +53 -149
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/residentTransformProcess.d.ts +15 -2
- package/lib/compiler/internal/residentTransformProcess.js +159 -39
- package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +6 -0
- package/lib/compiler/internal/runBuild.js +143 -44
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.d.ts +5 -1
- package/lib/compiler/internal/startResidentTransform.js +3 -1
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +12 -2
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/parser.d.ts +19 -0
- package/lib/flags/parser.js +78 -36
- package/lib/flags/parser.js.map +1 -1
- package/lib/flags/schema.d.ts +49 -11
- package/lib/flags/schema.js +94 -22
- package/lib/flags/schema.js.map +1 -1
- package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +5 -0
- package/lib/internal/assertSafeExplicitCacheDirectory.js +26 -0
- package/lib/internal/assertSafeExplicitCacheDirectory.js.map +1 -0
- package/lib/launcher/internal/runTtsc.js +107 -69
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +28 -41
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +15 -0
- package/lib/launcher/internal/runtimeHooks.js +18 -1
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/launcher/internal/watchTopology.d.ts +43 -0
- package/lib/launcher/internal/watchTopology.js +360 -0
- package/lib/launcher/internal/watchTopology.js.map +1 -0
- package/lib/plugin/internal/buildSourcePlugin.d.ts +14 -3
- package/lib/plugin/internal/buildSourcePlugin.js +247 -61
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.js +63 -2
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerTransformation.d.ts +16 -0
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +2 -0
- package/package.json +8 -8
- package/shim/ast/shim.go +48 -3
- package/shim/astnav/go.mod +14 -0
- package/shim/astnav/go.sum +20 -0
- package/shim/astnav/shim.go +15 -0
- package/shim/checker/shim.go +100 -0
- package/shim/core/shim.go +47 -0
- package/shim/diagnosticwriter/lint.go +50 -0
- package/src/TtscCompiler.ts +5 -1
- package/src/TtscService.ts +37 -10
- package/src/compiler/internal/project/readConfigJson.ts +209 -0
- package/src/compiler/internal/project/readProjectConfig.ts +62 -158
- package/src/compiler/internal/residentTransformProcess.ts +197 -39
- package/src/compiler/internal/runBuild.ts +169 -47
- package/src/compiler/internal/startResidentTransform.ts +12 -1
- package/src/compiler/internal/transformProjectInMemory.ts +12 -1
- package/src/flags/parser.ts +113 -42
- package/src/flags/schema.ts +113 -31
- package/src/internal/assertSafeExplicitCacheDirectory.ts +29 -0
- package/src/launcher/internal/runTtsc.ts +117 -68
- package/src/launcher/internal/runTtsx.ts +29 -44
- package/src/launcher/internal/runtimeHooks.ts +30 -2
- package/src/launcher/internal/watchTopology.ts +466 -0
- package/src/plugin/internal/buildSourcePlugin.ts +326 -64
- package/src/plugin/internal/loadProjectPlugins.ts +80 -2
- package/src/structures/ITtscCompilerTransformation.ts +17 -0
- package/src/structures/internal/ITtscParsedProjectConfig.ts +2 -0
- package/tools/shim_audit/baseline.json +0 -3
- package/tools/shim_audit/main.go +42 -14
- package/tools/shim_audit/shim_dir_coverage_test.go +25 -0
- package/utility/flags_gen.go +3 -3
- package/utility/host.go +9 -3
package/cmd/ttscgraph/serve.go
CHANGED
|
@@ -14,7 +14,6 @@ import (
|
|
|
14
14
|
"sort"
|
|
15
15
|
"strings"
|
|
16
16
|
|
|
17
|
-
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
18
17
|
shimtsoptions "github.com/microsoft/typescript-go/shim/tsoptions"
|
|
19
18
|
shimtspath "github.com/microsoft/typescript-go/shim/tspath"
|
|
20
19
|
|
|
@@ -128,6 +127,10 @@ type graphSession struct {
|
|
|
128
127
|
configDigests []graph.FileDigest
|
|
129
128
|
roots []graph.RootFile
|
|
130
129
|
initialized bool
|
|
130
|
+
// pendingDumpMode remembers a generation whose state was captured but whose
|
|
131
|
+
// dump failed. Until an input change lets the session rebuild, an unchanged
|
|
132
|
+
// request must retry that dump instead of falsely confirming the older graph.
|
|
133
|
+
pendingDumpMode string
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
func newGraphSession(cwd, tsconfig string) (*graphSession, error) {
|
|
@@ -147,8 +150,17 @@ func (s *graphSession) Close() error {
|
|
|
147
150
|
|
|
148
151
|
func (s *graphSession) Snapshot() (*graph.Dump, string, bool, error) {
|
|
149
152
|
if !s.initialized {
|
|
150
|
-
dump
|
|
153
|
+
// The captured compiler state is initialized even when its first dump is
|
|
154
|
+
// not publishable. Mark the attempt before building so a later request can
|
|
155
|
+
// observe a config/source edit that repairs the path error instead of
|
|
156
|
+
// retrying the stale Program forever.
|
|
151
157
|
s.initialized = true
|
|
158
|
+
dump, err := s.buildDump()
|
|
159
|
+
if err != nil {
|
|
160
|
+
s.pendingDumpMode = serveModeInitial
|
|
161
|
+
return nil, "", false, err
|
|
162
|
+
}
|
|
163
|
+
s.pendingDumpMode = ""
|
|
152
164
|
return &dump, serveModeInitial, true, nil
|
|
153
165
|
}
|
|
154
166
|
|
|
@@ -160,16 +172,14 @@ func (s *graphSession) Snapshot() (*graph.Dump, string, bool, error) {
|
|
|
160
172
|
if err := s.reload(); err != nil {
|
|
161
173
|
return nil, "", false, err
|
|
162
174
|
}
|
|
163
|
-
|
|
164
|
-
return &dump, serveModeReload, true, nil
|
|
175
|
+
return s.changedSnapshot(serveModeReload)
|
|
165
176
|
}
|
|
166
177
|
|
|
167
178
|
if diskStatesChanged(s.auxStates) {
|
|
168
179
|
if err := s.reload(); err != nil {
|
|
169
180
|
return nil, "", false, err
|
|
170
181
|
}
|
|
171
|
-
|
|
172
|
-
return &dump, serveModeReload, true, nil
|
|
182
|
+
return s.changedSnapshot(serveModeReload)
|
|
173
183
|
}
|
|
174
184
|
|
|
175
185
|
roots, err := projectRootFiles(s.compiler.Program(), true)
|
|
@@ -180,8 +190,7 @@ func (s *graphSession) Snapshot() (*graph.Dump, string, bool, error) {
|
|
|
180
190
|
if err := s.reload(); err != nil {
|
|
181
191
|
return nil, "", false, err
|
|
182
192
|
}
|
|
183
|
-
|
|
184
|
-
return &dump, serveModeReload, true, nil
|
|
193
|
+
return s.changedSnapshot(serveModeReload)
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
changed, deleted, err := changedSources(s.sourceHashes)
|
|
@@ -192,18 +201,19 @@ func (s *graphSession) Snapshot() (*graph.Dump, string, bool, error) {
|
|
|
192
201
|
if err := s.reload(); err != nil {
|
|
193
202
|
return nil, "", false, err
|
|
194
203
|
}
|
|
195
|
-
|
|
196
|
-
return &dump, serveModeReload, true, nil
|
|
204
|
+
return s.changedSnapshot(serveModeReload)
|
|
197
205
|
}
|
|
198
206
|
if len(changed) == 0 {
|
|
207
|
+
if s.pendingDumpMode != "" {
|
|
208
|
+
return s.changedSnapshot(s.pendingDumpMode)
|
|
209
|
+
}
|
|
199
210
|
return nil, serveModeUnchanged, false, nil
|
|
200
211
|
}
|
|
201
212
|
if s.compiler.Program().HasLinkedProgramPlugins() {
|
|
202
213
|
if err := s.reload(); err != nil {
|
|
203
214
|
return nil, "", false, err
|
|
204
215
|
}
|
|
205
|
-
|
|
206
|
-
return &dump, serveModeReload, true, nil
|
|
216
|
+
return s.changedSnapshot(serveModeReload)
|
|
207
217
|
}
|
|
208
218
|
|
|
209
219
|
mode := serveModeIncremental
|
|
@@ -222,14 +232,22 @@ func (s *graphSession) Snapshot() (*graph.Dump, string, bool, error) {
|
|
|
222
232
|
if err := s.reload(); err != nil {
|
|
223
233
|
return nil, "", false, err
|
|
224
234
|
}
|
|
225
|
-
|
|
226
|
-
return &dump, serveModeReload, true, nil
|
|
235
|
+
return s.changedSnapshot(serveModeReload)
|
|
227
236
|
}
|
|
228
237
|
}
|
|
229
238
|
if err := s.captureState(); err != nil {
|
|
230
239
|
return nil, "", false, err
|
|
231
240
|
}
|
|
232
|
-
|
|
241
|
+
return s.changedSnapshot(mode)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
func (s *graphSession) changedSnapshot(mode string) (*graph.Dump, string, bool, error) {
|
|
245
|
+
dump, err := s.buildDump()
|
|
246
|
+
if err != nil {
|
|
247
|
+
s.pendingDumpMode = mode
|
|
248
|
+
return nil, "", false, err
|
|
249
|
+
}
|
|
250
|
+
s.pendingDumpMode = ""
|
|
233
251
|
return &dump, mode, true, nil
|
|
234
252
|
}
|
|
235
253
|
|
|
@@ -323,7 +341,7 @@ func missingRootInputs(configs []*shimtsoptions.ParsedCommandLine, sourceHashes
|
|
|
323
341
|
return missing
|
|
324
342
|
}
|
|
325
343
|
|
|
326
|
-
func (s *graphSession) buildDump() graph.Dump {
|
|
344
|
+
func (s *graphSession) buildDump() (graph.Dump, error) {
|
|
327
345
|
program := s.compiler.Program()
|
|
328
346
|
built := graph.Build(program)
|
|
329
347
|
// One texts map feeds both the spans and the manifest digests, so the bytes a
|
|
@@ -337,7 +355,6 @@ func (s *graphSession) buildDump() graph.Dump {
|
|
|
337
355
|
texts,
|
|
338
356
|
graph.DumpOrigin{
|
|
339
357
|
Provenance: graph.NewProvenance(
|
|
340
|
-
s.cwd,
|
|
341
358
|
serveProducer(),
|
|
342
359
|
fullSnapshotCapabilities,
|
|
343
360
|
s.configDigests,
|
|
@@ -345,7 +362,7 @@ func (s *graphSession) buildDump() graph.Dump {
|
|
|
345
362
|
texts,
|
|
346
363
|
s.diskDigests,
|
|
347
364
|
),
|
|
348
|
-
Diagnostics: graph.NewDiagnostics(program
|
|
365
|
+
Diagnostics: graph.NewDiagnostics(program),
|
|
349
366
|
},
|
|
350
367
|
)
|
|
351
368
|
}
|
|
@@ -553,11 +570,6 @@ type diskState struct {
|
|
|
553
570
|
Exists bool
|
|
554
571
|
}
|
|
555
572
|
|
|
556
|
-
type packageTarget struct {
|
|
557
|
-
path string
|
|
558
|
-
wildcard string
|
|
559
|
-
}
|
|
560
|
-
|
|
561
573
|
// captureDiskStates records the freshness state of speculative resolution
|
|
562
574
|
// candidates. Most candidates do not exist, and a module specifier can name a
|
|
563
575
|
// path the host OS cannot even parse (`./style.css?inline`, a `data:` URL on
|
|
@@ -614,17 +626,35 @@ func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCom
|
|
|
614
626
|
directory := filepath.Dir(file)
|
|
615
627
|
inputs = appendAncestorInputs(inputs, directory, cwd)
|
|
616
628
|
for _, reference := range source.ReferencedFiles {
|
|
617
|
-
inputs = append(inputs,
|
|
629
|
+
inputs = append(inputs, driver.FileCandidates(filepath.Join(directory, filepath.FromSlash(reference.FileName)))...)
|
|
618
630
|
}
|
|
619
631
|
for _, reference := range source.TypeReferenceDirectives {
|
|
620
|
-
inputs = append(inputs,
|
|
632
|
+
inputs = append(inputs, driver.TypeReferenceCandidates(configs, directory, cwd, reference.FileName)...)
|
|
621
633
|
}
|
|
622
|
-
for _, specifier := range
|
|
634
|
+
for _, specifier := range driver.SourceModuleSpecifiers(source) {
|
|
635
|
+
context := driver.ModuleResolutionContext{
|
|
636
|
+
Mode: program.TSProgram.GetModeForUsageLocation(source, specifier),
|
|
637
|
+
}
|
|
638
|
+
for _, parsed := range configs {
|
|
639
|
+
if parsed != nil && parsed.ParsedConfig != nil && parsed.ParsedConfig.CompilerOptions != nil {
|
|
640
|
+
context.Options = parsed.ParsedConfig.CompilerOptions
|
|
641
|
+
break
|
|
642
|
+
}
|
|
643
|
+
}
|
|
623
644
|
resolved := program.TSProgram.GetResolvedModuleFromModuleSpecifier(source, specifier)
|
|
624
645
|
if resolved != nil && resolved.IsResolved() {
|
|
646
|
+
inputs = append(inputs, driver.ModuleResolutionPredecessors(
|
|
647
|
+
configs,
|
|
648
|
+
directory,
|
|
649
|
+
cwd,
|
|
650
|
+
specifier.Text(),
|
|
651
|
+
resolved.ResolvedFileName,
|
|
652
|
+
program.FS.UseCaseSensitiveFileNames(),
|
|
653
|
+
context,
|
|
654
|
+
)...)
|
|
625
655
|
continue
|
|
626
656
|
}
|
|
627
|
-
inputs = append(inputs,
|
|
657
|
+
inputs = append(inputs, driver.ModuleResolutionCandidates(configs, directory, cwd, specifier.Text(), context)...)
|
|
628
658
|
}
|
|
629
659
|
}
|
|
630
660
|
// Config `types` entries request type packages without any source syntax, so
|
|
@@ -635,82 +665,12 @@ func auxiliaryInputs(program *driver.Program, configs []*shimtsoptions.ParsedCom
|
|
|
635
665
|
continue
|
|
636
666
|
}
|
|
637
667
|
for _, name := range parsed.ParsedConfig.CompilerOptions.Types {
|
|
638
|
-
inputs = append(inputs,
|
|
668
|
+
inputs = append(inputs, driver.TypeReferenceCandidates(configs, parsed.GetCurrentDirectory(), cwd, name)...)
|
|
639
669
|
}
|
|
640
670
|
}
|
|
641
671
|
return compactSortedStrings(inputs)
|
|
642
672
|
}
|
|
643
673
|
|
|
644
|
-
func typeReferenceCandidates(configs []*shimtsoptions.ParsedCommandLine, directory, cwd, name string) []string {
|
|
645
|
-
candidates := []string{}
|
|
646
|
-
for _, parsed := range configs {
|
|
647
|
-
if parsed == nil || parsed.ParsedConfig == nil || parsed.ParsedConfig.CompilerOptions == nil {
|
|
648
|
-
continue
|
|
649
|
-
}
|
|
650
|
-
for _, root := range parsed.ParsedConfig.CompilerOptions.TypeRoots {
|
|
651
|
-
candidates = append(candidates, fileCandidates(filepath.Join(root, filepath.FromSlash(name)))...)
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
for current := filepath.Clean(directory); ; current = filepath.Dir(current) {
|
|
655
|
-
candidates = append(candidates, fileCandidates(filepath.Join(current, "node_modules", "@types", filepath.FromSlash(name)))...)
|
|
656
|
-
if current == filepath.Clean(cwd) || filepath.Dir(current) == current {
|
|
657
|
-
return candidates
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
func sourceModuleSpecifiers(source *shimast.SourceFile) []*shimast.Node {
|
|
663
|
-
if source == nil {
|
|
664
|
-
return nil
|
|
665
|
-
}
|
|
666
|
-
specifiers := []*shimast.Node{}
|
|
667
|
-
var walk func(*shimast.Node) bool
|
|
668
|
-
walk = func(node *shimast.Node) bool {
|
|
669
|
-
if node == nil {
|
|
670
|
-
return false
|
|
671
|
-
}
|
|
672
|
-
var specifier *shimast.Node
|
|
673
|
-
switch node.Kind {
|
|
674
|
-
case shimast.KindImportDeclaration, shimast.KindJSImportDeclaration:
|
|
675
|
-
specifier = node.AsImportDeclaration().ModuleSpecifier
|
|
676
|
-
case shimast.KindExportDeclaration:
|
|
677
|
-
specifier = node.AsExportDeclaration().ModuleSpecifier
|
|
678
|
-
case shimast.KindImportEqualsDeclaration:
|
|
679
|
-
reference := node.AsImportEqualsDeclaration().ModuleReference
|
|
680
|
-
if reference != nil && reference.Kind == shimast.KindExternalModuleReference {
|
|
681
|
-
specifier = reference.AsExternalModuleReference().Expression
|
|
682
|
-
}
|
|
683
|
-
case shimast.KindImportType:
|
|
684
|
-
argument := node.AsImportTypeNode().Argument
|
|
685
|
-
if argument != nil && argument.Kind == shimast.KindLiteralType {
|
|
686
|
-
specifier = argument.AsLiteralTypeNode().Literal
|
|
687
|
-
}
|
|
688
|
-
case shimast.KindCallExpression:
|
|
689
|
-
call := node.AsCallExpression()
|
|
690
|
-
if isModuleSpecifierCall(call) && call.Arguments != nil && len(call.Arguments.Nodes) > 0 {
|
|
691
|
-
specifier = call.Arguments.Nodes[0]
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
if specifier != nil && (specifier.Kind == shimast.KindStringLiteral || specifier.Kind == shimast.KindNoSubstitutionTemplateLiteral) {
|
|
695
|
-
specifiers = append(specifiers, specifier)
|
|
696
|
-
}
|
|
697
|
-
node.ForEachChild(walk)
|
|
698
|
-
return false
|
|
699
|
-
}
|
|
700
|
-
walk(source.AsNode())
|
|
701
|
-
return specifiers
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
func isModuleSpecifierCall(call *shimast.CallExpression) bool {
|
|
705
|
-
if call == nil || call.Expression == nil {
|
|
706
|
-
return false
|
|
707
|
-
}
|
|
708
|
-
if call.Expression.Kind == shimast.KindImportKeyword {
|
|
709
|
-
return true
|
|
710
|
-
}
|
|
711
|
-
return call.Expression.Kind == shimast.KindIdentifier && call.Expression.Text() == "require"
|
|
712
|
-
}
|
|
713
|
-
|
|
714
674
|
func appendAncestorInputs(inputs []string, directory, stop string) []string {
|
|
715
675
|
stop = filepath.Clean(stop)
|
|
716
676
|
for current := filepath.Clean(directory); ; current = filepath.Dir(current) {
|
|
@@ -721,216 +681,6 @@ func appendAncestorInputs(inputs []string, directory, stop string) []string {
|
|
|
721
681
|
}
|
|
722
682
|
}
|
|
723
683
|
|
|
724
|
-
func unresolvedModuleCandidates(configs []*shimtsoptions.ParsedCommandLine, directory, cwd, specifier string) []string {
|
|
725
|
-
if specifier == "" {
|
|
726
|
-
return nil
|
|
727
|
-
}
|
|
728
|
-
if strings.HasPrefix(specifier, ".") {
|
|
729
|
-
candidates := fileCandidates(filepath.Clean(filepath.Join(directory, filepath.FromSlash(specifier))))
|
|
730
|
-
return append(candidates, rootDirsCandidates(configs, directory, specifier)...)
|
|
731
|
-
}
|
|
732
|
-
candidates := compilerOptionCandidates(configs, specifier)
|
|
733
|
-
if strings.HasPrefix(specifier, "#") {
|
|
734
|
-
for current := filepath.Clean(directory); ; current = filepath.Dir(current) {
|
|
735
|
-
candidates = append(candidates, packageManifestCandidates(current, specifier)...)
|
|
736
|
-
if current == filepath.Clean(cwd) || filepath.Dir(current) == current {
|
|
737
|
-
return candidates
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
for current := filepath.Clean(directory); ; current = filepath.Dir(current) {
|
|
742
|
-
base := filepath.Join(current, "node_modules", filepath.FromSlash(specifier))
|
|
743
|
-
root := packageRoot(base, specifier)
|
|
744
|
-
candidates = append(candidates, fileCandidates(base)...)
|
|
745
|
-
candidates = append(candidates, filepath.Join(root, "package.json"))
|
|
746
|
-
candidates = append(candidates, packageManifestCandidates(root, packageSubpath(specifier))...)
|
|
747
|
-
if current == filepath.Clean(cwd) || filepath.Dir(current) == current {
|
|
748
|
-
break
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
return candidates
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
func packageManifestCandidates(root, wildcard string) []string {
|
|
755
|
-
content, err := os.ReadFile(filepath.Join(root, "package.json"))
|
|
756
|
-
if err != nil {
|
|
757
|
-
return nil
|
|
758
|
-
}
|
|
759
|
-
var manifest struct {
|
|
760
|
-
Main string `json:"main"`
|
|
761
|
-
Module string `json:"module"`
|
|
762
|
-
Types string `json:"types"`
|
|
763
|
-
Typings string `json:"typings"`
|
|
764
|
-
Exports any `json:"exports"`
|
|
765
|
-
Imports any `json:"imports"`
|
|
766
|
-
TypesVersions any `json:"typesVersions"`
|
|
767
|
-
}
|
|
768
|
-
if json.Unmarshal(content, &manifest) != nil {
|
|
769
|
-
return nil
|
|
770
|
-
}
|
|
771
|
-
defaultWildcard := strings.TrimPrefix(strings.TrimPrefix(wildcard, "./"), "#")
|
|
772
|
-
targets := []packageTarget{
|
|
773
|
-
{path: manifest.Main, wildcard: defaultWildcard},
|
|
774
|
-
{path: manifest.Module, wildcard: defaultWildcard},
|
|
775
|
-
{path: manifest.Types, wildcard: defaultWildcard},
|
|
776
|
-
{path: manifest.Typings, wildcard: defaultWildcard},
|
|
777
|
-
}
|
|
778
|
-
exportRequest := "."
|
|
779
|
-
if wildcard != "" && !strings.HasPrefix(wildcard, "#") {
|
|
780
|
-
exportRequest = "./" + strings.TrimPrefix(wildcard, "./")
|
|
781
|
-
}
|
|
782
|
-
collectPackageMappingTargets(manifest.Exports, exportRequest, defaultWildcard, &targets)
|
|
783
|
-
collectPackageMappingTargets(manifest.Imports, wildcard, defaultWildcard, &targets)
|
|
784
|
-
collectPackageTargets(manifest.TypesVersions, defaultWildcard, &targets)
|
|
785
|
-
candidates := []string{}
|
|
786
|
-
for _, target := range targets {
|
|
787
|
-
if target.path == "" || filepath.IsAbs(target.path) || strings.Contains(target.path, "://") {
|
|
788
|
-
continue
|
|
789
|
-
}
|
|
790
|
-
path := strings.Replace(target.path, "*", target.wildcard, 1)
|
|
791
|
-
candidates = append(candidates, fileCandidates(filepath.Join(root, filepath.FromSlash(path)))...)
|
|
792
|
-
}
|
|
793
|
-
return candidates
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
func collectPackageMappingTargets(value any, request, wildcard string, targets *[]packageTarget) {
|
|
797
|
-
if object, ok := value.(map[string]any); ok {
|
|
798
|
-
mapping := false
|
|
799
|
-
for key := range object {
|
|
800
|
-
if strings.HasPrefix(key, ".") || strings.HasPrefix(key, "#") {
|
|
801
|
-
mapping = true
|
|
802
|
-
break
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
if mapping {
|
|
806
|
-
for pattern, child := range object {
|
|
807
|
-
matched, ok := matchPathPattern(pattern, request)
|
|
808
|
-
if ok {
|
|
809
|
-
collectPackageTargets(child, matched, targets)
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
return
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
collectPackageTargets(value, wildcard, targets)
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
func collectPackageTargets(value any, wildcard string, targets *[]packageTarget) {
|
|
819
|
-
switch value := value.(type) {
|
|
820
|
-
case string:
|
|
821
|
-
*targets = append(*targets, packageTarget{path: value, wildcard: wildcard})
|
|
822
|
-
case []any:
|
|
823
|
-
for _, child := range value {
|
|
824
|
-
collectPackageTargets(child, wildcard, targets)
|
|
825
|
-
}
|
|
826
|
-
case map[string]any:
|
|
827
|
-
for _, child := range value {
|
|
828
|
-
collectPackageTargets(child, wildcard, targets)
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
func packageSubpath(specifier string) string {
|
|
834
|
-
parts := strings.Split(filepath.ToSlash(specifier), "/")
|
|
835
|
-
count := 1
|
|
836
|
-
if strings.HasPrefix(specifier, "@") && len(parts) > 1 {
|
|
837
|
-
count = 2
|
|
838
|
-
}
|
|
839
|
-
if len(parts) <= count {
|
|
840
|
-
return ""
|
|
841
|
-
}
|
|
842
|
-
return strings.Join(parts[count:], "/")
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
func compilerOptionCandidates(configs []*shimtsoptions.ParsedCommandLine, specifier string) []string {
|
|
846
|
-
candidates := []string{}
|
|
847
|
-
for _, parsed := range configs {
|
|
848
|
-
if parsed == nil || parsed.ParsedConfig == nil || parsed.ParsedConfig.CompilerOptions == nil {
|
|
849
|
-
continue
|
|
850
|
-
}
|
|
851
|
-
options := parsed.ParsedConfig.CompilerOptions
|
|
852
|
-
if options.BaseUrl != "" {
|
|
853
|
-
candidates = append(candidates, fileCandidates(filepath.Join(options.BaseUrl, filepath.FromSlash(specifier)))...)
|
|
854
|
-
}
|
|
855
|
-
if options.Paths == nil {
|
|
856
|
-
continue
|
|
857
|
-
}
|
|
858
|
-
base := options.GetPathsBasePath(parsed.GetCurrentDirectory())
|
|
859
|
-
for pattern, targets := range options.Paths.Entries() {
|
|
860
|
-
matched, ok := matchPathPattern(pattern, specifier)
|
|
861
|
-
if !ok {
|
|
862
|
-
continue
|
|
863
|
-
}
|
|
864
|
-
for _, target := range targets {
|
|
865
|
-
target = strings.Replace(target, "*", matched, 1)
|
|
866
|
-
candidates = append(candidates, fileCandidates(filepath.Join(base, filepath.FromSlash(target)))...)
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return candidates
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
func rootDirsCandidates(configs []*shimtsoptions.ParsedCommandLine, directory, specifier string) []string {
|
|
874
|
-
candidates := []string{}
|
|
875
|
-
for _, parsed := range configs {
|
|
876
|
-
if parsed == nil || parsed.ParsedConfig == nil || parsed.ParsedConfig.CompilerOptions == nil {
|
|
877
|
-
continue
|
|
878
|
-
}
|
|
879
|
-
roots := parsed.ParsedConfig.CompilerOptions.RootDirs
|
|
880
|
-
for _, sourceRoot := range roots {
|
|
881
|
-
relative, err := filepath.Rel(sourceRoot, directory)
|
|
882
|
-
if err != nil || relative == ".." || strings.HasPrefix(relative, ".."+string(filepath.Separator)) {
|
|
883
|
-
continue
|
|
884
|
-
}
|
|
885
|
-
suffix := filepath.Join(relative, filepath.FromSlash(specifier))
|
|
886
|
-
for _, targetRoot := range roots {
|
|
887
|
-
candidates = append(candidates, fileCandidates(filepath.Join(targetRoot, suffix))...)
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
return candidates
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
func matchPathPattern(pattern, specifier string) (string, bool) {
|
|
895
|
-
star := strings.IndexByte(pattern, '*')
|
|
896
|
-
if star < 0 {
|
|
897
|
-
return "", pattern == specifier
|
|
898
|
-
}
|
|
899
|
-
prefix := pattern[:star]
|
|
900
|
-
suffix := pattern[star+1:]
|
|
901
|
-
if len(specifier) < len(prefix)+len(suffix) || !strings.HasPrefix(specifier, prefix) || !strings.HasSuffix(specifier, suffix) {
|
|
902
|
-
return "", false
|
|
903
|
-
}
|
|
904
|
-
return specifier[len(prefix) : len(specifier)-len(suffix)], true
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
func packageRoot(base, specifier string) string {
|
|
908
|
-
parts := strings.Split(filepath.ToSlash(specifier), "/")
|
|
909
|
-
count := 1
|
|
910
|
-
if strings.HasPrefix(specifier, "@") && len(parts) > 1 {
|
|
911
|
-
count = 2
|
|
912
|
-
}
|
|
913
|
-
suffixCount := len(parts) - count
|
|
914
|
-
root := base
|
|
915
|
-
for range suffixCount {
|
|
916
|
-
root = filepath.Dir(root)
|
|
917
|
-
}
|
|
918
|
-
return root
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
func fileCandidates(base string) []string {
|
|
922
|
-
candidates := []string{base}
|
|
923
|
-
extension := strings.ToLower(filepath.Ext(base))
|
|
924
|
-
if extension == ".js" || extension == ".jsx" || extension == ".mjs" || extension == ".cjs" {
|
|
925
|
-
base = strings.TrimSuffix(base, filepath.Ext(base))
|
|
926
|
-
}
|
|
927
|
-
for _, suffix := range []string{".ts", ".tsx", ".mts", ".cts", ".d.ts", ".d.mts", ".d.cts", ".js", ".jsx", ".mjs", ".cjs", ".json"} {
|
|
928
|
-
candidates = append(candidates, base+suffix, filepath.Join(base, "index"+suffix))
|
|
929
|
-
}
|
|
930
|
-
candidates = append(candidates, filepath.Join(base, "package.json"))
|
|
931
|
-
return candidates
|
|
932
|
-
}
|
|
933
|
-
|
|
934
684
|
func compactSortedStrings(input []string) []string {
|
|
935
685
|
out := make([]string, 0, len(input))
|
|
936
686
|
for _, value := range input {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestServeSessionKeepsBaseURLFallbackUnchanged verifies an unmatched
|
|
9
|
+
// baseUrl-style file does not invalidate a paths resolution.
|
|
10
|
+
//
|
|
11
|
+
// The pinned TypeScript-Go resolver applies a matching paths substitution and
|
|
12
|
+
// does not fall back to baseUrl afterward. Recording a baseUrl probe would make
|
|
13
|
+
// an irrelevant file creation rebuild a resident session without changing the
|
|
14
|
+
// selected module.
|
|
15
|
+
//
|
|
16
|
+
// 1. Load a paths import whose configured fallback target exists.
|
|
17
|
+
// 2. Create only the corresponding baseUrl-style file.
|
|
18
|
+
// 3. Assert the session remains unchanged because the paths target still wins.
|
|
19
|
+
func TestServeSessionKeepsBaseURLFallbackUnchanged(t *testing.T) {
|
|
20
|
+
root := t.TempDir()
|
|
21
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
22
|
+
"compilerOptions": {
|
|
23
|
+
"baseUrl": ".",
|
|
24
|
+
"module": "commonjs",
|
|
25
|
+
"paths": { "@generated/*": ["fallback/*"] },
|
|
26
|
+
"target": "ES2022"
|
|
27
|
+
},
|
|
28
|
+
"files": ["src/main.ts"]
|
|
29
|
+
}`)
|
|
30
|
+
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from '@generated/value';\nexport function main(): void { winner(); }\n")
|
|
31
|
+
writeGraphFile(t, filepath.Join(root, "fallback", "value.ts"), "export function winner(): void {}\n")
|
|
32
|
+
|
|
33
|
+
session, err := newGraphSession(root, "tsconfig.json")
|
|
34
|
+
if err != nil {
|
|
35
|
+
t.Fatal(err)
|
|
36
|
+
}
|
|
37
|
+
defer session.Close()
|
|
38
|
+
if _, _, _, err := session.Snapshot(); err != nil {
|
|
39
|
+
t.Fatal(err)
|
|
40
|
+
}
|
|
41
|
+
writeGraphFile(t, filepath.Join(root, "@generated", "value.ts"), "export function winner(): void {}\n")
|
|
42
|
+
dump, mode, changed, err := session.Snapshot()
|
|
43
|
+
if err != nil {
|
|
44
|
+
t.Fatal(err)
|
|
45
|
+
}
|
|
46
|
+
if dump != nil || mode != serveModeUnchanged || changed {
|
|
47
|
+
t.Fatalf("baseUrl fallback = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"testing"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// TestServeSessionKeepsESMDirectoryCandidateUnchanged verifies ESM relative
|
|
10
|
+
// resolution does not inherit CommonJS directory probes.
|
|
11
|
+
//
|
|
12
|
+
// TypeScript-Go may substitute value.ts for the explicit value.js import, but
|
|
13
|
+
// it never performs the CommonJS value/package.json or value/index.* lookup in
|
|
14
|
+
// ESM mode. Those directory members must therefore stay out of a resident
|
|
15
|
+
// session's freshness inputs.
|
|
16
|
+
func TestServeSessionKeepsESMDirectoryCandidateUnchanged(t *testing.T) {
|
|
17
|
+
root := t.TempDir()
|
|
18
|
+
writeGraphFile(t, filepath.Join(root, "package.json"), `{"type":"module"}`)
|
|
19
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
20
|
+
"compilerOptions": {
|
|
21
|
+
"allowJs": true,
|
|
22
|
+
"module": "nodenext",
|
|
23
|
+
"moduleResolution": "nodenext",
|
|
24
|
+
"target": "ES2022"
|
|
25
|
+
},
|
|
26
|
+
"files": ["src/main.ts"]
|
|
27
|
+
}`)
|
|
28
|
+
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from './value.js';\nexport function main(): void { winner(); }\n")
|
|
29
|
+
writeGraphFile(t, filepath.Join(root, "src", "value.js"), "export function winner() {}\n")
|
|
30
|
+
|
|
31
|
+
session, err := newGraphSession(root, "tsconfig.json")
|
|
32
|
+
if err != nil {
|
|
33
|
+
t.Fatal(err)
|
|
34
|
+
}
|
|
35
|
+
defer session.Close()
|
|
36
|
+
if _, _, _, err := session.Snapshot(); err != nil {
|
|
37
|
+
t.Fatal(err)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if err := os.MkdirAll(filepath.Join(root, "src", "value"), 0o755); err != nil {
|
|
41
|
+
t.Fatal(err)
|
|
42
|
+
}
|
|
43
|
+
writeGraphFile(t, filepath.Join(root, "src", "value", "package.json"), `{"type":"module"}`)
|
|
44
|
+
writeGraphFile(t, filepath.Join(root, "src", "value", "index.ts"), "export function winner(): void {}\n")
|
|
45
|
+
dump, mode, changed, err := session.Snapshot()
|
|
46
|
+
if err != nil {
|
|
47
|
+
t.Fatal(err)
|
|
48
|
+
}
|
|
49
|
+
if dump != nil || mode != serveModeUnchanged || changed {
|
|
50
|
+
t.Fatalf("ESM directory candidate = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
writeGraphFile(t, filepath.Join(root, "src", "value.ts"), "export function winner(): void {}\nexport function typescriptWinner(): void {}\n")
|
|
54
|
+
dump, mode, changed, err = session.Snapshot()
|
|
55
|
+
if err != nil {
|
|
56
|
+
t.Fatal(err)
|
|
57
|
+
}
|
|
58
|
+
if dump == nil || mode != serveModeReload || !changed || !hasDumpNode(*dump, "typescriptWinner") {
|
|
59
|
+
t.Fatalf("ESM higher-priority file = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestServeSessionKeepsExportsBlockedFileCandidatesUnchanged verifies a
|
|
9
|
+
// package export map prevents unlisted bare-file candidates from invalidating a
|
|
10
|
+
// resident session.
|
|
11
|
+
//
|
|
12
|
+
// An export map controls subpath resolution before TypeScript considers an
|
|
13
|
+
// on-disk package file. Recording that blocked file as a predecessor would make
|
|
14
|
+
// unrelated package contents churn the snapshot despite the selected export
|
|
15
|
+
// remaining exactly the same.
|
|
16
|
+
//
|
|
17
|
+
// 1. Load a package subpath resolved through its export-map fallback target.
|
|
18
|
+
// 2. Create an unlisted file at the bare subpath without changing package.json.
|
|
19
|
+
// 3. Assert the session is unchanged, then create the export-map target that
|
|
20
|
+
// genuinely precedes the fallback and assert it reloads.
|
|
21
|
+
func TestServeSessionKeepsExportsBlockedFileCandidatesUnchanged(t *testing.T) {
|
|
22
|
+
root := t.TempDir()
|
|
23
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
24
|
+
"compilerOptions": {
|
|
25
|
+
"allowJs": true,
|
|
26
|
+
"module": "nodenext",
|
|
27
|
+
"moduleResolution": "nodenext",
|
|
28
|
+
"target": "ES2022"
|
|
29
|
+
},
|
|
30
|
+
"files": ["src/main.ts"]
|
|
31
|
+
}`)
|
|
32
|
+
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from 'fixture-package/feature';\nexport function main(): void { winner(); }\n")
|
|
33
|
+
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "package.json"), `{
|
|
34
|
+
"name": "fixture-package",
|
|
35
|
+
"exports": { "./feature": ["./dist/first.js", "./dist/fallback.js"] }
|
|
36
|
+
}`)
|
|
37
|
+
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "fallback.js"), "export function winner() {}\n")
|
|
38
|
+
|
|
39
|
+
session, err := newGraphSession(root, "tsconfig.json")
|
|
40
|
+
if err != nil {
|
|
41
|
+
t.Fatal(err)
|
|
42
|
+
}
|
|
43
|
+
defer session.Close()
|
|
44
|
+
if _, _, _, err := session.Snapshot(); err != nil {
|
|
45
|
+
t.Fatal(err)
|
|
46
|
+
}
|
|
47
|
+
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "feature.ts"), "export function winner(): void {}\n")
|
|
48
|
+
dump, mode, changed, err := session.Snapshot()
|
|
49
|
+
if err != nil {
|
|
50
|
+
t.Fatal(err)
|
|
51
|
+
}
|
|
52
|
+
if dump != nil || mode != serveModeUnchanged || changed {
|
|
53
|
+
t.Fatalf("exports-blocked feature.ts = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "first.js"), "export function winner() {}\nexport function exportsWinner() {}\n")
|
|
57
|
+
dump, mode, changed, err = session.Snapshot()
|
|
58
|
+
if err != nil {
|
|
59
|
+
t.Fatal(err)
|
|
60
|
+
}
|
|
61
|
+
if dump == nil || mode != serveModeReload || !changed {
|
|
62
|
+
t.Fatalf("export-map first target = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
63
|
+
}
|
|
64
|
+
}
|