Files
osmedeus/internal/parser/validator.go
T
j3ssie 1403d20a4d feat: add LLM step executor with vision and tool support, event workflow system, and inheritance
- Add LLM executor supporting OpenAI vision, tool calling, embeddings, and structured outputs
- Introduce event emitter/receiver workflows with deduplication and filtering (generate_event functions)
- Add workflow extends/override system enabling inheritance chains and step merge modes
- Update function naming to snake_case across all testdata (fileExists→file_exists, etc.)
- Add comprehensive test fixtures for linter, events, CDN, step dependencies, and extends workflows
2026-01-20 18:23:57 +08:00

142 lines
3.7 KiB
Go

package parser
import (
"fmt"
"github.com/j3ssie/osmedeus/v5/internal/core"
"github.com/j3ssie/osmedeus/v5/internal/utils"
)
// DependencyChecker validates workflow dependencies
type DependencyChecker struct{}
// NewDependencyChecker creates a new dependency checker
func NewDependencyChecker() *DependencyChecker {
return &DependencyChecker{}
}
// CheckCommands checks if required commands are available in binariesPath or system PATH
func (c *DependencyChecker) CheckCommands(commands []string, binariesPath string) error {
var missing []string
for _, cmd := range commands {
if _, err := utils.LookPathWithBinaries(cmd, binariesPath); err != nil {
missing = append(missing, cmd)
}
}
if len(missing) > 0 {
return &DependencyError{
Type: "commands",
Missing: missing,
}
}
return nil
}
// CheckFiles checks if required files exist
func (c *DependencyChecker) CheckFiles(files []string, ctx map[string]interface{}) error {
// Files would need template rendering first
// This is a placeholder for the actual implementation
return nil
}
// CheckVariables validates required variables are present and valid
func (c *DependencyChecker) CheckVariables(deps []core.VariableDep, ctx map[string]interface{}) error {
var errors []string
for _, dep := range deps {
if !dep.Required {
continue
}
value, ok := ctx[dep.Name]
if !ok || value == nil || value == "" {
errors = append(errors, fmt.Sprintf("required variable '%s' is missing", dep.Name))
continue
}
// Validate type
if err := c.validateType(dep.Name, value, dep.Type); err != nil {
errors = append(errors, err.Error())
}
}
if len(errors) > 0 {
return &DependencyError{
Type: "variables",
Errors: errors,
}
}
return nil
}
// validateType validates a value against a variable type.
// Supports comma-separated types (e.g., "domain,url") where matching any type is sufficient.
func (c *DependencyChecker) validateType(name string, value interface{}, varType core.VariableType) error {
str, ok := value.(string)
if !ok {
return fmt.Errorf("variable '%s' must be a string", name)
}
// Use MatchesAnyVariableType to support comma-separated types
ok, err := core.MatchesAnyVariableType(str, varType)
if err != nil {
return fmt.Errorf("variable '%s' has invalid type: %w", name, err)
}
if !ok {
return fmt.Errorf("variable '%s' does not match type '%s'", name, varType)
}
return nil
}
// CheckAll performs all dependency checks
// Note: FunctionsConditions are checked at runtime by the executor, not here
func (c *DependencyChecker) CheckAll(deps *core.Dependencies, ctx map[string]interface{}, binariesPath string) error {
if deps == nil {
return nil
}
if len(deps.Commands) > 0 {
if err := c.CheckCommands(deps.Commands, binariesPath); err != nil {
return err
}
}
if len(deps.Files) > 0 {
if err := c.CheckFiles(deps.Files, ctx); err != nil {
return err
}
}
if len(deps.Variables) > 0 {
if err := c.CheckVariables(deps.Variables, ctx); err != nil {
return err
}
}
return nil
}
// DependencyError represents a dependency check failure
type DependencyError struct {
Type string
Missing []string
Errors []string
}
func (e *DependencyError) Error() string {
if len(e.Missing) > 0 {
return fmt.Sprintf("missing %s: %v", e.Type, e.Missing)
}
return fmt.Sprintf("%s validation errors: %v", e.Type, e.Errors)
}
// isValidDomain checks if a string is a valid domain
// DefaultDependencyChecker is the global dependency checker
var DefaultDependencyChecker = NewDependencyChecker()
// CheckDependencies checks all dependencies using the default checker
func CheckDependencies(deps *core.Dependencies, ctx map[string]interface{}, binariesPath string) error {
return DefaultDependencyChecker.CheckAll(deps, ctx, binariesPath)
}