@ttsc/lint 0.33.1 → 0.34.1
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/go.mod +2 -2
- package/linthost/ast_helpers.go +2 -2
- package/linthost/base_chain_walk_crosses_generic_boundary_test.go +3 -3
- package/linthost/check_observations.go +14 -14
- package/linthost/check_observations_retains_failed_program_and_raw_inputs_test.go +3 -2
- package/linthost/command_check_preserves_compiler_argument_cwd_test.go +2 -2
- package/linthost/comment_scan_handles_malformed_parser_recovery_test.go +2 -1
- package/linthost/comment_scan_uses_parser_lexical_ranges_across_source_modes_test.go +2 -1
- package/linthost/compile.go +5 -8
- package/linthost/config.go +4 -2
- package/linthost/config_loader_sources_escape_every_literal_percent_test.go +2 -1
- package/linthost/contributor_diagnostic_ranges_are_bounded_test.go +19 -19
- package/linthost/contributor_range_fix_bounds_diagnostic_independently_from_edit_test.go +2 -2
- package/linthost/contributor_report_related_reaches_finding_test.go +1 -1
- package/linthost/engine.go +1 -1
- package/linthost/engine_quarantines_panicking_rule_per_file_test.go +4 -4
- package/linthost/engine_run_parallel_matches_serial_finding_set_test.go +1 -1
- package/linthost/fix.go +1 -1
- package/linthost/helpers_test.go +5 -4
- package/linthost/host.go +130 -52
- package/linthost/imported_tsx_source_joins_the_read_scope_test.go +1 -1
- package/linthost/input_observation.go +24 -27
- package/linthost/invalid_contributor_range_cannot_panic_inline_directive_filtering_test.go +1 -1
- package/linthost/lint_corpus_filename_separators_share_materialized_source_identity_test.go +1 -1
- package/linthost/load_config_resolver_compact_globs_preserve_entry_policy_test.go +2 -2
- package/linthost/load_program_keeps_checker_pool_for_type_aware_rules_test.go +4 -4
- package/linthost/lsp.go +10 -5
- package/linthost/no_floating_promises_javascript_generic_defaults_test.go +1 -1
- package/linthost/no_floating_promises_rejects_inapplicable_generic_receiver_branches_test.go +1 -1
- package/linthost/project_engine.go +1 -1
- package/linthost/project_rule_sources_apply_only_global_ignores_test.go +1 -1
- package/linthost/project_rule_sources_include_imported_sibling_source_test.go +2 -2
- package/linthost/project_source_files_follow_tsconfig_selection_test.go +2 -2
- package/linthost/project_source_selection_preserves_explicit_bundled_roots_test.go +6 -5
- package/linthost/resident_whole_corpus_matches_cold_load_test.go +1 -1
- package/linthost/rules_boundaries.go +7 -7
- package/linthost/rules_boundaries_dependencies.go +9 -9
- package/linthost/rules_format_declaration_header.go +11 -4
- package/linthost/rules_gap.go +1 -1
- package/linthost/rules_jsdoc.go +1 -1
- package/linthost/rules_logic.go +2 -2
- package/linthost/rules_nextjs.go +1 -1
- package/linthost/rules_no_loop_func.go +4 -4
- package/linthost/rules_no_promise_executor_return.go +1 -1
- package/linthost/rules_promise.go +16 -16
- package/linthost/rules_react_perf.go +1 -1
- package/linthost/rules_react_refresh.go +2 -2
- package/linthost/rules_security.go +4 -4
- package/linthost/rules_storybook.go +1 -1
- package/linthost/rules_testing_library.go +1 -1
- package/linthost/rules_ts_no_base_to_string.go +1 -1
- package/linthost/rules_ts_no_deprecated.go +3 -3
- package/linthost/rules_ts_no_unnecessary_qualifier.go +4 -4
- package/linthost/rules_ts_no_unnecessary_type_arguments.go +2 -2
- package/linthost/rules_ts_no_unsafe_assignment.go +1 -1
- package/linthost/rules_ts_no_unsafe_enum_comparison.go +1 -1
- package/linthost/rules_ts_prefer_readonly.go +1 -1
- package/linthost/rules_ts_switch_exhaustiveness_check.go +2 -2
- package/linthost/rules_ts_unbound_method.go +1 -1
- package/linthost/rules_unicorn_consistent_destructuring.go +2 -2
- package/linthost/rules_unicorn_consistent_existence_index_check.go +2 -2
- package/linthost/rules_unicorn_consistent_function_scoping.go +7 -7
- package/linthost/rules_unicorn_filename_case.go +1 -1
- package/linthost/rules_unicorn_isolated_functions.go +3 -3
- package/linthost/rules_unicorn_no_typeof_undefined.go +1 -1
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +1 -1
- package/linthost/rules_unicorn_no_unused_properties.go +3 -3
- package/linthost/rules_unicorn_prefer_number_properties.go +1 -1
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +1 -1
- package/linthost/rules_unicorn_prevent_abbreviations.go +7 -7
- package/linthost/rules_var.go +1 -1
- package/linthost/solid_helpers_test.go +1 -1
- package/linthost/type_alias_reference_node_uses_borrowed_builder_context_test.go +2 -2
- package/linthost/type_instantiation_mappers_reach_runtime_endpoints_test.go +3 -3
- package/linthost/user_source_files_exclude_imported_declarations_and_javascript_test.go +2 -2
- package/linthost/user_source_files_span_program_typescript_sources_test.go +1 -1
- package/linthost/windows_project_source_selection_preserves_physical_aliases_test.go +5 -4
- package/package.json +2 -2
package/linthost/host.go
CHANGED
|
@@ -48,9 +48,12 @@ type program struct {
|
|
|
48
48
|
configInputs []configDependencyFingerprint
|
|
49
49
|
tsProgram *shimcompiler.Program
|
|
50
50
|
parsed *tsoptions.ParsedCommandLine
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// hosts builds every generation's compiler host and owns the content-mapper
|
|
52
|
+
// processes those hosts share on the TypeScript 7.1 target; close releases it.
|
|
53
|
+
hosts *shimcompiler.ProjectHosts
|
|
54
|
+
checker *shimchecker.Checker
|
|
55
|
+
identity publicrule.ProjectIdentity
|
|
56
|
+
projectCycle *projectCycle
|
|
54
57
|
// projectRoots memoizes projectSourceFileNames, which resolves every
|
|
55
58
|
// selected file's path and therefore costs filesystem work. The tsconfig
|
|
56
59
|
// selection cannot change while one program is loaded — a config edit or a
|
|
@@ -107,6 +110,14 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
107
110
|
if !filepath.IsAbs(resolved) {
|
|
108
111
|
resolved = filepath.Join(cwd, resolved)
|
|
109
112
|
}
|
|
113
|
+
configFile, ok := shimtspath.TryRootedFilePathFromAbsolute(resolved)
|
|
114
|
+
if !ok {
|
|
115
|
+
return nil, nil, fmt.Errorf("loadProgram: tsconfig path is not absolute: %s", resolved)
|
|
116
|
+
}
|
|
117
|
+
cwdDir, ok := rootedDirectory(cwd)
|
|
118
|
+
if !ok {
|
|
119
|
+
return nil, nil, fmt.Errorf("loadProgram: cwd is not absolute: %s", cwd)
|
|
120
|
+
}
|
|
110
121
|
|
|
111
122
|
var fs vfs.FS = bundled.WrapFS(cachedvfs.From(osvfs.FS()))
|
|
112
123
|
var observer *inputObservationFS
|
|
@@ -116,18 +127,19 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
116
127
|
reader = newProjectInputReader(observer)
|
|
117
128
|
fs = observer
|
|
118
129
|
}
|
|
119
|
-
|
|
120
|
-
|
|
130
|
+
// Forwarded flags convert relative values against their own argv base, so
|
|
131
|
+
// only the parser's directory changes.
|
|
132
|
+
argumentDir := cwdDir
|
|
121
133
|
if options.tsgoArgsCwd != "" {
|
|
122
134
|
argumentCwd := options.tsgoArgsCwd
|
|
123
135
|
if !filepath.IsAbs(argumentCwd) {
|
|
124
136
|
argumentCwd = filepath.Join(cwd, argumentCwd)
|
|
125
137
|
}
|
|
126
|
-
if argumentCwd
|
|
127
|
-
|
|
138
|
+
if argumentDir, ok = rootedDirectory(argumentCwd); !ok {
|
|
139
|
+
return nil, nil, fmt.Errorf("loadProgram: tsgo args cwd is not absolute: %s", argumentCwd)
|
|
128
140
|
}
|
|
129
141
|
}
|
|
130
|
-
commandLine, cliDiags := parseTsgoArgs(options.tsgoArgs,
|
|
142
|
+
commandLine, cliDiags := parseTsgoArgs(options.tsgoArgs, fs, argumentDir)
|
|
131
143
|
if len(cliDiags) > 0 {
|
|
132
144
|
return nil, cliDiags, nil
|
|
133
145
|
}
|
|
@@ -140,10 +152,10 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
140
152
|
cliOptions = &shimcore.CompilerOptions{}
|
|
141
153
|
}
|
|
142
154
|
parsed, parseDiags := tsoptions.GetParsedCommandLineOfConfigFile(
|
|
143
|
-
|
|
155
|
+
configFile,
|
|
144
156
|
cliOptions,
|
|
145
157
|
tsoptions.CommandLineRawOptions(commandLine),
|
|
146
|
-
|
|
158
|
+
tsoptions.NewParseConfigHost(fs, argumentDir),
|
|
147
159
|
nil,
|
|
148
160
|
)
|
|
149
161
|
if parsed == nil {
|
|
@@ -155,9 +167,13 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
155
167
|
if len(parsed.Errors) > 0 {
|
|
156
168
|
return nil, parsed.Errors, nil
|
|
157
169
|
}
|
|
158
|
-
|
|
170
|
+
parsed, semanticDiags, err := parseSemanticConfig(parsed, options.semanticConfigPath, commandLine, fs)
|
|
171
|
+
if err != nil {
|
|
159
172
|
return nil, nil, err
|
|
160
173
|
}
|
|
174
|
+
if len(semanticDiags) > 0 {
|
|
175
|
+
return nil, semanticDiags, nil
|
|
176
|
+
}
|
|
161
177
|
if options.forceNoEmit {
|
|
162
178
|
forceNoEmit(parsed)
|
|
163
179
|
}
|
|
@@ -165,9 +181,13 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
165
181
|
forceEmit(parsed)
|
|
166
182
|
}
|
|
167
183
|
if options.outDir != "" {
|
|
168
|
-
overrideOutDir(
|
|
184
|
+
overrideOutDir(cwdDir, parsed, options.outDir)
|
|
169
185
|
}
|
|
170
186
|
applyThreading(parsed, options.singleThreaded, options.checkers)
|
|
187
|
+
// The parsed project decides whether its content mappers run, so the
|
|
188
|
+
// Program's host is built only now, over the same filesystem.
|
|
189
|
+
hosts := shimcompiler.NewProjectHosts(parsed)
|
|
190
|
+
host := hosts.Host(cwdDir, fs, shimtspath.RootedDirectoryPath(bundled.LibPath()))
|
|
171
191
|
|
|
172
192
|
// Keep the user's checker pool intact for parallel semantic diagnostics.
|
|
173
193
|
// Type-aware lint rules cannot borrow one member of that pool: they walk
|
|
@@ -177,11 +197,7 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
177
197
|
// Every lint type is then produced by one checker, while the Program's pool
|
|
178
198
|
// remains free to check its file groups in parallel. The engine serializes
|
|
179
199
|
// type-aware walks, so this dedicated checker is never accessed concurrently.
|
|
180
|
-
tsProgram := shimcompiler.NewProgram(shimcompiler.
|
|
181
|
-
Config: parsed,
|
|
182
|
-
Host: host,
|
|
183
|
-
UseSourceOfProjectReference: true,
|
|
184
|
-
})
|
|
200
|
+
tsProgram := shimcompiler.NewProgram(shimcompiler.NewProgramOptions(parsed, host, true))
|
|
185
201
|
if tsProgram == nil {
|
|
186
202
|
return nil, nil, errors.New("compiler.NewProgram returned nil")
|
|
187
203
|
}
|
|
@@ -195,21 +211,53 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
195
211
|
inputReader: reader,
|
|
196
212
|
tsProgram: tsProgram,
|
|
197
213
|
parsed: parsed,
|
|
214
|
+
hosts: hosts,
|
|
198
215
|
checker: checker,
|
|
199
216
|
identity: normalizeProjectIdentity(options.projectIdentity, cwd, resolved),
|
|
200
217
|
}, nil, nil
|
|
201
218
|
}
|
|
202
219
|
|
|
203
|
-
|
|
220
|
+
// parseSemanticConfig makes the user-authored config the parsed project when
|
|
221
|
+
// a generated wrapper extends it from a scratch directory. TypeScript-Go
|
|
222
|
+
// anchors resolution, automatic type discovery and the Program's current
|
|
223
|
+
// directory at the directory of the config file it parsed, so the wrapper must
|
|
224
|
+
// not become the project. The wrapper's merged options, which already carry the
|
|
225
|
+
// user config's own options, the overlay and the command line, take
|
|
226
|
+
// command-line precedence over a fresh parse of the user config; the command
|
|
227
|
+
// line's raw options keep its resets.
|
|
228
|
+
func parseSemanticConfig(wrapper *tsoptions.ParsedCommandLine, semanticConfigPath string, commandLine *tsoptions.ParsedCommandLine, fs vfs.FS) (*tsoptions.ParsedCommandLine, []*shimast.Diagnostic, error) {
|
|
204
229
|
configured := strings.TrimSpace(semanticConfigPath)
|
|
205
230
|
if configured == "" {
|
|
206
|
-
return nil
|
|
231
|
+
return wrapper, nil, nil
|
|
207
232
|
}
|
|
208
233
|
if !filepath.IsAbs(configured) {
|
|
209
|
-
return fmt.Errorf("linthost: semantic config path must be absolute: %s", configured)
|
|
234
|
+
return nil, nil, fmt.Errorf("linthost: semantic config path must be absolute: %s", configured)
|
|
210
235
|
}
|
|
211
|
-
|
|
212
|
-
|
|
236
|
+
semanticConfig, ok := shimtspath.TryRootedFilePathFromAbsolute(configured)
|
|
237
|
+
if !ok {
|
|
238
|
+
return nil, nil, fmt.Errorf("linthost: semantic config path cannot be rooted: %s", configured)
|
|
239
|
+
}
|
|
240
|
+
wrapperConfig := wrapper.CompilerOptions().ConfigFilePath
|
|
241
|
+
if wrapperConfig != "" && shimtspath.CompareFilePaths(vfs.CaseSensitivityOf(fs), wrapperConfig, semanticConfig) == 0 {
|
|
242
|
+
return wrapper, nil, nil
|
|
243
|
+
}
|
|
244
|
+
parsed, diagnostics := tsoptions.GetParsedCommandLineOfConfigFile(
|
|
245
|
+
semanticConfig,
|
|
246
|
+
wrapper.CompilerOptions().Clone(),
|
|
247
|
+
tsoptions.CommandLineRawOptions(commandLine),
|
|
248
|
+
tsoptions.NewParseConfigHost(fs, shimtspath.FileDirectory(semanticConfig)),
|
|
249
|
+
nil,
|
|
250
|
+
)
|
|
251
|
+
if parsed == nil {
|
|
252
|
+
return nil, nil, fmt.Errorf("tsoptions: parsed command line was nil for %s", string(semanticConfig))
|
|
253
|
+
}
|
|
254
|
+
if len(diagnostics) > 0 {
|
|
255
|
+
return nil, diagnostics, nil
|
|
256
|
+
}
|
|
257
|
+
if len(parsed.Errors) > 0 {
|
|
258
|
+
return nil, parsed.Errors, nil
|
|
259
|
+
}
|
|
260
|
+
return parsed, nil, nil
|
|
213
261
|
}
|
|
214
262
|
|
|
215
263
|
func normalizeProjectIdentity(
|
|
@@ -394,13 +442,17 @@ func (p *program) runCycleOver(engine *Engine, files []*shimast.SourceFile) []*F
|
|
|
394
442
|
return append(p.projectCycle.finalize(), fileFindings...)
|
|
395
443
|
}
|
|
396
444
|
|
|
397
|
-
// close drops the standalone lint checker
|
|
398
|
-
//
|
|
445
|
+
// close drops the standalone lint checker and stops the project's
|
|
446
|
+
// content-mapper processes. Safe to call on a nil receiver and idempotent after
|
|
447
|
+
// the first call. A mapper that fails to stop has already been killed, and no
|
|
448
|
+
// lint result depends on its exit, so the close error is not reported.
|
|
399
449
|
func (p *program) close() {
|
|
400
450
|
if p == nil {
|
|
401
451
|
return
|
|
402
452
|
}
|
|
403
453
|
p.checker = nil
|
|
454
|
+
_ = p.hosts.Close()
|
|
455
|
+
p.hosts = nil
|
|
404
456
|
}
|
|
405
457
|
|
|
406
458
|
// sourceFileByPath returns the resident Program's source file whose name matches
|
|
@@ -415,7 +467,7 @@ func (p *program) sourceFileByPath(absPath string) *shimast.SourceFile {
|
|
|
415
467
|
if file == nil {
|
|
416
468
|
continue
|
|
417
469
|
}
|
|
418
|
-
if filepath.ToSlash(file.FileName()) == normalized {
|
|
470
|
+
if filepath.ToSlash(string(file.FileName())) == normalized {
|
|
419
471
|
return file
|
|
420
472
|
}
|
|
421
473
|
}
|
|
@@ -432,18 +484,23 @@ func (p *program) sourceFileByPath(absPath string) *shimast.SourceFile {
|
|
|
432
484
|
// when the edit reshaped the import graph, and that rebuilt Program is still
|
|
433
485
|
// correct, but callers use the reused flag to distinguish incremental updates
|
|
434
486
|
// from full Program reconstruction in product telemetry.
|
|
487
|
+
// It returns false, leaving the Program unchanged, when absPath has no rooted
|
|
488
|
+
// file name.
|
|
435
489
|
func (p *program) applyChange(absPath string) bool {
|
|
436
490
|
if p == nil || p.tsProgram == nil {
|
|
437
491
|
return false
|
|
438
492
|
}
|
|
439
|
-
name := absPath
|
|
440
|
-
if
|
|
441
|
-
|
|
493
|
+
name, ok := p.changedFileName(absPath)
|
|
494
|
+
if !ok {
|
|
495
|
+
return false
|
|
442
496
|
}
|
|
443
497
|
fs := bundled.WrapFS(cachedvfs.From(osvfs.FS()))
|
|
444
|
-
host
|
|
445
|
-
|
|
446
|
-
|
|
498
|
+
// The new host keeps the Program's content mappers, so a mapped file is
|
|
499
|
+
// still transformed by the processes the first generation started.
|
|
500
|
+
host := p.hosts.Host(shimtspath.RootedDirectoryPath(p.cwd), fs, shimtspath.RootedDirectoryPath(bundled.LibPath()))
|
|
501
|
+
// The second result is the changed file as host parsed it, returned so a
|
|
502
|
+
// host with a parse cache can release it; this host parses without one.
|
|
503
|
+
newProg, _, reused := shimcompiler.UpdateProgram(p.tsProgram, shimcompiler.ProgramPathKey(p.tsProgram, name), host)
|
|
447
504
|
if newProg != nil {
|
|
448
505
|
// An updated generation cannot inherit a one-shot check's observed inputs.
|
|
449
506
|
// Resident commands currently negotiate no check sidecar; keep an explicit
|
|
@@ -464,6 +521,31 @@ func (p *program) applyChange(absPath string) bool {
|
|
|
464
521
|
return reused
|
|
465
522
|
}
|
|
466
523
|
|
|
524
|
+
// changedFileName names the file absPath addresses as the compiler keys it. The
|
|
525
|
+
// resident Program's own spelling wins; otherwise absPath resolves against the
|
|
526
|
+
// Program's cwd. It reports false when no rooted name exists.
|
|
527
|
+
func (p *program) changedFileName(absPath string) (shimtspath.RootedFilePath, bool) {
|
|
528
|
+
if file := p.sourceFileByPath(absPath); file != nil {
|
|
529
|
+
return file.FileName(), true
|
|
530
|
+
}
|
|
531
|
+
cwd, ok := rootedDirectory(p.cwd)
|
|
532
|
+
if !ok || absPath == "" {
|
|
533
|
+
return "", false
|
|
534
|
+
}
|
|
535
|
+
return shimtspath.ToRootedFilePath(absPath, cwd), true
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// rootedDirectory gives an absolute native directory the compiler's rooted
|
|
539
|
+
// identity. A relative directory has no such identity, so it reports false
|
|
540
|
+
// instead of resolving against an implicit working directory.
|
|
541
|
+
func rootedDirectory(absolute string) (shimtspath.RootedDirectoryPath, bool) {
|
|
542
|
+
path, ok := shimtspath.TryRootedPathFromAbsolute(absolute)
|
|
543
|
+
if !ok {
|
|
544
|
+
return "", false
|
|
545
|
+
}
|
|
546
|
+
return shimtspath.RootedDirectoryPathFromPath(path), true
|
|
547
|
+
}
|
|
548
|
+
|
|
467
549
|
// userSourceFiles returns the source files the lint engine reads for one cycle:
|
|
468
550
|
// the tsconfig-selected TS/JS roots plus every TypeScript source the Program
|
|
469
551
|
// pulled in through an import.
|
|
@@ -495,7 +577,7 @@ func (p *program) userSourceFiles() []*shimast.SourceFile {
|
|
|
495
577
|
if f == nil {
|
|
496
578
|
continue
|
|
497
579
|
}
|
|
498
|
-
if p.selectedByProject(roots, f.FileName()) {
|
|
580
|
+
if p.selectedByProject(roots, string(f.FileName())) {
|
|
499
581
|
out = append(out, f)
|
|
500
582
|
continue
|
|
501
583
|
}
|
|
@@ -516,7 +598,7 @@ func (p *program) projectSourceFiles() []*shimast.SourceFile {
|
|
|
516
598
|
if f == nil {
|
|
517
599
|
continue
|
|
518
600
|
}
|
|
519
|
-
if !p.selectedByProject(roots, f.FileName()) {
|
|
601
|
+
if !p.selectedByProject(roots, string(f.FileName())) {
|
|
520
602
|
continue
|
|
521
603
|
}
|
|
522
604
|
out = append(out, f)
|
|
@@ -555,14 +637,14 @@ func (p *program) projectSourceFileNames() map[string]struct{} {
|
|
|
555
637
|
out := make(map[string]struct{})
|
|
556
638
|
if p.parsed != nil && p.parsed.ParsedConfig != nil {
|
|
557
639
|
for _, fileName := range p.parsed.ParsedConfig.FileNames {
|
|
558
|
-
if !isLintSourceFileName(fileName) {
|
|
640
|
+
if !isLintSourceFileName(string(fileName)) {
|
|
559
641
|
continue
|
|
560
642
|
}
|
|
561
|
-
if bundled.IsBundled(fileName) {
|
|
562
|
-
out[fileName] = struct{}{}
|
|
643
|
+
if bundled.IsBundled(string(fileName)) {
|
|
644
|
+
out[string(fileName)] = struct{}{}
|
|
563
645
|
continue
|
|
564
646
|
}
|
|
565
|
-
absolute := absoluteProjectPath(p.cwd, fileName)
|
|
647
|
+
absolute := absoluteProjectPath(p.cwd, string(fileName))
|
|
566
648
|
out[canonicalProjectPath(p.cwd, absolute)] = struct{}{}
|
|
567
649
|
out[canonicalProjectPath(p.cwd, realProjectPath(absolute))] = struct{}{}
|
|
568
650
|
}
|
|
@@ -617,7 +699,7 @@ func (p *program) projectWritableFindings(findings []*Finding) []*Finding {
|
|
|
617
699
|
if finding == nil || finding.File == nil {
|
|
618
700
|
continue
|
|
619
701
|
}
|
|
620
|
-
if !p.selectedByProject(roots, finding.File.FileName()) {
|
|
702
|
+
if !p.selectedByProject(roots, string(finding.File.FileName())) {
|
|
621
703
|
continue
|
|
622
704
|
}
|
|
623
705
|
out = append(out, finding)
|
|
@@ -638,7 +720,7 @@ func isImportedLintSourceFile(file *shimast.SourceFile) bool {
|
|
|
638
720
|
if file == nil || file.IsDeclarationFile {
|
|
639
721
|
return false
|
|
640
722
|
}
|
|
641
|
-
return isTypeScriptSourceFileName(file.FileName())
|
|
723
|
+
return isTypeScriptSourceFileName(string(file.FileName()))
|
|
642
724
|
}
|
|
643
725
|
|
|
644
726
|
// isLintSourceFileName reports whether a tsconfig-selected file is a lint/format
|
|
@@ -695,7 +777,7 @@ func (p *program) programDiagnostics() []*shimast.Diagnostic {
|
|
|
695
777
|
func (p *program) findSourceFile(target string) *shimast.SourceFile {
|
|
696
778
|
want := shimtspath.NormalizePath(target)
|
|
697
779
|
for _, file := range p.tsProgram.SourceFiles() {
|
|
698
|
-
if shimtspath.NormalizePath(file.FileName()) == want {
|
|
780
|
+
if shimtspath.NormalizePath(string(file.FileName())) == want {
|
|
699
781
|
return file
|
|
700
782
|
}
|
|
701
783
|
}
|
|
@@ -728,11 +810,11 @@ func forceNoEmit(parsed *tsoptions.ParsedCommandLine) {
|
|
|
728
810
|
// loadProgram merges over the tsconfig — so a flag like `ttsc --strict` reaches
|
|
729
811
|
// the in-process lint program even though @ttsc/lint never shells out to
|
|
730
812
|
// `tsgo`. Returns nil when there are no forwarded flags.
|
|
731
|
-
func parseTsgoArgs(args []string,
|
|
813
|
+
func parseTsgoArgs(args []string, fs vfs.FS, cwd shimtspath.RootedDirectoryPath) (*tsoptions.ParsedCommandLine, []*shimast.Diagnostic) {
|
|
732
814
|
if len(args) == 0 {
|
|
733
815
|
return nil, nil
|
|
734
816
|
}
|
|
735
|
-
cli := tsoptions.
|
|
817
|
+
cli := tsoptions.ParseCommandLineAt(args, fs, cwd)
|
|
736
818
|
if cli == nil {
|
|
737
819
|
return nil, nil
|
|
738
820
|
}
|
|
@@ -764,19 +846,15 @@ func applyThreading(parsed *tsoptions.ParsedCommandLine, singleThreaded bool, ch
|
|
|
764
846
|
}
|
|
765
847
|
}
|
|
766
848
|
|
|
767
|
-
// overrideOutDir replaces the parsed config's OutDir with
|
|
768
|
-
// Relative
|
|
769
|
-
//
|
|
770
|
-
//
|
|
771
|
-
func overrideOutDir(cwd
|
|
849
|
+
// overrideOutDir replaces the parsed config's OutDir with outDir, which the
|
|
850
|
+
// caller has checked is nonempty. Relative values resolve against cwd, and
|
|
851
|
+
// absolute values keep their location. The compiler stores the result as a
|
|
852
|
+
// rooted directory, which expresses the forward-slash form tsgo expects.
|
|
853
|
+
func overrideOutDir(cwd shimtspath.RootedDirectoryPath, parsed *tsoptions.ParsedCommandLine, outDir string) {
|
|
772
854
|
if parsed == nil || parsed.ParsedConfig == nil || parsed.ParsedConfig.CompilerOptions == nil {
|
|
773
855
|
return
|
|
774
856
|
}
|
|
775
|
-
|
|
776
|
-
parsed.ParsedConfig.CompilerOptions.OutDir = filepath.ToSlash(outDir)
|
|
777
|
-
return
|
|
778
|
-
}
|
|
779
|
-
parsed.ParsedConfig.CompilerOptions.OutDir = filepath.ToSlash(filepath.Join(cwd, outDir))
|
|
857
|
+
parsed.ParsedConfig.CompilerOptions.OutDir = shimtspath.ToRootedDirectoryPath(outDir, cwd)
|
|
780
858
|
}
|
|
781
859
|
|
|
782
860
|
// projectInputReaders exposes only this loaded generation's reader. Manual or
|
|
@@ -52,7 +52,7 @@ func TestImportedTsxSourceJoinsTheReadScope(t *testing.T) {
|
|
|
52
52
|
|
|
53
53
|
names := make([]string, 0)
|
|
54
54
|
for _, file := range prog.userSourceFiles() {
|
|
55
|
-
rel, err := filepath.Rel(root, file.FileName())
|
|
55
|
+
rel, err := filepath.Rel(root, string(file.FileName()))
|
|
56
56
|
if err != nil {
|
|
57
57
|
t.Fatal(err)
|
|
58
58
|
}
|
|
@@ -113,7 +113,7 @@ type observedInput struct {
|
|
|
113
113
|
// released; returned listing/text sizes still determine retained bytes.
|
|
114
114
|
type inputObservationFS struct {
|
|
115
115
|
vfs.FS
|
|
116
|
-
|
|
116
|
+
caseSensitivity shimtspath.CaseSensitivity
|
|
117
117
|
mu sync.Mutex
|
|
118
118
|
observations map[string]observedInput
|
|
119
119
|
observationOrder []string
|
|
@@ -125,7 +125,7 @@ type inputObservationFS struct {
|
|
|
125
125
|
func newInputObservationFS(inner vfs.FS) *inputObservationFS {
|
|
126
126
|
return &inputObservationFS{
|
|
127
127
|
FS: inner,
|
|
128
|
-
|
|
128
|
+
caseSensitivity: vfs.CaseSensitivityOf(inner),
|
|
129
129
|
observations: map[string]observedInput{},
|
|
130
130
|
observationSpellings: map[string]string{},
|
|
131
131
|
}
|
|
@@ -133,34 +133,34 @@ func newInputObservationFS(inner vfs.FS) *inputObservationFS {
|
|
|
133
133
|
|
|
134
134
|
// FileExists records the returned existence answer; a true answer additionally
|
|
135
135
|
// records the same VFS's identity spelling without inventing file contents.
|
|
136
|
-
func (fs *inputObservationFS) FileExists(path
|
|
136
|
+
func (fs *inputObservationFS) FileExists(path shimtspath.RootedFilePath) bool {
|
|
137
137
|
exists := fs.FS.FileExists(path)
|
|
138
138
|
proof := transformInputObservation{FileExists: boolPointer(exists)}
|
|
139
139
|
if exists {
|
|
140
140
|
// Existence participates in resolution, but only ReadFile returns bytes
|
|
141
141
|
// that can influence the resident Program. Do not duplicate every
|
|
142
142
|
// resolver probe with an eager file read.
|
|
143
|
-
proof.Realpath = fs.currentRealpath(path)
|
|
143
|
+
proof.Realpath = fs.currentRealpath(shimtspath.RootedPath(path))
|
|
144
144
|
}
|
|
145
|
-
fs.observe(path, observedInput{proof: proof})
|
|
145
|
+
fs.observe(string(path), observedInput{proof: proof})
|
|
146
146
|
return exists
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
// ReadFile hashes the text actually returned by the compiler VFS. A failed read
|
|
150
150
|
// records failure without hashing a second read or guessing the path's kind.
|
|
151
|
-
func (fs *inputObservationFS) ReadFile(path
|
|
151
|
+
func (fs *inputObservationFS) ReadFile(path shimtspath.RootedFilePath) (string, bool) {
|
|
152
152
|
contents, ok := fs.FS.ReadFile(path)
|
|
153
153
|
if ok {
|
|
154
154
|
digest := sha256.Sum256([]byte(contents))
|
|
155
155
|
hash := hex.EncodeToString(digest[:])
|
|
156
|
-
fs.observe(path, observedInput{
|
|
156
|
+
fs.observe(string(path), observedInput{
|
|
157
157
|
proof: transformInputObservation{
|
|
158
158
|
ReadFile: &transformInputReadObservation{OK: true, Hash: hash},
|
|
159
|
-
Realpath: fs.currentRealpath(path),
|
|
159
|
+
Realpath: fs.currentRealpath(shimtspath.RootedPath(path)),
|
|
160
160
|
},
|
|
161
161
|
})
|
|
162
162
|
} else {
|
|
163
|
-
fs.observe(path, observedInput{
|
|
163
|
+
fs.observe(string(path), observedInput{
|
|
164
164
|
proof: transformInputObservation{
|
|
165
165
|
ReadFile: &transformInputReadObservation{OK: false},
|
|
166
166
|
},
|
|
@@ -171,21 +171,21 @@ func (fs *inputObservationFS) ReadFile(path string) (string, bool) {
|
|
|
171
171
|
|
|
172
172
|
// DirectoryExists records existence independently of FileExists, since a
|
|
173
173
|
// false file predicate and a true directory predicate are compatible.
|
|
174
|
-
func (fs *inputObservationFS) DirectoryExists(path
|
|
174
|
+
func (fs *inputObservationFS) DirectoryExists(path shimtspath.RootedDirectoryPath) bool {
|
|
175
175
|
exists := fs.FS.DirectoryExists(path)
|
|
176
176
|
proof := transformInputObservation{DirectoryExists: boolPointer(exists)}
|
|
177
177
|
if exists {
|
|
178
|
-
proof.Realpath = fs.currentRealpath(path)
|
|
178
|
+
proof.Realpath = fs.currentRealpath(shimtspath.RootedPath(path))
|
|
179
179
|
}
|
|
180
|
-
fs.observe(path, observedInput{proof: proof})
|
|
180
|
+
fs.observe(string(path), observedInput{proof: proof})
|
|
181
181
|
return exists
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
// GetAccessibleEntries copies the returned lists before retaining them so the
|
|
185
185
|
// caller cannot mutate the witness. It does not add an unconsumed traversal.
|
|
186
|
-
func (fs *inputObservationFS) GetAccessibleEntries(path
|
|
186
|
+
func (fs *inputObservationFS) GetAccessibleEntries(path shimtspath.RootedDirectoryPath) vfs.Entries {
|
|
187
187
|
entries := fs.FS.GetAccessibleEntries(path)
|
|
188
|
-
fs.observe(path, observedInput{
|
|
188
|
+
fs.observe(string(path), observedInput{
|
|
189
189
|
proof: transformInputObservation{
|
|
190
190
|
AccessibleEntries: &transformInputEntriesObservation{
|
|
191
191
|
Directories: append([]string{}, entries.Directories...),
|
|
@@ -198,16 +198,16 @@ func (fs *inputObservationFS) GetAccessibleEntries(path string) vfs.Entries {
|
|
|
198
198
|
|
|
199
199
|
// Stat records the supplied VFS's nil/file/directory distinction and its
|
|
200
200
|
// identity spelling for existing objects, preserving the returned FileInfo.
|
|
201
|
-
func (fs *inputObservationFS) Stat(path
|
|
201
|
+
func (fs *inputObservationFS) Stat(path shimtspath.RootedPath) vfs.FileInfo {
|
|
202
202
|
info := fs.FS.Stat(path)
|
|
203
203
|
kind := "missing"
|
|
204
204
|
if info == nil {
|
|
205
|
-
fs.observe(path, observedInput{
|
|
205
|
+
fs.observe(string(path), observedInput{
|
|
206
206
|
proof: transformInputObservation{Stat: &kind},
|
|
207
207
|
})
|
|
208
208
|
} else if info.IsDir() {
|
|
209
209
|
kind = "directory"
|
|
210
|
-
fs.observe(path, observedInput{
|
|
210
|
+
fs.observe(string(path), observedInput{
|
|
211
211
|
proof: transformInputObservation{
|
|
212
212
|
Stat: &kind,
|
|
213
213
|
Realpath: fs.currentRealpath(path),
|
|
@@ -215,7 +215,7 @@ func (fs *inputObservationFS) Stat(path string) vfs.FileInfo {
|
|
|
215
215
|
})
|
|
216
216
|
} else {
|
|
217
217
|
kind = "file"
|
|
218
|
-
fs.observe(path, observedInput{
|
|
218
|
+
fs.observe(string(path), observedInput{
|
|
219
219
|
proof: transformInputObservation{
|
|
220
220
|
Stat: &kind,
|
|
221
221
|
Realpath: fs.currentRealpath(path),
|
|
@@ -227,18 +227,18 @@ func (fs *inputObservationFS) Stat(path string) vfs.FileInfo {
|
|
|
227
227
|
|
|
228
228
|
// Realpath records the adapter's answer and returns it unchanged; a lexical
|
|
229
229
|
// fallback remains an adapter answer, not separately proven physical identity.
|
|
230
|
-
func (fs *inputObservationFS) Realpath(path
|
|
230
|
+
func (fs *inputObservationFS) Realpath(path shimtspath.RootedPath) shimtspath.RootedPath {
|
|
231
231
|
realpath := fs.FS.Realpath(path)
|
|
232
|
-
fs.observe(path, observedInput{
|
|
233
|
-
proof: transformInputObservation{Realpath: realpathObservation(realpath)},
|
|
232
|
+
fs.observe(string(path), observedInput{
|
|
233
|
+
proof: transformInputObservation{Realpath: realpathObservation(string(realpath))},
|
|
234
234
|
})
|
|
235
235
|
return realpath
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
// currentRealpath obtains the identity predicate beside an existing-object
|
|
239
239
|
// query without routing that supporting call back through the observer.
|
|
240
|
-
func (fs *inputObservationFS) currentRealpath(path
|
|
241
|
-
return realpathObservation(fs.FS.Realpath(path))
|
|
240
|
+
func (fs *inputObservationFS) currentRealpath(path shimtspath.RootedPath) *transformInputRealpathObservation {
|
|
241
|
+
return realpathObservation(string(fs.FS.Realpath(path)))
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
// realpathObservation distinguishes an empty adapter result from its cleaned
|
|
@@ -264,10 +264,7 @@ func (fs *inputObservationFS) observationKey(path string) string {
|
|
|
264
264
|
if !filepath.IsAbs(path) {
|
|
265
265
|
return ""
|
|
266
266
|
}
|
|
267
|
-
return shimtspath.
|
|
268
|
-
shimtspath.NormalizePath(path),
|
|
269
|
-
fs.caseSensitive,
|
|
270
|
-
)
|
|
267
|
+
return shimtspath.Canonicalize(fs.caseSensitivity, shimtspath.NormalizePath(path))
|
|
271
268
|
}
|
|
272
269
|
|
|
273
270
|
// observe merges under the ledger lock and preserves first lexical spelling.
|
|
@@ -21,7 +21,7 @@ func TestInvalidContributorRangeCannotPanicInlineDirectiveFiltering(t *testing.T
|
|
|
21
21
|
const value = 1;
|
|
22
22
|
`)
|
|
23
23
|
contributor := &boundedDiagnosticRangeContributor{
|
|
24
|
-
spans: map[string][2]int{file.FileName(): {999, 1200}},
|
|
24
|
+
spans: map[string][2]int{string(file.FileName()): {999, 1200}},
|
|
25
25
|
}
|
|
26
26
|
metadata, err := inspectContributor(contributor)
|
|
27
27
|
if err != nil {
|
|
@@ -70,7 +70,7 @@ func TestLintCorpusFilenameSeparatorsShareMaterializedSourceIdentity(t *testing.
|
|
|
70
70
|
finding := findings[0]
|
|
71
71
|
start := strings.Index(source, "var legacy")
|
|
72
72
|
end := start + len("var legacy = 1;")
|
|
73
|
-
if finding.Pos != start || finding.End != end || finding.File.FileName() != filepath.ToSlash(location) {
|
|
73
|
+
if finding.Pos != start || finding.End != end || string(finding.File.FileName()) != filepath.ToSlash(location) {
|
|
74
74
|
t.Fatalf("main source identity/range: got %s [%d,%d), want %s [%d,%d)", finding.File.FileName(), finding.Pos, finding.End, filepath.ToSlash(location), start, end)
|
|
75
75
|
}
|
|
76
76
|
})
|
|
@@ -79,7 +79,7 @@ func TestLoadConfigResolverCompactGlobsPreserveEntryPolicy(t *testing.T) {
|
|
|
79
79
|
scoped := filepath.Join(root, "scoped.config.json")
|
|
80
80
|
writeFile(t, scoped, `{"files":["{src,test}/**/{main,unit}.ts"],"ignores":["src/{local,other}/**"],"format":{"severity":"off","semi":false}}`)
|
|
81
81
|
scopedResolver := load(scoped)
|
|
82
|
-
selected := (formatCommandResolver{inner: scopedResolver}).ResolveRules(main.FileName())
|
|
82
|
+
selected := (formatCommandResolver{inner: scopedResolver}).ResolveRules(string(main.FileName()))
|
|
83
83
|
if selected.OutOfScope || selected.Ignored || selected.Rules.Severity("format/semi") != SeverityWarn || string(selected.RuleOptions("format/semi")) != `{"prefer":"never"}` {
|
|
84
84
|
t.Errorf("scoped formatter positive did not execute its selected policy: %+v options=%s", selected, selected.RuleOptions("format/semi"))
|
|
85
85
|
}
|
|
@@ -91,7 +91,7 @@ func TestLoadConfigResolverCompactGlobsPreserveEntryPolicy(t *testing.T) {
|
|
|
91
91
|
}
|
|
92
92
|
writeFile(t, base, `{"rules":{"no-var":"error"}}`)
|
|
93
93
|
reloaded := load(final)
|
|
94
|
-
if got := reloaded.ResolveRules(ignored.FileName()); got.Ignored || got.Rules.Severity("no-var") != SeverityError {
|
|
94
|
+
if got := reloaded.ResolveRules(string(ignored.FileName())); got.Ignored || got.Rules.Severity("no-var") != SeverityError {
|
|
95
95
|
t.Errorf("changed global ignore did not refresh: %+v", got)
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -122,7 +122,7 @@ func TestLoadProgramKeepsCheckerPoolForTypeAwareRules(t *testing.T) {
|
|
|
122
122
|
t.Fatalf("unexpected generated-wrapper diagnostics: %#v", generatedDiags)
|
|
123
123
|
}
|
|
124
124
|
defer generated.close()
|
|
125
|
-
if got := generated.tsProgram.Options().ConfigFilePath; got != shimtspath.ResolvePath(semanticConfig) {
|
|
125
|
+
if got := string(generated.tsProgram.Options().ConfigFilePath); got != shimtspath.ResolvePath(semanticConfig) {
|
|
126
126
|
t.Fatalf("generated wrapper semantic config = %q, want %q", got, shimtspath.ResolvePath(semanticConfig))
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -143,7 +143,7 @@ func TestLoadProgramKeepsCheckerPoolForTypeAwareRules(t *testing.T) {
|
|
|
143
143
|
if len(coldLSPDiags) != 0 {
|
|
144
144
|
t.Fatalf("unexpected cold LSP diagnostics: %#v", coldLSPDiags)
|
|
145
145
|
}
|
|
146
|
-
if got := coldLSP.tsProgram.Options().ConfigFilePath; got != shimtspath.ResolvePath(semanticConfig) {
|
|
146
|
+
if got := string(coldLSP.tsProgram.Options().ConfigFilePath); got != shimtspath.ResolvePath(semanticConfig) {
|
|
147
147
|
t.Fatalf("cold LSP semantic config = %q, want %q", got, shimtspath.ResolvePath(semanticConfig))
|
|
148
148
|
}
|
|
149
149
|
|
|
@@ -155,7 +155,7 @@ func TestLoadProgramKeepsCheckerPoolForTypeAwareRules(t *testing.T) {
|
|
|
155
155
|
if len(residentLSPDiags) != 0 {
|
|
156
156
|
t.Fatalf("unexpected resident LSP diagnostics: %#v", residentLSPDiags)
|
|
157
157
|
}
|
|
158
|
-
if got := residentLSP.tsProgram.Options().ConfigFilePath; got != shimtspath.ResolvePath(semanticConfig) {
|
|
158
|
+
if got := string(residentLSP.tsProgram.Options().ConfigFilePath); got != shimtspath.ResolvePath(semanticConfig) {
|
|
159
159
|
t.Fatalf("resident LSP semantic config = %q, want %q", got, shimtspath.ResolvePath(semanticConfig))
|
|
160
160
|
}
|
|
161
161
|
resident.invalidate()
|
|
@@ -168,7 +168,7 @@ func TestLoadProgramKeepsCheckerPoolForTypeAwareRules(t *testing.T) {
|
|
|
168
168
|
t.Fatalf("unexpected unmarked-wrapper diagnostics: %#v", unmarkedDiags)
|
|
169
169
|
}
|
|
170
170
|
defer unmarked.close()
|
|
171
|
-
if got := unmarked.tsProgram.Options().ConfigFilePath; got != shimtspath.ResolvePath(generatedConfig) {
|
|
171
|
+
if got := string(unmarked.tsProgram.Options().ConfigFilePath); got != shimtspath.ResolvePath(generatedConfig) {
|
|
172
172
|
t.Fatalf("unmarked wrapper inherited ambient semantic config = %q, want %q", got, shimtspath.ResolvePath(generatedConfig))
|
|
173
173
|
}
|
|
174
174
|
invalid, _, err := loadProgram(root, generatedConfig, loadProgramOptions{semanticConfigPath: "relative.json"})
|
package/linthost/lsp.go
CHANGED
|
@@ -20,6 +20,7 @@ import (
|
|
|
20
20
|
shimcore "github.com/microsoft/typescript-go/shim/core"
|
|
21
21
|
shimparser "github.com/microsoft/typescript-go/shim/parser"
|
|
22
22
|
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
23
|
+
shimtspath "github.com/microsoft/typescript-go/shim/tspath"
|
|
23
24
|
|
|
24
25
|
publicrule "github.com/samchon/ttsc/packages/lint/rule"
|
|
25
26
|
)
|
|
@@ -602,7 +603,7 @@ func filterFindingsForPath(findings []*Finding, target string) []*Finding {
|
|
|
602
603
|
if finding == nil || finding.File == nil {
|
|
603
604
|
continue
|
|
604
605
|
}
|
|
605
|
-
if canonicalProjectPath("", realProjectPath(finding.File.FileName())) == target {
|
|
606
|
+
if canonicalProjectPath("", realProjectPath(string(finding.File.FileName()))) == target {
|
|
606
607
|
out = append(out, finding)
|
|
607
608
|
}
|
|
608
609
|
}
|
|
@@ -631,7 +632,7 @@ func lspRelatedInformationForFinding(finding *Finding) []lspRelatedInformation {
|
|
|
631
632
|
if finding == nil || len(finding.RelatedInformation) == 0 || finding.File == nil {
|
|
632
633
|
return nil
|
|
633
634
|
}
|
|
634
|
-
uri := fileURL(finding.File.FileName())
|
|
635
|
+
uri := fileURL(string(finding.File.FileName()))
|
|
635
636
|
out := make([]lspRelatedInformation, 0, len(finding.RelatedInformation))
|
|
636
637
|
for _, item := range finding.RelatedInformation {
|
|
637
638
|
out = append(out, lspRelatedInformation{
|
|
@@ -1185,9 +1186,13 @@ func lspFormatBuffer(content string, opts *lspCommandOptions) (*lspWorkspaceEdit
|
|
|
1185
1186
|
|
|
1186
1187
|
text := content
|
|
1187
1188
|
converged := false
|
|
1188
|
-
// The
|
|
1189
|
-
// `target
|
|
1190
|
-
parseName :=
|
|
1189
|
+
// The parser takes a rooted file name: the normalized, forward-slash form of
|
|
1190
|
+
// `target`, which filePathFromURI made absolute.
|
|
1191
|
+
parseName, ok := shimtspath.TryRootedFilePathFromAbsolute(target)
|
|
1192
|
+
if !ok {
|
|
1193
|
+
fmt.Fprintf(os.Stderr, "@ttsc/lint: LSP format target is not a rooted path: %s\n", target)
|
|
1194
|
+
return nil, 2
|
|
1195
|
+
}
|
|
1191
1196
|
for pass := 0; pass < maxFormatPasses; pass++ {
|
|
1192
1197
|
file := shimparser.ParseSourceFile(shimast.SourceFileParseOptions{FileName: parseName}, text, scriptKind)
|
|
1193
1198
|
if file == nil || len(file.Diagnostics()) > 0 || len(file.JSDiagnostics()) > 0 {
|
|
@@ -84,7 +84,7 @@ export class JsSafeCatch {
|
|
|
84
84
|
}
|
|
85
85
|
var file *shimast.SourceFile
|
|
86
86
|
for _, candidate := range prog.userSourceFiles() {
|
|
87
|
-
if filepath.Base(candidate.FileName()) == "main.ts" {
|
|
87
|
+
if filepath.Base(string(candidate.FileName())) == "main.ts" {
|
|
88
88
|
file = candidate
|
|
89
89
|
break
|
|
90
90
|
}
|
package/linthost/no_floating_promises_rejects_inapplicable_generic_receiver_branches_test.go
CHANGED
|
@@ -228,7 +228,7 @@ function checkUncertainArray<U>(
|
|
|
228
228
|
if diagnostic == nil || diagnostic.Code() != 2349 || diagnostic.File() == nil {
|
|
229
229
|
continue
|
|
230
230
|
}
|
|
231
|
-
fileName := strings.ReplaceAll(diagnostic.File().FileName(), "\\", "/")
|
|
231
|
+
fileName := strings.ReplaceAll(string(diagnostic.File().FileName()), "\\", "/")
|
|
232
232
|
if fileName != "main.ts" && !strings.HasSuffix(fileName, "/main.ts") {
|
|
233
233
|
continue
|
|
234
234
|
}
|