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 +7 -0
- data/lib/jekyll-namespaces.rb +238 -0
- data/lib/jekyll-namespaces/context.rb +13 -0
- data/lib/jekyll-namespaces/node.rb +22 -0
- data/lib/jekyll-namespaces/version.rb +5 -0
- metadata +50 -0
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,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
|
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: []
|