mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
refactor(ssh_config): Use Diagnostics instead of LSPError
This commit is contained in:
parent
b7f01f0bd4
commit
a0c0ccce25
@ -38,12 +38,9 @@ func Analyze(
|
|||||||
}
|
}
|
||||||
|
|
||||||
analyzeValuesAreValid(ctx)
|
analyzeValuesAreValid(ctx)
|
||||||
|
analyzeDependents(ctx)
|
||||||
|
analyzeBlocks(ctx)
|
||||||
|
analyzeMatchBlocks(ctx)
|
||||||
|
|
||||||
return ctx.diagnostics
|
return ctx.diagnostics
|
||||||
|
|
||||||
errors = append(errors, analyzeDependents(d)...)
|
|
||||||
errors = append(errors, analyzeBlocks(d)...)
|
|
||||||
errors = append(errors, analyzeMatchBlocks(d)...)
|
|
||||||
|
|
||||||
return common.ErrsToDiagnostics(errors)
|
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,23 @@ package analyzer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
sshconfig "config-lsp/handlers/ssh_config"
|
|
||||||
"errors"
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func analyzeBlocks(
|
func analyzeBlocks(
|
||||||
d *sshconfig.SSHDocument,
|
ctx *analyzerContext,
|
||||||
) []common.LSPError {
|
) {
|
||||||
errs := make([]common.LSPError, 0)
|
for _, block := range ctx.document.GetAllBlocks() {
|
||||||
|
|
||||||
for _, block := range d.GetAllBlocks() {
|
|
||||||
if block.GetOptions().Size() == 0 {
|
if block.GetOptions().Size() == 0 {
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: block.GetEntryOption().LocationRange,
|
Range: block.GetEntryOption().LocationRange.ToLSPRange(),
|
||||||
Err: errors.New("This block is empty"),
|
Message: "This block is empty",
|
||||||
|
Severity: &common.SeverityHint,
|
||||||
|
Tags: []protocol.DiagnosticTag{
|
||||||
|
protocol.DiagnosticTagUnnecessary,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package analyzer
|
|||||||
import (
|
import (
|
||||||
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBlockEmptyBlock(
|
func TestBlockEmptyBlock(
|
||||||
@ -11,10 +13,14 @@ func TestBlockEmptyBlock(
|
|||||||
d := testutils_test.DocumentFromInput(t, `
|
d := testutils_test.DocumentFromInput(t, `
|
||||||
Host *
|
Host *
|
||||||
`)
|
`)
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: *d,
|
||||||
|
diagnostics: make([]protocol.Diagnostic, 0),
|
||||||
|
}
|
||||||
|
|
||||||
errors := analyzeBlocks(d)
|
analyzeBlocks(ctx)
|
||||||
|
|
||||||
if !(len(errors) == 1) {
|
if !(len(ctx.diagnostics) == 1) {
|
||||||
t.Errorf("Expected an error, but got %v", len(errors))
|
t.Errorf("Expected an error, but got %v", len(ctx.diagnostics))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,40 +2,34 @@ package analyzer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
sshconfig "config-lsp/handlers/ssh_config"
|
|
||||||
"config-lsp/handlers/ssh_config/ast"
|
"config-lsp/handlers/ssh_config/ast"
|
||||||
"config-lsp/handlers/ssh_config/fields"
|
"config-lsp/handlers/ssh_config/fields"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func analyzeDependents(
|
func analyzeDependents(
|
||||||
d *sshconfig.SSHDocument,
|
ctx *analyzerContext,
|
||||||
) []common.LSPError {
|
) {
|
||||||
errs := make([]common.LSPError, 0)
|
for _, option := range ctx.document.Config.GetAllOptions() {
|
||||||
|
checkIsDependent(ctx, option.Option.Key, option.Block)
|
||||||
for _, option := range d.Config.GetAllOptions() {
|
|
||||||
errs = append(errs, checkIsDependent(d, option.Option.Key, option.Block)...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkIsDependent(
|
func checkIsDependent(
|
||||||
d *sshconfig.SSHDocument,
|
ctx *analyzerContext,
|
||||||
key *ast.SSHKey,
|
key *ast.SSHKey,
|
||||||
block ast.SSHBlock,
|
block ast.SSHBlock,
|
||||||
) []common.LSPError {
|
) {
|
||||||
errs := make([]common.LSPError, 0)
|
|
||||||
|
|
||||||
dependentOptions, found := fields.DependentFields[key.Key]
|
dependentOptions, found := fields.DependentFields[key.Key]
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
return errs
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dependentOption := range dependentOptions {
|
for _, dependentOption := range dependentOptions {
|
||||||
if opts, found := d.Indexes.AllOptionsPerName[dependentOption]; found {
|
if opts, found := ctx.document.Indexes.AllOptionsPerName[dependentOption]; found {
|
||||||
_, existsInBlock := opts[block]
|
_, existsInBlock := opts[block]
|
||||||
_, existsInGlobal := opts[nil]
|
_, existsInGlobal := opts[nil]
|
||||||
|
|
||||||
@ -44,11 +38,10 @@ func checkIsDependent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: key.LocationRange,
|
Range: key.LocationRange.ToLSPRange(),
|
||||||
Err: errors.New(fmt.Sprintf("Option '%s' requires option '%s' to be present", key.Key, dependentOption)),
|
Message: fmt.Sprintf("Option '%s' requires option '%s' to be present", key.Key, dependentOption),
|
||||||
|
Severity: &common.SeverityError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
@ -2,77 +2,78 @@ package analyzer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
sshconfig "config-lsp/handlers/ssh_config"
|
|
||||||
"config-lsp/handlers/ssh_config/fields"
|
"config-lsp/handlers/ssh_config/fields"
|
||||||
matchparser "config-lsp/handlers/ssh_config/match-parser"
|
matchparser "config-lsp/handlers/ssh_config/match-parser"
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func analyzeMatchBlocks(
|
func analyzeMatchBlocks(
|
||||||
d *sshconfig.SSHDocument,
|
ctx *analyzerContext,
|
||||||
) []common.LSPError {
|
) {
|
||||||
errs := make([]common.LSPError, 0)
|
for _, matchBlock := range ctx.document.GetAllMatchBlocks() {
|
||||||
|
isValid := isMatchStructureValid(ctx, matchBlock.MatchValue)
|
||||||
|
|
||||||
for _, matchBlock := range d.GetAllMatchBlocks() {
|
if !isValid {
|
||||||
structureErrs := isMatchStructureValid(matchBlock.MatchValue)
|
|
||||||
errs = append(errs, structureErrs...)
|
|
||||||
|
|
||||||
if len(structureErrs) > 0 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, checkMatch(matchBlock.MatchValue)...)
|
checkMatch(ctx, matchBlock.MatchValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isMatchStructureValid(
|
func isMatchStructureValid(
|
||||||
|
ctx *analyzerContext,
|
||||||
m *matchparser.Match,
|
m *matchparser.Match,
|
||||||
) []common.LSPError {
|
) bool {
|
||||||
errs := make([]common.LSPError, 0)
|
isValid := true
|
||||||
|
|
||||||
for _, entry := range m.Entries {
|
for _, entry := range m.Entries {
|
||||||
if !utils.KeyExists(fields.MatchSingleOptionCriterias, entry.Criteria.Type) && entry.Value.Value == "" {
|
if !utils.KeyExists(fields.MatchSingleOptionCriterias, entry.Criteria.Type) && entry.Value.Value == "" {
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: entry.LocationRange,
|
Range: entry.LocationRange.ToLSPRange(),
|
||||||
Err: errors.New(fmt.Sprintf("Argument '%s' requires a value", entry.Criteria.Type)),
|
Message: fmt.Sprintf("Argument '%s' requires a value", entry.Criteria.Type),
|
||||||
|
Severity: &common.SeverityError,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
isValid = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
return isValid
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMatch(
|
func checkMatch(
|
||||||
|
ctx *analyzerContext,
|
||||||
m *matchparser.Match,
|
m *matchparser.Match,
|
||||||
) []common.LSPError {
|
) {
|
||||||
errs := make([]common.LSPError, 0)
|
|
||||||
|
|
||||||
// Check single options
|
// Check single options
|
||||||
allEntries := m.FindEntries("all")
|
allEntries := m.FindEntries("all")
|
||||||
if len(allEntries) > 1 {
|
if len(allEntries) > 1 {
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: allEntries[1].LocationRange,
|
Range: allEntries[1].LocationRange.ToLSPRange(),
|
||||||
Err: errors.New("'all' may only be used once"),
|
Message: "'all' may only be used once",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
canonicalEntries := m.FindEntries("canonical")
|
canonicalEntries := m.FindEntries("canonical")
|
||||||
if len(canonicalEntries) > 1 {
|
if len(canonicalEntries) > 1 {
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: canonicalEntries[1].LocationRange,
|
Range: canonicalEntries[1].LocationRange.ToLSPRange(),
|
||||||
Err: errors.New("'canonical' may only be used once"),
|
Message: "'canonical' may only be used once",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
finalEntries := m.FindEntries("final")
|
finalEntries := m.FindEntries("final")
|
||||||
if len(finalEntries) > 1 {
|
if len(finalEntries) > 1 {
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: finalEntries[1].LocationRange,
|
Range: finalEntries[1].LocationRange.ToLSPRange(),
|
||||||
Err: errors.New("'final' may only be used once"),
|
Message: "'final' may only be used once",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,12 +83,11 @@ func checkMatch(
|
|||||||
previousEntry := m.GetPreviousEntry(allEntry)
|
previousEntry := m.GetPreviousEntry(allEntry)
|
||||||
|
|
||||||
if previousEntry != nil && !utils.KeyExists(fields.MatchAllArgumentAllowedPreviousOptions, previousEntry.Criteria.Type) {
|
if previousEntry != nil && !utils.KeyExists(fields.MatchAllArgumentAllowedPreviousOptions, previousEntry.Criteria.Type) {
|
||||||
errs = append(errs, common.LSPError{
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
Range: allEntry.LocationRange,
|
Range: allEntry.LocationRange.ToLSPRange(),
|
||||||
Err: errors.New("'all' should either be the first entry or immediately follow 'final' or 'canonical'"),
|
Message: "'all' should either be the first entry or immediately follow 'final' or 'canonical'",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package analyzer
|
|||||||
import (
|
import (
|
||||||
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMatchInvalidAllArgument(
|
func TestMatchInvalidAllArgument(
|
||||||
@ -11,10 +13,14 @@ func TestMatchInvalidAllArgument(
|
|||||||
d := testutils_test.DocumentFromInput(t, `
|
d := testutils_test.DocumentFromInput(t, `
|
||||||
Match user lena all
|
Match user lena all
|
||||||
`)
|
`)
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: *d,
|
||||||
|
diagnostics: make([]protocol.Diagnostic, 0),
|
||||||
|
}
|
||||||
|
|
||||||
errors := analyzeMatchBlocks(d)
|
analyzeMatchBlocks(ctx)
|
||||||
|
|
||||||
if !(len(errors) == 1 && errors[0].Range.Start.Line == 0) {
|
if !(len(ctx.diagnostics) == 1 && ctx.diagnostics[0].Range.Start.Line == 0) {
|
||||||
t.Fatalf("Expected one error, got %v", errors)
|
t.Fatalf("Expected one error, got %v", ctx.diagnostics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package analyzer
|
|||||||
import (
|
import (
|
||||||
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
testutils_test "config-lsp/handlers/ssh_config/test_utils"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSimpleInvalidQuotesExample(
|
func TestSimpleInvalidQuotesExample(
|
||||||
@ -68,12 +70,16 @@ func TestDependentOptionsExample(
|
|||||||
Port 1234
|
Port 1234
|
||||||
CanonicalDomains example.com
|
CanonicalDomains example.com
|
||||||
`)
|
`)
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: *d,
|
||||||
|
diagnostics: make([]protocol.Diagnostic, 0),
|
||||||
|
}
|
||||||
|
|
||||||
option := d.FindOptionsByName("canonicaldomains")[0]
|
option := d.FindOptionsByName("canonicaldomains")[0]
|
||||||
errors := checkIsDependent(d, option.Option.Key, option.Block)
|
checkIsDependent(ctx, option.Option.Key, option.Block)
|
||||||
|
|
||||||
if !(len(errors) == 1) {
|
if !(len(ctx.diagnostics) == 1) {
|
||||||
t.Errorf("Expected 1 error, got %v", len(errors))
|
t.Errorf("Expected 1 error, got %v", len(ctx.diagnostics))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,11 +91,15 @@ Port 1234
|
|||||||
CanonicalizeHostname yes
|
CanonicalizeHostname yes
|
||||||
CanonicalDomains example.com
|
CanonicalDomains example.com
|
||||||
`)
|
`)
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: *d,
|
||||||
|
diagnostics: make([]protocol.Diagnostic, 0),
|
||||||
|
}
|
||||||
|
|
||||||
option := d.FindOptionsByName("canonicaldomains")[0]
|
option := d.FindOptionsByName("canonicaldomains")[0]
|
||||||
errors := checkIsDependent(d, option.Option.Key, option.Block)
|
checkIsDependent(ctx, option.Option.Key, option.Block)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(ctx.diagnostics) > 0 {
|
||||||
t.Errorf("Expected no errors, got %v", len(errors))
|
t.Errorf("Expected no errors, got %v", len(ctx.diagnostics))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user