From 03bbd783a128e282b4c6bf6de2605859ea2d0cdc Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2026 18:16:01 -0800 Subject: [PATCH] Skip hidden files and absolutize feed asset URLs --- lib/site_generator.rb | 8 +++++++- lib/views/feed_post_view.rb | 11 ++++++++++- spec/posts/json_feed_spec.rb | 27 +++++++++++++++++++++++++++ spec/site_generator_spec.rb | 19 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/lib/site_generator.rb b/lib/site_generator.rb index c8b1879..98f204c 100644 --- a/lib/site_generator.rb +++ b/lib/site_generator.rb @@ -47,7 +47,7 @@ module Pressa Dir.glob(File.join(public_dir, "**", "*"), File::FNM_DOTMATCH).each do |source_file| next if File.directory?(source_file) - next if File.basename(source_file) == "." || File.basename(source_file) == ".." + next if skip_file?(source_file) filename = File.basename(source_file) ext = File.extname(source_file)[1..] @@ -75,6 +75,7 @@ module Pressa site.renderers.each do |renderer| Dir.glob(File.join(public_dir, "**", "*"), File::FNM_DOTMATCH).each do |source_file| next if File.directory?(source_file) + next if skip_file?(source_file) filename = File.basename(source_file) ext = File.extname(source_file)[1..] @@ -93,5 +94,10 @@ module Pressa end end end + + def skip_file?(source_file) + basename = File.basename(source_file) + basename.start_with?(".") + end end end diff --git a/lib/views/feed_post_view.rb b/lib/views/feed_post_view.rb index cfd001a..fabbc4b 100644 --- a/lib/views/feed_post_view.rb +++ b/lib/views/feed_post_view.rb @@ -11,7 +11,7 @@ module Pressa def view_template div do p(class: "time") { @post.formatted_date } - raw(safe(@post.body)) + raw(safe(normalized_body)) p do a(class: "permalink", href: @site.url_for(@post.path)) { "∞" } end @@ -19,6 +19,15 @@ module Pressa end private + + def normalized_body + @post.body.gsub(/(href|src)=(['"])(\/(?!\/)[^'"]*)\2/) do + attr = Regexp.last_match(1) + quote = Regexp.last_match(2) + path = Regexp.last_match(3) + %(#{attr}=#{quote}#{@site.url_for(path)}#{quote}) + end + end end end end diff --git a/spec/posts/json_feed_spec.rb b/spec/posts/json_feed_spec.rb index b5f041e..70f249b 100644 --- a/spec/posts/json_feed_spec.rb +++ b/spec/posts/json_feed_spec.rb @@ -69,5 +69,32 @@ RSpec.describe Pressa::Posts::JSONFeedWriter do expect(item).not_to have_key("external_url") end end + + it "expands root-relative links in content_html to absolute URLs" do + post_with_assets = Pressa::Posts::Post.new( + slug: "swift-optional-or", + title: "Swift Optional OR", + author: "Sami Samhuri", + date: DateTime.parse("2017-10-01T10:00:00-07:00"), + formatted_date: "1st October, 2017", + body: '

read

' \ + '

me

' \ + '

cdn

', + excerpt: "hello...", + path: "/posts/2017/10/swift-optional-or" + ) + allow(posts_by_year).to receive(:recent_posts).and_return([post_with_assets]) + + Dir.mktmpdir do |dir| + writer.write_feed(target_path: dir, limit: 30) + feed = JSON.parse(File.read(File.join(dir, "feed.json"))) + item = feed.fetch("items").first + content_html = item.fetch("content_html") + + expect(content_html).to include('href="https://samhuri.net/posts/2010/01/basics-of-the-mach-o-file-format"') + expect(content_html).to include('src="https://samhuri.net/images/me.jpg"') + expect(content_html).to include('href="//cdn.example.net/app.js"') + end + end end end diff --git a/spec/site_generator_spec.rb b/spec/site_generator_spec.rb index 5caf0ba..9b04ab1 100644 --- a/spec/site_generator_spec.rb +++ b/spec/site_generator_spec.rb @@ -30,4 +30,23 @@ RSpec.describe Pressa::SiteGenerator do expect(File.read(source_file)).to eq("safe") end end + + it "does not copy ignored dotfiles from public" do + Dir.mktmpdir do |dir| + source_path = File.join(dir, "source") + target_path = File.join(dir, "target") + public_path = File.join(source_path, "public") + FileUtils.mkdir_p(public_path) + + File.write(File.join(public_path, ".DS_Store"), "finder cache") + File.write(File.join(public_path, ".gitkeep"), "") + File.write(File.join(public_path, "visible.txt"), "ok") + + described_class.new(site:).generate(source_path:, target_path:) + + expect(File.exist?(File.join(target_path, "visible.txt"))).to be(true) + expect(File.exist?(File.join(target_path, ".DS_Store"))).to be(false) + expect(File.exist?(File.join(target_path, ".gitkeep"))).to be(false) + end + end end