jekyll-namespaces 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6b18126c3527c30dd23fe45e39414c918bcc046bcc85a9955e43476457298be2
4
+ data.tar.gz: 0a61c1b500793f8eded07a8a55575b25f7e6e9983dbac9df4a77c0591c0c220c
5
+ SHA512:
6
+ metadata.gz: 5ff7599ba50975db33b0d72f14e41606e5b9c0d21126732271dfbc152a08d4c9c9a9dcc422a22bf671bf864ebc637ce14bc58f25c1cd792174ea22b6f64894e5
7
+ data.tar.gz: 9f3c5053343f86090eac806c00bcf806034d34fb31ddbb64f17efda9060bd17bf78378482f84f09902bc557b3581bbcc2c2eb2b24ade705bd516136d08e15656
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+ require "jekyll"
3
+
4
+ require_relative "jekyll-namespaces/context"
5
+ require_relative "jekyll-namespaces/node"
6
+ require_relative "jekyll-namespaces/version"
7
+
8
+ module JekyllNamespaces
9
+ class Generator < Jekyll::Generator
10
+ attr_accessor :site, :config
11
+
12
+ # Use Jekyll's native relative_url filter
13
+ include Jekyll::Filters::URLFilters
14
+
15
+ CONVERTER_CLASS = Jekyll::Converters::Markdown
16
+ # config
17
+ CONFIG_KEY = "namespaces"
18
+ ENABLED_KEY = "enabled"
19
+ INCLUDE_KEY = "include"
20
+ # graph config
21
+ GRAPH_DATA_KEY = "d3_graph_data"
22
+ ENABLED_GRAPH_DATA_KEY = "enabled"
23
+ EXCLUDE_GRAPH_KEY = "exclude"
24
+ GRAPH_ASSETS_LOCATION_KEY = "path"
25
+
26
+ def initialize(config)
27
+ @config ||= config
28
+ @testing ||= config['testing'] if config.keys.include?('testing')
29
+ end
30
+
31
+ def generate(site)
32
+ return if disabled?
33
+
34
+ # setup site
35
+ @site = site
36
+ @context ||= Context.new(site)
37
+
38
+ # setup markdown docs
39
+ docs = []
40
+ docs += site.pages if include?(:pages)
41
+ docs += site.docs_to_write.filter { |d| include?(d.type) }
42
+ @md_docs = docs.filter {|doc| markdown_extension?(doc.extname) }
43
+
44
+ # setup tree
45
+ root_doc = @md_docs.detect {|doc| doc.data['slug'] == 'root' }
46
+ root = Node.new(root_doc.data['id'], 'root', root_doc.data['title'], root_doc)
47
+ # build tree
48
+ @md_docs.each do |cur_doc|
49
+ # add path to tree
50
+ if !cur_doc.data['slug'].nil? and cur_doc.data['slug'] != 'root'
51
+ self.add_path(root, cur_doc)
52
+ end
53
+ end
54
+
55
+ # print_tree(root)
56
+
57
+ # generate tree metadata
58
+ @md_docs.each do |cur_doc|
59
+ if !excluded_in_graph?(cur_doc)
60
+ # TODO: cur_doc.data['namespace'] = cur_doc.basename_without_ext
61
+ cur_doc.data['namespace'] = cur_doc.basename[0...-3]
62
+ cur_doc.data['ancestors'], cur_doc.data['children'] = self.find_doc_immediate_relatives(cur_doc, root)
63
+ end
64
+ end
65
+ # graph
66
+ if !disabled_graph_data?
67
+ self.write_graph(root)
68
+ end
69
+ end
70
+
71
+ # config helpers
72
+
73
+ def disabled?
74
+ option(ENABLED_KEY) == false
75
+ end
76
+
77
+ def include?(type)
78
+ return false unless option(INCLUDE_KEY)
79
+ return option(INCLUDE_KEY).include?(type.to_s)
80
+ end
81
+
82
+ def markdown_extension?(extension)
83
+ markdown_converter.matches(extension)
84
+ end
85
+
86
+ def markdown_converter
87
+ @markdown_converter ||= @site.find_converter_instance(CONVERTER_CLASS)
88
+ end
89
+
90
+ def option(key)
91
+ config[CONFIG_KEY] && config[CONFIG_KEY][key]
92
+ end
93
+
94
+ # graph config helpers
95
+
96
+ def disabled_graph_data?
97
+ option_graph(ENABLED_GRAPH_DATA_KEY) == false
98
+ end
99
+
100
+ def excluded_in_graph?(type)
101
+ return false unless option_graph(EXCLUDE_GRAPH_KEY)
102
+ return option_graph(EXCLUDE_GRAPH_KEY).include?(type.to_s)
103
+ end
104
+
105
+ def has_custom_assets_path?
106
+ return !!option_graph(GRAPH_ASSETS_LOCATION_KEY)
107
+ end
108
+
109
+ def option_graph(key)
110
+ config[GRAPH_DATA_KEY] && config[GRAPH_DATA_KEY][key]
111
+ end
112
+
113
+ # helpers
114
+
115
+ # add unique path for the given doc to tree (node-class).
116
+ def add_path(node, doc, depth=1)
117
+ chunked_namespace = doc.data['slug'].split(/\s|\./)
118
+ # handle doc if the given node was not root and we are at depth
119
+ if depth == chunked_namespace.length
120
+ cur_nd_namespace = 'root' + '.' + doc.data['slug']
121
+ cur_nd_id = doc.data['id']
122
+ cur_nd_title = doc.data['title']
123
+ # create node if one does not exist
124
+ unless node.children.any?{ |c| c.namespace == cur_nd_namespace }
125
+ new_node = Node.new(cur_nd_id, cur_nd_namespace, cur_nd_title, doc)
126
+ node.children << new_node
127
+ # fill-in node if one already exists
128
+ else
129
+ cur_node = node.children.detect {|c| c.namespace == cur_nd_namespace }
130
+ cur_node.id = cur_nd_id
131
+ cur_node.title = cur_nd_title
132
+ cur_node.doc = doc
133
+ end
134
+ return
135
+ # create temp node and recurse
136
+ else
137
+ cur_namespace = 'root' + '.' + chunked_namespace[0..(depth - 1)].join('.')
138
+ unless node.children.any?{ |c| c.namespace == cur_namespace }
139
+ new_node = Node.new('', cur_namespace, '', '')
140
+ node.children << new_node
141
+ else
142
+ new_node = node.children.detect {|c| c.namespace == cur_namespace }
143
+ end
144
+ end
145
+ self.add_path(new_node, doc, depth + 1)
146
+ end
147
+
148
+ # find the parent and children of the 'target_doc'.
149
+ # ('node' as in the current node, which first is root.)
150
+ def find_doc_immediate_relatives(target_doc, node, ancestors=[])
151
+ if target_doc.data['id'] == node.id
152
+ children = []
153
+ node.children.each do |child|
154
+ if child.id == ''
155
+ children << {
156
+ 'id' => '',
157
+ 'title' => child.namespace.match('([^.]*$)')[0].gsub('-', ' ')
158
+ }
159
+ else
160
+ children << child.doc
161
+ end
162
+ end
163
+ return ancestors, children
164
+ else
165
+ if node.id == ''
166
+ ancestors << {
167
+ 'id' => '',
168
+ 'title' => node.namespace.match('([^.]*$)')[0].gsub('-', ' ')
169
+ }
170
+ else
171
+ ancestors << node.doc
172
+ end
173
+ results = []
174
+ node.children.each do |child_node|
175
+ results.concat self.find_doc_immediate_relatives(target_doc, child_node, ancestors.clone)
176
+ end
177
+ return results.select { |r| !r.nil? }
178
+ end
179
+ end
180
+
181
+ # ...for debugging
182
+ def print_tree(node, ancestors=[])
183
+ Jekyll.logger.warn "Ancestors: ", ancestors.length
184
+ Jekyll.logger.warn node
185
+ Jekyll.logger.warn "Children: ", node.children
186
+ ancestors.append(node.id)
187
+ node.children.each do |child_node|
188
+ self.print_tree(child_node, ancestors.clone)
189
+ end
190
+ end
191
+
192
+ # graph helpers
193
+
194
+ # convert tree (node-class) to json
195
+ def tree_to_json(baseurl, node, json_node={})
196
+ if node.id.empty?
197
+ Jekyll.logger.warn "Tree node missing: ", node.namespace
198
+ label = node.namespace.match('([^.]*$)')[0].gsub('-', ' ')
199
+ node_url = ''
200
+ else
201
+ label = node.title
202
+ node_url = relative_url(node.doc.url)
203
+ end
204
+ json_children = []
205
+ node.children.each do |child|
206
+ new_child = self.tree_to_json(baseurl, child)
207
+ json_children.append(new_child)
208
+ end
209
+ json_node = {
210
+ # "id": node.id,
211
+ "id": node_url,
212
+ "namespace": node.namespace,
213
+ "label": label,
214
+ "children": json_children,
215
+ "url": node_url,
216
+ }
217
+ return json_node
218
+ end
219
+
220
+ def write_graph(root)
221
+ assets_path = has_custom_assets_path? ? option_graph(GRAPH_ASSETS_LOCATION_KEY) : "/assets"
222
+ if !File.directory?(File.join(site.source, assets_path))
223
+ Jekyll.logger.error "Assets location does not exist, please create required directories for path: ", assets_path
224
+ end
225
+ # from: https://github.com/jekyll/jekyll/issues/7195#issuecomment-415696200
226
+ static_file = Jekyll::StaticFile.new(site, site.source, assets_path, "graph-tree.json")
227
+ json_formatted_tree = self.tree_to_json(@site.baseurl, root)
228
+ File.write(@site.source + static_file.relative_path, JSON.dump(
229
+ json_formatted_tree
230
+ ))
231
+ # tests fail without manually adding the static file, but actual site builds seem to do ok
232
+ # ...although there does seem to be a race condition which causes a rebuild to be necessary in order to detect the graph data file
233
+ if @testing
234
+ @site.static_files << static_file if !@site.static_files.include?(static_file)
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Context
4
+ attr_reader :site
5
+
6
+ def initialize(site)
7
+ @site = site
8
+ end
9
+
10
+ def registers
11
+ { :site => site }
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # helper class for tree-building.
4
+ class Node
5
+ attr_accessor :id, :namespace, :title, :children, :doc
6
+
7
+ def initialize(id, namespace, title, doc)
8
+ @id = id
9
+ @children = []
10
+ @namespace = namespace
11
+ @title = title
12
+ @doc = doc
13
+ end
14
+
15
+ def type
16
+ return doc.type
17
+ end
18
+
19
+ def to_s
20
+ "namespace: #{@namespace}"
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JekyllNamespaces
4
+ VERSION = "0.0.1"
5
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-namespaces
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - manunamz
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-07-23 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - manunamz@pm.me
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/jekyll-namespaces.rb
21
+ - lib/jekyll-namespaces/context.rb
22
+ - lib/jekyll-namespaces/node.rb
23
+ - lib/jekyll-namespaces/version.rb
24
+ homepage: https://github.com/manunamz/jekyll-namespaces
25
+ licenses:
26
+ - MIT
27
+ metadata:
28
+ homepage_uri: https://github.com/manunamz/jekyll-namespaces
29
+ source_code_uri: https://github.com/manunamz/jekyll-namespaces
30
+ changelog_uri: https://github.com/manunamz/jekyll-namespaces/blob/main/CHANGELOG.md
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 2.4.0
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubygems_version: 3.2.17
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Add jekyll support for namespaced.filenames (in markdown files).
50
+ test_files: []