mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-03-25 09:05:47 +00:00
Remove frontmatter conversion tooling
This commit is contained in:
parent
d67d1488b9
commit
a3dc9b55f8
6 changed files with 1 additions and 384 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
www
|
||||
Tests/*/actual
|
||||
spec/examples.txt
|
||||
|
|
|
|||
|
|
@ -56,12 +56,6 @@ bin/new-draft "Post title"
|
|||
bin/publish-draft public/drafts/post-title.md
|
||||
```
|
||||
|
||||
## Post Utilities
|
||||
|
||||
```bash
|
||||
bin/convert-frontmatter posts/2025/11/some-post.md
|
||||
```
|
||||
|
||||
## Tests And Lint
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require_relative '../lib/utils/frontmatter_converter'
|
||||
|
||||
if ARGV.empty?
|
||||
puts "Usage: convert-frontmatter FILE [FILE...]"
|
||||
puts ""
|
||||
puts "Converts front-matter from custom format to YAML in-place."
|
||||
puts ""
|
||||
puts "Examples:"
|
||||
puts " convert-frontmatter posts/2025/11/*.md"
|
||||
puts " convert-frontmatter posts/**/*.md"
|
||||
exit 1
|
||||
end
|
||||
|
||||
converted_count = 0
|
||||
error_count = 0
|
||||
|
||||
ARGV.each do |file_path|
|
||||
unless File.exist?(file_path)
|
||||
puts "ERROR: File not found: #{file_path}"
|
||||
error_count += 1
|
||||
next
|
||||
end
|
||||
|
||||
begin
|
||||
Pressa::Utils::FrontmatterConverter.convert_file(file_path)
|
||||
puts "✓ #{file_path}"
|
||||
converted_count += 1
|
||||
rescue => e
|
||||
puts "ERROR: #{file_path}: #{e.message}"
|
||||
error_count += 1
|
||||
end
|
||||
end
|
||||
|
||||
puts ""
|
||||
puts "Converted: #{converted_count}"
|
||||
puts "Errors: #{error_count}" if error_count > 0
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
module Pressa
|
||||
module Utils
|
||||
class FrontmatterConverter
|
||||
FIELD_PATTERN = /^([A-Z][A-Za-z\s]+):\s*(.+)$/
|
||||
|
||||
def self.convert_file(input_path, output_path = nil)
|
||||
content = File.read(input_path)
|
||||
converted = convert_content(content)
|
||||
|
||||
if output_path
|
||||
File.write(output_path, converted)
|
||||
else
|
||||
File.write(input_path, converted)
|
||||
end
|
||||
end
|
||||
|
||||
def self.convert_content(content)
|
||||
unless content.start_with?("---\n")
|
||||
raise "File does not start with front-matter delimiter"
|
||||
end
|
||||
|
||||
parts = content.split(/^---\n/, 3)
|
||||
if parts.length < 3
|
||||
raise "Could not find end of front-matter"
|
||||
end
|
||||
|
||||
frontmatter = parts[1]
|
||||
body = parts[2]
|
||||
|
||||
yaml_frontmatter = convert_frontmatter_to_yaml(frontmatter)
|
||||
|
||||
"---\n#{yaml_frontmatter}---\n#{body}"
|
||||
end
|
||||
|
||||
def self.convert_frontmatter_to_yaml(frontmatter)
|
||||
fields = {}
|
||||
|
||||
frontmatter.each_line do |line|
|
||||
line = line.strip
|
||||
next if line.empty?
|
||||
|
||||
if line =~ FIELD_PATTERN
|
||||
field_name = $1.strip
|
||||
field_value = $2.strip
|
||||
|
||||
fields[field_name] = field_value
|
||||
end
|
||||
end
|
||||
|
||||
yaml_lines = []
|
||||
fields.each do |name, value|
|
||||
yaml_lines << format_yaml_field(name, value)
|
||||
end
|
||||
|
||||
yaml_lines.join("\n") + "\n"
|
||||
end
|
||||
|
||||
private_class_method def self.format_yaml_field(name, value)
|
||||
return "#{name}: #{value}" if name == 'Timestamp'
|
||||
|
||||
if name == 'Tags'
|
||||
tags = value.split(',').map(&:strip)
|
||||
return "#{name}: [#{tags.join(', ')}]"
|
||||
end
|
||||
|
||||
if name == 'Title'
|
||||
escaped_value = value.gsub('\\', '\\\\\\\\').gsub('"', '\\"')
|
||||
return "#{name}: \"#{escaped_value}\""
|
||||
end
|
||||
|
||||
has_special_chars = value.include?('\\') || value.include?('"')
|
||||
needs_quoting = has_special_chars ||
|
||||
(value.include?(':') && !value.start_with?('http')) ||
|
||||
value.include?(',') ||
|
||||
name == 'Date'
|
||||
|
||||
if needs_quoting
|
||||
escaped_value = value.gsub('\\', '\\\\\\\\').gsub('"', '\\"')
|
||||
"#{name}: \"#{escaped_value}\""
|
||||
else
|
||||
"#{name}: #{value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
example_id | status | run_time |
|
||||
------------------------------------------------- | ------ | --------------- |
|
||||
./spec/posts/metadata_spec.rb[1:1:1] | passed | 0.00051 seconds |
|
||||
./spec/posts/metadata_spec.rb[1:1:2] | passed | 0.00066 seconds |
|
||||
./spec/posts/metadata_spec.rb[1:1:3] | passed | 0.00467 seconds |
|
||||
./spec/posts/repo_spec.rb[1:1:1] | passed | 0.00124 seconds |
|
||||
./spec/posts/repo_spec.rb[1:1:2] | passed | 0.02703 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:1] | passed | 0.00057 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:2] | passed | 0.00004 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:3] | passed | 0.00003 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:4] | passed | 0.00003 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:5] | passed | 0.00006 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:6] | passed | 0.00005 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:7] | passed | 0.00004 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:1:8] | passed | 0.00004 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:2:1] | passed | 0.00005 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:2:2] | passed | 0.0002 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:2:3] | passed | 0.00004 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:2:4] | passed | 0.00006 seconds |
|
||||
./spec/utils/frontmatter_converter_spec.rb[1:2:5] | passed | 0.00003 seconds |
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
require 'spec_helper'
|
||||
require_relative '../../lib/utils/frontmatter_converter'
|
||||
|
||||
RSpec.describe Pressa::Utils::FrontmatterConverter do
|
||||
describe '.convert_content' do
|
||||
it 'converts simple front-matter to YAML' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Test Post
|
||||
Author: Sami Samhuri
|
||||
Date: 11th November, 2025
|
||||
Timestamp: 2025-11-11T14:00:00-08:00
|
||||
---
|
||||
|
||||
This is the post body.
|
||||
MARKDOWN
|
||||
|
||||
output = described_class.convert_content(input)
|
||||
|
||||
expect(output).to start_with("---\n")
|
||||
expect(output).to include("Title: \"Test Post\"")
|
||||
expect(output).to include("Author: Sami Samhuri")
|
||||
expect(output).to include("Date: \"11th November, 2025\"")
|
||||
expect(output).to include("Timestamp: 2025-11-11T14:00:00-08:00")
|
||||
expect(output).to end_with("---\n\nThis is the post body.\n")
|
||||
end
|
||||
|
||||
it 'converts front-matter with tags' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Zelda Tones for iOS
|
||||
Author: Sami Samhuri
|
||||
Date: 6th March, 2013
|
||||
Timestamp: 2013-03-06T18:51:13-08:00
|
||||
Tags: zelda, nintendo, pacman, ringtones, tones, ios
|
||||
---
|
||||
|
||||
<h2>Zelda</h2>
|
||||
|
||||
<p>
|
||||
<a href="http://mattgemmell.com">Matt Gemmell</a> recently shared some
|
||||
<a href="http://mattgemmell.com/2013/03/05/iphone-5-super-nintendo-wallpapers/">sweet Super Nintendo wallpapers for iPhone 5</a>.
|
||||
</p>
|
||||
MARKDOWN
|
||||
|
||||
output = described_class.convert_content(input)
|
||||
|
||||
expect(output).to include("Title: \"Zelda Tones for iOS\"")
|
||||
expect(output).to include("Tags: [zelda, nintendo, pacman, ringtones, tones, ios]")
|
||||
expect(output).to include("<h2>Zelda</h2>")
|
||||
end
|
||||
|
||||
it 'converts front-matter with Link field' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo
|
||||
Author: Sami Samhuri
|
||||
Date: 16th September, 2006
|
||||
Timestamp: 2006-09-16T22:11:00-07:00
|
||||
Tags: amusement, buffalo
|
||||
Link: http://en.wikipedia.org/wiki/Buffalo_buffalo_buffalo_buffalo_buffalo_buffalo_buffalo_buffalo
|
||||
---
|
||||
|
||||
Wouldn't the sentence 'I want to put a hyphen between the words Fish and And...
|
||||
MARKDOWN
|
||||
|
||||
output = described_class.convert_content(input)
|
||||
|
||||
expect(output).to include("Link: http://en.wikipedia.org/wiki/Buffalo_buffalo_buffalo_buffalo_buffalo_buffalo_buffalo_buffalo")
|
||||
expect(output).to include("Tags: [amusement, buffalo]")
|
||||
end
|
||||
|
||||
it 'converts front-matter with Scripts and Styles' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Code Example Post
|
||||
Author: Sami Samhuri
|
||||
Date: 1st January, 2025
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
Scripts: highlight.js, custom.js
|
||||
Styles: code.css, theme.css
|
||||
---
|
||||
|
||||
Some code here.
|
||||
MARKDOWN
|
||||
|
||||
output = described_class.convert_content(input)
|
||||
|
||||
expect(output).to include("Scripts: \"highlight.js, custom.js\"")
|
||||
expect(output).to include("Styles: \"code.css, theme.css\"")
|
||||
end
|
||||
|
||||
it 'handles Date fields with colons correctly' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Test
|
||||
Author: Sami Samhuri
|
||||
Date: 1st January, 2025
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
---
|
||||
|
||||
Body
|
||||
MARKDOWN
|
||||
|
||||
output = described_class.convert_content(input)
|
||||
|
||||
expect(output).to include("Date: \"1st January, 2025\"")
|
||||
expect(output).to include("Timestamp: 2025-01-01T12:00:00-08:00")
|
||||
end
|
||||
|
||||
it 'raises error if no front-matter delimiter' do
|
||||
input = "Just some content without front-matter"
|
||||
|
||||
expect {
|
||||
described_class.convert_content(input)
|
||||
}.to raise_error("File does not start with front-matter delimiter")
|
||||
end
|
||||
|
||||
it 'raises error if front-matter is not closed' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Unclosed
|
||||
Author: Test
|
||||
|
||||
Body without closing delimiter
|
||||
MARKDOWN
|
||||
|
||||
expect {
|
||||
described_class.convert_content(input)
|
||||
}.to raise_error("Could not find end of front-matter")
|
||||
end
|
||||
|
||||
it 'preserves empty lines in body' do
|
||||
input = <<~MARKDOWN
|
||||
---
|
||||
Title: Test
|
||||
Author: Sami Samhuri
|
||||
Date: 1st January, 2025
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
---
|
||||
|
||||
First paragraph.
|
||||
|
||||
Second paragraph after empty line.
|
||||
MARKDOWN
|
||||
|
||||
output = described_class.convert_content(input)
|
||||
|
||||
expect(output).to include("\nFirst paragraph.\n\nSecond paragraph after empty line.\n")
|
||||
end
|
||||
end
|
||||
|
||||
describe '.convert_frontmatter_to_yaml' do
|
||||
it 'converts all standard fields' do
|
||||
input = <<~FRONTMATTER
|
||||
Title: Test Post
|
||||
Author: Sami Samhuri
|
||||
Date: 11th November, 2025
|
||||
Timestamp: 2025-11-11T14:00:00-08:00
|
||||
Tags: Ruby, Testing
|
||||
Link: https://example.net
|
||||
Scripts: app.js
|
||||
Styles: style.css
|
||||
FRONTMATTER
|
||||
|
||||
yaml = described_class.convert_frontmatter_to_yaml(input)
|
||||
|
||||
expect(yaml).to include("Title: \"Test Post\"")
|
||||
expect(yaml).to include("Author: Sami Samhuri")
|
||||
expect(yaml).to include("Date: \"11th November, 2025\"")
|
||||
expect(yaml).to include("Timestamp: 2025-11-11T14:00:00-08:00")
|
||||
expect(yaml).to include("Tags: [Ruby, Testing]")
|
||||
expect(yaml).to include("Link: https://example.net")
|
||||
expect(yaml).to include("Scripts: app.js")
|
||||
expect(yaml).to include("Styles: style.css")
|
||||
end
|
||||
|
||||
it 'handles empty lines gracefully' do
|
||||
input = <<~FRONTMATTER
|
||||
Title: Test
|
||||
|
||||
Author: Sami Samhuri
|
||||
Date: 1st January, 2025
|
||||
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
FRONTMATTER
|
||||
|
||||
yaml = described_class.convert_frontmatter_to_yaml(input)
|
||||
|
||||
expect(yaml).to include("Title: \"Test\"")
|
||||
expect(yaml).to include("Author: Sami Samhuri")
|
||||
end
|
||||
|
||||
it 'handles multi-word field names' do
|
||||
input = <<~FRONTMATTER
|
||||
Title: About Page
|
||||
Page type: page
|
||||
Show extension: false
|
||||
Date: 1st January, 2025
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
FRONTMATTER
|
||||
|
||||
yaml = described_class.convert_frontmatter_to_yaml(input)
|
||||
|
||||
expect(yaml).to include("Page type: page")
|
||||
expect(yaml).to include("Show extension: false")
|
||||
end
|
||||
|
||||
it 'escapes embedded quotes in values' do
|
||||
input = <<~FRONTMATTER
|
||||
Title: The "Swift" Programming Language
|
||||
Date: 1st January, 2025
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
FRONTMATTER
|
||||
|
||||
yaml = described_class.convert_frontmatter_to_yaml(input)
|
||||
|
||||
expect(yaml).to include('Title: "The \"Swift\" Programming Language"')
|
||||
expect(yaml).not_to include('Title: "The "Swift" Programming Language"')
|
||||
end
|
||||
|
||||
it 'escapes backslashes in values' do
|
||||
input = <<~FRONTMATTER
|
||||
Title: Paths\\and\\backslashes, oh my
|
||||
Date: 1st January, 2025
|
||||
Timestamp: 2025-01-01T12:00:00-08:00
|
||||
FRONTMATTER
|
||||
|
||||
yaml = described_class.convert_frontmatter_to_yaml(input)
|
||||
|
||||
expect(yaml).to include('Title: "Paths\\\\and\\\\backslashes, oh my"')
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue