Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-cloudflare-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/tsgo": patch
---

Skip Effect diagnostics for source files resolved from external libraries.
8 changes: 8 additions & 0 deletions _patches/002-checker-checker.patch
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ index 2e1622418..66059cab4 100644
// CheckMode

type CheckMode uint32
@@ -559,6 +593,7 @@ type Program interface {
GetImportHelpersImportSpecifier(path tspath.Path) *ast.Node
SourceFileMayBeEmitted(sourceFile *ast.SourceFile, forceDtsEmit bool) bool
IsSourceFileDefaultLibrary(path tspath.Path) bool
+ IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool
GetProjectReferenceFromOutputDts(path tspath.Path) *tsoptions.SourceOutputAndProjectReference
GetRedirectForResolution(file ast.HasFileName) *tsoptions.ParsedCommandLine
CommonSourceDirectory() string
@@ -2145,6 +2179,8 @@ func (c *Checker) checkSourceFile(ctx context.Context, sourceFile *ast.SourceFil
links := c.sourceFileLinks.Get(sourceFile)
if !links.typeChecked {
Expand Down
15 changes: 15 additions & 0 deletions _patches/018-ls-autoimport-stylepolicy.patch
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,18 @@ index b2107443f..bf5161047 100644
}

// getAddAsTypeOnly determines if an import should be type-only based on usage context
diff --git a/internal/ls/autoimport/aliasresolver.go b/internal/ls/autoimport/aliasresolver.go
--- a/internal/ls/autoimport/aliasresolver.go
+++ b/internal/ls/autoimport/aliasresolver.go
@@ -220,6 +220,11 @@ func (r *aliasResolver) IsSourceFileDefaultLibrary(path tspath.Path) bool {
panic("unimplemented")
}

+// IsSourceFileFromExternalLibrary implements checker.Program.
+func (r *aliasResolver) IsSourceFileFromExternalLibrary(file *ast.SourceFile) bool {
+ return false
+}
+
// IsSourceFromProjectReference implements checker.Program.
func (r *aliasResolver) IsSourceFromProjectReference(path tspath.Path) bool {
panic("unimplemented")
98 changes: 98 additions & 0 deletions etscheckerhooks/external_library_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package etscheckerhooks_test

import (
"context"
"strings"
"testing"
"testing/fstest"

_ "github.com/effect-ts/tsgo/etscheckerhooks"
"github.com/effect-ts/tsgo/etscore"
"github.com/microsoft/typescript-go/shim/ast"
"github.com/microsoft/typescript-go/shim/bundled"
"github.com/microsoft/typescript-go/shim/compiler"
"github.com/microsoft/typescript-go/shim/core"
"github.com/microsoft/typescript-go/shim/tsoptions"
"github.com/microsoft/typescript-go/shim/vfs/vfstest"
)

func TestEffectDiagnosticsSkipExternalLibrarySourceFiles(t *testing.T) {
t.Parallel()

testfs := map[string]any{
"/src/main.ts": &fstest.MapFile{
Data: []byte(`import { ExternalProblem } from "problem"

export class LocalProblem extends Error {}
export const value = ExternalProblem
`),
},
"/node_modules/problem/package.json": &fstest.MapFile{
Data: []byte(`{"name":"problem","version":"1.0.0","types":"index.ts"}`),
},
"/node_modules/problem/index.ts": &fstest.MapFile{
Data: []byte(`export class ExternalProblem extends Error {}`),
},
}

fs := bundled.WrapFS(vfstest.FromMap(testfs, true))
options := &core.CompilerOptions{
NewLine: core.NewLineKindLF,
NoErrorTruncation: core.TSTrue,
Target: core.ScriptTargetESNext,
Module: core.ModuleKindCommonJS,
ModuleResolution: core.ModuleResolutionKindNode10,
Effect: &etscore.EffectPluginOptions{
Diagnostics: true,
DiagnosticSeverity: map[string]etscore.Severity{
"extendsNativeError": etscore.SeverityError,
},
},
}
program := compiler.NewProgram(compiler.ProgramOptions{
Config: &tsoptions.ParsedCommandLine{
ParsedConfig: &core.ParsedOptions{
CompilerOptions: options,
FileNames: []string{"/src/main.ts"},
},
},
Host: compiler.NewCompilerHost("/", fs, bundled.LibPath(), nil, nil),
SingleThreaded: core.TSTrue,
})

dependencySource := program.GetSourceFile("/node_modules/problem/index.ts")
if dependencySource == nil {
t.Fatal("expected dependency source file to be resolved")
}
if !program.IsSourceFileFromExternalLibrary(dependencySource) {
t.Fatal("expected dependency source file to be marked as external library")
}

diagnostics := program.GetSemanticDiagnostics(context.Background(), nil)
localEffectDiagnostics := 0
externalEffectDiagnostics := 0
for _, diag := range diagnostics {
if !isEffectDiagnostic(diag) || diag.File() == nil {
continue
}
fileName := diag.File().FileName()
switch {
case strings.Contains(fileName, "/node_modules/"):
externalEffectDiagnostics++
case fileName == "/src/main.ts":
localEffectDiagnostics++
}
}

if externalEffectDiagnostics != 0 {
t.Fatalf("expected no Effect diagnostics from external libraries, got %d", externalEffectDiagnostics)
}
if localEffectDiagnostics == 0 {
t.Fatal("expected Effect diagnostics for project source file")
}
}

func isEffectDiagnostic(diag *ast.Diagnostic) bool {
code := diag.Code()
return code >= 377000 && code < 378000
}
9 changes: 4 additions & 5 deletions etscheckerhooks/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ type RuleDiagnostic struct {
// afterCheckSourceFile is called after type checking each source file.
// It runs Effect diagnostics if the plugin is enabled.
func afterCheckSourceFile(ctx context.Context, program checker.Program, c *checker.Checker, sf *ast.SourceFile) {
tp := typeparser.NewTypeParser(program, c)
if sf.IsDeclarationFile || program.IsSourceFileFromExternalLibrary(sf) {
return
}

// Get Effect config from program options (parsed during config loading)
effectConfig := getEffectConfig(program)
Expand All @@ -71,10 +73,7 @@ func afterCheckSourceFile(ctx context.Context, program checker.Program, c *check
return
}

// Skip declaration files
if sf.IsDeclarationFile {
return
}
tp := typeparser.NewTypeParser(program, c)

// Collect directives from source file for suppression support
sourceText := sf.Text()
Expand Down
16 changes: 8 additions & 8 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading