vetra 0.1.0.pre.alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +196 -0
- data/bin/vetra +6 -0
- data/docs/ir/v0.1.schema.json +941 -0
- data/docs/ir/v0.2.schema.json +951 -0
- data/docs/ir/v0.3.schema.json +961 -0
- data/lib/vetra/cli.rb +64 -0
- data/lib/vetra/graph/analysis.rb +94 -0
- data/lib/vetra/graph/canonical.rb +52 -0
- data/lib/vetra/graph/capabilities.rb +22 -0
- data/lib/vetra/graph/compiler.rb +119 -0
- data/lib/vetra/graph/currency.rb +28 -0
- data/lib/vetra/graph/data.rb +48 -0
- data/lib/vetra/graph/declaration_loader.rb +62 -0
- data/lib/vetra/graph/diagnostic.rb +23 -0
- data/lib/vetra/graph/diff.rb +412 -0
- data/lib/vetra/graph/diff_source.rb +51 -0
- data/lib/vetra/graph/dsl.rb +444 -0
- data/lib/vetra/graph/linked_graph.rb +26 -0
- data/lib/vetra/graph/linker.rb +95 -0
- data/lib/vetra/graph/live_dependencies.rb +48 -0
- data/lib/vetra/graph/manifest.rb +78 -0
- data/lib/vetra/graph/normalizer.rb +689 -0
- data/lib/vetra/graph/registry.rb +50 -0
- data/lib/vetra/graph/schema.rb +78 -0
- data/lib/vetra/graph/validator.rb +600 -0
- data/lib/vetra/version.rb +3 -0
- data/lib/vetra.rb +29 -0
- metadata +141 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Vetra
|
|
2
|
+
module Graph
|
|
3
|
+
class Registry
|
|
4
|
+
attr_reader :declarations, :bindings, :application
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@declarations = []
|
|
8
|
+
@bindings = {}
|
|
9
|
+
@application = nil
|
|
10
|
+
@sealed = false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def app(attributes)
|
|
14
|
+
ensure_open!
|
|
15
|
+
raise Error.single("duplicate_app", "Declare Vetra.app uma única vez.", source: attributes['source']) if @application
|
|
16
|
+
@application = attributes
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def add(declaration, block: nil)
|
|
20
|
+
ensure_open!
|
|
21
|
+
key = declaration.values_at("kind", "id")
|
|
22
|
+
if declarations.any? { |entry| entry.values_at("kind", "id") == key }
|
|
23
|
+
raise Error.single("duplicate_id", "Identidade repetida: #{key.join(' ')}.", source: declaration['source'])
|
|
24
|
+
end
|
|
25
|
+
if block
|
|
26
|
+
reference = "#{declaration.fetch('id')}#call"
|
|
27
|
+
raise Error.single("duplicate_implementation", "Implementação repetida: #{reference}.", source: declaration['source']) if bindings.key?(reference)
|
|
28
|
+
@bindings[reference] = block
|
|
29
|
+
end
|
|
30
|
+
@declarations << declaration
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def seal!
|
|
34
|
+
ensure_open!
|
|
35
|
+
@sealed = true
|
|
36
|
+
Data.freeze(@application)
|
|
37
|
+
Data.freeze(@declarations)
|
|
38
|
+
@bindings.each_value(&:freeze)
|
|
39
|
+
@bindings.freeze
|
|
40
|
+
freeze
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def ensure_open!
|
|
46
|
+
raise Error.single("registry_frozen", "O registro já está congelado; inicie outro build.") if @sealed
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require "json_schemer"
|
|
2
|
+
|
|
3
|
+
module Vetra
|
|
4
|
+
module Graph
|
|
5
|
+
class Schema
|
|
6
|
+
VERSION = "0.3"
|
|
7
|
+
LEGACY_VERSION = "0.1"
|
|
8
|
+
PREVIOUS_VERSION = "0.2"
|
|
9
|
+
FEATURES = %w[vetra.core vetra.timestamps vetra.structured_outputs vetra.live].freeze
|
|
10
|
+
CRUD_ACTIONS = %w[create read update delete].freeze
|
|
11
|
+
PATH = File.expand_path("../../../docs/ir/v0.3.schema.json", __dir__)
|
|
12
|
+
PREVIOUS_PATH = File.expand_path("../../../docs/ir/v0.2.schema.json", __dir__)
|
|
13
|
+
LEGACY_PATH = File.expand_path("../../../docs/ir/v0.1.schema.json", __dir__)
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@schemas = {}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def validate!(document)
|
|
20
|
+
unless document.is_a?(Hash) && [LEGACY_VERSION, PREVIOUS_VERSION, VERSION].include?(document["ir_version"])
|
|
21
|
+
raise Error.single("ir_version", "Versão de IR não suportada; este compilador aceita #{LEGACY_VERSION}, #{PREVIOUS_VERSION} e #{VERSION}.", pointer: "/ir_version")
|
|
22
|
+
end
|
|
23
|
+
version = document.fetch('ir_version')
|
|
24
|
+
supported = case version
|
|
25
|
+
when LEGACY_VERSION then ['vetra.core']
|
|
26
|
+
when PREVIOUS_VERSION then %w[vetra.core vetra.timestamps]
|
|
27
|
+
else FEATURES
|
|
28
|
+
end
|
|
29
|
+
unknown = Array(document["requires"]) - supported
|
|
30
|
+
unless unknown.empty?
|
|
31
|
+
raise Error.single("ir_feature", "Recursos não implementados: #{unknown.join(', ')}.", pointer: "/requires")
|
|
32
|
+
end
|
|
33
|
+
envelope, nodes = validators(version)
|
|
34
|
+
diagnostics = errors(envelope, document)
|
|
35
|
+
raise Error.new(diagnostics) unless diagnostics.empty?
|
|
36
|
+
document.fetch("nodes").each_with_index do |node, index|
|
|
37
|
+
validator = nodes[node["kind"]]
|
|
38
|
+
if validator
|
|
39
|
+
diagnostics.concat(errors(validator, node, "/nodes/#{index}", node["source"]))
|
|
40
|
+
else
|
|
41
|
+
diagnostics << Diagnostic.new(code: "node_kind", message: "Tipo de nó desconhecido.", pointer: "/nodes/#{index}/kind", source: node["source"], severity: :error)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
raise Error.new(diagnostics) unless diagnostics.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def validators(version)
|
|
50
|
+
@schemas[version] ||= begin
|
|
51
|
+
path = case version
|
|
52
|
+
when LEGACY_VERSION then LEGACY_PATH
|
|
53
|
+
when PREVIOUS_VERSION then PREVIOUS_PATH
|
|
54
|
+
else PATH
|
|
55
|
+
end
|
|
56
|
+
definition = JSON.parse(File.read(path, encoding: Encoding::UTF_8))
|
|
57
|
+
properties = definition.fetch('properties')
|
|
58
|
+
envelope = definition.merge('properties' => properties.merge('nodes' => properties.fetch('nodes').merge('items' => { 'type' => 'object' })))
|
|
59
|
+
nodes = properties.fetch('nodes').fetch('items').fetch('oneOf').to_h do |branch|
|
|
60
|
+
kind = branch.fetch('$ref').split('/').last
|
|
61
|
+
[kind, schemer(definition.merge('$ref' => branch.fetch('$ref')).reject { |key, _| %w[type properties required additionalProperties].include?(key) })]
|
|
62
|
+
end
|
|
63
|
+
[schemer(envelope), nodes]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def schemer(schema)
|
|
68
|
+
JSONSchemer.schema(schema, ref_resolver: proc { |uri| raise Error.single("schema_reference", "Referência externa proibida: #{uri}.") }, regexp_resolver: proc { |pattern| Regexp.new(pattern.sub(/\A\^/, '\\A').sub(/\$\z/, '\\z')) })
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def errors(validator, value, prefix = "", source = nil)
|
|
72
|
+
validator.validate(value).map do |error|
|
|
73
|
+
Diagnostic.new(code: "schema", message: error.fetch("error"), pointer: "#{prefix}#{error.fetch('data_pointer')}", source: source, severity: :error)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|