Module: Yaml::Merge

Defined in:
lib/yaml/merge.rb,
lib/yaml/merge/emitter.rb,
lib/yaml/merge/version.rb,
lib/yaml/merge/debug_logger.rb,
lib/yaml/merge/merge_result.rb,
lib/yaml/merge/node_wrapper.rb,
lib/yaml/merge/smart_merger.rb,
lib/yaml/merge/file_analysis.rb

Overview

The YAML language layer owns this parser-neutral contract. Keep this facade co-located so psych-merge can depend on it without a reverse edge. rubocop:disable Metrics/ModuleLength -- the public YAML facade owns this structural boundary

Defined Under Namespace

Modules: DebugLogger, Version Classes: DestinationParseError, Emitter, Error, FileAnalysis, MergeResult, NodeWrapper, ParseError, SmartMerger, TemplateParseError

Constant Summary collapse

PACKAGE_NAME =
'yaml-merge'
DESTINATION_WINS_ARRAY_POLICY =
{
  surface: 'array',
  name: 'destination_wins_array'
}.freeze
BACKEND_REFERENCE =
TreeHaver::KREUZBERG_LANGUAGE_PACK_BACKEND
BACKEND_REGISTRY =
Struct.new(:registered, :mutex).new(false, Mutex.new)
YAML_TREE_NODE_HANDLERS =
{
  child: :yaml_value_from_tree_child_node,
  mapping: :yaml_mapping_from_tree_node,
  sequence: :yaml_sequence_from_tree_node,
  scalar: :yaml_scalar_from_tree_node
}.freeze
YAML_DOUBLE_QUOTE_ESCAPES =
{
  '"' => '"',
  '\\' => '\\',
  '/' => '/',
  'b' => "\b",
  'f' => "\f",
  'n' => "\n",
  'r' => "\r",
  't' => "\t"
}.freeze
VERSION =

Current gem version exposed at the traditional constant location.

Version::VERSION

Class Method Summary collapse

Class Method Details

.analyze_yaml_document(parsed, dialect) ⇒ Object



123
124
125
126
127
128
129
130
131
# File 'lib/yaml/merge.rb', line 123

def analyze_yaml_document(parsed, dialect)
  return unsupported_feature_parse_result("Unsupported YAML dialect #{dialect}.") unless dialect == 'yaml'
  return parse_error_result('YAML documents must parse to a mapping root.') unless parsed.is_a?(Hash)

  validated = validate_yaml_node(parsed, '')
  return invalid_yaml_analysis(validated) unless validated[:ok]

  yaml_analysis_result(validated[:value])
end

.available_yaml_backendsObject



72
73
74
# File 'lib/yaml/merge.rb', line 72

def available_yaml_backends
  yaml_backend_available_for_analysis?(BACKEND_REFERENCE.id) ? [BACKEND_REFERENCE] : []
end

.match_yaml_owners(template, destination) ⇒ Object



160
161
162
# File 'lib/yaml/merge.rb', line 160

def match_yaml_owners(template, destination)
  Ast::Merge::OwnerSelection.match_by_path(template, destination)
end

.merge_yaml(template_source, destination_source, dialect, backend: nil) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/yaml/merge.rb', line 164

def merge_yaml(template_source, destination_source, dialect, backend: nil)
  requested = backend.to_s.empty? ? nil : backend.to_s
  unless yaml_backend_available_for_analysis?(requested)
    diagnostic_backend = requested || TreeHaver.current_backend_id || 'tree-sitter'
    return unsupported_feature_merge_result("Unsupported YAML backend #{diagnostic_backend}.")
  end

  merge_yaml_with_parser(template_source, destination_source, dialect,
                         backend: requested) do |source, parse_dialect|
    parse_yaml(source, parse_dialect, backend: requested)
  end
end

.merge_yaml_with_parser(template_source, destination_source, dialect, backend: nil) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/yaml/merge.rb', line 177

def merge_yaml_with_parser(template_source, destination_source, dialect, backend: nil)
  template = yield(template_source, dialect)
  return parser_failure_result(template, :template) unless template[:ok]

  destination = yield(destination_source, dialect)
  return parser_failure_result(destination, :destination) unless destination[:ok]

  return parse_error_merge_result('YAML documents must parse to a mapping root.') unless
    yaml_parse_results_valid?(template, destination)

  yaml_merge_result(template_source, destination_source, backend)
rescue StandardError => e
  parser_exception_result(e)
end

.parse_yaml(source, dialect, backend: nil) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/yaml/merge.rb', line 102

def parse_yaml(source, dialect, backend: nil)
  return unsupported_feature_parse_result("Unsupported YAML dialect #{dialect}.") unless dialect == 'yaml'

  requested = backend.to_s.empty? ? nil : backend.to_s
  unless yaml_backend_available_for_analysis?(requested)
    diagnostic_backend = requested || TreeHaver.current_backend_id || 'tree-sitter'
    return unsupported_feature_parse_result("Unsupported YAML backend #{diagnostic_backend}.")
  end

  parse_yaml_tree(source, dialect, requested)
rescue TreeHaver::Error, StandardError => e
  parse_error_result(e.message)
end

.register_backend!Object



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/yaml/merge.rb', line 51

def register_backend!
  BACKEND_REGISTRY.mutex.synchronize do
    return if BACKEND_REGISTRY.registered && TreeHaver.registered_languages(:yaml).any?

    TreeHaver::BackendRegistry.register(BACKEND_REFERENCE)

    grammar_finder = TreeHaver::GrammarFinder.new(:yaml)
    grammar_finder.register! if grammar_finder.available?

    BACKEND_REGISTRY.registered = true
  end
end

.yaml_backend_feature_profile(backend: nil) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/yaml/merge.rb', line 76

def yaml_backend_feature_profile(backend: nil)
  resolved_backend = resolve_backend(backend)
  unless resolved_backend == BACKEND_REFERENCE.id && yaml_backend_available_for_analysis?(resolved_backend)
    return unsupported_feature_result("Unsupported YAML backend #{resolved_backend}.")
  end

  yaml_feature_profile.merge(
    backend: BACKEND_REFERENCE.id,
    backend_ref: BACKEND_REFERENCE.to_h
  )
end

.yaml_feature_profileObject



64
65
66
67
68
69
70
# File 'lib/yaml/merge.rb', line 64

def yaml_feature_profile
  {
    family: 'yaml',
    supported_dialects: ['yaml'],
    supported_policies: [DESTINATION_WINS_ARRAY_POLICY]
  }
end

.yaml_plan_context(backend: nil) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/yaml/merge.rb', line 88

def yaml_plan_context(backend: nil)
  profile = yaml_backend_feature_profile(backend: backend)
  return profile if profile[:ok] == false

  {
    family_profile: yaml_feature_profile,
    feature_profile: {
      backend: profile[:backend],
      supports_dialects: false,
      supported_policies: profile[:supported_policies]
    }
  }
end