Class: Markdown::Merge::LinkReferenceRehydrator

Inherits:
Object
  • Object
show all
Defined in:
lib/markdown/merge/link_reference_rehydrator.rb

Overview

Rehydrates inline links and images to use link reference definitions.

When markdown is processed through to_commonmark, reference-style links [text][label] are converted to inline links [text](url). This class reverses that transformation by:

  1. Parsing link reference definitions from content using LinkParser
  2. Finding inline links/images using LinkParser's PEG-based parsing
  3. Replacing inline URLs with reference labels where a definition exists

Uses Parslet-based parsing for robust handling of:

  • Emoji in labels (e.g., [🖼️galtzo-discord])
  • Nested brackets (for linked images like [![alt][ref]](url))
  • Multi-byte UTF-8 characters

Examples:

Standalone usage

content = <<~MD
  Check out [Example](https://example.com) for more info.

  [example]: https://example.com
MD
result = LinkReferenceRehydrator.rehydrate(content)
# => "Check out [Example][example] for more info.\n\n[example]: https://example.com\n"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(content) ⇒ LinkReferenceRehydrator

Initialize a new rehydrator.

Parameters:

  • content (String)

    Content to process



48
49
50
51
52
53
54
55
56
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 48

def initialize(content)
  @content = content
  @problems = DocumentProblems.new
  @link_definitions = nil
  @duplicate_definitions = nil
  @url_to_label = nil
  @parser = LinkParser.new
  @rehydration_count = 0
end

Instance Attribute Details

#contentString (readonly)

Returns The original content.

Returns:

  • (String)

    The original content



30
31
32
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 30

def content
  @content
end

#problemsDocumentProblems (readonly)

Returns Problems found during rehydration.

Returns:



33
34
35
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 33

def problems
  @problems
end

#rehydration_countInteger (readonly)

Get count of links/images rehydrated.

Returns:

  • (Integer)

    Number of rehydrations performed



125
126
127
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 125

def rehydration_count
  @rehydration_count
end

Class Method Details

.rehydrate(content) ⇒ String

Rehydrate inline links/images to reference style (class method).

Parameters:

  • content (String)

    Content to rehydrate

Returns:

  • (String)

    Rehydrated content



40
41
42
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 40

def rehydrate(content)
  new(content).rehydrate
end

Instance Method Details

#changed?Boolean

Check if rehydration made any changes.

Returns:

  • (Boolean)

    true if any links were rehydrated



118
119
120
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 118

def changed?
  @rehydration_count.positive?
end

#duplicate_definitionsHash<String, Array<String>>

Get duplicate definitions (multiple labels for same URL).

Returns:

  • (Hash<String, Array<String>>)

    URL => [labels] for duplicates only



69
70
71
72
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 69

def duplicate_definitions
  build_definition_maps unless @duplicate_definitions
  @duplicate_definitions
end

Get the map of URLs to their preferred label.

Returns:

  • (Hash<String, String>)

    URL => label mapping



61
62
63
64
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 61

def link_definitions
  build_definition_maps unless @link_definitions
  @link_definitions
end

#rehydrateString

Rehydrate inline links and images to use reference definitions.

Uses a tree-based approach to handle nested structures like linked images [![alt](img-url)](link-url). The parser builds a tree of link constructs, and we process them in leaf-first (post-order) traversal to ensure inner replacements are applied before outer ones.

For linked images, this means:

  1. First, the inner image ![alt](img-url) is replaced with ![alt][img-label]
  2. Then, the outer link's text is updated to include the replaced image
  3. Finally, the outer link [![alt][img-label]](link-url) is replaced with [![alt][img-label]][link-label]

This is done in a single pass by tracking replacement offsets.

Returns:

  • (String)

    Rehydrated content



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
# File 'lib/markdown/merge/link_reference_rehydrator.rb', line 89

def rehydrate
  build_definition_maps unless @link_definitions
  record_duplicate_problems

  return content if @url_to_label.empty?

  # Use the new tree-based approach
  # 1. Find all link constructs with proper nesting detection
  tree = @parser.find_all_link_constructs(content)

  # 2. Collect all replacements using recursive tree processing
  # This properly handles nested structures by processing children first
  # and adjusting parent text to include child replacements
  replacements = collect_nested_replacements(tree, content)

  # 3. Apply replacements in reverse position order
  result = content.dup
  replacements.sort_by { |r| -r[:start_pos] }.each do |replacement|
    result = result[0...replacement[:start_pos]] +
             replacement[:replacement] +
             result[replacement[:end_pos]..]
  end

  result
end