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
7 changes: 7 additions & 0 deletions .changeset/effect-diagnostics-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@effect/tsgo": minor
---

Add a native `getEffectDiagnostics` API entrypoint that runs Effect diagnostics for a specific source file with explicit rule selection and Effect options.

This also exposes a shared internal rule runner so the checker hook and native API use the same directive, severity, and override behavior.
3 changes: 2 additions & 1 deletion _patches/001-cmd-tsgo-main.patch
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ diff --git a/cmd/tsgo/main.go b/cmd/tsgo/main.go
index a2fe02e8c..10044042c 100644
--- a/cmd/tsgo/main.go
+++ b/cmd/tsgo/main.go
@@ -3,7 +3,12 @@ package main
@@ -3,6 +3,12 @@ package main
import (
"os"

+ // Import Effect hooks to register via init()
+ _ "github.com/effect-ts/tsgo/etsapihooks" // native API hooks
+ _ "github.com/effect-ts/tsgo/etsexecutehooks" // exit-code filtering hooks
+ _ "github.com/effect-ts/tsgo/etscheckerhooks" // checker diagnostics hooks
+ _ "github.com/effect-ts/tsgo/etslshooks" // LS codefix hooks
Expand Down
120 changes: 120 additions & 0 deletions _patches/028-api-effect-diagnostics.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
diff --git a/internal/api/proto.go b/internal/api/proto.go
--- a/internal/api/proto.go
+++ b/internal/api/proto.go
@@ -6,6 +6,7 @@ import (
"strconv"
"strings"

+ "github.com/effect-ts/tsgo/etscore"
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/checker"
"github.com/microsoft/typescript-go/internal/core"
@@ -156,6 +157,7 @@ const (
// Diagnostic methods
MethodGetSyntacticDiagnostics Method = "getSyntacticDiagnostics"
MethodGetSemanticDiagnostics Method = "getSemanticDiagnostics"
+ MethodGetEffectDiagnostics Method = "getEffectDiagnostics"
MethodGetSuggestionDiagnostics Method = "getSuggestionDiagnostics"
MethodGetDeclarationDiagnostics Method = "getDeclarationDiagnostics"
MethodGetConfigFileParsingDiagnostics Method = "getConfigFileParsingDiagnostics"
@@ -389,6 +391,7 @@ var unmarshalers = map[Method]func(json.Value) (any, error){
MethodGetESSymbolType: unmarshallerFor[GetIntrinsicTypeParams],
MethodGetSyntacticDiagnostics: unmarshallerFor[GetDiagnosticsParams],
MethodGetSemanticDiagnostics: unmarshallerFor[GetDiagnosticsParams],
+ MethodGetEffectDiagnostics: unmarshallerFor[GetEffectDiagnosticsParams],
MethodGetSuggestionDiagnostics: unmarshallerFor[GetDiagnosticsParams],
MethodGetDeclarationDiagnostics: unmarshallerFor[GetDiagnosticsParams],
MethodGetConfigFileParsingDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams],
@@ -863,6 +866,15 @@ type GetDiagnosticsParams struct {
File *DocumentIdentifier `json:"file,omitempty"`
}

+// GetEffectDiagnosticsParams are parameters for Effect diagnostic rules.
+type GetEffectDiagnosticsParams struct {
+ Snapshot Handle[project.Snapshot] `json:"snapshot"`
+ Project Handle[project.Project] `json:"project"`
+ File DocumentIdentifier `json:"file"`
+ Options *etscore.EffectPluginOptions `json:"options,omitempty"`
+ Rules []string `json:"rules,omitempty"`
+}
+
// GetProjectDiagnosticsParams are parameters for project-wide diagnostic methods.
type GetProjectDiagnosticsParams struct {
Snapshot Handle[project.Snapshot] `json:"snapshot"`
diff --git a/internal/api/session.go b/internal/api/session.go
--- a/internal/api/session.go
+++ b/internal/api/session.go
@@ -7,6 +7,7 @@ import (
"sync"
"sync/atomic"

+ "github.com/effect-ts/tsgo/etscore"
"github.com/microsoft/typescript-go/internal/api/encoder"
"github.com/microsoft/typescript-go/internal/ast"
"github.com/microsoft/typescript-go/internal/astnav"
@@ -21,6 +22,15 @@ import (
"github.com/microsoft/typescript-go/internal/tspath"
)

+// GetEffectDiagnosticsCallback is invoked by the API getEffectDiagnostics method.
+// It is registered by external packages to keep Effect rule evaluation outside TypeScript-Go.
+var GetEffectDiagnosticsCallback func(ctx context.Context, program *compiler.Program, c *checker.Checker, sourceFile *ast.SourceFile, options *etscore.EffectPluginOptions, rules []string) ([]*ast.Diagnostic, error)
+
+// RegisterGetEffectDiagnosticsCallback registers the getEffectDiagnostics API callback.
+func RegisterGetEffectDiagnosticsCallback(cb func(ctx context.Context, program *compiler.Program, c *checker.Checker, sourceFile *ast.SourceFile, options *etscore.EffectPluginOptions, rules []string) ([]*ast.Diagnostic, error)) {
+ GetEffectDiagnosticsCallback = cb
+}
+
var sessionIDCounter atomic.Uint64

// snapshotData holds the per-snapshot state including the snapshot itself
@@ -459,6 +469,8 @@ func (s *Session) HandleRequest(ctx context.Context, method string, params json.
return s.handleGetSyntacticDiagnostics(ctx, parsed.(*GetDiagnosticsParams))
case string(MethodGetSemanticDiagnostics):
return s.handleGetSemanticDiagnostics(ctx, parsed.(*GetDiagnosticsParams))
+ case string(MethodGetEffectDiagnostics):
+ return s.handleGetEffectDiagnostics(ctx, parsed.(*GetEffectDiagnosticsParams))
case string(MethodGetSuggestionDiagnostics):
return s.handleGetSuggestionDiagnostics(ctx, parsed.(*GetDiagnosticsParams))
case string(MethodGetDeclarationDiagnostics):
@@ -2003,6 +2015,40 @@ func (s *Session) handleGetSemanticDiagnostics(ctx context.Context, params *GetD
return NewDiagnosticResponses(diags), nil
}

+// handleGetEffectDiagnostics returns Effect diagnostics for a file using explicit API options.
+func (s *Session) handleGetEffectDiagnostics(ctx context.Context, params *GetEffectDiagnosticsParams) ([]*DiagnosticResponse, error) {
+ if GetEffectDiagnosticsCallback == nil {
+ return nil, fmt.Errorf("getEffectDiagnostics callback is not registered")
+ }
+
+ sd, err := s.getSnapshotData(params.Snapshot)
+ if err != nil {
+ return nil, err
+ }
+
+ program, err := sd.getProgram(params.Project)
+ if err != nil {
+ return nil, err
+ }
+
+ sourceFile := program.GetSourceFile(params.File.ToFileName())
+ if sourceFile == nil {
+ return nil, fmt.Errorf("source file not found: %s", params.File.ToFileName())
+ }
+
+ c, done := program.GetTypeCheckerForFileExclusive(ctx, sourceFile)
+ defer done()
+
+ // Ensure the source file is checked before running rules that rely on type information.
+ c.GetDiagnostics(ctx, sourceFile)
+
+ diags, err := GetEffectDiagnosticsCallback(ctx, program, c, sourceFile, params.Options, params.Rules)
+ if err != nil {
+ return nil, err
+ }
+ return NewDiagnosticResponses(diags), nil
+}
+
// handleGetSuggestionDiagnostics returns suggestion diagnostics for a file or all files.
func (s *Session) handleGetSuggestionDiagnostics(ctx context.Context, params *GetDiagnosticsParams) ([]*DiagnosticResponse, error) {
sd, err := s.getSnapshotData(params.Snapshot)
1 change: 1 addition & 0 deletions _tools/gen_shims/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type ExtraShim struct {

func main() {
packagesToShim := []string{
"api",
"ast",
"astnav",
"bundled",
Expand Down
5 changes: 5 additions & 0 deletions etsapihooks/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Package etsapihooks registers Effect API hooks for TypeScript-Go.
//
// This package should be imported with a blank identifier by the main entry point
// to register API-only Effect diagnostics.
package etsapihooks
25 changes: 25 additions & 0 deletions etsapihooks/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package etsapihooks

import (
"context"

"github.com/effect-ts/tsgo/etscore"
"github.com/effect-ts/tsgo/internal/effectconfigraw"
"github.com/effect-ts/tsgo/internal/rulerunner"
"github.com/microsoft/typescript-go/shim/api"
"github.com/microsoft/typescript-go/shim/ast"
"github.com/microsoft/typescript-go/shim/checker"
"github.com/microsoft/typescript-go/shim/compiler"
)

func init() {
effectconfigraw.Register()
api.RegisterGetEffectDiagnosticsCallback(getEffectDiagnostics)
}

func getEffectDiagnostics(ctx context.Context, program *compiler.Program, c *checker.Checker, sf *ast.SourceFile, options *etscore.EffectPluginOptions, ruleNames []string) ([]*ast.Diagnostic, error) {
if options == nil {
options = program.Options().Effect
}
return rulerunner.Run(ctx, program, c, sf, options, ruleNames)
}
Loading
Loading