From 0ee8001c567f3bd5e427a63d5602d9853bcee132 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 May 2025 18:29:17 +0000 Subject: [PATCH 1/3] Initial plan for issue From 5e901422ff5a16d4dfd98546d8e0ee894d89d62b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 May 2025 18:40:36 +0000 Subject: [PATCH 2/3] Implement link validation feature Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com> --- README.md | 12 ++++++++++++ lib/jekyll-relative-links/generator.rb | 11 +++++++++++ spec/jekyll-relative-links/generator_spec.rb | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/README.md b/README.md index 1b5f2cc..5728e2e 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ You can configure this plugin in `_config.yml` under the `relative_links` key. T relative_links: enabled: true collections: false + validate_links: false ``` ### Excluding files @@ -104,3 +105,14 @@ File | Link ### Disabling Even if the plugin is enabled (e.g., via the `:jekyll_plugins` group in your Gemfile) you can disable it by setting the `enabled` key to `false`. + +### Validating Links + +By default, the plugin doesn't validate if linked files exist. It will silently keep the original Markdown links when the target file doesn't exist. + +Setting the `validate_links` option to `true` enables link validation, causing Jekyll to raise an error when attempting to link to a nonexistent file, similar to Jekyll's native `{% link %}` tag. + +```yml +relative_links: + validate_links: true +``` diff --git a/lib/jekyll-relative-links/generator.rb b/lib/jekyll-relative-links/generator.rb index aa99db4..90bf321 100644 --- a/lib/jekyll-relative-links/generator.rb +++ b/lib/jekyll-relative-links/generator.rb @@ -18,6 +18,7 @@ class Generator < Jekyll::Generator CONFIG_KEY = "relative_links" ENABLED_KEY = "enabled" COLLECTIONS_KEY = "collections" + VALIDATE_LINKS_KEY = "validate_links" LOG_KEY = "Relative Links:" safe true @@ -55,6 +56,12 @@ def replace_relative_links!(document) path = path_from_root(link.path, url_base) url = url_for_path(path) + + if url.nil? && validate_links? + source = document.relative_path + raise "Invalid reference to '#{link.path}' in '#{source}'" + end + next original unless url link.path = url @@ -151,6 +158,10 @@ def collections? option(COLLECTIONS_KEY) == true end + def validate_links? + option(VALIDATE_LINKS_KEY) == true + end + def excluded?(document) return false unless option("exclude") diff --git a/spec/jekyll-relative-links/generator_spec.rb b/spec/jekyll-relative-links/generator_spec.rb index c30f539..1ceb312 100644 --- a/spec/jekyll-relative-links/generator_spec.rb +++ b/spec/jekyll-relative-links/generator_spec.rb @@ -340,6 +340,25 @@ end end + context "link validation" do + it "knows when validation is enabled" do + plugin_config = { "validate_links" => true } + generator = described_class.new({ "relative_links" => plugin_config }) + expect(generator.send(:validate_links?)).to be true + end + + it "knows when validation is disabled" do + plugin_config = { "validate_links" => false } + generator = described_class.new({ "relative_links" => plugin_config }) + expect(generator.send(:validate_links?)).to be false + end + + it "has validation disabled by default" do + generator = described_class.new({}) + expect(generator.send(:validate_links?)).to be false + end + end + context "a page without content" do before { page_by_path(site, "page.md").content = nil } From 64404231be912d643b3aac21960001a935dadd1d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 May 2025 16:22:12 +0000 Subject: [PATCH 3/3] Fix failing tests by addressing RuboCop violations Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com> --- lib/jekyll-relative-links/generator.rb | 6 ++++-- spec/jekyll-relative-links/generator_spec.rb | 22 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/jekyll-relative-links/generator.rb b/lib/jekyll-relative-links/generator.rb index d7db780..cab3e5a 100644 --- a/lib/jekyll-relative-links/generator.rb +++ b/lib/jekyll-relative-links/generator.rb @@ -46,6 +46,7 @@ def generate(site) end end + # rubocop:disable Metrics/AbcSize def replace_relative_links!(document) url_base = File.dirname(document.relative_path) return document if document.content.nil? @@ -56,12 +57,12 @@ def replace_relative_links!(document) path = path_from_root(link.path, url_base) url = url_for_path(path) - + if url.nil? && validate_links? source = document.relative_path raise "Invalid reference to '#{link.path}' in '#{source}'" end - + next original unless url link.path = url @@ -72,6 +73,7 @@ def replace_relative_links!(document) rescue ArgumentError => e raise e unless e.to_s.start_with?("invalid byte sequence in UTF-8") end + # rubocop:enable Metrics/AbcSize private diff --git a/spec/jekyll-relative-links/generator_spec.rb b/spec/jekyll-relative-links/generator_spec.rb index 1ceb312..cebe4e7 100644 --- a/spec/jekyll-relative-links/generator_spec.rb +++ b/spec/jekyll-relative-links/generator_spec.rb @@ -346,17 +346,35 @@ generator = described_class.new({ "relative_links" => plugin_config }) expect(generator.send(:validate_links?)).to be true end - + it "knows when validation is disabled" do plugin_config = { "validate_links" => false } generator = described_class.new({ "relative_links" => plugin_config }) expect(generator.send(:validate_links?)).to be false end - + it "has validation disabled by default" do generator = described_class.new({}) expect(generator.send(:validate_links?)).to be false end + + context "when validation is enabled" do + let(:plugin_config) { { "validate_links" => true } } + + before do + site.reset + site.read + subject.instance_variable_set :@site, site + end + + it "raises an error when a file doesn't exist" do + page.content = "[Missing](./nonexistent.md)" + + expect do + subject.replace_relative_links!(page) + end.to raise_error(%r!Invalid reference to './nonexistent.md' in 'page.md'!) + end + end end context "a page without content" do