Module: Textus::Protocol::Manifest::Schema::Validator

Defined in:
lib/textus/protocol/manifest/schema/validator.rb

Overview

Orchestrates structural validation (dry-schema Contract) then cross-field semantic checks (Semantics). Public interface unchanged: Validator.validate!(raw).

Class Method Summary collapse

Class Method Details

.format_first_error(messages) ⇒ Object

Format the first dry-schema error to match the legacy path-prefixed style: "unknown key 'x' at '$.lanes'" for extra-key errors; "manifest structure error at : " for type/value errors.



31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/textus/protocol/manifest/schema/validator.rb', line 31

def format_first_error(messages)
  msg = messages.first
  return "manifest structure error: unknown" unless msg

  parent = format_path(msg.path[0..-2])
  key    = msg.path.last

  if msg.text == "is not allowed"
    "unknown key '#{key}' at '#{parent}'"
  else
    "manifest structure error at #{format_path(msg.path)}: #{msg.text}"
  end
end

.format_path(parts) ⇒ Object



45
46
47
# File 'lib/textus/protocol/manifest/schema/validator.rb', line 45

def format_path(parts)
  "$" + Array(parts).map { |p| p.is_a?(Integer) ? "[#{p}]" : ".#{p}" }.join
end

.validate!(raw) ⇒ Object

Raises:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/textus/protocol/manifest/schema/validator.rb', line 12

def validate!(raw)
  raise BadManifest.new("manifest must be a hash") unless raw.is_a?(Hash)

  # Root unknown-key check before Contract so it fires even when lanes: is empty.
  Schema.walk(raw, ROOT_KEYS, "$")

  result = Contract.call(raw)
  raise BadManifest.new(format_first_error(result.errors.messages)) unless result.success?

  if raw.key?("data")
    raise BadManifest.new("manifest must declare data:") if raw["data"].nil?
  elsif Array(raw["lanes"]).empty?
    raise BadManifest.new("manifest must declare lanes:")
  end
end