Class: Rbs::Merge::Provider

Inherits:
Object
  • Object
show all
Defined in:
lib/rbs/merge/provider.rb,
sig/rbs/merge.rbs

Overview

Base-aware, source-preserving provider for normalized RBS declarations. rubocop:disable Metrics/AbcSize, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/ParameterLists, Metrics/PerceivedComplexity -- provider decisions, source plans, and verification form one boundary

Defined Under Namespace

Classes: Decision, Document, ExactDocument, Owner

Constant Summary collapse

DEFAULT_PROFILE =
:source_preserving
SUPPORTED_BACKENDS =
%i[rbs tslp kreuzberg-language-pack].freeze

Instance Method Summary collapse

Instance Method Details

#analyze(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rbs/merge/provider.rb', line 36

def analyze(request)
  document = parse_document(:analyze, request, :source)
  return document if provider_failure?(document)

  result(
    :analyze,
    request,
    analysis: {
      backend: document.backend.to_s,
      valid: true,
      declarations: document.owners.map { |owner| owner_description(owner) }
    },
    verification: { source_parsed: true }
  )
end

#capabilitiesHash[Symbol, untyped]

Returns:

  • (Hash[Symbol, untyped])


21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/rbs/merge/provider.rb', line 21

def capabilities
  {
    operations: Ast::Merge::ProviderContract::OPERATIONS,
    dialects: %i[rbs],
    backends: SUPPORTED_BACKENDS,
    profiles: [DEFAULT_PROFILE],
    role: :workflow,
    parser_requirements: {
      allowed_backend_families: %w[rbs tree-sitter],
      required_capabilities: %w[normalized-nodes exact-byte-spans]
    },
    source_preservation: %i[exact_source declaration_fragments line_provenance reparse semantic_verification]
  }.freeze
end

#diff2(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rbs/merge/provider.rb', line 52

def diff2(request)
  before = parse_document(:diff2, request, :before)
  return before if provider_failure?(before)

  after = parse_document(:diff2, request, :after)
  return after if provider_failure?(after)

  changes = diff_documents(before, after)
  result(
    :diff2,
    request,
    diff: { changes: changes },
    changes: changes,
    verification: { before_parsed: true, after_parsed: true }
  )
end

#familyString

Returns:

  • (String)


19
# File 'lib/rbs/merge/provider.rb', line 19

def family = 'rbs'

#merge2(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rbs/merge/provider.rb', line 69

def merge2(request)
  incoming = parse_document(:merge2, request, :incoming)
  return incoming if provider_failure?(incoming)

  current = parse_document(:merge2, request, :current)
  return current if provider_failure?(current)

  merged = with_requested_backend(request) do
    SmartMerger.new(
      request.fetch(:incoming_source),
      request.fetch(:current_source),
      add_template_only_nodes: true
    ).merge_result
  end
  output = merged.to_s
  parsed = parse_source(output, :output, request)
  return parse_failure(:merge2, request, :output, parsed) if provider_failure?(parsed)

  planned_ids = current.owners.map(&:id) + incoming.owners.reject do |owner|
    current.by_id.key?(owner.id)
  end.map(&:id)
  actual_ids = parsed.owners.map(&:id)
  verification = {
    output_reparsed: true,
    semantic_match: actual_ids == planned_ids,
    ordered_declaration_signatures_verified: actual_ids == planned_ids,
    planned_declaration_count: planned_ids.length,
    output_declaration_count: actual_ids.length
  }
  unless verification[:semantic_match]
    return failure(
      :merge2,
      request,
      category: :render_failure,
      message: 'RBS two-way merge did not match the planned ordered declaration structure.',
      verification: verification
    )
  end

  changes = diff_documents(current, parsed)
  result(
    :merge2,
    request,
    output: output,
    changes: changes,
    render_report: {
      strategy: :rbs_substrate,
      decisions: merged.decisions,
      summary: merged.summary
    },
    verification: verification
  )
rescue StandardError => e
  failure(:merge2, request, category: :merge_failure, message: e.message)
end

#merge3(request) ⇒ Hash[Symbol, untyped]

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rbs/merge/provider.rb', line 125

def merge3(request)
  exact_role = exact_revision_role(request)
  return merge3_exact(request, exact_role) if exact_role

  documents = parse_merge3_documents(request)
  return documents if provider_failure?(documents)

  decision = decide(documents, include_unmanaged_conflict: true)
  return render_conflicts(request, documents, decision) unless decision.conflicts.empty?

  render_composite(request, documents, decision)
end

#provider_idString

Returns:

  • (String)


18
# File 'lib/rbs/merge/provider.rb', line 18

def provider_id = 'ruby.rbs'