yarrow 0.5.0 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +23 -0
  3. data/.gitignore +2 -1
  4. data/README.md +13 -19
  5. data/Rakefile +15 -1
  6. data/lib/yarrow.rb +17 -6
  7. data/lib/yarrow/config.rb +59 -0
  8. data/lib/yarrow/configuration.rb +35 -63
  9. data/lib/yarrow/content/collection_expander.rb +218 -0
  10. data/lib/yarrow/content/content_type.rb +42 -0
  11. data/lib/yarrow/content/graph.rb +13 -21
  12. data/lib/yarrow/content/source.rb +11 -0
  13. data/lib/yarrow/extensions.rb +1 -0
  14. data/lib/yarrow/extensions/mementus.rb +24 -0
  15. data/lib/yarrow/output/context.rb +0 -4
  16. data/lib/yarrow/output/generator.rb +2 -2
  17. data/lib/yarrow/output/web/indexed_file.rb +39 -0
  18. data/lib/yarrow/process/expand_content.rb +12 -0
  19. data/lib/yarrow/process/extract_source.rb +12 -0
  20. data/lib/yarrow/process/project_manifest.rb +20 -0
  21. data/lib/yarrow/process/step_processor.rb +43 -0
  22. data/lib/yarrow/process/workflow.rb +36 -0
  23. data/lib/yarrow/schema.rb +132 -0
  24. data/lib/yarrow/schema/validations/array.rb +0 -0
  25. data/lib/yarrow/schema/validations/object.rb +0 -0
  26. data/lib/yarrow/schema/validations/string.rb +0 -0
  27. data/lib/yarrow/server.rb +8 -5
  28. data/lib/yarrow/source/graph.rb +6 -0
  29. data/lib/yarrow/symbols.rb +19 -0
  30. data/lib/yarrow/tools/content_utils.rb +74 -0
  31. data/lib/yarrow/tools/front_matter.rb +4 -2
  32. data/lib/yarrow/version.rb +3 -2
  33. data/lib/yarrow/web/html_document.rb +9 -0
  34. data/lib/yarrow/web/manifest.rb +9 -0
  35. data/lib/yarrow/web/static_asset.rb +9 -0
  36. data/lib/yarrow/web/template.rb +9 -0
  37. data/yarrow.gemspec +6 -7
  38. metadata +52 -48
  39. data/.travis.yml +0 -16
  40. data/lib/yarrow/html.rb +0 -1
  41. data/lib/yarrow/html/asset_tags.rb +0 -59
  42. data/lib/yarrow/html/content_tags.rb +0 -7
  43. data/lib/yarrow/tools/output_file.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7360a9c100d2a45cbf57a77fcec6a02f21156a6af46d22a6c438dd43ab07557f
4
- data.tar.gz: c71c2e48c2b3118b1d3d734430925f9bee7981a89462df9a8e05bfc5d12fc3c7
3
+ metadata.gz: 4be44c931a92757c5be67d594977711597a71560b8ea37f6ea666842c128ddd8
4
+ data.tar.gz: c8af0e56a102cec9b111d921a5333c703bd341084ebd839fb4eb870728530dff
5
5
  SHA512:
6
- metadata.gz: 77ed4fe864b0ad9f7d4a73b9787619f166eb5aa2631c70377e57de4c1f781f8da2bca717dafd98a940aff2e637590335e0076894b99a2f4e7ebbf94151acaa56
7
- data.tar.gz: 6732e24c0275884b3cfbab5a417ab755b900ca8d94ffa00d7a84a6c90a042325615221785085d1913f1a0b26b54399b500d90f5beb6b6cd1c7183236e12beade
6
+ metadata.gz: 265f331b400a0ddcfa6163da67c7fb30c57ee4c3506fa2ae8be4e346512884134dfcc8cfc9ee0ffd7e55575d7a7f3433d3c3f1b1f8fc172939f3423dac92c154
7
+ data.tar.gz: 4ea5214183ac720a1cec31f9ac6b6371012c2ac79476278afc2bb55dcdcf6155c8e6688ab03c349a2035aa62c6ef6e5ca0b0ae75318975d590274a1f1a4913b3
@@ -0,0 +1,23 @@
1
+ name: ruby
2
+ on:
3
+ push:
4
+ branches: [ main ]
5
+ pull_request:
6
+ branches: [ main ]
7
+ jobs:
8
+ test:
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ os: [ubuntu-latest, macos-latest]
13
+ ruby: [2.7, '3.0', jruby-head]
14
+ runs-on: ${{ matrix.os }}
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - name: Set up Ruby
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: ${{ matrix.ruby }}
21
+ bundler-cache: true
22
+ - name: Run tests
23
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -4,4 +4,5 @@ fabfile.pyc
4
4
  pirum.xml
5
5
  Gemfile.lock
6
6
  yarrow-*.gem
7
- coverage
7
+ coverage
8
+ bin/scripts
data/README.md CHANGED
@@ -1,21 +1,15 @@
1
1
  Yarrow
2
2
  ======
3
3
 
4
- [![Gem Version](http://img.shields.io/gem/v/yarrow.svg)][gem]
5
- [![Build Status](http://img.shields.io/travis/maetl/yarrow.svg)][travis]
6
- [![Dependency Status](http://img.shields.io/gemnasium/maetl/yarrow.svg)][gemnasium]
7
- [![Code Climate](http://img.shields.io/codeclimate/github/maetl/yarrow.svg)][codeclimate]
8
- [![Coverage Status](http://img.shields.io/coveralls/maetl/yarrow.svg)][coveralls]
4
+ [![Gem Version](https://img.shields.io/gem/v/yarrow.svg)][gem]
5
+ [![Build Status](https://img.shields.io/github/workflow/status/maetl/yarrow/ruby/main)][github]
9
6
 
10
7
  [gem]: https://rubygems.org/gems/yarrow
11
- [travis]: https://travis-ci.org/maetl/yarrow
12
- [gemnasium]: https://gemnasium.com/maetl/yarrow
13
- [codeclimate]: https://codeclimate.com/github/maetl/yarrow
14
- [coveralls]: https://coveralls.io/r/maetl/yarrow
8
+ [github]: https://github.com/maetl/yarrow
15
9
 
16
- Yarrow is a tool for generating well structured documentation from a variety of input sources.
10
+ Yarrow is a framework for generating well structured publishing outputs from a variety of input sources.
17
11
 
18
- Unlike most static site generators and code documentation tools, Yarrow is written with design and content-strategy in mind. It does not impose its own structure on your content. This makes it appropriate for building static sites and blogs as well as style guides and API docs.
12
+ Unlike most static site generators and code documentation tools, Yarrow is written with design and content-strategy in mind. It does not impose its own structure on your content. This makes it useful for building style guides, technical docs and complex ebooks as well as static sites and blogs.
19
13
 
20
14
  Installation
21
15
  ------------
@@ -37,7 +31,7 @@ Status
37
31
 
38
32
  Yarrow is an extraction from several existing private documentation projects. This repo is in alpha state, which means that many of the useful features are not yet folded into this codebase.
39
33
 
40
- Yarrow is being slowly developed as a part-time project to scratch a few itches. New features and bugfixes are pushed straight to master, and releases of the Gem are kept more or less in sync with the planned roadmap.
34
+ Yarrow is being slowly developed as a part-time project to scratch a few itches. New features and bugfixes are pushed straight to `main`, and releases of the Gem are kept more or less in sync with the planned roadmap.
41
35
 
42
36
  Roadmap
43
37
  -------
@@ -46,13 +40,13 @@ A rough sketch of the project direction.
46
40
 
47
41
  | Version | Features |
48
42
  |---------|----------|
49
- | `0.3` | **[Local dev server and asset pipeline](https://github.com/maetl/yarrow/issues/48)** |
50
- | `0.4` | Default media type mapping, collector, markup converters |
51
- | `0.5` | Content model/object mapping, template/site context |
52
- | `0.6` | HTML tag helpers, default layout templates |
53
- | `0.7` | Rake integration, task library |
54
- | `0.8` | Generic command line runner |
55
- | `0.9` | Refactoring, performance fixes, lock down API |
43
+ | `0.6` | Default media type mapping, graph collectors, markup converters |
44
+ | `0.7` | Content model/object mapping, template/site context |
45
+ | `0.8` | HTML publishing workflow |
46
+ | `0.9` | PDF publishing workflow |
47
+ | `0.10` | Media and video publishing workflow |
48
+ | `0.11` | Generic command line runner |
49
+ | `1.0` | Refactoring, performance fixes, lock down API |
56
50
 
57
51
  License
58
52
  -------
data/Rakefile CHANGED
@@ -1,4 +1,18 @@
1
+ $LOAD_PATH.unshift File.expand_path("./lib", __dir__)
2
+ require "yarrow"
3
+
4
+ task :version do
5
+ puts Yarrow::VERSION
6
+ end
7
+
8
+ task :build do
9
+ sh "gem build yarrow.gemspec"
10
+ end
11
+
12
+ task :publish do
13
+ sh "gem push yarrow-#{Yarrow::VERSION}.gem"
14
+ end
1
15
 
2
16
  task :clean do
3
- sh 'rm yarrow-*.gem'
17
+ sh "rm yarrow-*.gem"
4
18
  end
data/lib/yarrow.rb CHANGED
@@ -1,25 +1,36 @@
1
- require 'hashie'
1
+ require 'pathname'
2
2
  require 'yaml'
3
3
 
4
4
  require 'yarrow/version'
5
+ require 'yarrow/extensions'
6
+ require 'yarrow/symbols'
5
7
  require 'yarrow/logging'
8
+ require 'yarrow/schema'
9
+ require 'yarrow/config'
6
10
  require 'yarrow/configuration'
7
11
  require 'yarrow/console_runner'
8
12
  require 'yarrow/generator'
9
- require 'yarrow/assets'
13
+ require 'yarrow/tools/front_matter'
14
+ require 'yarrow/tools/content_utils'
10
15
  require 'yarrow/content/graph'
11
- #require 'yarrow/content/resource_expander'
16
+ require 'yarrow/content/content_type'
17
+ require 'yarrow/content/source'
12
18
  require 'yarrow/content/source_collector'
13
- require 'yarrow/html/asset_tags'
19
+ require 'yarrow/content/collection_expander'
14
20
  require 'yarrow/output/mapper'
15
21
  require 'yarrow/output/generator'
16
22
  require 'yarrow/output/context'
23
+ require 'yarrow/output/web/indexed_file'
17
24
  require 'yarrow/content_map'
18
- require 'yarrow/html'
19
- require 'yarrow/tools/front_matter'
20
25
  require 'yarrow/server'
21
26
  require 'yarrow/server/livereload'
22
27
 
28
+ require 'yarrow/process/workflow'
29
+ require 'yarrow/process/step_processor'
30
+ require 'yarrow/process/expand_content'
31
+ require 'yarrow/process/extract_source'
32
+ require 'yarrow/process/project_manifest'
33
+
23
34
  # Dir[File.dirname(__FILE__) + '/yarrow/generators/*.rb'].each do |generator|
24
35
  # require generator
25
36
  # end
@@ -0,0 +1,59 @@
1
+ # Replacement for the legacy Hashie::Mash/Module mixin configuration
2
+ # pattern. This provides the same API (chaining nested attribute calls) but
3
+ # handles schema validation and doesn’t pollute other namespaces.
4
+ module Yarrow
5
+ module Config
6
+ # Basic defaults which can be used to populate HTML metadata as well as
7
+ # used in CLI listings and other generated docs. The default H1 if no
8
+ # specific output config or template themes are provided.
9
+ #
10
+ # For larger web publishing projects, this should be moved out into a
11
+ # template context or language/translation files to make it editable
12
+ # for a larger group of people.
13
+ Meta = Yarrow::Schema::Value.new(
14
+ :title,
15
+ :author
16
+ # :copyright TODO: what other basic details to include?
17
+ )
18
+
19
+ # Dev server config. This is mainly useful if you want to set up a specific
20
+ # chain of Rack middleware and handlers. If you don’t care about default
21
+ # directory indexes or port handling, you can completely ignore this.
22
+ #
23
+ # There are many better live reloading options available in JS, so the Rack
24
+ # infrastructure here should be ignored for UI-heavy jobs. It’s otherwise
25
+ # fine for slower-paced general purpose web publishing.
26
+ #
27
+ # The default index config could possibly move into a dedicated namespace
28
+ # in future if it makes sense to use the underlying graph infrastructure
29
+ # as a live lookup rather than a compiler-generated artifact. This would
30
+ # mean rather than doing a ls on the directory, the index pages would
31
+ # grab a list of entries out of a graph projection for the directory.
32
+ Server = Yarrow::Schema::Value.new(
33
+ :live_reload,
34
+ :auto_index,
35
+ :default_index,
36
+ :default_type,
37
+ :port,
38
+ :host,
39
+ :handler,
40
+ :middleware,
41
+ :root_dir
42
+ )
43
+
44
+ # Top level root config namespace. Source, content and output are directory
45
+ # paths and should be the only required defaults for a complete batch run.
46
+ #
47
+ # Additional server config is optional and only needed if running the dev
48
+ # server locally.
49
+ #
50
+ # TODO: meta should be union of Type::Optional and Config::Meta
51
+ Instance = Yarrow::Schema::Value.new(
52
+ source: Pathname,
53
+ content: Pathname,
54
+ output_dir: Pathname,
55
+ meta: Yarrow::Schema::Type::Any,
56
+ server: Yarrow::Schema::Type::Any
57
+ )
58
+ end
59
+ end
@@ -1,50 +1,6 @@
1
1
  module Yarrow
2
- ##
3
- # Hash-like object containing runtime configuration values. Can be accessed indifferently
4
- # via object style lookups or symbol keys.
5
- #
6
- class Configuration < Hashie::Mash
2
+ class Configuration
7
3
  class << self
8
- ##
9
- # Provides access to the registered global configuration.
10
- #
11
- # If no configuration is registered, returns a blank object.
12
- #
13
- # @return [Yarrow::Configuration]
14
- #
15
- def instance
16
- @@configuration ||= self.new
17
- end
18
-
19
- ##
20
- # Loads and registers a global configuration instance.
21
- #
22
- # This will reset any previously initialized configuration.
23
- #
24
- # @param [String] path to YAML file
25
- #
26
- def register(file)
27
- @@configuration = load(file)
28
- end
29
-
30
- ##
31
- # Loads and registers a global configuration instance with
32
- # library-provided defaults.
33
- #
34
- # This will reset any previously initialized configuration.
35
- #
36
- def register_defaults
37
- @@configuration = load_defaults
38
- end
39
-
40
- ##
41
- # Clears the global configuration to the empty default.
42
- #
43
- def clear
44
- @@configuration = self.new
45
- end
46
-
47
- ##
48
4
  # Merges the given configuration or hash-like object with the
49
5
  # registered global configuration.
50
6
  #
@@ -54,18 +10,16 @@ module Yarrow
54
10
  instance.deep_merge!(config)
55
11
  end
56
12
 
57
- ##
58
13
  # Loads a configuration object from the given YAML file.
59
14
  #
60
15
  # @param [String] path to YAML file
61
16
  #
62
- # @return [Yarrow::Configuration]
17
+ # @return [Yarrow::Config]
63
18
  #
64
19
  def load(file)
65
- self.new(YAML.load_file(file))
20
+ coerce_config_struct(YAML.load(File.read(file), symbolize_names: true))
66
21
  end
67
22
 
68
- ##
69
23
  # Yarrow is distributed with a `defaults.yml` which provides minimum
70
24
  # boostrap configuration and default settings for various internal
71
25
  # classes. Use this method to automatically load these defaults.
@@ -74,21 +28,39 @@ module Yarrow
74
28
  def load_defaults
75
29
  load(File.join(File.dirname(__FILE__), 'defaults.yml'))
76
30
  end
77
- end
78
- end
79
31
 
80
- ##
81
- # Embeds global configuration access in a client object.
82
- #
83
- module Configurable
84
- ##
85
- # Provides access to the registered global configuration. This can
86
- # be overriden by subclasses to customize behaviour (eg: in test cases).
87
- #
88
- # @return [Yarrow::Configuration]
89
- #
90
- def config
91
- Configuration.instance
32
+ private
33
+
34
+ # TODO: this should be folded into the schema machinery with type coercions
35
+ def coerce_config_struct(config)
36
+ meta_obj = if config.key?(:meta)
37
+ Yarrow::Config::Meta.new(
38
+ title: config[:meta][:title],
39
+ author: config[:meta][:author]
40
+ )
41
+ else
42
+ nil
43
+ end
44
+
45
+ server_obj = if config.key?(:server)
46
+ Yarrow::Config::Server.new(**config[:server])
47
+ else
48
+ nil
49
+ end
50
+
51
+ # TODO: messy hack to get rid of Hashie::Mash, this should either be
52
+ # automated as part of the schema types or a default value should be
53
+ # generated here (eg: `"#{Dir.pwd}/docs"`)
54
+ out_dir_or_string = config[:output_dir] || ""
55
+
56
+ Yarrow::Config::Instance.new(
57
+ output_dir: Pathname.new(File.expand_path(out_dir_or_string)),
58
+ source: Pathname.new(File.expand_path(out_dir_or_string)),
59
+ content: Pathname.new(File.expand_path(out_dir_or_string)),
60
+ meta: meta_obj,
61
+ server: server_obj
62
+ )
63
+ end
92
64
  end
93
65
  end
94
66
 
@@ -0,0 +1,218 @@
1
+ module Yarrow
2
+ module Content
3
+ class CollectionExpander
4
+ include Yarrow::Tools::FrontMatter
5
+
6
+ def initialize(content_types=nil)
7
+ @content_types = content_types || [
8
+ Yarrow::Content::ContentType.from_name(:pages)
9
+ ]
10
+ end
11
+
12
+ def expand(graph)
13
+ @content_types.each do |content_type|
14
+ expand_nested(graph, content_type)
15
+ end
16
+ end
17
+
18
+ def expand_nested(graph, content_type)
19
+ type = content_type.collection
20
+ exts = content_type.extensions
21
+
22
+ # If match path represents entire content dir, then include the entire
23
+ # content dir instead of scanning from a subfolder matching the name of
24
+ # the collection.
25
+ start_node = if content_type.match_path == "."
26
+ graph.n(:root)
27
+ else
28
+ graph.n(:root).out(name: type.to_s)
29
+ end
30
+
31
+ # Extract metadata from given start node
32
+ data = extract_metadata(start_node, type)
33
+
34
+ # Collects all nested collections in the subgraph for this content type
35
+ subcollections = {}
36
+ index = nil
37
+
38
+ # Define alias for accessing metadata in the loop
39
+ metadata = data
40
+
41
+ # Scan and collect all nested directories under the top level source
42
+ start_node.depth_first.each do |node|
43
+ if node.label == :directory
44
+ # Check if this entry has metadata defined at the top level
45
+ if data[:collections]
46
+ item = data[:collections].find { |c| c[:slug] == node.props[:slug] }
47
+ metadata = item if item
48
+ end
49
+
50
+ # Create a collection node representing a collection of documents
51
+ index = graph.create_node do |collection_node|
52
+ collection_node.label = :collection
53
+ collection_node.props[:type] = type
54
+ collection_node.props[:name] = node.props[:name]
55
+ collection_node.props[:slug] = node.props[:slug]
56
+ collection_node.props[:title] = metadata[:title]
57
+
58
+ # Override default status so that mapped index collections always show
59
+ # up in the resulting document manifest, when they don’t have
60
+ # associated metadata. This is the opposite of how individual pieces
61
+ # of content behave (default to draft status if one isn’t supplied).
62
+ collection_node.props[:status] = if data[:status]
63
+ data[:status]
64
+ else
65
+ "published"
66
+ end
67
+
68
+ # TODO: URL generation might need to happen elsewhere
69
+ collection_node.props[:url] = if data[:url]
70
+ data[:url]
71
+ else
72
+ "#{node.props[:path].split('./content').last}/"
73
+ end
74
+ end
75
+
76
+ # Add this collection id to the lookup table for edge construction
77
+ subcollections[node.props[:path]] = index
78
+
79
+ # Join the collection to its parent
80
+ unless node.props[:slug] == type.to_s || !subcollections.key?(node.props[:entry].parent.to_s)
81
+ graph.create_edge do |edge|
82
+ edge.label = :child
83
+ edge.from = subcollections[node.props[:entry].parent.to_s].id
84
+ edge.to = index.id
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ subcollections.each do |path, index|
91
+ # Group files matching the same slug under a common key
92
+ objects = graph.n(path: path).out(:file).all.select do |file|
93
+ file.props[:name].end_with?(*exts)
94
+ end.group_by do |file|
95
+ file.props[:slug]
96
+ end
97
+
98
+ build_content_nodes(graph, objects, type, index)
99
+ end
100
+ end
101
+
102
+ # Extract collection level configuration/metadata from the root node for
103
+ # this content type.
104
+ def extract_metadata(node, type)
105
+ # TODO: support _index or _slug convention as well
106
+ meta_file = node.out(slug: type.to_s).first
107
+
108
+ if meta_file
109
+ # Process metadata and add it to the collection node
110
+ # TODO: pass in content converter object
111
+ # TODO: index/body content by default if extracted from frontmatter
112
+ body, data = process_content(meta_file.props[:entry])
113
+ else
114
+ # Otherwise, assume default collection behaviour
115
+ data = {}
116
+ end
117
+
118
+ # Generate a default title if not provided in metadata
119
+ unless data.key?(:title)
120
+ data[:title] = type.to_s.capitalize
121
+ end
122
+
123
+ data
124
+ end
125
+
126
+ def build_content_nodes(graph, objects, type, parent_index)
127
+ # TODO: this may need to use a strategy that can be overriden
128
+ content_type = Yarrow::Symbols.to_singular(type)
129
+
130
+ # Process collected content objects and generate entity nodes
131
+ objects.each do |name, sources|
132
+ item_node = graph.create_node do |node|
133
+ # TODO: Rename this to :entry and support similar fields to Atom
134
+ node.label = :item
135
+ node.props[:name] = name
136
+ node.props[:type] = content_type
137
+
138
+ meta = {}
139
+ content = ""
140
+
141
+ sources.each do |source|
142
+ body, data = process_content(source.props[:entry])
143
+ meta.merge!(data) unless data.nil?
144
+ content << body unless body.nil?
145
+ end
146
+
147
+ if meta[:url]
148
+ # If a URL is explicitly proided in metadata then use it
149
+ node.props[:url] = meta[:url]
150
+ elsif meta[:permalink]
151
+ # Support for legacy permalink attribute
152
+ node.props[:url] = meta[:permalink]
153
+ else
154
+ # Default URL generation strategy when no explicit URL is provided
155
+ # TODO: collection nodes need URL generation too
156
+ # TODO: replace this with URL generation strategy
157
+ # TODO: slug vs name - why do some nodes have 2 and some 3 props?
158
+ node.props[:url] = if parent_index.props[:name].to_sym == parent_index.props[:type]
159
+ "/#{parent_index.props[:type]}/#{name}"
160
+ else
161
+ "/#{parent_index.props[:type]}/#{parent_index.props[:slug]}/#{name}"
162
+ end
163
+ end
164
+
165
+ # For now, we are storing title, url, etc on the top-level item.
166
+ node.props[:title] = meta[:title]
167
+
168
+ # TODO: What belongs on the entity and what belongs on the item?
169
+ entity_props = meta.merge(body: content, name: meta[:id], url: node.props[:url])
170
+
171
+
172
+ # TODO: consider whether to provide `body` on the item/document or at
173
+ # the custom content type level.
174
+ begin
175
+ content_struct = Yarrow::Symbols.to_const(content_type)
176
+ rescue
177
+ # No immutable struct found: fall back to slower dynamically typed open struct
178
+ require "ostruct"
179
+ content_struct = OpenStruct
180
+ end
181
+
182
+ node.props[:entity] = content_struct.new(entity_props)
183
+ end
184
+
185
+ # Connect entity with source content
186
+ sources.each do |source|
187
+ graph.create_edge do |edge|
188
+ edge.label = :source
189
+ edge.from = item_node
190
+ edge.to = source.id
191
+ end
192
+ end
193
+
194
+ # Connect entity with parent collection
195
+ graph.create_edge do |edge|
196
+ edge.label = :child
197
+ edge.from = parent_index
198
+ edge.to = item_node
199
+ end
200
+ end
201
+ end
202
+
203
+ # Workaround for handling meta and content source in multiple files or a single
204
+ # file with front matter.
205
+ def process_content(path)
206
+ case path.extname
207
+ when '.htm', '.md'
208
+ read_split_content(path.to_s, symbolize_keys: true)
209
+ # when '.md'
210
+ # body, data = read_split_content(path.to_s, symbolize_keys: true)
211
+ # [Kramdown::Document.new(body).to_html, data]
212
+ when '.yml'
213
+ [nil, YAML.load(File.read(path.to_s), symbolize_names: true)]
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end