Module: LanguageOperator::CLI::Commands::System::Helpers::TemplateValidator
- Defined in:
- lib/language_operator/cli/commands/system/helpers/template_validator.rb
Overview
Template validation utilities
Instance Method Summary collapse
-
#extract_code_examples(template) ⇒ Object
Extract Ruby code examples from template Returns array of String, start_line: Integer.
-
#extract_method_calls(template) ⇒ Object
Extract method calls from template code Returns array of method name strings.
-
#extract_methods_from_ast(node, methods) ⇒ Object
Recursively extract method names from AST.
-
#validate_code_against_schema(code) ⇒ Object
Validate Ruby code against DSL schema Returns Boolean, errors: Array
, warnings: Array . -
#validate_template_content(content, type) ⇒ Object
Validate template syntax and structure.
Instance Method Details
#extract_code_examples(template) ⇒ Object
Extract Ruby code examples from template Returns array of String, start_line: Integer
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/language_operator/cli/commands/system/helpers/template_validator.rb', line 73 def extract_code_examples(template) examples = [] lines = template.split("\n") in_code_block = false current_code = [] start_line = 0 lines.each_with_index do |line, idx| if line.strip.start_with?('```ruby') in_code_block = true start_line = idx + 2 # idx is 0-based, we want line number (1-based) of first code line current_code = [] elsif line.strip == '```' && in_code_block in_code_block = false examples << { code: current_code.join("\n"), start_line: start_line } unless current_code.empty? elsif in_code_block current_code << line end end examples end |
#extract_method_calls(template) ⇒ Object
Extract method calls from template code Returns array of method name strings
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/language_operator/cli/commands/system/helpers/template_validator.rb', line 98 def extract_method_calls(template) require 'prism' method_calls = [] code_examples = extract_code_examples(template) code_examples.each do |example| # Parse the code to find method calls result = Prism.parse(example[:code]) # Walk the AST to find method calls extract_methods_from_ast(result.value, method_calls) if result.success? rescue Prism::ParseError # Skip code with syntax errors - they'll be caught by validate_code_against_schema next end method_calls.uniq end |
#extract_methods_from_ast(node, methods) ⇒ Object
Recursively extract method names from AST
119 120 121 122 123 124 125 126 127 |
# File 'lib/language_operator/cli/commands/system/helpers/template_validator.rb', line 119 def extract_methods_from_ast(node, methods) return unless node methods << node.name.to_s if node.is_a?(Prism::CallNode) node.compact_child_nodes.each do |child| extract_methods_from_ast(child, methods) end end |
#validate_code_against_schema(code) ⇒ Object
Validate Ruby code against DSL schema
Returns Boolean, errors: Array
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/language_operator/cli/commands/system/helpers/template_validator.rb', line 131 def validate_code_against_schema(code) require 'language_operator/agent/safety/ast_validator' validator = LanguageOperator::Agent::Safety::ASTValidator.new violations = validator.validate(code, '(template)') errors = [] warnings = [] violations.each do |violation| case violation[:type] when :syntax_error errors << { type: :syntax_error, location: 0, message: violation[:message] } when :dangerous_method, :dangerous_constant, :dangerous_constant_access, :dangerous_global, :backtick_execution errors << { type: violation[:type], location: violation[:location], message: violation[:message] } else warnings << { type: violation[:type], location: violation[:location] || 0, message: violation[:message] } end end { valid: errors.empty?, errors: errors, warnings: warnings } end |
#validate_template_content(content, type) ⇒ Object
Validate template syntax and structure
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/language_operator/cli/commands/system/helpers/template_validator.rb', line 11 def validate_template_content(content, type) errors = [] warnings = [] # Check for required placeholders based on type required_placeholders = if type == 'agent' %w[ Instructions ToolsList ModelsList AgentName TemporalIntent ] else %w[ PersonaName PersonaDescription PersonaSystemPrompt AgentInstructions AgentTools ] end required_placeholders.each do |placeholder| errors << "Missing required placeholder: {{.#{placeholder}}}" unless content.include?("{{.#{placeholder}}}") end # Check for balanced braces open_braces = content.scan(/{{/).count close_braces = content.scan(/}}/).count errors << "Unbalanced template braces ({{ vs }}): #{open_braces} open, #{close_braces} close" if open_braces != close_braces # Extract and validate Ruby code blocks code_examples = extract_code_examples(content) code_examples.each do |example| code_result = validate_code_against_schema(example[:code]) unless code_result[:valid] code_result[:errors].each do |err| # Adjust line numbers to be relative to template line = example[:start_line] + (err[:location] || 0) errors << "Line #{line}: #{err[:message]}" end end code_result[:warnings].each do |warn| line = example[:start_line] + (warn[:location] || 0) warnings << "Line #{line}: #{warn[:message]}" end end # Extract method calls and check if they're in the safe list method_calls = extract_method_calls(content) safe_methods = Dsl::Schema.safe_agent_methods + Dsl::Schema.safe_tool_methods + Dsl::Schema.safe_helper_methods method_calls.each do |method| next if safe_methods.include?(method) warnings << "Method '#{method}' not in safe methods list (may be valid Ruby builtin)" end { valid: errors.empty?, errors: errors, warnings: warnings } end |