Working
This commit is contained in:
95
internal/validator/validator.go
Normal file
95
internal/validator/validator.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/marte-dev/marte-dev-tools/internal/parser"
|
||||
"github.com/marte-dev/marte-dev-tools/internal/index"
|
||||
)
|
||||
|
||||
type DiagnosticLevel int
|
||||
|
||||
const (
|
||||
LevelError DiagnosticLevel = iota
|
||||
LevelWarning
|
||||
)
|
||||
|
||||
type Diagnostic struct {
|
||||
Level DiagnosticLevel
|
||||
Message string
|
||||
Position parser.Position
|
||||
File string
|
||||
}
|
||||
|
||||
type Validator struct {
|
||||
Diagnostics []Diagnostic
|
||||
Index *index.Index
|
||||
}
|
||||
|
||||
func NewValidator(idx *index.Index) *Validator {
|
||||
return &Validator{Index: idx}
|
||||
}
|
||||
|
||||
func (v *Validator) Validate(file string, config *parser.Configuration) {
|
||||
for _, def := range config.Definitions {
|
||||
v.validateDefinition(file, "", config, def)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Validator) validateDefinition(file string, path string, config *parser.Configuration, def parser.Definition) {
|
||||
switch d := def.(type) {
|
||||
case *parser.ObjectNode:
|
||||
name := d.Name
|
||||
fullPath := name
|
||||
if path != "" {
|
||||
fullPath = path + "." + name
|
||||
}
|
||||
|
||||
// Check for mandatory 'Class' field for +/$ nodes
|
||||
if d.Name != "" && (d.Name[0] == '+' || d.Name[0] == '$') {
|
||||
hasClass := false
|
||||
for _, subDef := range d.Subnode.Definitions {
|
||||
if f, ok := subDef.(*parser.Field); ok && f.Name == "Class" {
|
||||
hasClass = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasClass {
|
||||
v.Diagnostics = append(v.Diagnostics, Diagnostic{
|
||||
Level: LevelError,
|
||||
Message: fmt.Sprintf("Node %s is an object and must contain a 'Class' field", d.Name),
|
||||
Position: d.Position,
|
||||
File: file,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// GAM specific validation
|
||||
// (This is a placeholder, real logic would check if it's a GAM)
|
||||
|
||||
for _, subDef := range d.Subnode.Definitions {
|
||||
v.validateDefinition(file, fullPath, config, subDef)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Validator) CheckUnused() {
|
||||
if v.Index == nil {
|
||||
return
|
||||
}
|
||||
|
||||
referencedSymbols := make(map[*index.Symbol]bool)
|
||||
for _, ref := range v.Index.References {
|
||||
if ref.Target != nil {
|
||||
referencedSymbols[ref.Target] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, sym := range v.Index.Symbols {
|
||||
// Heuristic: if it's a GAM or Signal, check if referenced
|
||||
// (Refining this later with proper class checks)
|
||||
if !referencedSymbols[sym] {
|
||||
// Logic to determine if it should be warned as unused
|
||||
// e.g. if sym.Class is a GAM or if it's a signal in a DataSource
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user