Class: Dotenv::Merge::Provider

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

Overview

Source-preserving, base-aware provider for dotenv assignment documents. rubocop:disable Metrics/AbcSize, Metrics/BlockLength, Metrics/ClassLength, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/ParameterLists, Metrics/PerceivedComplexity -- provider planning, rendering, and reporting form one boundary

Defined Under Namespace

Classes: Analysis, Decision

Constant Summary collapse

DEFAULT_PROFILE =
:source_preserving
DIALECTS =
%i[dotenv].freeze

Instance Method Summary collapse

Instance Method Details

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

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


30
31
32
33
34
35
36
37
38
39
# File 'lib/dotenv/merge/provider.rb', line 30

def analyze(request)
  analysis = analyze_role(:source, request.fetch(:source))
  result(
    :analyze,
    request,
    analysis: analysis_payload(analysis),
    diagnostics: diagnostics_for(analysis),
    verification: { source_parsed: true, structurally_unambiguous: analysis.issues.empty? }
  )
end

#capabilitiesHash[Symbol, untyped]

Returns:

  • (Hash[Symbol, untyped])


19
20
21
22
23
24
25
26
27
28
# File 'lib/dotenv/merge/provider.rb', line 19

def capabilities
  {
    operations: Ast::Merge::ProviderContract::OPERATIONS,
    dialects: DIALECTS,
    backends: [Dotenv::Merge::BACKEND_REFERENCE.id.to_sym],
    profiles: [DEFAULT_PROFILE],
    role: :workflow,
    source_preservation: %i[exact_source assignment_fragments line_provenance reparse]
  }.freeze
end

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

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/dotenv/merge/provider.rb', line 41

def diff2(request)
  before = analyze_role(:before, request.fetch(:before_source))
  after = analyze_role(:after, request.fetch(:after_source))
  changes = assignment_changes(before, after)
  result(
    :diff2,
    request,
    diff: { before: analysis_payload(before), after: analysis_payload(after), changes: changes },
    changes: changes,
    diagnostics: diagnostics_for(before, after),
    verification: { before_parsed: true, after_parsed: true }
  )
end

#familyString

Returns:

  • (String)


17
# File 'lib/dotenv/merge/provider.rb', line 17

def family = 'dotenv'

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

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/dotenv/merge/provider.rb', line 55

def merge2(request)
  incoming = request.fetch(:incoming_source)
  current = request.fetch(:current_source)
  inputs = [
    analyze_role(:incoming, incoming),
    analyze_role(:current, current)
  ]
  unsafe = inputs.reject { |analysis| analysis.issues.empty? }
  unless unsafe.empty?
    return unsafe_failure(
      :merge2,
      request,
      unsafe,
      message: 'dotenv merge2 input is structurally ambiguous'
    )
  end

  merged = SmartMerger.new(incoming, current, add_template_only_nodes: true).merge.to_s
  output = analyze_role(:output, merged)
  unless output.issues.empty?
    return unsafe_failure(
      :merge2,
      request,
      [output],
      message: 'dotenv merge2 output is structurally ambiguous'
    )
  end

  result(
    :merge2,
    request,
    output: merged,
    render_report: { strategy: :dotenv_smart_merger, synthesis: :family_emission },
    verification: { output_reparsed: true, ordered_assignments: semantic_assignments(output) }
  )
rescue Dotenv::Merge::ParseError => e
  failure(:merge2, request, category: :parse_error, message: e.message)
end

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

Parameters:

  • request (Hash[Symbol, untyped])

Returns:

  • (Hash[Symbol, untyped])


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/dotenv/merge/provider.rb', line 94

def merge3(request)
  analyses = %i[base ours theirs].to_h do |role|
    [role, analyze_role(role, request.fetch(:"#{role}_source"))]
  end
  exact_role = exact_revision_role(analyses)
  if exact_role
    winner = analyses.fetch(exact_role)
    return unsafe_conflict(request, analyses, [winner]) unless winner.issues.empty?

    return render_exact(request, analyses, exact_role)
  end

  unsafe = analyses.values.reject { |analysis| analysis.issues.empty? }
  return unsafe_conflict(request, analyses, unsafe) unless unsafe.empty?
  return unowned_conflict(request, analyses) unless unowned_unchanged?(analyses)

  decisions = three_way_decisions(analyses)
  conflicts = decisions.select(&:conflict)
  return render_conflicts(request, analyses, decisions, conflicts) unless conflicts.empty?

  render_composite(request, analyses, decisions)
end

#provider_idString

Returns:

  • (String)


16
# File 'lib/dotenv/merge/provider.rb', line 16

def provider_id = 'ruby.dotenv'