jekyll-namespaces 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []