File: generator.rb

package info (click to toggle)
ruby-jekyll-titles-from-headings 0.5.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 84 kB
  • sloc: ruby: 130; makefile: 2
file content (133 lines) | stat: -rw-r--r-- 3,713 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
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
124
125
126
127
128
129
130
131
132
133
# frozen_string_literal: true

module JekyllTitlesFromHeadings
  class Generator < Jekyll::Generator
    attr_accessor :site
    TITLE_REGEX =
      %r!
        \A\s*                             # Beginning and whitespace
          (?:                             # either
            \#{1,3}\s+(.*)(?:\s+\#{1,3})? # atx-style header
            |                             # or
            (.*)\r?\n[-=]+\s*             # Setex-style header
          )$                              # end of line
      !x.freeze

    CONVERTER_CLASS = Jekyll::Converters::Markdown
    STRIP_MARKUP_FILTERS = [:markdownify, :strip_html, :normalize_whitespace].freeze

    # Regex to strip extra markup still present after markdownify
    # (footnotes at the moment).
    EXTRA_MARKUP_REGEX = %r!\[\^[^\]]*\]!.freeze

    CONFIG_KEY = "titles_from_headings"
    ENABLED_KEY = "enabled"
    STRIP_TITLE_KEY = "strip_title"
    COLLECTIONS_KEY = "collections"

    safe true
    priority :lowest

    def initialize(site)
      @site = site
    end

    def generate(site)
      @site = site
      return if disabled?

      documents = site.pages
      documents = site.pages + site.docs_to_write if collections?

      documents.each do |document|
        next unless should_add_title?(document)
        next if document.is_a?(Jekyll::StaticFile)

        document.data["title"] = title_for(document)
        strip_title!(document) if strip_title?(document)
      end
    end

    def should_add_title?(document)
      markdown?(document) && !title?(document)
    end

    def title?(document)
      !inferred_title?(document) && !document.data["title"].nil?
    end

    def markdown?(document)
      markdown_converter.matches(document.extname)
    end

    def markdown_converter
      @markdown_converter ||= site.find_converter_instance(CONVERTER_CLASS)
    end

    def title_for(document)
      return document.data["title"] if title?(document)

      matches = document.content.to_s.match(TITLE_REGEX)
      return strip_markup(matches[1] || matches[2]) if matches

      document.data["title"] # If we cant match a title, we use the inferred one.
    rescue ArgumentError => e
      raise e unless e.to_s.start_with?("invalid byte sequence in UTF-8")
    end

    private

    def strip_markup(string)
      STRIP_MARKUP_FILTERS.reduce(string) do |memo, method|
        filters.public_send(method, memo)
      end.gsub(EXTRA_MARKUP_REGEX, "")
    end

    def option(key)
      site.config[CONFIG_KEY] && site.config[CONFIG_KEY][key]
    end

    def disabled?
      option(ENABLED_KEY) == false
    end

    def strip_title?(document)
      if document.data.key?(STRIP_TITLE_KEY)
        document.data[STRIP_TITLE_KEY] == true
      else
        option(STRIP_TITLE_KEY) == true
      end
    end

    def strip_title_excerpt?(document)
      document.is_a?(Jekyll::Document) &&
        document.collection.label == "posts" &&
        document.generate_excerpt?
    end

    def collections?
      option(COLLECTIONS_KEY) == true
    end

    # Documents (posts and collection items) have their title inferred from the filename.
    # We want to override these titles, because they were not excplicitly set.
    def inferred_title?(document)
      document.is_a?(Jekyll::Document)
    end

    def strip_title!(document)
      if document.content
        document.content = document.content.gsub(TITLE_REGEX, "").strip
        strip_title_excerpt!(document) if strip_title_excerpt?(document)
      end
    end

    def strip_title_excerpt!(document)
      document.data["excerpt"] = Jekyll::Excerpt.new(document)
    end

    def filters
      @filters ||= JekyllTitlesFromHeadings::Filters.new(site)
    end
  end
end