diff --git a/CHANGELOG.md b/CHANGELOG.md
index 860f3406..da4b225e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
# master
+- Support TOML as frontmatter and data.
- Handle the removal of a file in dependencies. Fixes #2292
- Update rubocop + use enable-frozen-string-literal (#2354)
- Add ability to external pipeline ignore process exit code (#2353)
diff --git a/Gemfile.lock b/Gemfile.lock
index ed6b4309..b2d7675e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -29,6 +29,7 @@ PATH
sassc (~> 2.0)
servolux
tilt (~> 2.0.9)
+ toml
uglifier (~> 4.1)
GEM
@@ -132,7 +133,7 @@ GEM
lazy_priority_queue (0.1.1)
libv8 (8.4.255.0)
liquid (4.0.3)
- listen (3.2.1)
+ listen (3.3.2)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
memoist (0.16.2)
@@ -149,7 +150,7 @@ GEM
nio4r (2.5.2)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
- oj (3.10.8)
+ oj (3.10.16)
padrino-helpers (0.14.4)
i18n (~> 0.6, >= 0.6.7)
padrino-support (= 0.14.4)
@@ -158,6 +159,7 @@ GEM
parallel (1.20.1)
parser (2.7.2.0)
ast (~> 2.4.1)
+ parslet (1.8.2)
protobuf-cucumber (3.10.8)
activesupport (>= 3.2)
middleware
@@ -243,6 +245,8 @@ GEM
thread_safe (0.3.6)
tilt (2.0.10)
timers (4.3.0)
+ toml (0.2.0)
+ parslet (~> 1.8.0)
tzinfo (1.2.7)
thread_safe (~> 0.1)
uglifier (4.2.0)
diff --git a/middleman-core/features/data.feature b/middleman-core/features/data.feature
index 460658a8..3ba7807e 100644
--- a/middleman-core/features/data.feature
+++ b/middleman-core/features/data.feature
@@ -92,3 +92,23 @@ Feature: Local Data API
Then I should see "
With Content
"
Then I should see ''
Then I should see "Paragraph 1
"
+
+ Scenario: Rendering toml
+ Given the Server is running at "basic-data-app"
+ When I go to "/data4.html"
+ Then I should see "One:Two"
+ When the file "data/test3.toml" has the contents
+ """
+ [titles]
+
+ [titles.first]
+ title = "Three"
+
+ [titles.second]
+ title = "Four"
+ """
+ When I go to "/data4.html"
+ Then I should see "Three:Four"
+ When the file "data/test3.toml" is removed
+ When I go to "/data4.html"
+ Then I should see "No Test Data"
\ No newline at end of file
diff --git a/middleman-core/features/front-matter-neighbor.feature b/middleman-core/features/front-matter-neighbor.feature
index 9260ff41..0e069289 100644
--- a/middleman-core/features/front-matter-neighbor.feature
+++ b/middleman-core/features/front-matter-neighbor.feature
@@ -23,6 +23,12 @@ Feature: Neighboring YAML Front Matter
When I go to "/raw-front-matter.php.frontmatter"
Then I should see "File Not Found"
+ Scenario: Rendering raw (template-less) (toml)
+ Given the Server is running at "frontmatter-neighbor-app"
+ When I go to "/raw-front-matter-toml.html"
+ Then I should see "<%= current_page.data.title %>
"
+ Then I should not see "---"
+
Scenario: YAML not on first line, with encoding
Given the Server is running at "frontmatter-neighbor-app"
When I go to "/front-matter-encoding.html"
@@ -65,10 +71,10 @@ Feature: Neighboring YAML Front Matter
Scenario: A template should handle an empty YAML feed
Given the Server is running at "frontmatter-neighbor-app"
And the file "source/front-matter-change.html.erb.frontmatter" has the contents
- """
- ---
- ---
- """
+ """
+ ---
+ ---
+ """
When I go to "/front-matter-change.html"
Then I should not see "Hello World"
Then I should not see "Hola Mundo"
@@ -78,14 +84,14 @@ Feature: Neighboring YAML Front Matter
Scenario: Setting layout, ignoring, and disabling directory indexes through frontmatter (build)
Given a successfully built app at "frontmatter-settings-neighbor-app"
Then the following files should exist:
- | build/proxied.html |
+ | build/proxied.html |
And the file "build/alternate_layout.html" should contain "Alternate layout"
And the following files should not exist:
- | build/ignored.html |
- | build/alternate_layout.html.erb.frontmatter |
- | build/ignored.html.erb.frontmatter |
+ | build/ignored.html |
+ | build/alternate_layout.html.erb.frontmatter |
+ | build/ignored.html.erb.frontmatter |
| build/override_layout.html.erb.frontmatter |
- | build/page_mentioned.html.erb.frontmatter |
+ | build/page_mentioned.html.erb.frontmatter |
Scenario: Setting layout, ignoring, and disabling directory indexes through frontmatter (preview)
Given the Server is running at "frontmatter-settings-neighbor-app"
@@ -130,22 +136,22 @@ Feature: Neighboring YAML Front Matter
When I go to "/page_mentioned.html.erb.frontmatter"
Then I should see "File Not Found"
- # Scenario: Neighbor frontmatter for destination of proxy resources
- # Given the Server is running at "frontmatter-settings-neighbor-app"
- # And the file "source/proxied_with_frontmatter.html.frontmatter" has the contents
- # """
- # ---
- # title: Proxied title
- # ---
- # """
- # And the file "source/ignored.html.erb" has the contents
- # """
- # ---
- # ignored: true
- # ---
+# Scenario: Neighbor frontmatter for destination of proxy resources
+# Given the Server is running at "frontmatter-settings-neighbor-app"
+# And the file "source/proxied_with_frontmatter.html.frontmatter" has the contents
+# """
+# ---
+# title: Proxied title
+# ---
+# """
+# And the file "source/ignored.html.erb" has the contents
+# """
+# ---
+# ignored: true
+# ---
- # <%= current_resource.data.inspect %>
- # <%= current_resource.data.title %>
- # """
- # When I go to "/proxied_with_frontmatter.html"
- # Then I should see "Proxied title"
+# <%= current_resource.data.inspect %>
+# <%= current_resource.data.title %>
+# """
+# When I go to "/proxied_with_frontmatter.html"
+# Then I should see "Proxied title"
diff --git a/middleman-core/features/front-matter.feature b/middleman-core/features/front-matter.feature
index 45f20743..9cc3d957 100644
--- a/middleman-core/features/front-matter.feature
+++ b/middleman-core/features/front-matter.feature
@@ -90,10 +90,16 @@ Feature: YAML Front Matter
Scenario: A template should handle an empty YAML feed
Given the Server is running at "frontmatter-app"
And the file "source/front-matter-change.html.erb" has the contents
- """
- ---
- ---
- Hello World
- """
+ """
+ ---
+ ---
+ Hello World
+ """
When I go to "/front-matter-change.html"
Then I should see "Hello World"
+
+ Scenario: Rendering raw (template-less) (toml)
+ Given the Server is running at "frontmatter-app"
+ When I go to "/raw-front-matter-toml.html"
+ Then I should see "<%= current_page.data.title %>
"
+ Then I should not see "---"
\ No newline at end of file
diff --git a/middleman-core/fixtures/basic-data-app/data/test3.toml b/middleman-core/fixtures/basic-data-app/data/test3.toml
new file mode 100644
index 00000000..65234e79
--- /dev/null
+++ b/middleman-core/fixtures/basic-data-app/data/test3.toml
@@ -0,0 +1,7 @@
+[titles]
+
+ [titles.first]
+ title = "One"
+
+ [titles.second]
+ title = "Two"
diff --git a/middleman-core/fixtures/basic-data-app/source/data4.html.erb b/middleman-core/fixtures/basic-data-app/source/data4.html.erb
new file mode 100644
index 00000000..fb532fbc
--- /dev/null
+++ b/middleman-core/fixtures/basic-data-app/source/data4.html.erb
@@ -0,0 +1,5 @@
+<% if data.respond_to?(:test3) && data.test3.respond_to?(:titles) %>
+ <%= data.test3.titles.map { |r| r[1].title }.join(":") %>
+<% else %>
+ No Test Data
+<% end %>
\ No newline at end of file
diff --git a/middleman-core/fixtures/frontmatter-app/source/raw-front-matter-toml.html b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter-toml.html
new file mode 100644
index 00000000..3358a7d4
--- /dev/null
+++ b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter-toml.html
@@ -0,0 +1,6 @@
++++
+layout = false
+title = "This is the title"
++++
+
+<%= current_page.data.title %>
\ No newline at end of file
diff --git a/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html
index fcae7374..43aa3c3b 100644
--- a/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html
+++ b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html
@@ -3,4 +3,4 @@ layout: false
title: This is the title
---
-<%= current_page.data.title %>
+<%= current_page.data.title %>
\ No newline at end of file
diff --git a/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html
new file mode 100644
index 00000000..2797ea86
--- /dev/null
+++ b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html
@@ -0,0 +1 @@
+<%= current_page.data.title %>
\ No newline at end of file
diff --git a/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html.frontmatter b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html.frontmatter
new file mode 100644
index 00000000..b95e0526
--- /dev/null
+++ b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html.frontmatter
@@ -0,0 +1,4 @@
++++
+layout = false
+title = "This is the title"
++++
\ No newline at end of file
diff --git a/middleman-core/lib/middleman-core/core_extensions/data.rb b/middleman-core/lib/middleman-core/core_extensions/data.rb
index 6dfa1180..d4fa9885 100644
--- a/middleman-core/lib/middleman-core/core_extensions/data.rb
+++ b/middleman-core/lib/middleman-core/core_extensions/data.rb
@@ -21,7 +21,7 @@ module Middleman
expose_to_template internal_data_store: :data_store
# The regex which tells Middleman which files are for data
- DATA_FILE_MATCHER = /^(.*?)[\w-]+\.(yml|yaml|json)$/.freeze
+ DATA_FILE_MATCHER = /^(.*?)[\w-]+\.(yml|yaml|json|toml)$/.freeze
Contract IsA['::Middleman::Application'], Hash => Any
def initialize(app, options_hash = ::Middleman::EMPTY_HASH, &block)
diff --git a/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb b/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb
index e21f3df7..546a21d7 100644
--- a/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb
+++ b/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb
@@ -18,7 +18,8 @@ module Middleman
YAML_EXTS = Set.new %w[.yaml .yml]
JSON_EXTS = Set.new %w[.json]
- ALL_EXTS = YAML_EXTS | JSON_EXTS
+ TOML_EXTS = Set.new %w[.toml]
+ ALL_EXTS = YAML_EXTS | JSON_EXTS | TOML_EXTS
def_delegators :@local_data, :keys, :key?, :[]
@@ -55,6 +56,8 @@ module Middleman
data[:postscript] = postscript if !postscript.nil? && data.is_a?(Hash)
elsif JSON_EXTS.include?(extension)
data, _postscript = ::Middleman::Util::Data.parse(file, @app.config[:frontmatter_delims], :json)
+ elsif TOML_EXTS.include?(extension)
+ data, _postscript = ::Middleman::Util::Data.parse(file, @app.config[:frontmatter_delims], :toml)
end
data_branch = @local_data
diff --git a/middleman-core/lib/middleman-core/core_extensions/front_matter.rb b/middleman-core/lib/middleman-core/core_extensions/front_matter.rb
index edae9824..4e469481 100644
--- a/middleman-core/lib/middleman-core/core_extensions/front_matter.rb
+++ b/middleman-core/lib/middleman-core/core_extensions/front_matter.rb
@@ -16,7 +16,30 @@ module Middleman::CoreExtensions
# Set textual delimiters that denote the start and end of frontmatter
define_setting :frontmatter_delims, {
- json: [%w[;;; ;;;]],
+ json: [
+ %w[;;; ;;;],
+
+ # Haml with commented frontmatter
+ ["-#\n ;;;", ' ;;;'],
+
+ # Slim with commented frontmatter
+ ["\/\n ;;;", ' ;;;'],
+
+ # ERb with commented frontmatter
+ ["<%#\n ;;;", " ;;;\n%>"]
+ ],
+ toml: [
+ %w[+++ +++],
+
+ # Haml with commented frontmatter
+ ["-#\n +++", ' +++'],
+
+ # Slim with commented frontmatter
+ ["\/\n +++", ' +++'],
+
+ # ERb with commented frontmatter
+ ["<%#\n +++", " +++\n%>"]
+ ],
yaml: [
# Normal
%w[--- ---],
diff --git a/middleman-core/lib/middleman-core/util/data.rb b/middleman-core/lib/middleman-core/util/data.rb
index 4828d9fe..8729076b 100644
--- a/middleman-core/lib/middleman-core/util/data.rb
+++ b/middleman-core/lib/middleman-core/util/data.rb
@@ -2,6 +2,7 @@
require 'yaml'
require 'json'
+require 'toml'
require 'pathname'
require 'hashie'
require 'memoist'
@@ -72,6 +73,8 @@ module Middleman
return [parse_yaml(content, full_path), nil]
when :json
return [parse_json(content, full_path), nil]
+ when :toml
+ return [parse_toml(content, full_path), nil]
end
end
@@ -86,6 +89,11 @@ module Middleman
parse_json("{#{match[:frontmatter]}}", full_path),
match[:additional_content]
]
+ when *frontmatter_delims[:toml]
+ [
+ parse_toml(match[:frontmatter], full_path),
+ match[:additional_content]
+ ]
else
[
{},
@@ -129,6 +137,26 @@ module Middleman
end
memoize :parse_yaml
+ # Parse TOML frontmatter out of a string
+ # @param [String] content
+ # @return [Hash]
+ Contract String, Pathname => Hash
+ def parse_toml(content, full_path)
+ c = begin
+ ::Middleman::Util.instrument 'parse.toml' do
+ ::TOML.load(content)
+ end
+ rescue StandardError
+ # TOML parser swallows useful error, so we can't warn about it.
+ # https://github.com/jm/toml/issues/47
+ warn "TOML Exception parsing #{full_path}"
+ {}
+ end
+
+ c ? symbolize_recursive(c) : {}
+ end
+ memoize :parse_yaml
+
# Parse JSON frontmatter out of a string
# @param [String] content
# @return [Hash]
diff --git a/middleman-core/middleman-core.gemspec b/middleman-core/middleman-core.gemspec
index 9b025601..334b0d76 100644
--- a/middleman-core/middleman-core.gemspec
+++ b/middleman-core/middleman-core.gemspec
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
s.add_dependency('servolux')
s.add_dependency('dotenv')
s.add_dependency('rgl', ['~> 0.5.3'])
+ s.add_dependency('toml')
# Helpers
s.add_dependency('activesupport', ['>= 5.0.0'])