@@ -15,6 +15,7 @@ import (
1515 "github.com/microsoft/typescript-go/shim/core"
1616 "github.com/microsoft/typescript-go/shim/scanner"
1717 "github.com/microsoft/typescript-go/shim/tspath"
18+ "github.com/microsoft/typescript-go/shim/vfs"
1819 "github.com/microsoft/typescript-go/shim/vfs/cachedvfs"
1920 "github.com/microsoft/typescript-go/shim/vfs/osvfs"
2021 api "github.com/web-infra-dev/rslint/internal/api"
@@ -87,17 +88,16 @@ func (h *IPCHandler) HandleLint(req api.LintRequest) (*api.LintResponse, error)
8788 }
8889 }
8990 // Apply file contents if provided
91+ var fileContents map [string ]string
9092 if len (req .FileContents ) > 0 {
9193 if allowedFiles == nil {
9294 allowedFiles = make ([]string , 0 , len (req .FileContents ))
9395 }
94- fileContents : = make (map [string ]string , len (req .FileContents ))
96+ fileContents = make (map [string ]string , len (req .FileContents ))
9597 for k , v := range req .FileContents {
9698 normalizedPath := addAllowedFile (k )
9799 fileContents [normalizedPath ] = v
98100 }
99- fs = utils .NewOverlayVFS (fs , fileContents )
100-
101101 }
102102
103103 // Initialize rule registry with all available rules
@@ -121,6 +121,10 @@ func (h *IPCHandler) HandleLint(req api.LintRequest) (*api.LintResponse, error)
121121 configDirectory = currentDirectory
122122 }
123123 configDirectory = tspath .NormalizePath (configDirectory )
124+ if len (fileContents ) > 0 {
125+ addEquivalentFileContentPaths (fileContents , configDirectory , currentDirectory , fs )
126+ fs = utils .NewOverlayVFS (fs , fileContents )
127+ }
124128 var gitignoreGlobs []string
125129 if len (allowedFiles ) > 0 {
126130 gitignoreGlobs = rslintconfig .ReadGitignoreAsGlobsForFiles (configDirectory , fs , allowedFiles )
@@ -166,10 +170,10 @@ func (h *IPCHandler) HandleLint(req api.LintRequest) (*api.LintResponse, error)
166170 // list).
167171 // The --api path never runs the type-check phase (RunLinterOptions.TypeCheck
168172 // stays false), so there is no per-program type-check skip mask to build.
169- programs , typeInfoFiles , _ , _ , targetsByProgram := buildProgramsWithLintTargets (
173+ programs , typeInfoFiles , _ , _ , targetsByProgram , configPathBySourcePath := buildProgramsWithLintTargets (
170174 programs , nil , rslintConfig , configDirectory , nil , nil , fs , allowedFiles , nil , parseCache , false ,
171175 )
172- fileConfigResolver := rslintconfig . NewFileConfigResolver ( rslintConfig , configDirectory , true )
176+ fileConfigResolver := newLintConfigResolver ( nil , rslintConfig , configDirectory , true , typeInfoFiles , configPathBySourcePath )
173177
174178 // Collect diagnostics and source files
175179 var diagnostics []api.Diagnostic
@@ -337,7 +341,7 @@ func (h *IPCHandler) HandleLint(req api.LintRequest) (*api.LintResponse, error)
337341 // so a rule carrying a plugin prefix runs only when its plugin is
338342 // declared in the config's `plugins` — matching CLI and ESLint
339343 // semantics (a rule whose plugin is not declared is skipped).
340- return fileConfigResolver .ActiveRulesForFile (sourceFile .FileName (), typeInfoFiles )
344+ return fileConfigResolver .ActiveRulesForFile (sourceFile .FileName ())
341345 },
342346 OnDiagnostic : diagnosticCollector ,
343347 })
@@ -435,6 +439,56 @@ func (h *IPCHandler) HandleLint(req api.LintRequest) (*api.LintResponse, error)
435439 return response , nil
436440}
437441
442+ func addEquivalentFileContentPaths (fileContents map [string ]string , configDirectory string , currentDirectory string , fs vfs.FS ) {
443+ if len (fileContents ) == 0 || fs == nil {
444+ return
445+ }
446+
447+ type fileContentEntry struct {
448+ path string
449+ content string
450+ }
451+ entries := make ([]fileContentEntry , 0 , len (fileContents ))
452+ for filePath , content := range fileContents {
453+ entries = append (entries , fileContentEntry {path : filePath , content : content })
454+ }
455+
456+ comparePathOptions := tspath.ComparePathsOptions {
457+ CurrentDirectory : currentDirectory ,
458+ UseCaseSensitiveFileNames : fs .UseCaseSensitiveFileNames (),
459+ }
460+ addAlias := func (alias string , content string ) {
461+ if alias == "" {
462+ return
463+ }
464+ if _ , exists := fileContents [alias ]; exists {
465+ return
466+ }
467+ fileContents [alias ] = content
468+ }
469+ addDirectoryAlias := func (fromDir string , toDir string , filePath string , content string ) {
470+ if fromDir == "" || toDir == "" || ! tspath .ContainsPath (fromDir , filePath , comparePathOptions ) {
471+ return
472+ }
473+ relativePath := tspath .GetRelativePathFromDirectory (fromDir , filePath , comparePathOptions )
474+ if relativePath == "" {
475+ return
476+ }
477+ addAlias (tspath .ResolvePath (toDir , relativePath ), content )
478+ }
479+
480+ realConfigDirectory := fs .Realpath (configDirectory )
481+ for _ , entry := range entries {
482+ if realPath := fs .Realpath (entry .path ); realPath != "" && realPath != entry .path {
483+ addAlias (realPath , entry .content )
484+ }
485+ if realConfigDirectory != "" && tspath .ComparePaths (configDirectory , realConfigDirectory , comparePathOptions ) != 0 {
486+ addDirectoryAlias (configDirectory , realConfigDirectory , entry .path , entry .content )
487+ addDirectoryAlias (realConfigDirectory , configDirectory , entry .path , entry .content )
488+ }
489+ }
490+ }
491+
438492// HandleGetAstInfo handles get AST info requests in IPC mode
439493func (h * IPCHandler ) HandleGetAstInfo (req api.GetAstInfoRequest ) (* api.GetAstInfoResponse , error ) {
440494 // Fixed user file name for program creation
0 commit comments