jekyll-wikirefs 0.0.1 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/jekyll-wikirefs/config.rb +113 -0
- data/lib/jekyll-wikirefs/patch/context.rb +19 -0
- data/lib/jekyll-wikirefs/patch/doc_manager.rb +117 -0
- data/lib/jekyll-wikirefs/patch/site.rb +12 -0
- data/lib/jekyll-wikirefs/plugins/converter.rb +53 -0
- data/lib/jekyll-wikirefs/plugins/filter.rb +81 -0
- data/lib/jekyll-wikirefs/plugins/generator.rb +41 -0
- data/lib/jekyll-wikirefs/util/link_index.rb +99 -0
- data/lib/jekyll-wikirefs/util/parser.rb +182 -0
- data/lib/jekyll-wikirefs/util/regex.rb +72 -0
- data/lib/jekyll-wikirefs/util/wikiref.rb +312 -0
- data/lib/jekyll-wikirefs/version.rb +1 -1
- data/lib/jekyll-wikirefs.rb +24 -4
- metadata +33 -8
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 6ffaf29b4a348e3036a6508d41df6cc915ae3459a2afb250a4c778242f4dff69
         | 
| 4 | 
            +
              data.tar.gz: 939fa037711ee9f265ee73edc709f34264188f71dca4f7d7e8f972f97be9eb3b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 97d3144acc57f975dfb1fb6799bc90df9c93de66b9b1bca5f2c6cfc34a5fe4b24316830d87410a90e5ba867516f68326dc9e4de688098e879e5cfd50f2ab0e33
         | 
| 7 | 
            +
              data.tar.gz: 01c27427d75cb71a22965f91f890deca40fbfa8955560aea6fa01518d02343da53a26c927389624f12d771d574127383af61a7f65255a7111d1d1ef7b3d5b90f
         | 
| @@ -0,0 +1,113 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require "jekyll"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Jekyll
         | 
| 5 | 
            +
              module WikiRefs
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class PluginConfig
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  ATTR_KEY = "attributes"
         | 
| 10 | 
            +
                  CONFIG_KEY = "wikirefs"
         | 
| 11 | 
            +
                  ENABLED_KEY = "enabled"
         | 
| 12 | 
            +
                  EXCLUDE_KEY = "exclude"
         | 
| 13 | 
            +
                  # css-related
         | 
| 14 | 
            +
                  CSS_KEY = "css"
         | 
| 15 | 
            +
                  NAME_KEY = "name"
         | 
| 16 | 
            +
                  # names
         | 
| 17 | 
            +
                  ## valid
         | 
| 18 | 
            +
                  TYPED_KEY = "typed"
         | 
| 19 | 
            +
                  WEB_KEY = "web"
         | 
| 20 | 
            +
                  WIKI_KEY = "wiki"
         | 
| 21 | 
            +
                  ## invalid
         | 
| 22 | 
            +
                  INV_WIKI_KEY = "invalid_wiki"
         | 
| 23 | 
            +
                  # INV_WEB_KEY = "invalid_web"
         | 
| 24 | 
            +
                  ## embed
         | 
| 25 | 
            +
                  EMBED_WRAPPER_KEY = "embed_wrapper"
         | 
| 26 | 
            +
                  EMBED_TITLE_KEY = "embed_title"
         | 
| 27 | 
            +
                  EMBED_CONTENT_KEY = "embed_content"
         | 
| 28 | 
            +
                  EMBED_LINK_KEY = "embed_wiki_link"
         | 
| 29 | 
            +
                  EMBED_IMG_WRAPPER_KEY = "embed_image_wrapper"
         | 
| 30 | 
            +
                  EMBED_IMG_KEY = "embed_image"
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def initialize(config)
         | 
| 33 | 
            +
                    @config ||= config
         | 
| 34 | 
            +
                    self.old_config_warn()
         | 
| 35 | 
            +
                    Jekyll.logger.debug("Jekyll-WikiRefs: Excluded jekyll types: #{option(EXCLUDE_KEY)}") unless disabled?
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  # util
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def css_name(name_key)
         | 
| 41 | 
            +
                    return option_css_name(name_key) if option_css_name(name_key)
         | 
| 42 | 
            +
                    return "typed"                   if name_key == TYPED_KEY
         | 
| 43 | 
            +
                    # valid
         | 
| 44 | 
            +
                    return "wiki-link"               if name_key == WIKI_KEY
         | 
| 45 | 
            +
                    # invalid
         | 
| 46 | 
            +
                    return "invalid-wiki-link"       if name_key == INV_WIKI_KEY
         | 
| 47 | 
            +
                    # return "invalid-web-link" if name_key == INV_WEB_KEY
         | 
| 48 | 
            +
                    # embeds
         | 
| 49 | 
            +
                    return "embed-wrapper"           if name_key == EMBED_WRAPPER_KEY
         | 
| 50 | 
            +
                    return "embed-title"             if name_key == EMBED_TITLE_KEY
         | 
| 51 | 
            +
                    return "embed-content"           if name_key == EMBED_CONTENT_KEY
         | 
| 52 | 
            +
                    return "embed-wiki-link"         if name_key == EMBED_LINK_KEY
         | 
| 53 | 
            +
                    # img
         | 
| 54 | 
            +
                    return "embed-image-wrapper"     if name_key == EMBED_IMG_WRAPPER_KEY
         | 
| 55 | 
            +
                    return "embed-image"             if name_key == EMBED_IMG_KEY
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  def disabled?
         | 
| 59 | 
            +
                    option(ENABLED_KEY) == false
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def disabled_attributes?
         | 
| 63 | 
            +
                    option_attributes(ENABLED_KEY) == false
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def exclude?(type)
         | 
| 67 | 
            +
                    return false unless option(EXCLUDE_KEY)
         | 
| 68 | 
            +
                    return option(EXCLUDE_KEY).include?(type.to_s)
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def excluded_css_names
         | 
| 72 | 
            +
                    return self.option_css(EXCLUDE_KEY)
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  # options
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  def option(key)
         | 
| 78 | 
            +
                    @config[CONFIG_KEY] && @config[CONFIG_KEY][key]
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  def option_attributes(key)
         | 
| 82 | 
            +
                    @config[CONFIG_KEY] && @config[CONFIG_KEY][ATTR_KEY] && @config[CONFIG_KEY][ATTR_KEY][key]
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  def option_css(key)
         | 
| 86 | 
            +
                    @config[CONFIG_KEY] && @config[CONFIG_KEY][CSS_KEY] && @config[CONFIG_KEY][CSS_KEY][key]
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  def option_css_name(key)
         | 
| 90 | 
            +
                    option_css(NAME_KEY) && @config[CONFIG_KEY][CSS_KEY][NAME_KEY][key]
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  # !! deprecated !!
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  def option_exist?(key)
         | 
| 96 | 
            +
                    @config[CONFIG_KEY] && @config[CONFIG_KEY].include?(key)
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  def old_config_warn()
         | 
| 100 | 
            +
                    if @config.include?("wikilinks_collection")
         | 
| 101 | 
            +
                      Jekyll.logger.warn("Jekyll-WikiRefs: As of 0.0.3, 'wikilinks_collection' is no longer used for configs. Jekyll-WikiRefs will scan all markdown files by default. Check README for details.")
         | 
| 102 | 
            +
                    end
         | 
| 103 | 
            +
                    if option_exist?("assets_rel_path")
         | 
| 104 | 
            +
                      Jekyll.logger.warn("Jekyll-WikiRefs: As of 0.0.5, 'assets_rel_path' is now 'path'.")
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                    if @config.include?("d3_graph_data")
         | 
| 107 | 
            +
                      Jekyll.logger.warn("Jekyll-WikiRefs: As of 0.0.6, 'd3_graph_data' and graph functionality have been moved to the 'jekyll-graph' plugin.")
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
            end
         | 
| @@ -0,0 +1,117 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require_relative "../util/regex"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Jekyll
         | 
| 5 | 
            +
              module WikiRefs
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # todo: move these methods to the 'WikiRef' classes...?
         | 
| 8 | 
            +
                #
         | 
| 9 | 
            +
                # this class is responsible for answering any questions
         | 
| 10 | 
            +
                # related to jekyll markdown documents
         | 
| 11 | 
            +
                # that are meant to be processed by the wikirefs plugin.
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                # the following methods are specifically to address two things:
         | 
| 14 | 
            +
                #  1. ruby's 'find' / 'detect' function does not throw errors if 
         | 
| 15 | 
            +
                #     there are multiple matches. fail fast, i want to know if there
         | 
| 16 | 
            +
                #     are duplicates. 
         | 
| 17 | 
            +
                #     (not using sets because i don't want to clobber existing documents)
         | 
| 18 | 
            +
                #  2. handle all jekyll documents in one place. i don't want to
         | 
| 19 | 
            +
                #     have to filter all documents for target markdown documents 
         | 
| 20 | 
            +
                #     every time i need to check if a file exists.
         | 
| 21 | 
            +
                # 
         | 
| 22 | 
            +
                # there is probably a better way to do this...i would prefer to have
         | 
| 23 | 
            +
                # a plugin-wide function that just wraps all of this and can be called
         | 
| 24 | 
            +
                # from anywhere in the plugin...but ruby is not a functional language...
         | 
| 25 | 
            +
                # gotta have classes...
         | 
| 26 | 
            +
                # 
         | 
| 27 | 
            +
                class DocManager
         | 
| 28 | 
            +
                  CONVERTER_CLASS = Jekyll::Converters::Markdown
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def initialize(site)
         | 
| 31 | 
            +
                    return if $wiki_conf.disabled?
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    markdown_converter = site.find_converter_instance(CONVERTER_CLASS)
         | 
| 34 | 
            +
                    # filter docs based on configs
         | 
| 35 | 
            +
                    docs = []
         | 
| 36 | 
            +
                    docs += site.pages if !$wiki_conf.exclude?(:pages)
         | 
| 37 | 
            +
                    docs += site.docs_to_write.filter { |d| !$wiki_conf.exclude?(d.type) }
         | 
| 38 | 
            +
                    @md_docs = docs.filter { |doc| markdown_converter.matches(doc.extname) }
         | 
| 39 | 
            +
                    if @md_docs.nil? || @md_docs.empty?
         | 
| 40 | 
            +
                      Jekyll.logger.warn("Jekyll-WikiRefs: No documents to process.")
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    @static_files ||= site.static_files
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  # accessors
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def all
         | 
| 49 | 
            +
                    return @md_docs
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def get_doc_by_fname(filename)
         | 
| 53 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'filename'") if filename.nil? || filename.empty?
         | 
| 54 | 
            +
                    docs = @md_docs.select{ |d| File.basename(d.basename, File.extname(d.basename)) == filename }
         | 
| 55 | 
            +
                    return nil if docs.nil? || docs.empty? || docs.size > 1
         | 
| 56 | 
            +
                    return docs[0]
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def get_doc_by_fpath(file_path)
         | 
| 60 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'file_path'") if file_path.nil? || file_path.empty?
         | 
| 61 | 
            +
                    docs = @md_docs.select{ |d| d.relative_path == (file_path + ".md") }
         | 
| 62 | 
            +
                    return nil if docs.nil? || docs.empty? || docs.size > 1
         | 
| 63 | 
            +
                    return docs[0]
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def get_doc_by_url(url)
         | 
| 67 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'url'") if url.nil? || url.empty?
         | 
| 68 | 
            +
                    docs = @md_docs.select{ |d| d.url == url }
         | 
| 69 | 
            +
                    return nil if docs.nil? || docs.empty? || docs.size > 1
         | 
| 70 | 
            +
                    return docs[0]
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  def get_doc_content(filename)
         | 
| 74 | 
            +
                    doc = self.get_doc_by_fname(filename)
         | 
| 75 | 
            +
                    return nil if docs.nil?
         | 
| 76 | 
            +
                    return doc.content
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  def get_image_by_fname(filename)
         | 
| 80 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'filename'") if filename.nil? || filename.empty?
         | 
| 81 | 
            +
                    return nil if @static_files.size == 0 || !SUPPORTED_IMG_FORMATS.any?{ |ext| ext == File.extname(filename).downcase }
         | 
| 82 | 
            +
                    docs = @static_files.select{ |d| File.basename(d.relative_path) == filename }
         | 
| 83 | 
            +
                    return nil if docs.nil? || docs.empty? || docs.size > 1
         | 
| 84 | 
            +
                    return docs[0]
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  # validators
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  def file_exists?(filename, file_path=nil)
         | 
| 90 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'filename'") if filename.nil? || filename.empty?
         | 
| 91 | 
            +
                    if file_path.nil?
         | 
| 92 | 
            +
                      return false if get_doc_by_fname(filename).nil? && get_image_by_fname(filename).nil?
         | 
| 93 | 
            +
                      return true
         | 
| 94 | 
            +
                    else
         | 
| 95 | 
            +
                      return false if get_doc_by_fpath(file_path).nil?
         | 
| 96 | 
            +
                      return true
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  def doc_has_header?(doc, header)
         | 
| 101 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'header'") if header.nil? || header.empty?
         | 
| 102 | 
            +
                    # leading + trailing whitespace is ignored when matching headers
         | 
| 103 | 
            +
                    header_results = doc.content.scan(REGEX_ATX_HEADER).flatten.map { |htxt| htxt.downcase.strip }
         | 
| 104 | 
            +
                    setext_header_results = doc.content.scan(REGEX_SETEXT_HEADER).flatten.map { |htxt| htxt.downcase.strip }
         | 
| 105 | 
            +
                    return header_results.include?(header.downcase.strip) || setext_header_results.include?(header.downcase.strip)
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  def doc_has_block_id?(doc, block_id)
         | 
| 109 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: Must provide a 'block_id'") if block_id.nil? || block_id.empty?
         | 
| 110 | 
            +
                    # leading + trailing whitespace is ignored when matching blocks
         | 
| 111 | 
            +
                    block_id_results = doc.content.scan(REGEX_BLOCK).flatten.map { |bid| bid.strip }
         | 
| 112 | 
            +
                    return block_id_results.include?(block_id)
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            require "jekyll"
         | 
| 2 | 
            +
            require "nokogiri"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Jekyll
         | 
| 5 | 
            +
              module WikiRefs
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class WebLinkConverter < Jekyll::Converter
         | 
| 8 | 
            +
                  priority :low
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # config
         | 
| 11 | 
            +
                  CSS_KEY = "css"
         | 
| 12 | 
            +
                  CONFIG_KEY = "wikirefs"
         | 
| 13 | 
            +
                  EXCLUDE_KEY = "exclude"
         | 
| 14 | 
            +
                  # link types
         | 
| 15 | 
            +
                  # WEB_KEY = "web"
         | 
| 16 | 
            +
                  # WIKIL_KEY = "wiki"
         | 
| 17 | 
            +
                  # INVALID_KEY = "invalid"
         | 
| 18 | 
            +
                  # WIKI_EMBED_KEY = "wiki_embed"
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def matches(ext)
         | 
| 21 | 
            +
                    ext =~ /^\.md$/i
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def output_ext(ext)
         | 
| 25 | 
            +
                    ".html"
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # add 'web-link' css class to links that aren't
         | 
| 29 | 
            +
                  # - wikilinks
         | 
| 30 | 
            +
                  # - contain an excluded css class
         | 
| 31 | 
            +
                  def convert(content)
         | 
| 32 | 
            +
                    excluded_classes = option_css(EXCLUDE_KEY)
         | 
| 33 | 
            +
                    if excluded_classes.nil? || excluded_classes.empty?
         | 
| 34 | 
            +
                      css_def = "a:not(.#{$wiki_conf.css_name("wiki")}):not(.#{$wiki_conf.css_name("embed_wiki_link")})"
         | 
| 35 | 
            +
                    else
         | 
| 36 | 
            +
                      css_def = "a:not(.#{$wiki_conf.css_name("wiki")}):not(.#{$wiki_conf.css_name("embed_wiki_link")}):not(.#{excluded_classes.join("):not(.")})"
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                    parsed_content = Nokogiri::HTML::fragment(content)
         | 
| 39 | 
            +
                    parsed_content.css(css_def).each do |link|
         | 
| 40 | 
            +
                      link.add_class('web-link')
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    content = parsed_content.to_html
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  # config helpers
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def option_css(key)
         | 
| 48 | 
            +
                    @config[CONFIG_KEY] && @config[CONFIG_KEY][CSS_KEY] && @config[CONFIG_KEY][CSS_KEY][key]
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Jekyll
         | 
| 4 | 
            +
              module WikiRefs
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                module TypeFilters
         | 
| 7 | 
            +
                  # 'links' accepts untyped links, typed links, and attributes; fore and back.
         | 
| 8 | 
            +
                  # why: these filters are useful when you want to list backlinks of certain type(s) and don't want type mismatches to display as "missing"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # usage: {% assign note_links = page.links | doc_type: "notes" %}
         | 
| 11 | 
            +
                  def doc_type(links, doc_type)
         | 
| 12 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: 'links' invalid") if links.nil?
         | 
| 13 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: 'doc_type' invalid") if doc_type.nil? || doc_type.empty?
         | 
| 14 | 
            +
                    return [] if links.empty?
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    site = @context.registers[:site]
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    links_of_type = []
         | 
| 19 | 
            +
                    links.each do |l|
         | 
| 20 | 
            +
                      # links
         | 
| 21 | 
            +
                      if l.keys.include?('url')
         | 
| 22 | 
            +
                        docs = site.documents.select{ |d| d.url == l['url'] && d.type.to_s == doc_type.to_s }
         | 
| 23 | 
            +
                        if !docs.nil? && docs.size == 1
         | 
| 24 | 
            +
                          links_of_type << l
         | 
| 25 | 
            +
                        end
         | 
| 26 | 
            +
                      # attributes
         | 
| 27 | 
            +
                      elsif l.keys.include?('urls')
         | 
| 28 | 
            +
                        l['urls'].each do |lurl|
         | 
| 29 | 
            +
                          docs = site.documents.select{ |d| d.url == lurl && d.type.to_s == doc_type.to_s }
         | 
| 30 | 
            +
                          if !docs.nil? && docs.size == 1
         | 
| 31 | 
            +
                            links_of_type << l
         | 
| 32 | 
            +
                          end
         | 
| 33 | 
            +
                        end
         | 
| 34 | 
            +
                      else
         | 
| 35 | 
            +
                        Jekyll.logger.error("Jekyll-WikiRefs: In 'doc_type' filter, 'links' do not have 'url' or 'urls'")
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                    return links_of_type.uniq
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # usage: {% assign author_links = page.links | link_type: "author" %}
         | 
| 42 | 
            +
                  def link_type(links, link_type)
         | 
| 43 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: 'links' invalid") if links.nil?
         | 
| 44 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: 'link_type' invalid") if link_type.nil?
         | 
| 45 | 
            +
                    return [] if links.empty?
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    site = @context.registers[:site]
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    links_of_type = []
         | 
| 50 | 
            +
                    links.each do |l|
         | 
| 51 | 
            +
                      if l['type'].to_s == link_type.to_s
         | 
| 52 | 
            +
                        # links
         | 
| 53 | 
            +
                        if l.keys.include?('url')
         | 
| 54 | 
            +
                          docs = site.documents.select{ |d| d.url == l['url'] }
         | 
| 55 | 
            +
                          if !doc.nil? && docs.size != 1
         | 
| 56 | 
            +
                            links_of_type << l
         | 
| 57 | 
            +
                          end
         | 
| 58 | 
            +
                        # attributes
         | 
| 59 | 
            +
                        elsif l.keys.include?('urls')
         | 
| 60 | 
            +
                          all_docs_exist = true
         | 
| 61 | 
            +
                          l['urls'].each do |lurl|
         | 
| 62 | 
            +
                            docs = site.documents.select{ |d| d.url == lurl }
         | 
| 63 | 
            +
                            if !docs.nil? && docs.size != 1
         | 
| 64 | 
            +
                              all_docs_exist = false
         | 
| 65 | 
            +
                            end
         | 
| 66 | 
            +
                          end
         | 
| 67 | 
            +
                          if all_docs_exist
         | 
| 68 | 
            +
                            links_of_type << l
         | 
| 69 | 
            +
                          end
         | 
| 70 | 
            +
                        else
         | 
| 71 | 
            +
                          Jekyll.logge.error("Jekyll-WikiRefs: In 'link_type' filter, 'links' do not have 'url' or 'urls'")
         | 
| 72 | 
            +
                        end
         | 
| 73 | 
            +
                      end
         | 
| 74 | 
            +
                    end
         | 
| 75 | 
            +
                    return links_of_type.uniq
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require "jekyll"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative "../patch/context"
         | 
| 5 | 
            +
            require_relative "../patch/doc_manager"
         | 
| 6 | 
            +
            require_relative "../patch/site"
         | 
| 7 | 
            +
            require_relative "../util/link_index"
         | 
| 8 | 
            +
            require_relative "../util/parser"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            module Jekyll
         | 
| 11 | 
            +
              module WikiRefs
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                class Generator < Jekyll::Generator
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def generate(site)
         | 
| 16 | 
            +
                    return if $wiki_conf.disabled?
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    @site ||= site
         | 
| 19 | 
            +
                    @context ||= Jekyll::WikiRefs::Context.new(site)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    # setup helper classes
         | 
| 22 | 
            +
                    @parser = Parser.new(@site)
         | 
| 23 | 
            +
                    @site.link_index = LinkIndex.new(@site)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    @site.doc_mngr.all.each do |doc|
         | 
| 26 | 
            +
                      filename = File.basename(doc.basename, File.extname(doc.basename))
         | 
| 27 | 
            +
                      @parser.parse(filename, doc.content)
         | 
| 28 | 
            +
                      @site.link_index.populate(doc, @parser.wikilink_blocks, @parser.wikilink_inlines)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                    # wait until all docs are processed before assigning backward facing metadata,
         | 
| 31 | 
            +
                    # this ensures all attributed/backlinks are collected for assignment
         | 
| 32 | 
            +
                    @site.doc_mngr.all.each do |doc|
         | 
| 33 | 
            +
                      # populate frontmatter metadata from (wiki)link index
         | 
| 34 | 
            +
                      @site.link_index.assign_metadata(doc)
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,99 @@ | |
| 1 | 
            +
            require_relative 'regex'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Jekyll
         | 
| 4 | 
            +
              module WikiRefs
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                class LinkIndex
         | 
| 7 | 
            +
                  attr_reader :index
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def initialize(site)
         | 
| 10 | 
            +
                    @baseurl = site.baseurl
         | 
| 11 | 
            +
                    @index = {}
         | 
| 12 | 
            +
                    site.doc_mngr.all.each do |doc|
         | 
| 13 | 
            +
                      @index[doc.url] = DocLinks.new()
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def assign_metadata(doc)
         | 
| 18 | 
            +
                    doc.data['attributed'] = @index[doc.url].attributed.uniq
         | 
| 19 | 
            +
                    doc.data['attributes'] = @index[doc.url].attributes.uniq
         | 
| 20 | 
            +
                    doc.data['backlinks']  = @index[doc.url].backlinks.uniq
         | 
| 21 | 
            +
                    doc.data['forelinks']  = @index[doc.url].forelinks.uniq
         | 
| 22 | 
            +
                    doc.data['missing']    = @index[doc.url].missing.uniq
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def populate(doc, wikilink_blocks, wikilink_inlines)
         | 
| 26 | 
            +
                    #        #
         | 
| 27 | 
            +
                    # blocks #
         | 
| 28 | 
            +
                    #        #
         | 
| 29 | 
            +
                    wikilink_blocks.each do |wlbl|
         | 
| 30 | 
            +
                      if wlbl.is_valid?
         | 
| 31 | 
            +
                        #
         | 
| 32 | 
            +
                        # attributes
         | 
| 33 | 
            +
                        #
         | 
| 34 | 
            +
                        target_attr = @index[doc.url].attributes.detect { |atr| atr['type'] == wlbl.link_type }
         | 
| 35 | 
            +
                        # create
         | 
| 36 | 
            +
                        if target_attr.nil?
         | 
| 37 | 
            +
                          @index[doc.url].attributes << wlbl.linked_fm_data
         | 
| 38 | 
            +
                        # append
         | 
| 39 | 
            +
                        else
         | 
| 40 | 
            +
                          target_attr['urls'] += wlbl.urls 
         | 
| 41 | 
            +
                        end
         | 
| 42 | 
            +
                        ## append missing docs
         | 
| 43 | 
            +
                        @index[doc.url].missing += wlbl.missing_doc_filenames 
         | 
| 44 | 
            +
                        #
         | 
| 45 | 
            +
                        # attributed
         | 
| 46 | 
            +
                        #
         | 
| 47 | 
            +
                        wlbl.linked_docs.each do |linked_doc|
         | 
| 48 | 
            +
                          target_attr = @index[linked_doc.url].attributed.detect { |atr| atr['type'] == wlbl.link_type }
         | 
| 49 | 
            +
                          # create
         | 
| 50 | 
            +
                          if target_attr.nil?
         | 
| 51 | 
            +
                            @index[linked_doc.url].attributed << wlbl.context_fm_data
         | 
| 52 | 
            +
                          # append
         | 
| 53 | 
            +
                          else
         | 
| 54 | 
            +
                            target_attr['urls'] << doc.url
         | 
| 55 | 
            +
                          end
         | 
| 56 | 
            +
                        end
         | 
| 57 | 
            +
                      else
         | 
| 58 | 
            +
                        #
         | 
| 59 | 
            +
                        # invalid || empty
         | 
| 60 | 
            +
                        #
         | 
| 61 | 
            +
                        @index[doc.url].missing += wlbl.missing_doc_filenames
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                    #         #
         | 
| 65 | 
            +
                    # inlines #
         | 
| 66 | 
            +
                    #         #
         | 
| 67 | 
            +
                    wikilink_inlines.each do |wlil|
         | 
| 68 | 
            +
                      return if wlil.is_img?
         | 
| 69 | 
            +
                      if wlil.is_valid?
         | 
| 70 | 
            +
                        # forelink
         | 
| 71 | 
            +
                        @index[doc.url].forelinks << wlil.linked_fm_data
         | 
| 72 | 
            +
                        # backlink
         | 
| 73 | 
            +
                        @index[wlil.linked_doc.url].backlinks << wlil.context_fm_data
         | 
| 74 | 
            +
                      else
         | 
| 75 | 
            +
                        @index[doc.url].missing << wlil.filename
         | 
| 76 | 
            +
                      end
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  # def remove_baseurl(url)
         | 
| 81 | 
            +
                  #   return url.gsub(@baseurl, '') if !@baseurl.nil?
         | 
| 82 | 
            +
                  #   return url
         | 
| 83 | 
            +
                  # end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  class DocLinks
         | 
| 86 | 
            +
                    attr_accessor :attributes, :attributed, :backlinks, :forelinks, :missing
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    def initialize
         | 
| 89 | 
            +
                      @attributed = [] # block typed backlinks;            { 'type' => str, 'urls' => [ str ] }
         | 
| 90 | 
            +
                      @attributes = [] # block typed forelinks;            { 'type' => str, 'urls' => [ str ] }
         | 
| 91 | 
            +
                      @backlinks  = [] # inline typed and basic backlinks; { 'type' => str, 'url'  => str }
         | 
| 92 | 
            +
                      @forelinks  = [] # inline typed and basic forelinks; { 'type' => str, 'url'  => str }
         | 
| 93 | 
            +
                      @missing    = [] # missing forelinks + attributes;   ( built from (missing) filenames )
         | 
| 94 | 
            +
                    end
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
            end
         | 
| @@ -0,0 +1,182 @@ | |
| 1 | 
            +
            require "nokogiri"
         | 
| 2 | 
            +
            require_relative "regex"
         | 
| 3 | 
            +
            require_relative "wikiref"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Jekyll
         | 
| 6 | 
            +
              module WikiRefs
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                # more of a "parser" than a parser
         | 
| 9 | 
            +
                class Parser
         | 
| 10 | 
            +
                  attr_accessor :doc_manager, :markdown_converter, :wikilink_inlines, :wikilink_blocks
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  # Use Jekyll's native relative_url filter
         | 
| 13 | 
            +
                  include Jekyll::Filters::URLFilters
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  CONVERTER_CLASS = Jekyll::Converters::Markdown
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def initialize(site)
         | 
| 18 | 
            +
                    @context ||= Jekyll::WikiRefs::Context.new(site)
         | 
| 19 | 
            +
                    # do not use @dm in parser -- it is only meant to be passed down into wikilink classes. 
         | 
| 20 | 
            +
                    @doc_manager ||= site.doc_mngr
         | 
| 21 | 
            +
                    @markdown_converter ||= site.find_converter_instance(CONVERTER_CLASS)
         | 
| 22 | 
            +
                    @wikilink_blocks, @wikilink_inlines = [], []
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  # parsing
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def parse(doc_filename, doc_content)
         | 
| 28 | 
            +
                    @wikilink_blocks, @wikilink_inlines = [], []
         | 
| 29 | 
            +
                    if !$wiki_conf.disabled_attributes?
         | 
| 30 | 
            +
                      self.parse_blocks(doc_filename, doc_content)
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                    self.parse_inlines(doc_filename, doc_content)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def parse_blocks(doc_filename, doc_content)
         | 
| 36 | 
            +
                    block_matches = doc_content.scan(REGEX_WIKI_LINK_BLOCKS)
         | 
| 37 | 
            +
                    if !block_matches.nil? && block_matches.size != 0
         | 
| 38 | 
            +
                      block_matches.each do |w_match|
         | 
| 39 | 
            +
                        # init block wikilink
         | 
| 40 | 
            +
                        wikilink_block = WikiLinkBlock.new(
         | 
| 41 | 
            +
                          @doc_manager,
         | 
| 42 | 
            +
                          doc_filename,
         | 
| 43 | 
            +
                          w_match[0], # link_type
         | 
| 44 | 
            +
                          w_match[2], # bullet_type
         | 
| 45 | 
            +
                        )
         | 
| 46 | 
            +
                        # extract + add filenames
         | 
| 47 | 
            +
                        items = w_match[1]
         | 
| 48 | 
            +
                        filename_matches = items.scan(/#{REGEX_LINK_LEFT}#{REGEX_FILENAME}#{REGEX_LINK_RIGHT}/i)
         | 
| 49 | 
            +
                        filename_matches.each do |match|
         | 
| 50 | 
            +
                          match.each do |fname|
         | 
| 51 | 
            +
                            wikilink_block.add_item(fname)
         | 
| 52 | 
            +
                          end
         | 
| 53 | 
            +
                        end
         | 
| 54 | 
            +
                        # replace text
         | 
| 55 | 
            +
                        doc_content.gsub!(wikilink_block.md_regex, "\n")
         | 
| 56 | 
            +
                        @wikilink_blocks << wikilink_block
         | 
| 57 | 
            +
                      end
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  def parse_inlines(doc_filename, doc_content)
         | 
| 62 | 
            +
                    inline_matches = doc_content.scan(REGEX_WIKI_LINK_INLINES)
         | 
| 63 | 
            +
                    if !inline_matches.nil? && inline_matches.size != 0
         | 
| 64 | 
            +
                      inline_matches.each do |w_match|
         | 
| 65 | 
            +
                        @wikilink_inlines << WikiLinkInline.new(
         | 
| 66 | 
            +
                          @doc_manager,
         | 
| 67 | 
            +
                          doc_filename,
         | 
| 68 | 
            +
                          w_match[0],
         | 
| 69 | 
            +
                          w_match[1],
         | 
| 70 | 
            +
                          w_match[2],
         | 
| 71 | 
            +
                          w_match[3],
         | 
| 72 | 
            +
                          w_match[4],
         | 
| 73 | 
            +
                          w_match[5],
         | 
| 74 | 
            +
                        )
         | 
| 75 | 
            +
                      end
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
                    # replace text
         | 
| 78 | 
            +
                    return if @wikilink_inlines.nil?
         | 
| 79 | 
            +
                    # process typed wikilinks first so we don't accidentally 
         | 
| 80 | 
            +
                    # overwrite them when handling untyped wikilinks
         | 
| 81 | 
            +
                    self.sort_for_replacement
         | 
| 82 | 
            +
                    @wikilink_inlines.each do |wikilink|
         | 
| 83 | 
            +
                      doc_content.gsub!(
         | 
| 84 | 
            +
                        wikilink.md_regex,
         | 
| 85 | 
            +
                        self.build_html(wikilink)
         | 
| 86 | 
            +
                      )
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  # building/converting
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  def build_html_embed(title, content, url)
         | 
| 93 | 
            +
                    # multi-line for readability
         | 
| 94 | 
            +
                    return [
         | 
| 95 | 
            +
                      "<div class=\"#{$wiki_conf.css_name("embed_wrapper")}\">",
         | 
| 96 | 
            +
                        "<div class=\"#{$wiki_conf.css_name("embed_title")}\">",
         | 
| 97 | 
            +
                          "#{title}",
         | 
| 98 | 
            +
                        "</div>",
         | 
| 99 | 
            +
                        "<div class=\"#{$wiki_conf.css_name("embed_content")}\">",
         | 
| 100 | 
            +
                          "#{@markdown_converter.convert(content)}",
         | 
| 101 | 
            +
                        "</div>",
         | 
| 102 | 
            +
                        "<a class=\"#{$wiki_conf.css_name("embed_wiki_link")}\" href=\"#{url}\"></a>",
         | 
| 103 | 
            +
                      "</div>",
         | 
| 104 | 
            +
                    ].join("\n").gsub!("\n", "")
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  def build_html_img_embed(static_doc, is_svg=false)
         | 
| 108 | 
            +
                    svg_content = ""
         | 
| 109 | 
            +
                    if is_svg
         | 
| 110 | 
            +
                      File.open(static_doc.path, "r") do |svg_img|
         | 
| 111 | 
            +
                        svg_content = svg_img.read
         | 
| 112 | 
            +
                      end
         | 
| 113 | 
            +
                      return "<p><span class=\"#{$wiki_conf.css_name("embed_image_wrapper")}\">#{svg_content}</span></p>"
         | 
| 114 | 
            +
                    else
         | 
| 115 | 
            +
                      return "<p><span class=\"#{$wiki_conf.css_name("embed_image_wrapper")}\"><img class=\"#{$wiki_conf.css_name("embed_image")}\" src=\"#{relative_url(static_doc.relative_path)}\"></span></p>"
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              		def build_html(wikilink)
         | 
| 120 | 
            +
                    if !wikilink.is_valid?
         | 
| 121 | 
            +
                      return '<span class="' + $wiki_conf.css_name("invalid_wiki") + '">' + wikilink.md_str + '</span>'
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
                    # image processing
         | 
| 124 | 
            +
                    if wikilink.embedded? && wikilink.is_img?
         | 
| 125 | 
            +
                      return build_html_img_embed(wikilink.linked_img, is_svg=wikilink.is_img_svg?)
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
                    # markdown file processing
         | 
| 128 | 
            +
                    linked_doc = wikilink.linked_doc
         | 
| 129 | 
            +
                    link_type_txt = wikilink.is_typed? ? " #{$wiki_conf.css_name("typed")} #{wikilink.link_type}" : ""
         | 
| 130 | 
            +
                    lnk_doc_rel_url = relative_url(linked_doc.url)
         | 
| 131 | 
            +
                    if wikilink.labelled?
         | 
| 132 | 
            +
                      inner_txt = wikilink.label_txt
         | 
| 133 | 
            +
                    elsif linked_doc.data.keys.include?('title')
         | 
| 134 | 
            +
                      inner_txt = linked_doc.data['title'].downcase
         | 
| 135 | 
            +
                    # in case there is no 'title' frontmatter attribute 
         | 
| 136 | 
            +
                    # (i'm seeing deprecation warnings, but there might 
         | 
| 137 | 
            +
                    #  be bugs caused by not using this...)
         | 
| 138 | 
            +
                    elsif linked_doc.respond_to?(:title)
         | 
| 139 | 
            +
                      inner_txt = linked_doc.title.downcase
         | 
| 140 | 
            +
                    # pages don't have automatically generated titles
         | 
| 141 | 
            +
                    else
         | 
| 142 | 
            +
                      inner_txt = Jekyll::Utils.slugify(linked_doc.basename)
         | 
| 143 | 
            +
                    end
         | 
| 144 | 
            +
                    # level-specific
         | 
| 145 | 
            +
                    if (wikilink.level == "file_path" || wikilink.level == "filename")
         | 
| 146 | 
            +
                      return build_html_embed(
         | 
| 147 | 
            +
                        linked_doc.title,
         | 
| 148 | 
            +
                        linked_doc.content,
         | 
| 149 | 
            +
                        lnk_doc_rel_url
         | 
| 150 | 
            +
                      ) if wikilink.embedded?
         | 
| 151 | 
            +
                    elsif (wikilink.level == "header")
         | 
| 152 | 
            +
                      # from: https://github.com/jekyll/jekyll/blob/6855200ebda6c0e33f487da69e4e02ec3d8286b7/Rakefile#L74
         | 
| 153 | 
            +
                      lnk_doc_rel_url += "\#" + Jekyll::Utils.slugify(wikilink.header_txt)
         | 
| 154 | 
            +
                      inner_txt += " > #{wikilink.header_txt.downcase}" if !wikilink.labelled?
         | 
| 155 | 
            +
                    elsif (wikilink.level == "block")
         | 
| 156 | 
            +
                      lnk_doc_rel_url += "\#" + wikilink.block_id
         | 
| 157 | 
            +
                      inner_txt += " > ^#{wikilink.block_id}" if !wikilink.labelled?
         | 
| 158 | 
            +
                    else
         | 
| 159 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: Invalid wikilink level")
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
                    return '<a class="' + $wiki_conf.css_name("wiki") + link_type_txt + '" href="' + lnk_doc_rel_url + '">' + inner_txt + '</a>'
         | 
| 162 | 
            +
                  end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                  # helpers
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  def sort_for_replacement
         | 
| 167 | 
            +
                    # sorting inline wikilinks is necessary so when wikilinks are replaced,
         | 
| 168 | 
            +
                    # !embeds and longer strings are replaced first so as not to accidentally overwrite 
         | 
| 169 | 
            +
                    # substrings
         | 
| 170 | 
            +
                    # (this is especially likely if there is a matching wikilink that 
         | 
| 171 | 
            +
                    #  appears as both untyped and typed in a document or in a regular link and embed)
         | 
| 172 | 
            +
                    temp = @wikilink_inlines.dup
         | 
| 173 | 
            +
                    @wikilink_inlines.clear()
         | 
| 174 | 
            +
                    embeds = temp.select { |w| w.embedded? }
         | 
| 175 | 
            +
                    typed_wikilinks = temp.select { |w| w.is_typed? }
         | 
| 176 | 
            +
                    untyped_wikilinks = temp.select { |w| !w.is_typed? }
         | 
| 177 | 
            +
                    @wikilink_inlines = embeds.concat(typed_wikilinks.concat(untyped_wikilinks))
         | 
| 178 | 
            +
                  end
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
              end
         | 
| 182 | 
            +
            end
         | 
| @@ -0,0 +1,72 @@ | |
| 1 | 
            +
            # regex.rb
         | 
| 2 | 
            +
            # regex constants defining supported file types and valid names for files, variables, or text
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Jekyll
         | 
| 6 | 
            +
              module WikiRefs
         | 
| 7 | 
            +
                #  <regex_variables> only work with 'match' function, not with 'scan' function. :/
         | 
| 8 | 
            +
                #  oh well...they are there for easier debugging...
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # supported image formats
         | 
| 11 | 
            +
                # from: https://docs.github.com/en/github/managing-files-in-a-repository/working-with-non-code-files/rendering-and-diffing-images
         | 
| 12 | 
            +
                SUPPORTED_IMG_FORMATS = Set.new(['.png', '.jpg', '.gif', '.psd', '.svg'])
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # wikilink constants
         | 
| 15 | 
            +
                REGEX_LINK_LEFT       = /\[\[/
         | 
| 16 | 
            +
                REGEX_LINK_RIGHT      = /\]\]/
         | 
| 17 | 
            +
                REGEX_LINK_EMBED      = /(?<embed>\!)/
         | 
| 18 | 
            +
                REGEX_LINK_TYPE       = /\s*::\s*/
         | 
| 19 | 
            +
                REGEX_LINK_HEADER     = /\#/
         | 
| 20 | 
            +
                REGEX_LINK_BLOCK      = /\#\^/
         | 
| 21 | 
            +
                REGEX_LINK_LABEL      = /\|/
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                # wikitext usable char requirements
         | 
| 24 | 
            +
                REGEX_LINK_TYPE_CHARS = /[^\n\s\!\#\^\|\]]+/i
         | 
| 25 | 
            +
                REGEX_FILENAME_CHARS  = /[^\\:\#\^\|\[\]]+/i
         | 
| 26 | 
            +
                REGEX_HEADER_CHARS    = /[^\!\#\^\|\[\]]+/i
         | 
| 27 | 
            +
                REGEX_BLOCK_ID_CHARS  = /[^\\\/:\!\#\^\|\[\]^\n]+/i
         | 
| 28 | 
            +
                REGEX_LABEL_CHARS     = /(.+?)(?=\]{2}[^\]])/i
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # capture groups
         | 
| 31 | 
            +
                REGEX_LINK_TYPE_TXT   = /(?<link-type-txt>#{REGEX_LINK_TYPE_CHARS})/i
         | 
| 32 | 
            +
                REGEX_FILENAME        = /(?<filename>#{REGEX_FILENAME_CHARS})/i
         | 
| 33 | 
            +
                REGEX_HEADER_TXT      = /(?<header-txt>#{REGEX_HEADER_CHARS})/i
         | 
| 34 | 
            +
                REGEX_BLOCK_ID_TXT    = /(?<block-id>#{REGEX_BLOCK_ID_CHARS})/i
         | 
| 35 | 
            +
                REGEX_LABEL_TXT       = /(?<label-txt>#{REGEX_LABEL_CHARS})/i
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                # target markdown text (headers, lists, and blocks)
         | 
| 38 | 
            +
                ## kramdown regexes
         | 
| 39 | 
            +
                ### atx header: https://github.com/gettalong/kramdown/blob/master/lib/kramdown/parser/kramdown/header.rb#L29
         | 
| 40 | 
            +
                REGEX_ATX_HEADER      = /^\#{1,6}[\t ]*([^ \t].*)\n/i
         | 
| 41 | 
            +
                ### setext header: https://github.com/gettalong/kramdown/blob/master/lib/kramdown/parser/kramdown/header.rb#L17
         | 
| 42 | 
            +
                REGEX_SETEXT_HEADER   = /^\s{0,3}([^ \t].*)\n[-=][-=]*[ \t\r\f\v]*\n/i
         | 
| 43 | 
            +
                ## list item: https://github.com/gettalong/kramdown/blob/master/lib/kramdown/parser/kramdown/list.rb#L49
         | 
| 44 | 
            +
                REGEX_BULLET          = /(?<bullet>[+*-])/i
         | 
| 45 | 
            +
                ## markdown-style block-reference
         | 
| 46 | 
            +
                REGEX_BLOCK           = /.*\s\^#{REGEX_BLOCK_ID_TXT}/i
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                # wikilinks
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                ## inline
         | 
| 51 | 
            +
                REGEX_WIKI_LINK_INLINES = %r{                     # capture indeces
         | 
| 52 | 
            +
                  (#{REGEX_LINK_EMBED})?                          # 0
         | 
| 53 | 
            +
                  (#{REGEX_LINK_TYPE_TXT}#{REGEX_LINK_TYPE})?     # 1
         | 
| 54 | 
            +
                  #{REGEX_LINK_LEFT}
         | 
| 55 | 
            +
                    #{REGEX_FILENAME}                             # 2
         | 
| 56 | 
            +
                    (#{REGEX_LINK_HEADER}#{REGEX_HEADER_TXT})?    # 3
         | 
| 57 | 
            +
                    (#{REGEX_LINK_BLOCK}#{REGEX_BLOCK_ID_TXT})?   # 4
         | 
| 58 | 
            +
                    (#{REGEX_LINK_LABEL}#{REGEX_LABEL_TXT})?      # 5
         | 
| 59 | 
            +
                  #{REGEX_LINK_RIGHT}
         | 
| 60 | 
            +
                }x
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                ## block
         | 
| 63 | 
            +
                ### single
         | 
| 64 | 
            +
                REGEX_SINGLE           = /#{REGEX_LINK_LEFT}#{REGEX_FILENAME_CHARS}#{REGEX_LINK_RIGHT}/i
         | 
| 65 | 
            +
                ### list (comma is responsible for catching the single case)
         | 
| 66 | 
            +
                REGEX_LIST_COMMA       = /((?:\s*#{REGEX_SINGLE}\s*)(?:,\s*#{REGEX_SINGLE}\s*)*)/i
         | 
| 67 | 
            +
                REGEX_LIST_MKDN        = /((?<=\n)\s{0,3}#{REGEX_BULLET}\s#{REGEX_SINGLE}\s*)+/i # (see REGEX_LIST_ITEM)
         | 
| 68 | 
            +
                ### process
         | 
| 69 | 
            +
                REGEX_BLOCK_TYPES      = /((?<!\n)(?:#{REGEX_LIST_COMMA})|#{REGEX_LIST_MKDN})/i
         | 
| 70 | 
            +
                REGEX_WIKI_LINK_BLOCKS = /^\s{0,3}#{REGEX_LINK_TYPE_TXT}#{REGEX_LINK_TYPE}(?:\s*|\G)(?<items>#{REGEX_BLOCK_TYPES})\n/i
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
            end
         | 
| @@ -0,0 +1,312 @@ | |
| 1 | 
            +
            # wiki data structures
         | 
| 2 | 
            +
            require_relative "regex"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Jekyll
         | 
| 5 | 
            +
              module WikiRefs
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # wikilink classes know everything about the original markdown syntax and its semantic meaning
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                class WikiLinkBlock
         | 
| 10 | 
            +
                  attr_reader :link_type, :filenames
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  # parameters ordered by appearance in regex
         | 
| 13 | 
            +
                  def initialize(doc_mngr, context_filename, link_type, bullet_type=nil)
         | 
| 14 | 
            +
                    @doc_mngr ||= doc_mngr
         | 
| 15 | 
            +
                    @context_filename ||= context_filename
         | 
| 16 | 
            +
                    @link_type ||= link_type
         | 
| 17 | 
            +
                    @bullet_type ||= bullet_type
         | 
| 18 | 
            +
                    @filenames = []
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def add_item(filename)
         | 
| 22 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: 'filename' required") if filename.nil? || filename.empty?
         | 
| 23 | 
            +
                    @filenames << filename
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  # data
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def md_regex
         | 
| 29 | 
            +
                    if !is_typed? || !has_filenames? 
         | 
| 30 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: WikiLinkBlock.md_regex error -- type: #{@link_type}, fnames: #{@filenames.inspect}, for: #{@context_filename}")
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                    # comma (including singles)
         | 
| 33 | 
            +
                    if @bullet_type.nil?
         | 
| 34 | 
            +
                      link_type = /#{@link_type}#{REGEX_LINK_TYPE}/i
         | 
| 35 | 
            +
                      tmp_filenames = @filenames.dup
         | 
| 36 | 
            +
                      first_filename = /\s*#{REGEX_LINK_LEFT}#{tmp_filenames.shift()}#{REGEX_LINK_RIGHT}\s*/i
         | 
| 37 | 
            +
                      filename_strs = tmp_filenames.map { |f| /,\s*#{REGEX_LINK_LEFT}#{f}#{REGEX_LINK_RIGHT}\s*/i }
         | 
| 38 | 
            +
                      md_regex = /#{link_type}#{first_filename}#{filename_strs.join('')}\n/i
         | 
| 39 | 
            +
                    # mkdn
         | 
| 40 | 
            +
                    elsif !@bullet_type.match(REGEX_BULLET).nil?
         | 
| 41 | 
            +
                      link_type = /#{@link_type}#{REGEX_LINK_TYPE}\n/i
         | 
| 42 | 
            +
                      filename_strs = @filenames.map { |f| /\s{0,3}#{Regexp.escape(@bullet_type)}\s#{REGEX_LINK_LEFT}#{f}#{REGEX_LINK_RIGHT}\n/i }
         | 
| 43 | 
            +
                      md_regex = /#{link_type}#{filename_strs.join("")}/i
         | 
| 44 | 
            +
                    else
         | 
| 45 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: WikiLinkBlock.bullet_type error: #{@bullet_type}")
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                    return md_regex
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def md_str
         | 
| 51 | 
            +
                    if !is_typed? || !has_filenames?
         | 
| 52 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: WikiLinkBlockList.md_str error -- type: #{@link_type}, fnames: #{@filenames.inspect}, for: #{@context_filename}")
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                    # comma (including singles)
         | 
| 55 | 
            +
                    if @bullet_type.nil?
         | 
| 56 | 
            +
                      link_type = "#{@link_type}::"
         | 
| 57 | 
            +
                      filename_strs = @filenames.map { |f| "\[\[#{f}\]\]," }
         | 
| 58 | 
            +
                      md_str = (link_type + filename_strs.join('')).delete_suffix(",")
         | 
| 59 | 
            +
                    # mkdn
         | 
| 60 | 
            +
                    elsif !@bullet_type.match(REGEX_BULLET).nil?
         | 
| 61 | 
            +
                      link_type = "#{@link_type}::\n"
         | 
| 62 | 
            +
                      filename_strs = @filenames.map { |f| li[0] + " \[\[#{li[1]}\]\]\n" }
         | 
| 63 | 
            +
                      md_str = link_type + filename_strs.join('')
         | 
| 64 | 
            +
                    else
         | 
| 65 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: 'bullet_type' invalid: #{@bullet_type}")
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                    return md_str
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  def urls
         | 
| 71 | 
            +
                    # return @filenames.map { |f| @doc_mngr.get_doc_by_fname(f).url }.compact()
         | 
| 72 | 
            +
                    urls = []
         | 
| 73 | 
            +
                    @filenames.each do |f|
         | 
| 74 | 
            +
                      doc = @doc_mngr.get_doc_by_fname(f)
         | 
| 75 | 
            +
                      urls << doc.url if !doc.nil?
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
                    return urls
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                  
         | 
| 80 | 
            +
                  # 'fm' -> frontmatter
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  def context_fm_data
         | 
| 83 | 
            +
                    return {
         | 
| 84 | 
            +
                      'type' => @link_type,
         | 
| 85 | 
            +
                      'urls' => [self.context_doc.url],
         | 
| 86 | 
            +
                    }
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  def linked_fm_data
         | 
| 90 | 
            +
                    valid_urls = self.urls.select{ |url| @doc_mngr.get_doc_by_url(url) }
         | 
| 91 | 
            +
                    return {
         | 
| 92 | 
            +
                      'type' => @link_type,
         | 
| 93 | 
            +
                      'urls' => valid_urls,
         | 
| 94 | 
            +
                    }
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  def context_doc
         | 
| 98 | 
            +
                    return @doc_mngr.get_doc_by_fname(@context_filename)
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                  def linked_docs
         | 
| 102 | 
            +
                    docs = [] 
         | 
| 103 | 
            +
                    @filenames.each do |f|
         | 
| 104 | 
            +
                      doc = @doc_mngr.get_doc_by_fname(f)
         | 
| 105 | 
            +
                      docs << doc if !doc.nil?
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
                    return docs
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  def missing_doc_filenames
         | 
| 111 | 
            +
                    missing_doc_fnames = [] 
         | 
| 112 | 
            +
                    @filenames.each do |f|
         | 
| 113 | 
            +
                      doc = @doc_mngr.get_doc_by_fname(f)
         | 
| 114 | 
            +
                      missing_doc_fnames << f if doc.nil?
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
                    return missing_doc_fnames
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  # descriptor methods
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  def has_filenames?
         | 
| 122 | 
            +
                    return !@filenames.nil? && !@filenames.empty?
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  def is_typed?
         | 
| 126 | 
            +
                    return !@link_type.nil? && !@link_type.empty?
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  # validation methods
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  def is_valid?
         | 
| 132 | 
            +
                    all_filenames_missing = linked_docs.empty?
         | 
| 133 | 
            +
                    return false if !is_typed? || !has_filenames? || all_filenames_missing
         | 
| 134 | 
            +
                    return true
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                class WikiLinkInline
         | 
| 139 | 
            +
                  attr_reader :link_type, :filename, :header_txt, :block_id
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  FILE_PATH = "file_path"
         | 
| 142 | 
            +
                  FILENAME = "filename"
         | 
| 143 | 
            +
                  HEADER_TXT = "header_txt"
         | 
| 144 | 
            +
                  BLOCK_ID = "block_id"
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  # parameters ordered by appearance in regex
         | 
| 147 | 
            +
                  def initialize(doc_mngr, context_filename, embed, link_type, file_string, header_txt, block_id, label_txt)
         | 
| 148 | 
            +
                    if file_string.include?('/') && file_string[0] == '/'
         | 
| 149 | 
            +
                      @path_type = "absolute"
         | 
| 150 | 
            +
                      @file_path ||= file_string[1...] # remove leading '/' to match `jekyll_collection_doc.relative_path`
         | 
| 151 | 
            +
                      @filename ||= file_string.split('/').last
         | 
| 152 | 
            +
                    elsif file_string.include?('/') && file_string[0] != '/'
         | 
| 153 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: Relative file paths are not yet supported, please use absolute file paths that start with '/' for #{file_string}")
         | 
| 154 | 
            +
                      # todo:
         | 
| 155 | 
            +
                      # @path_type = "relative"
         | 
| 156 | 
            +
                    else
         | 
| 157 | 
            +
                      @filename ||= file_string
         | 
| 158 | 
            +
                    end
         | 
| 159 | 
            +
                    @doc_mngr ||= doc_mngr
         | 
| 160 | 
            +
                    @context_filename ||= context_filename
         | 
| 161 | 
            +
                    @embed ||= embed
         | 
| 162 | 
            +
                    @link_type ||= link_type
         | 
| 163 | 
            +
                    @header_txt ||= header_txt
         | 
| 164 | 
            +
                    @block_id ||= block_id
         | 
| 165 | 
            +
                    @label_txt ||= label_txt
         | 
| 166 | 
            +
                  end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                  # escape square brackets if they appear in label text
         | 
| 169 | 
            +
                  def label_txt
         | 
| 170 | 
            +
                    return @label_txt.sub("[", "\\[").sub("]", "\\]")
         | 
| 171 | 
            +
                  end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                  # data
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                  def md_regex
         | 
| 176 | 
            +
                    regex_embed = embedded? ? REGEX_LINK_EMBED : %r{}
         | 
| 177 | 
            +
                    regex_link_type = is_typed? ? %r{#{@link_type}#{REGEX_LINK_TYPE}} : %r{}
         | 
| 178 | 
            +
                    if !@file_path.nil?
         | 
| 179 | 
            +
                      file_string = described?(FILE_PATH) ? @file_path : ""
         | 
| 180 | 
            +
                      file_string = '/' + file_string if @path_type == "absolute"
         | 
| 181 | 
            +
                    else
         | 
| 182 | 
            +
                      file_string = described?(FILENAME) ? @filename : ""
         | 
| 183 | 
            +
                    end
         | 
| 184 | 
            +
                    if described?(HEADER_TXT)
         | 
| 185 | 
            +
                      header = %r{#{REGEX_LINK_HEADER}#{@header_txt}}
         | 
| 186 | 
            +
                      block = %r{}
         | 
| 187 | 
            +
                    elsif described?(BLOCK_ID)
         | 
| 188 | 
            +
                      header = %r{}
         | 
| 189 | 
            +
                      block = %r{#{REGEX_LINK_BLOCK}#{@block_id}}
         | 
| 190 | 
            +
                    elsif !described?(FILENAME) && !described?(FILE_PATH)
         | 
| 191 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: WikiLinkInline.md_regex error")
         | 
| 192 | 
            +
                    end
         | 
| 193 | 
            +
                    label_ =  labelled? ? %r{#{REGEX_LINK_LABEL}#{label_txt}} : %r{}
         | 
| 194 | 
            +
                    return %r{#{regex_embed}#{regex_link_type}#{REGEX_LINK_LEFT}#{file_string}#{header}#{block}#{label_}#{REGEX_LINK_RIGHT}}
         | 
| 195 | 
            +
                  end
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                  def md_str
         | 
| 198 | 
            +
                    embed = embedded? ? "!" : ""
         | 
| 199 | 
            +
                    link_type = is_typed? ? "#{@link_type}::" : ""
         | 
| 200 | 
            +
                    if !@file_path.nil?
         | 
| 201 | 
            +
                      file_string = described?(FILE_PATH) ? @file_path : ""
         | 
| 202 | 
            +
                      file_string = '/' + file_string if @path_type == "absolute"
         | 
| 203 | 
            +
                    else
         | 
| 204 | 
            +
                      file_string = described?(FILENAME) ? @filename : ""
         | 
| 205 | 
            +
                    end
         | 
| 206 | 
            +
                    if described?(HEADER_TXT)
         | 
| 207 | 
            +
                      header = "\##{@header_txt}"
         | 
| 208 | 
            +
                      block = ""
         | 
| 209 | 
            +
                    elsif described?(BLOCK_ID)
         | 
| 210 | 
            +
                      header = ""
         | 
| 211 | 
            +
                      block = "\#\^#{@block_id}"
         | 
| 212 | 
            +
                    elsif !described?(FILENAME) && !described?(FILE_PATH)
         | 
| 213 | 
            +
                      Jekyll.logger.error("Jekyll-WikiRefs: WikiLinkInline.md_str error")
         | 
| 214 | 
            +
                    end
         | 
| 215 | 
            +
                    label_ = labelled? ? "\|#{@label_txt}" : ""
         | 
| 216 | 
            +
                    return "#{embed}#{link_type}\[\[#{file_string}#{header}#{block}#{label_}\]\]"
         | 
| 217 | 
            +
                  end
         | 
| 218 | 
            +
             | 
| 219 | 
            +
                  # 'fm' -> frontmatter
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                  def context_fm_data
         | 
| 222 | 
            +
                    return {
         | 
| 223 | 
            +
                      'type' => @link_type,
         | 
| 224 | 
            +
                      'url' => self.context_doc.url,
         | 
| 225 | 
            +
                    }
         | 
| 226 | 
            +
                  end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                  def linked_fm_data
         | 
| 229 | 
            +
                    return {
         | 
| 230 | 
            +
                      'type' => @link_type,
         | 
| 231 | 
            +
                      'url' => self.linked_doc.url,
         | 
| 232 | 
            +
                    }
         | 
| 233 | 
            +
                  end
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                  def context_doc
         | 
| 236 | 
            +
                    return @doc_mngr.get_doc_by_fname(@context_filename)
         | 
| 237 | 
            +
                  end
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                  def linked_doc
         | 
| 240 | 
            +
                    # by file path
         | 
| 241 | 
            +
                    return @doc_mngr.get_doc_by_fpath(@file_path) if !@file_path.nil?
         | 
| 242 | 
            +
                    # by filename
         | 
| 243 | 
            +
                    return @doc_mngr.get_doc_by_fname(@filename) if @file_path.nil?
         | 
| 244 | 
            +
                    return nil
         | 
| 245 | 
            +
                  end
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                  def linked_img
         | 
| 248 | 
            +
                    return @doc_mngr.get_image_by_fname(@filename) if self.is_img?
         | 
| 249 | 
            +
                    return nil
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                  # descriptor methods
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                  # def describe
         | 
| 255 | 
            +
                  #   return {
         | 
| 256 | 
            +
                  #     'level' => level,
         | 
| 257 | 
            +
                  #     'labelled' => labelled?,
         | 
| 258 | 
            +
                  #     'embedded' => embedded?,
         | 
| 259 | 
            +
                  #     'typed_link' => is_typed?,
         | 
| 260 | 
            +
                  #   }
         | 
| 261 | 
            +
                  # end
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                  def labelled?
         | 
| 264 | 
            +
                    return !@label_txt.nil? && !@label_txt.empty?
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                  def is_typed?
         | 
| 268 | 
            +
                    return !@link_type.nil? && !@link_type.empty?
         | 
| 269 | 
            +
                  end
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                  def embedded?
         | 
| 272 | 
            +
                    return !@embed.nil? && @embed == "!"
         | 
| 273 | 
            +
                  end
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                  def is_img?
         | 
| 276 | 
            +
                    # github supported image formats: https://docs.github.com/en/github/managing-files-in-a-repository/working-with-non-code-files/rendering-and-diffing-images
         | 
| 277 | 
            +
                    return SUPPORTED_IMG_FORMATS.any?{ |ext| ext == File.extname(@filename).downcase }
         | 
| 278 | 
            +
                  end
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                  def is_img_svg?
         | 
| 281 | 
            +
                    return File.extname(@filename).downcase == ".svg"
         | 
| 282 | 
            +
                  end
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                  # this method helps to make the 'WikiLinkInline.level' code read like a clean truth table.
         | 
| 285 | 
            +
                  def described?(chunk)
         | 
| 286 | 
            +
                    return (!@file_path.nil? && !@file_path.empty?) if chunk == FILE_PATH
         | 
| 287 | 
            +
                    return (!@filename.nil? && !@filename.empty?) if chunk == FILENAME
         | 
| 288 | 
            +
                    return (!@header_txt.nil? && !@header_txt.empty?) if chunk == HEADER_TXT
         | 
| 289 | 
            +
                    return (!@block_id.nil? && !@block_id.empty?) if chunk == BLOCK_ID
         | 
| 290 | 
            +
                    Jekyll.logger.error("Jekyll-WikiRefs: There is no link level '#{chunk}' in the WikiLink Class")
         | 
| 291 | 
            +
                  end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                  def level
         | 
| 294 | 
            +
                    return "file_path" if described?(FILE_PATH) && described?(FILENAME) && !described?(HEADER_TXT) && !described?(BLOCK_ID)
         | 
| 295 | 
            +
                    return "filename"  if !described?(FILE_PATH) && described?(FILENAME) && !described?(HEADER_TXT) && !described?(BLOCK_ID)
         | 
| 296 | 
            +
                    return "header"    if (described?(FILE_PATH) || described?(FILENAME)) && described?(HEADER_TXT) && !described?(BLOCK_ID)
         | 
| 297 | 
            +
                    return "block"     if (described?(FILE_PATH) || described?(FILENAME)) && !described?(HEADER_TXT) && described?(BLOCK_ID)
         | 
| 298 | 
            +
                    return "invalid"
         | 
| 299 | 
            +
                  end
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                  # validation methods
         | 
| 302 | 
            +
             | 
| 303 | 
            +
                  def is_valid?
         | 
| 304 | 
            +
                    return false if !@doc_mngr.file_exists?(@filename, @file_path)
         | 
| 305 | 
            +
                    return false if (self.level == "header") && !@doc_mngr.doc_has_header?(self.linked_doc, @header_txt)
         | 
| 306 | 
            +
                    return false if (self.level == "block") && !@doc_mngr.doc_has_block_id?(self.linked_doc, @block_id)
         | 
| 307 | 
            +
                    return true
         | 
| 308 | 
            +
                  end
         | 
| 309 | 
            +
                end
         | 
| 310 | 
            +
             | 
| 311 | 
            +
              end
         | 
| 312 | 
            +
            end
         | 
    
        data/lib/jekyll-wikirefs.rb
    CHANGED
    
    | @@ -2,9 +2,29 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            require_relative "jekyll-wikirefs/version"
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 5 | 
            +
            # setup config
         | 
| 6 | 
            +
            require_relative "jekyll-wikirefs/config"
         | 
| 7 | 
            +
            Jekyll::Hooks.register :site, :after_init do |site|
         | 
| 8 | 
            +
              # global '$wiki_conf' to ensure that all local jekyll plugins
         | 
| 9 | 
            +
              # are reading from the same configuration
         | 
| 10 | 
            +
              # (global var is not ideal, but is DRY)
         | 
| 11 | 
            +
              $wiki_conf = Jekyll::WikiRefs::PluginConfig.new(site.config)
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            # setup docs (based on configs)
         | 
| 15 | 
            +
            require_relative "jekyll-wikirefs/patch/doc_manager"
         | 
| 16 | 
            +
            Jekyll::Hooks.register :site, :post_read do |site|
         | 
| 17 | 
            +
              if !$wiki_conf.disabled?
         | 
| 18 | 
            +
                site.doc_mngr = Jekyll::WikiRefs::DocManager.new(site)
         | 
| 9 19 | 
             
              end
         | 
| 10 20 | 
             
            end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            # parse wikilinks / generate metadata
         | 
| 23 | 
            +
            require_relative "jekyll-wikirefs/plugins/generator"
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            # convert weblinks
         | 
| 26 | 
            +
            require_relative "jekyll-wikirefs/plugins/converter"
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            # hook up liquid filters
         | 
| 29 | 
            +
            require_relative "jekyll-wikirefs/plugins/filter"
         | 
| 30 | 
            +
            Liquid::Template.register_filter(Jekyll::WikiRefs::TypeFilters)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: jekyll-wikirefs
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.14
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - manunamz
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-09-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: jekyll
         | 
| @@ -24,6 +24,20 @@ dependencies: | |
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: 4.2.0
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: nokogiri
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: 1.13.3
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: 1.13.3
         | 
| 27 41 | 
             
            description:
         | 
| 28 42 | 
             
            email:
         | 
| 29 43 | 
             
            - manunamz@pm.me
         | 
| @@ -32,14 +46,25 @@ extensions: [] | |
| 32 46 | 
             
            extra_rdoc_files: []
         | 
| 33 47 | 
             
            files:
         | 
| 34 48 | 
             
            - lib/jekyll-wikirefs.rb
         | 
| 49 | 
            +
            - lib/jekyll-wikirefs/config.rb
         | 
| 50 | 
            +
            - lib/jekyll-wikirefs/patch/context.rb
         | 
| 51 | 
            +
            - lib/jekyll-wikirefs/patch/doc_manager.rb
         | 
| 52 | 
            +
            - lib/jekyll-wikirefs/patch/site.rb
         | 
| 53 | 
            +
            - lib/jekyll-wikirefs/plugins/converter.rb
         | 
| 54 | 
            +
            - lib/jekyll-wikirefs/plugins/filter.rb
         | 
| 55 | 
            +
            - lib/jekyll-wikirefs/plugins/generator.rb
         | 
| 56 | 
            +
            - lib/jekyll-wikirefs/util/link_index.rb
         | 
| 57 | 
            +
            - lib/jekyll-wikirefs/util/parser.rb
         | 
| 58 | 
            +
            - lib/jekyll-wikirefs/util/regex.rb
         | 
| 59 | 
            +
            - lib/jekyll-wikirefs/util/wikiref.rb
         | 
| 35 60 | 
             
            - lib/jekyll-wikirefs/version.rb
         | 
| 36 | 
            -
            homepage: https://github.com/ | 
| 61 | 
            +
            homepage: https://github.com/wikibonsai/jekyll-wikirefs
         | 
| 37 62 | 
             
            licenses:
         | 
| 38 63 | 
             
            - MIT
         | 
| 39 64 | 
             
            metadata:
         | 
| 40 | 
            -
              homepage_uri: https://github.com/ | 
| 41 | 
            -
              source_code_uri: https://github.com/ | 
| 42 | 
            -
              changelog_uri: https://github.com/ | 
| 65 | 
            +
              homepage_uri: https://github.com/wikibonsai/jekyll-wikirefs
         | 
| 66 | 
            +
              source_code_uri: https://github.com/wikibonsai/jekyll-wikirefs
         | 
| 67 | 
            +
              changelog_uri: https://github.com/wikibonsai/jekyll-wikirefs/blob/main/CHANGELOG.md
         | 
| 43 68 | 
             
            post_install_message:
         | 
| 44 69 | 
             
            rdoc_options: []
         | 
| 45 70 | 
             
            require_paths:
         | 
| @@ -55,8 +80,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 55 80 | 
             
                - !ruby/object:Gem::Version
         | 
| 56 81 | 
             
                  version: '0'
         | 
| 57 82 | 
             
            requirements: []
         | 
| 58 | 
            -
            rubygems_version: 3.4. | 
| 83 | 
            +
            rubygems_version: 3.4.10
         | 
| 59 84 | 
             
            signing_key:
         | 
| 60 85 | 
             
            specification_version: 4
         | 
| 61 | 
            -
            summary:  | 
| 86 | 
            +
            summary: Add [[wikirefs]] support (in markdown files) for jekyll.
         | 
| 62 87 | 
             
            test_files: []
         |