jekyll-wikilinks 0.0.4 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f7349631b7b0ce9484512d06a368ac2808d3d3c64bdf7ccd66e845dc5f41380
4
- data.tar.gz: 87c6d80c73e79c260d3b58acb8cc2e3c62dc0c29c2574a9c54bd5f476e70e8cf
3
+ metadata.gz: 9faa067220a9b3603654fbcf2fc240fd66b9e143ad197700e5773c9c1876e5d0
4
+ data.tar.gz: fd3b93e960ed6dc0f7e2e7cc09a6ec7ee3d1742a5e377c801fe2d054927d0f2a
5
5
  SHA512:
6
- metadata.gz: 05a261827c04023b8072f85a566c88abad259885e6af6fd85909d61f93200849994de360076023b383f2abab7f3ad4d92e4e755f0ea9cd487e1c59692786d3bf
7
- data.tar.gz: 3b3862a5e00356d5227e39a346405e238255fe4cc4275c1f095a2ca828e62d7e1f3468035c99278c95dcbe2a340521588dd2ebc64571a9bec963affc19e9328e
6
+ metadata.gz: ca52556545cfaf6d09be217fe824e1e07f7d7621b4a8ca06d4e9c62dc85df95561f5c00468cf302d978bb2fd5b61548d14ac860ed746d91d2a25fa5e9d1cccee
7
+ data.tar.gz: cba704245f83e5eeed86b21a20fd26a7713312b76e4ce5ef44e60dfc1b55020c2af6d8c0de4bd258a927f3131d313312964ecc7a55d94a83dcf53beeeeb48ff7
@@ -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,75 @@
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 | rel_type: "author" %}
42
+ def rel_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.keys.include?('url')
52
+ if l['type'].to_s == link_type.to_s
53
+ docs = site.documents.select{ |d| d.url == l['url'] }
54
+ if !doc.nil? && doc.size != 1
55
+ links_of_type << l
56
+ end
57
+ end
58
+ elsif l.keys.include?('urls')
59
+ l['urls'].each do |lurl|
60
+ docs = site.documents.select{ |d| d.url == lurl }
61
+ if !doc.nil? && doc.size != 1
62
+ links_of_type << lurl
63
+ end
64
+ end
65
+ else
66
+ Jekyll.logge.error("Jekyll-Wikilinks: In 'rel_type' filter, 'links' do not have 'url' or 'urls'")
67
+ end
68
+ end
69
+ return links_of_type.uniq
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ 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