jekyll-wikilinks 0.0.5 → 0.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f6d8e47bdeb17eba9c47c70c35ed2622fe27ab4b6280fa1838d6c69f24723b9
4
- data.tar.gz: bfb12748858bd1c810b5613e1c2f516e64d65772082a680e24b3c796f37b6e80
3
+ metadata.gz: eb34f22e418709f097d81cbcd13a0917ab903247145bb0db4846a346c0b86f38
4
+ data.tar.gz: 62bff9a52a5e965a542071a0d577ea3a962c3acd604643d0955de449e924de7a
5
5
  SHA512:
6
- metadata.gz: 0e6483f4844cc0b0d8fd43be71040bce438b5357972e2139660ca1979a2b42843af2355577a46dc0f119902e281fb244b4fc53d8db7f8a3760889073be08db36
7
- data.tar.gz: 0af4216fa1fae8dbc086e785663d5ab4884afe83924c3b8fe5ef0ccb98fffa508dfc767b9c057b1dfec17efba36e3202eb494751ac53731209130c2108e43454
6
+ metadata.gz: '087c441fc74aa0da7659bf070eb3c2b079033d8a567002e00603825498afb6ef30d259372e18799506e4fc2b7b3cc3c3501f0a67dd4e559eefd463214ee6a502'
7
+ data.tar.gz: 8abe1efd8a9b2eecd13b1d83599c09ee29db9e2e943ed097bf49aa000fd1a6caea2c6cedc1bb05fdce6fb4bfa3d1852b01221420e91f647d8aff61b7bce6ac50
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+ require "jekyll"
3
+
4
+ module Jekyll
5
+ module WikiLinks
6
+
7
+ class PluginConfig
8
+
9
+ ATTR_KEY = "attributes"
10
+ CONFIG_KEY = "wikilinks"
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-Wikilinks: 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-Wikilinks: As of 0.0.3, 'wikilinks_collection' is no longer used for configs. jekyll-wikilinks 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-Wikilinks: 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-Wikilinks: 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,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module WikiLinks
5
+
6
+ class Context
7
+ attr_reader :site
8
+
9
+ def initialize(site)
10
+ @site = site
11
+ end
12
+
13
+ def registers
14
+ { :site => site }
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+ require_relative "../util/regex"
3
+
4
+ module Jekyll
5
+ module WikiLinks
6
+
7
+ #
8
+ # this class is responsible for answering any questions
9
+ # related to jekyll markdown documents
10
+ # that are meant to be processed by the wikilinks plugin.
11
+ #
12
+ # the following methods are specifically to address two things:
13
+ # 1. ruby's 'find' / 'detect' function does not throw errors if
14
+ # there are multiple matches. fail fast, i want to know if there
15
+ # are duplicates.
16
+ # (not using sets because i don't want to clobber existing documents)
17
+ # 2. handle all jekyll documents in one place. i don't want to
18
+ # have to filter all documents for target markdown documents
19
+ # every time i need to check if a file exists.
20
+ #
21
+ # there is probably a better way to do this...i would prefer to have
22
+ # a plugin-wide function that just wraps all of this and can be called
23
+ # from anywhere in the plugin...but ruby is not a functional language...
24
+ # gotta have classes...
25
+ #
26
+ class DocManager
27
+ CONVERTER_CLASS = Jekyll::Converters::Markdown
28
+
29
+ def initialize(site)
30
+ return if $wiki_conf.disabled?
31
+
32
+ markdown_converter = site.find_converter_instance(CONVERTER_CLASS)
33
+ # filter docs based on configs
34
+ docs = []
35
+ docs += site.pages if !$wiki_conf.exclude?(:pages)
36
+ docs += site.docs_to_write.filter { |d| !$wiki_conf.exclude?(d.type) }
37
+ @md_docs = docs.filter { |doc| markdown_converter.matches(doc.extname) }
38
+ if @md_docs.nil? || @md_docs.empty?
39
+ Jekyll.logger.warn("Jekyll-Wikilinks: No documents to process.")
40
+ end
41
+
42
+ @static_files ||= site.static_files
43
+ end
44
+
45
+ # accessors
46
+
47
+ def all
48
+ return @md_docs
49
+ end
50
+
51
+ def get_doc_by_fname(filename)
52
+ Jekyll.logger.error("Jekyll-Wikilinks: Must provide a 'filename'") if filename.nil? || filename.empty?
53
+ docs = @md_docs.select{ |d| File.basename(d.basename, File.extname(d.basename)) == filename }
54
+ return nil if docs.nil? || docs.empty? || docs.size > 1
55
+ return docs[0]
56
+ end
57
+
58
+ def get_doc_by_url(url)
59
+ Jekyll.logger.error("Jekyll-Wikilinks: Must provide a 'url'") if url.nil? || url.empty?
60
+ docs = @md_docs.select{ |d| d.url == url }
61
+ return nil if docs.nil? || docs.empty? || docs.size > 1
62
+ return docs[0]
63
+ end
64
+
65
+ def get_doc_content(filename)
66
+ doc = self.get_doc_by_fname(filename)
67
+ return nil if docs.nil?
68
+ return doc.content
69
+ end
70
+
71
+ def get_image_by_fname(filename)
72
+ Jekyll.logger.error("Jekyll-Wikilinks: Must provide a 'filename'") if filename.nil? || filename.empty?
73
+ return nil if @static_files.size == 0 || !SUPPORTED_IMG_FORMATS.any?{ |ext| ext == File.extname(filename).downcase }
74
+ docs = @static_files.select{ |d| File.basename(d.relative_path) == filename }
75
+ return nil if docs.nil? || docs.empty? || docs.size > 1
76
+ return docs[0]
77
+ end
78
+
79
+ # validators
80
+
81
+ def file_exists?(filename)
82
+ Jekyll.logger.error("Jekyll-Wikilinks: Must provide a 'filename'") if filename.nil? || filename.empty?
83
+ docs = @md_docs.select{ |d| File.basename(d.basename, File.extname(d.basename)) == filename }
84
+ docs += @static_files.select{ |d| File.basename(d.relative_path) == filename }
85
+ return false if docs.nil? || docs.empty? || docs.size > 1
86
+ return true
87
+ end
88
+
89
+ def doc_has_header?(doc, header)
90
+ Jekyll.logger.error("Jekyll-Wikilinks: Must provide a 'header'") if header.nil? || header.empty?
91
+ # leading + trailing whitespace is ignored when matching headers
92
+ header_results = doc.content.scan(REGEX_ATX_HEADER).flatten.map { |htxt| htxt.downcase.strip }
93
+ setext_header_results = doc.content.scan(REGEX_SETEXT_HEADER).flatten.map { |htxt| htxt.downcase.strip }
94
+ return header_results.include?(header.downcase.strip) || setext_header_results.include?(header.downcase.strip)
95
+ end
96
+
97
+ def doc_has_block_id?(doc, block_id)
98
+ Jekyll.logger.error("Jekyll-Wikilinks: Must provide a 'block_id'") if block_id.nil? || block_id.empty?
99
+ # leading + trailing whitespace is ignored when matching blocks
100
+ block_id_results = doc.content.scan(REGEX_BLOCK).flatten.map { |bid| bid.strip }
101
+ return block_id_results.include?(block_id)
102
+ end
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require "jekyll"
3
+
4
+ # appending to built-in jekyll site object to pass data to jekyll-graph
5
+
6
+ module Jekyll
7
+
8
+ class Site
9
+ attr_accessor :doc_mngr, :link_index, :wiki_parser
10
+ end
11
+
12
+ end
@@ -0,0 +1,53 @@
1
+ require "jekyll"
2
+ require "nokogiri"
3
+
4
+ module Jekyll
5
+ module WikiLinks
6
+
7
+ class WebLinkConverter < Jekyll::Converter
8
+ priority :low
9
+
10
+ # config
11
+ CSS_KEY = "css"
12
+ CONFIG_KEY = "wikilinks"
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 WikiLinks
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-Wikilinks: 'links' invalid") if links.nil?
13
+ Jekyll.logger.error("Jekyll-Wikilinks: '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-Wikilinks: 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-Wikilinks: 'links' invalid") if links.nil?
44
+ Jekyll.logger.error("Jekyll-Wikilinks: '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-Wikilinks: 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 WikiLinks
12
+
13
+ class Generator < Jekyll::Generator
14
+
15
+ def generate(site)
16
+ return if $wiki_conf.disabled?
17
+
18
+ @site ||= site
19
+ @context ||= Jekyll::WikiLinks::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,89 @@
1
+ require_relative 'regex'
2
+
3
+ module Jekyll
4
+ module WikiLinks
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
+ # blocks
27
+ wikilink_blocks.each do |wlbl|
28
+ if wlbl.is_valid?
29
+ # attributes
30
+ target_attr = @index[doc.url].attributes.detect { |atr| atr['type'] == wlbl.link_type }
31
+ ## create
32
+ if target_attr.nil?
33
+ @index[doc.url].attributes << wlbl.linked_fm_data
34
+ ## append
35
+ else
36
+ target_attr['urls'] += wlbl.urls
37
+ end
38
+ # attributed
39
+ wlbl.linked_docs.each do |linked_doc|
40
+ target_attr = @index[linked_doc.url].attributed.detect { |atr| atr['type'] == wlbl.link_type }
41
+ ## create
42
+ if target_attr.nil?
43
+ @index[linked_doc.url].attributed << wlbl.context_fm_data
44
+ ## append
45
+ else
46
+ target_attr['urls'] << doc.url
47
+ end
48
+ end
49
+ else
50
+ wlbl.filenames.each do |fn|
51
+ @index[doc.url].missing << fn
52
+ end
53
+ end
54
+ end
55
+ # inlines
56
+ wikilink_inlines.each do |wlil|
57
+ if !wlil.is_img?
58
+ if wlil.is_valid?
59
+ # forelink
60
+ @index[doc.url].forelinks << wlil.linked_fm_data
61
+ # backlink
62
+ @index[wlil.linked_doc.url].backlinks << wlil.context_fm_data
63
+ else
64
+ @index[doc.url].missing << wlil.filename
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ # def remove_baseurl(url)
71
+ # return url.gsub(@baseurl, '') if !@baseurl.nil?
72
+ # return url
73
+ # end
74
+
75
+ class DocLinks
76
+ attr_accessor :attributes, :attributed, :backlinks, :forelinks, :missing
77
+
78
+ def initialize
79
+ @attributed = [] # block typed backlinks; { 'type' => str, 'urls' => [ str ] }
80
+ @attributes = [] # block typed forelinks; { 'type' => str, 'urls' => [ str ] }
81
+ @backlinks = [] # inline typed and basic backlinks; { 'type' => str, 'url' => str }
82
+ @forelinks = [] # inline typed and basic forelinks; { 'type' => str, 'url' => str }
83
+ @missing = [] # missing forelinks + attributes; ( built from (missing) filenames )
84
+ end
85
+ end
86
+ end
87
+
88
+ end
89
+ end