From 5571dc766e2143e39762ff0b47c41d1c2e154f4c Mon Sep 17 00:00:00 2001 From: Benjamin Sanders Date: Sat, 11 Oct 2025 10:34:24 -0400 Subject: Vendor bundled gems for deployment --- .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/cache.rb | 186 +++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/cleaner.rb | 111 ++ .../gems/jekyll-4.4.1/lib/jekyll/collection.rb | 310 +++++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/command.rb | 105 ++ .../gems/jekyll-4.4.1/lib/jekyll/commands/build.rb | 82 ++ .../gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb | 44 + .../jekyll-4.4.1/lib/jekyll/commands/doctor.rb | 177 +++ .../gems/jekyll-4.4.1/lib/jekyll/commands/help.rb | 34 + .../gems/jekyll-4.4.1/lib/jekyll/commands/new.rb | 168 +++ .../jekyll-4.4.1/lib/jekyll/commands/new_theme.rb | 39 + .../gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb | 372 ++++++ .../jekyll/commands/serve/live_reload_reactor.rb | 119 ++ .../commands/serve/livereload_assets/livereload.js | 1183 ++++++++++++++++++++ .../jekyll/commands/serve/mime_types_charset.json | 71 ++ .../lib/jekyll/commands/serve/servlet.rb | 206 ++++ .../lib/jekyll/commands/serve/websockets.rb | 81 ++ .../gems/jekyll-4.4.1/lib/jekyll/configuration.rb | 313 ++++++ .../gems/jekyll-4.4.1/lib/jekyll/converter.rb | 54 + .../jekyll-4.4.1/lib/jekyll/converters/identity.rb | 41 + .../jekyll-4.4.1/lib/jekyll/converters/markdown.rb | 113 ++ .../jekyll/converters/markdown/kramdown_parser.rb | 197 ++++ .../lib/jekyll/converters/smartypants.rb | 70 ++ .../gems/jekyll-4.4.1/lib/jekyll/convertible.rb | 257 +++++ .../gems/jekyll-4.4.1/lib/jekyll/deprecator.rb | 50 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/document.rb | 543 +++++++++ .../lib/jekyll/drops/collection_drop.rb | 20 + .../jekyll-4.4.1/lib/jekyll/drops/document_drop.rb | 74 ++ .../gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb | 294 +++++ .../jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb | 23 + .../jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb | 32 + .../jekyll-4.4.1/lib/jekyll/drops/site_drop.rb | 66 ++ .../lib/jekyll/drops/static_file_drop.rb | 14 + .../jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb | 39 + .../lib/jekyll/drops/unified_payload_drop.rb | 30 + .../gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb | 140 +++ .../gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb | 117 ++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/errors.rb | 20 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb | 200 ++++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/external.rb | 75 ++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters.rb | 540 +++++++++ .../lib/jekyll/filters/date_filters.rb | 110 ++ .../lib/jekyll/filters/grouping_filters.rb | 64 ++ .../jekyll-4.4.1/lib/jekyll/filters/url_filters.rb | 98 ++ .../lib/jekyll/frontmatter_defaults.rb | 238 ++++ .../gems/jekyll-4.4.1/lib/jekyll/generator.rb | 5 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/hooks.rb | 107 ++ .../gems/jekyll-4.4.1/lib/jekyll/inclusion.rb | 32 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/layout.rb | 55 + .../jekyll-4.4.1/lib/jekyll/liquid_extensions.rb | 22 + .../jekyll-4.4.1/lib/jekyll/liquid_renderer.rb | 80 ++ .../lib/jekyll/liquid_renderer/file.rb | 77 ++ .../lib/jekyll/liquid_renderer/table.rb | 45 + .../gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb | 151 +++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/mime.types | 940 ++++++++++++++++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/page.rb | 215 ++++ .../gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb | 25 + .../jekyll-4.4.1/lib/jekyll/page_without_a_file.rb | 14 + .../gems/jekyll-4.4.1/lib/jekyll/path_manager.rb | 74 ++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin.rb | 92 ++ .../gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb | 123 ++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/profiler.rb | 51 + .../gems/jekyll-4.4.1/lib/jekyll/publisher.rb | 23 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/reader.rb | 209 ++++ .../lib/jekyll/readers/collection_reader.rb | 23 + .../jekyll-4.4.1/lib/jekyll/readers/data_reader.rb | 113 ++ .../lib/jekyll/readers/layout_reader.rb | 62 + .../jekyll-4.4.1/lib/jekyll/readers/page_reader.rb | 25 + .../jekyll-4.4.1/lib/jekyll/readers/post_reader.rb | 85 ++ .../lib/jekyll/readers/static_file_reader.rb | 25 + .../lib/jekyll/readers/theme_assets_reader.rb | 52 + .../gems/jekyll-4.4.1/lib/jekyll/regenerator.rb | 195 ++++ .../gems/jekyll-4.4.1/lib/jekyll/related_posts.rb | 52 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/renderer.rb | 263 +++++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb | 576 ++++++++++ .../gems/jekyll-4.4.1/lib/jekyll/static_file.rb | 203 ++++ .../gems/jekyll-4.4.1/lib/jekyll/stevenson.rb | 57 + .../gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb | 129 +++ .../gems/jekyll-4.4.1/lib/jekyll/tags/include.rb | 275 +++++ .../gems/jekyll-4.4.1/lib/jekyll/tags/link.rb | 42 + .../gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb | 106 ++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme.rb | 90 ++ .../gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb | 121 ++ .../ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/url.rb | 167 +++ .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils.rb | 371 ++++++ .../gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb | 57 + .../gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb | 26 + .../gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb | 37 + .../jekyll-4.4.1/lib/jekyll/utils/platforms.rb | 67 ++ .../jekyll-4.4.1/lib/jekyll/utils/thread_event.rb | 31 + .../gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb | 46 + .../3.4.0/gems/jekyll-4.4.1/lib/jekyll/version.rb | 5 + 91 files changed, 12761 insertions(+) create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cache.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cleaner.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/collection.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/command.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/configuration.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converter.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/convertible.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/document.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/errors.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/external.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/generator.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/hooks.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/layout.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/mime.types create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/profiler.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/publisher.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/renderer.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/static_file.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/url.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb create mode 100644 vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/version.rb (limited to 'vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll') diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cache.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cache.rb new file mode 100644 index 0000000..8bffd0d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cache.rb @@ -0,0 +1,186 @@ +# frozen_string_literal: true + +require "digest" + +module Jekyll + class Cache + # class-wide base cache + @base_cache = {} + + # class-wide directive to write cache to disk is enabled by default + @disk_cache_enabled = true + + class << self + attr_accessor :cache_dir # class-wide cache location + + attr_reader :base_cache, # class-wide base cache reader + :disk_cache_enabled # class-wide directive to write cache to disk + + # Disable Marshaling cached items to disk + def disable_disk_cache! + @disk_cache_enabled = false + end + + # Clear all caches + def clear + delete_cache_files + base_cache.each_value(&:clear) + end + + # Compare the current config to the cached config + # If they are different, clear all caches + # + # Returns nothing. + def clear_if_config_changed(config) + config = config.inspect + cache = Jekyll::Cache.new "Jekyll::Cache" + return if cache.key?("config") && cache["config"] == config + + clear + cache = Jekyll::Cache.new "Jekyll::Cache" + cache["config"] = config + nil + end + + private + + # Delete all cached items from all caches + # + # Returns nothing. + def delete_cache_files + FileUtils.rm_rf(@cache_dir) if disk_cache_enabled + end + end + + # + + # Get an existing named cache, or create a new one if none exists + # + # name - name of the cache + # + # Returns nothing. + def initialize(name) + @cache = Jekyll::Cache.base_cache[name] ||= {} + @name = name.gsub(%r![^\w\s-]!, "-") + end + + # Clear this particular cache + def clear + delete_cache_files + @cache.clear + end + + # Retrieve a cached item + # Raises if key does not exist in cache + # + # Returns cached value + def [](key) + return @cache[key] if @cache.key?(key) + + path = path_to(hash(key)) + if disk_cache_enabled? && File.file?(path) && File.readable?(path) + @cache[key] = load(path) + else + raise + end + end + + # Add an item to cache + # + # Returns nothing. + def []=(key, value) + @cache[key] = value + return unless disk_cache_enabled? + + path = path_to(hash(key)) + value = new Hash(value) if value.is_a?(Hash) && !value.default.nil? + dump(path, value) + rescue TypeError + Jekyll.logger.debug "Cache:", "Cannot dump object #{key}" + end + + # If an item already exists in the cache, retrieve it. + # Else execute code block, and add the result to the cache, and return that result. + def getset(key) + self[key] + rescue StandardError + value = yield + self[key] = value + value + end + + # Remove one particular item from the cache + # + # Returns nothing. + def delete(key) + @cache.delete(key) + File.delete(path_to(hash(key))) if disk_cache_enabled? + end + + # Check if `key` already exists in this cache + # + # Returns true if key exists in the cache, false otherwise + def key?(key) + # First, check if item is already cached in memory + return true if @cache.key?(key) + # Otherwise, it might be cached on disk + # but we should not consider the disk cache if it is disabled + return false unless disk_cache_enabled? + + path = path_to(hash(key)) + File.file?(path) && File.readable?(path) + end + + def disk_cache_enabled? + !!Jekyll::Cache.disk_cache_enabled + end + + private + + # Given a hashed key, return the path to where this item would be saved on disk. + def path_to(hash = nil) + @base_dir ||= File.join(Jekyll::Cache.cache_dir, @name) + return @base_dir if hash.nil? + + File.join(@base_dir, hash[0..1], hash[2..-1]).freeze + end + + # Given a key, return a SHA2 hash that can be used for caching this item to disk. + def hash(key) + Digest::SHA2.hexdigest(key).freeze + end + + # Remove all this caches items from disk + # + # Returns nothing. + def delete_cache_files + FileUtils.rm_rf(path_to) if disk_cache_enabled? + end + + # Load `path` from disk and return the result. + # This MUST NEVER be called in Safe Mode + # rubocop:disable Security/MarshalLoad + def load(path) + raise unless disk_cache_enabled? + + cached_file = File.open(path, "rb") + value = Marshal.load(cached_file) + cached_file.close + value + end + # rubocop:enable Security/MarshalLoad + + # Given a path and a value, save value to disk at path. + # This should NEVER be called in Safe Mode + # + # Returns nothing. + def dump(path, value) + return unless disk_cache_enabled? + + FileUtils.mkdir_p(File.dirname(path)) + File.open(path, "wb") do |cached_file| + Marshal.dump(value, cached_file) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cleaner.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cleaner.rb new file mode 100644 index 0000000..59e7c22 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/cleaner.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +module Jekyll + # Handles the cleanup of a site's destination before it is built. + class Cleaner + HIDDEN_FILE_REGEX = %r!/\.{1,2}$!.freeze + attr_reader :site + + def initialize(site) + @site = site + end + + # Cleans up the site's destination directory + def cleanup! + FileUtils.rm_rf(obsolete_files) + FileUtils.rm_rf(metadata_file) unless @site.incremental? + end + + private + + # Private: The list of files and directories to be deleted during cleanup process + # + # Returns an Array of the file and directory paths + def obsolete_files + out = (existing_files - new_files - new_dirs + replaced_files).to_a + Jekyll::Hooks.trigger :clean, :on_obsolete, out + out + end + + # Private: The metadata file storing dependency tree and build history + # + # Returns an Array with the metadata file as the only item + def metadata_file + [site.regenerator.metadata_file] + end + + # Private: The list of existing files, apart from those included in + # keep_files and hidden files. + # + # Returns a Set with the file paths + def existing_files + files = Set.new + regex = keep_file_regex + dirs = keep_dirs + + Utils.safe_glob(site.in_dest_dir, ["**", "*"], File::FNM_DOTMATCH).each do |file| + next if HIDDEN_FILE_REGEX.match?(file) || regex.match?(file) || dirs.include?(file) + + files << file + end + + files + end + + # Private: The list of files to be created when site is built. + # + # Returns a Set with the file paths + def new_files + @new_files ||= Set.new.tap do |files| + site.each_site_file { |item| files << item.destination(site.dest) } + end + end + + # Private: The list of directories to be created when site is built. + # These are the parent directories of the files in #new_files. + # + # Returns a Set with the directory paths + def new_dirs + @new_dirs ||= new_files.flat_map { |file| parent_dirs(file) }.to_set + end + + # Private: The list of parent directories of a given file + # + # Returns an Array with the directory paths + def parent_dirs(file) + parent_dir = File.dirname(file) + if parent_dir == site.dest + [] + else + parent_dirs(parent_dir).unshift(parent_dir) + end + end + + # Private: The list of existing files that will be replaced by a directory + # during build + # + # Returns a Set with the file paths + def replaced_files + new_dirs.select { |dir| File.file?(dir) }.to_set + end + + # Private: The list of directories that need to be kept because they are + # parent directories of files specified in keep_files + # + # Returns a Set with the directory paths + def keep_dirs + site.keep_files.flat_map { |file| parent_dirs(site.in_dest_dir(file)) }.to_set + end + + # Private: Creates a regular expression from the config's keep_files array + # + # Examples + # ['.git','.svn'] with site.dest "/myblog/_site" creates + # the following regex: /\A\/myblog\/_site\/(\.git|\/.svn)/ + # + # Returns the regular expression + def keep_file_regex + %r!\A#{Regexp.quote(site.dest)}/(#{Regexp.union(site.keep_files).source})! + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/collection.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/collection.rb new file mode 100644 index 0000000..1ce33bf --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/collection.rb @@ -0,0 +1,310 @@ +# frozen_string_literal: true + +module Jekyll + class Collection + attr_reader :site, :label, :metadata + attr_writer :docs + + # Create a new Collection. + # + # site - the site to which this collection belongs. + # label - the name of the collection + # + # Returns nothing. + def initialize(site, label) + @site = site + @label = sanitize_label(label) + @metadata = extract_metadata + end + + # Fetch the Documents in this collection. + # Defaults to an empty array if no documents have been read in. + # + # Returns an array of Jekyll::Document objects. + def docs + @docs ||= [] + end + + # Override of normal respond_to? to match method_missing's logic for + # looking in @data. + def respond_to_missing?(method, include_private = false) + docs.respond_to?(method.to_sym, include_private) || super + end + + # Override of method_missing to check in @data for the key. + def method_missing(method, *args, &blck) + if docs.respond_to?(method.to_sym) + Jekyll.logger.warn "Deprecation:", + "#{label}.#{method} should be changed to #{label}.docs.#{method}." + Jekyll.logger.warn "", "Called by #{caller(0..0)}." + docs.public_send(method.to_sym, *args, &blck) + else + super + end + end + + # Fetch the static files in this collection. + # Defaults to an empty array if no static files have been read in. + # + # Returns an array of Jekyll::StaticFile objects. + def files + @files ||= [] + end + + # Read the allowed documents into the collection's array of docs. + # + # Returns the sorted array of docs. + def read + filtered_entries.each do |file_path| + full_path = collection_dir(file_path) + next if File.directory?(full_path) + + if Utils.has_yaml_header? full_path + read_document(full_path) + else + read_static_file(file_path, full_path) + end + end + site.static_files.concat(files) unless files.empty? + sort_docs! + end + + # All the entries in this collection. + # + # Returns an Array of file paths to the documents in this collection + # relative to the collection's directory + def entries + return [] unless exists? + + @entries ||= begin + collection_dir_slash = "#{collection_dir}/" + Utils.safe_glob(collection_dir, ["**", "*"], File::FNM_DOTMATCH).map do |entry| + entry[collection_dir_slash] = "" + entry + end + end + end + + # Filtered version of the entries in this collection. + # See `Jekyll::EntryFilter#filter` for more information. + # + # Returns a list of filtered entry paths. + def filtered_entries + return [] unless exists? + + @filtered_entries ||= + Dir.chdir(directory) do + entry_filter.filter(entries).reject do |f| + path = collection_dir(f) + File.directory?(path) || entry_filter.symlink?(f) + end + end + end + + # The directory for this Collection, relative to the site source or the directory + # containing the collection. + # + # Returns a String containing the directory name where the collection + # is stored on the filesystem. + def relative_directory + @relative_directory ||= "_#{label}" + end + + # The full path to the directory containing the collection. + # + # Returns a String containing th directory name where the collection + # is stored on the filesystem. + def directory + @directory ||= site.in_source_dir( + File.join(container, relative_directory) + ) + end + + # The full path to the directory containing the collection, with + # optional subpaths. + # + # *files - (optional) any other path pieces relative to the + # directory to append to the path + # + # Returns a String containing th directory name where the collection + # is stored on the filesystem. + def collection_dir(*files) + return directory if files.empty? + + site.in_source_dir(container, relative_directory, *files) + end + + # Checks whether the directory "exists" for this collection. + # The directory must exist on the filesystem and must not be a symlink + # if in safe mode. + # + # Returns false if the directory doesn't exist or if it's a symlink + # and we're in safe mode. + def exists? + File.directory?(directory) && !entry_filter.symlink?(directory) + end + + # The entry filter for this collection. + # Creates an instance of Jekyll::EntryFilter. + # + # Returns the instance of Jekyll::EntryFilter for this collection. + def entry_filter + @entry_filter ||= Jekyll::EntryFilter.new(site, relative_directory) + end + + # An inspect string. + # + # Returns the inspect string + def inspect + "#<#{self.class} @label=#{label} docs=#{docs}>" + end + + # Produce a sanitized label name + # Label names may not contain anything but alphanumeric characters, + # underscores, and hyphens. + # + # label - the possibly-unsafe label + # + # Returns a sanitized version of the label. + def sanitize_label(label) + label.gsub(%r![^a-z0-9_\-.]!i, "") + end + + # Produce a representation of this Collection for use in Liquid. + # Exposes two attributes: + # - label + # - docs + # + # Returns a representation of this collection for use in Liquid. + def to_liquid + Drops::CollectionDrop.new self + end + + # Whether the collection's documents ought to be written as individual + # files in the output. + # + # Returns true if the 'write' metadata is true, false otherwise. + def write? + !!metadata.fetch("output", false) + end + + # The URL template to render collection's documents at. + # + # Returns the URL template to render collection's documents at. + def url_template + @url_template ||= metadata.fetch("permalink") do + Utils.add_permalink_suffix("/:collection/:path", site.permalink_style) + end + end + + # Extract options for this collection from the site configuration. + # + # Returns the metadata for this collection + def extract_metadata + if site.config["collections"].is_a?(Hash) + site.config["collections"][label] || {} + else + {} + end + end + + private + + def container + @container ||= site.config["collections_dir"] + end + + def read_document(full_path) + doc = Document.new(full_path, :site => site, :collection => self) + doc.read + docs << doc if site.unpublished || doc.published? + end + + def sort_docs! + if metadata["order"].is_a?(Array) + rearrange_docs! + elsif metadata["sort_by"].is_a?(String) + sort_docs_by_key! + else + docs.sort! + end + end + + # A custom sort function based on Schwartzian transform + # Refer https://byparker.com/blog/2017/schwartzian-transform-faster-sorting/ for details + def sort_docs_by_key! + meta_key = metadata["sort_by"] + # Modify `docs` array to cache document's property along with the Document instance + docs.map! { |doc| [doc.data[meta_key], doc] }.sort! do |apples, olives| + order = determine_sort_order(meta_key, apples, olives) + + # Fall back to `Document#<=>` if the properties were equal or were non-sortable + # Otherwise continue with current sort-order + if order.nil? || order.zero? + apples[-1] <=> olives[-1] + else + order + end + + # Finally restore the `docs` array with just the Document objects themselves + end.map!(&:last) + end + + def determine_sort_order(sort_key, apples, olives) + apple_property, apple_document = apples + olive_property, olive_document = olives + + if apple_property.nil? && !olive_property.nil? + order_with_warning(sort_key, apple_document, 1) + elsif !apple_property.nil? && olive_property.nil? + order_with_warning(sort_key, olive_document, -1) + else + apple_property <=> olive_property + end + end + + def order_with_warning(sort_key, document, order) + Jekyll.logger.warn "Sort warning:", "'#{sort_key}' not defined in #{document.relative_path}" + order + end + + # Rearrange documents within the `docs` array as listed in the `metadata["order"]` array. + # + # Involves converting the two arrays into hashes based on relative_paths as keys first, then + # merging them to remove duplicates and finally retrieving the Document instances from the + # merged array. + def rearrange_docs! + docs_table = {} + custom_order = {} + + # pre-sort to normalize default array across platforms and then proceed to create a Hash + # from that sorted array. + docs.sort.each do |doc| + docs_table[doc.relative_path] = doc + end + + metadata["order"].each do |entry| + custom_order[File.join(relative_directory, entry)] = nil + end + + result = Jekyll::Utils.deep_merge_hashes(custom_order, docs_table).values + result.compact! + self.docs = result + end + + def read_static_file(file_path, full_path) + relative_dir = Jekyll.sanitized_path( + relative_directory, + File.dirname(file_path) + ).chomp("/.") + + files << StaticFile.new( + site, + site.source, + relative_dir, + File.basename(full_path), + self + ) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/command.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/command.rb new file mode 100644 index 0000000..be8890e --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/command.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +module Jekyll + class Command + class << self + # A list of subclasses of Jekyll::Command + def subclasses + @subclasses ||= [] + end + + # Keep a list of subclasses of Jekyll::Command every time it's inherited + # Called automatically. + # + # base - the subclass + # + # Returns nothing + def inherited(base) + subclasses << base + super(base) + end + + # Run Site#process and catch errors + # + # site - the Jekyll::Site object + # + # Returns nothing + def process_site(site) + site.process + rescue Jekyll::Errors::FatalException => e + Jekyll.logger.error "ERROR:", "YOUR SITE COULD NOT BE BUILT:" + Jekyll.logger.error "", "------------------------------------" + Jekyll.logger.error "", e.message + exit(1) + end + + # Create a full Jekyll configuration with the options passed in as overrides + # + # options - the configuration overrides + # + # Returns a full Jekyll configuration + def configuration_from_options(options) + return options if options.is_a?(Jekyll::Configuration) + + Jekyll.configuration(options) + end + + # Add common options to a command for building configuration + # + # cmd - the Jekyll::Command to add these options to + # + # Returns nothing + # rubocop:disable Metrics/MethodLength + def add_build_options(cmd) + cmd.option "config", "--config CONFIG_FILE[,CONFIG_FILE2,...]", + Array, "Custom configuration file" + cmd.option "destination", "-d", "--destination DESTINATION", + "The current folder will be generated into DESTINATION" + cmd.option "source", "-s", "--source SOURCE", "Custom source directory" + cmd.option "future", "--future", "Publishes posts with a future date" + cmd.option "limit_posts", "--limit_posts MAX_POSTS", Integer, + "Limits the number of posts to parse and publish" + cmd.option "watch", "-w", "--[no-]watch", "Watch for changes and rebuild" + cmd.option "baseurl", "-b", "--baseurl URL", + "Serve the website from the given base URL" + cmd.option "force_polling", "--force_polling", "Force watch to use polling" + cmd.option "lsi", "--lsi", "Use LSI for improved related posts" + cmd.option "show_drafts", "-D", "--drafts", "Render posts in the _drafts folder" + cmd.option "unpublished", "--unpublished", + "Render posts that were marked as unpublished" + cmd.option "disable_disk_cache", "--disable-disk-cache", + "Disable caching to disk in non-safe mode" + cmd.option "quiet", "-q", "--quiet", "Silence output." + cmd.option "verbose", "-V", "--verbose", "Print verbose output." + cmd.option "incremental", "-I", "--incremental", "Enable incremental rebuild." + cmd.option "strict_front_matter", "--strict_front_matter", + "Fail if errors are present in front matter" + end + # rubocop:enable Metrics/MethodLength + + # Run ::process method in a given set of Jekyll::Command subclasses and suggest + # re-running the associated command with --trace switch to obtain any additional + # information or backtrace regarding the encountered Exception. + # + # cmd - the Jekyll::Command to be handled + # options - configuration overrides + # klass - an array of Jekyll::Command subclasses associated with the command + # + # Note that all exceptions are rescued.. + # rubocop: disable Lint/RescueException + def process_with_graceful_fail(cmd, options, *klass) + klass.each { |k| k.process(options) if k.respond_to?(:process) } + rescue Exception => e + raise e if cmd.trace + + msg = " Please append `--trace` to the `#{cmd.name}` command " + dashes = "-" * msg.length + Jekyll.logger.error "", dashes + Jekyll.logger.error "Jekyll #{Jekyll::VERSION} ", msg + Jekyll.logger.error "", " for any additional information or backtrace. " + Jekyll.logger.abort_with "", dashes + end + # rubocop: enable Lint/RescueException + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb new file mode 100644 index 0000000..204b2a1 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/build.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module Jekyll + module Commands + class Build < Command + class << self + # Create the Mercenary command for the Jekyll CLI for this Command + def init_with_program(prog) + prog.command(:build) do |c| + c.syntax "build [options]" + c.description "Build your site" + c.alias :b + + add_build_options(c) + + c.action do |_, options| + options["serving"] = false + process_with_graceful_fail(c, options, self) + end + end + end + + # Build your jekyll site + # Continuously watch if `watch` is set to true in the config. + def process(options) + # Adjust verbosity quickly + Jekyll.logger.adjust_verbosity(options) + + options = configuration_from_options(options) + site = Jekyll::Site.new(options) + + if options.fetch("skip_initial_build", false) + Jekyll.logger.warn "Build Warning:", + "Skipping the initial build. This may result in an out-of-date site." + else + build(site, options) + end + + if options.fetch("detach", false) + Jekyll.logger.info "Auto-regeneration:", + "disabled when running server detached." + elsif options.fetch("watch", false) + watch(site, options) + else + Jekyll.logger.info "Auto-regeneration:", "disabled. Use --watch to enable." + end + end + + # Build your Jekyll site. + # + # site - the Jekyll::Site instance to build + # options - A Hash of options passed to the command + # + # Returns nothing. + def build(site, options) + t = Time.now + source = File.expand_path(options["source"]) + destination = File.expand_path(options["destination"]) + incremental = options["incremental"] + Jekyll.logger.info "Source:", source + Jekyll.logger.info "Destination:", destination + Jekyll.logger.info "Incremental build:", + (incremental ? "enabled" : "disabled. Enable with --incremental") + Jekyll.logger.info "Generating..." + process_site(site) + Jekyll.logger.info "", "done in #{(Time.now - t).round(3)} seconds." + end + + # Private: Watch for file changes and rebuild the site. + # + # site - A Jekyll::Site instance + # options - A Hash of options passed to the command + # + # Returns nothing. + def watch(site, options) + External.require_with_graceful_fail "jekyll-watch" + Jekyll::Watcher.watch(options, site) + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb new file mode 100644 index 0000000..9b657a4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/clean.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Jekyll + module Commands + class Clean < Command + class << self + def init_with_program(prog) + prog.command(:clean) do |c| + c.syntax "clean [subcommand]" + c.description "Clean the site (removes site output and metadata file) without building." + + add_build_options(c) + + c.action do |_, options| + Jekyll::Commands::Clean.process(options) + end + end + end + + def process(options) + options = configuration_from_options(options) + destination = options["destination"] + metadata_file = File.join(options["source"], ".jekyll-metadata") + cache_dir = File.join(options["source"], options["cache_dir"]) + sass_cache = ".sass-cache" + + remove(destination, :checker_func => :directory?) + remove(metadata_file, :checker_func => :file?) + remove(cache_dir, :checker_func => :directory?) + remove(sass_cache, :checker_func => :directory?) + end + + def remove(filename, checker_func: :file?) + if File.public_send(checker_func, filename) + Jekyll.logger.info "Cleaner:", "Removing #{filename}..." + FileUtils.rm_rf(filename) + else + Jekyll.logger.info "Cleaner:", "Nothing to do for #{filename}." + end + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb new file mode 100644 index 0000000..eec7133 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/doctor.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true + +module Jekyll + module Commands + class Doctor < Command + class << self + def init_with_program(prog) + prog.command(:doctor) do |c| + c.syntax "doctor" + c.description "Search site and print specific deprecation warnings" + c.alias(:hyde) + + c.option "config", "--config CONFIG_FILE[,CONFIG_FILE2,...]", Array, + "Custom configuration file" + + c.action do |_, options| + Jekyll::Commands::Doctor.process(options) + end + end + end + + def process(options) + site = Jekyll::Site.new(configuration_from_options(options)) + site.reset + site.read + site.generate + + if healthy?(site) + Jekyll.logger.info "Your test results", "are in. Everything looks fine." + else + abort + end + end + + def healthy?(site) + [ + fsnotify_buggy?(site), + !deprecated_relative_permalinks(site), + !conflicting_urls(site), + !urls_only_differ_by_case(site), + proper_site_url?(site), + properly_gathered_posts?(site), + ].all? + end + + def properly_gathered_posts?(site) + return true if site.config["collections_dir"].empty? + + posts_at_root = site.in_source_dir("_posts") + return true unless File.directory?(posts_at_root) + + Jekyll.logger.warn "Warning:", + "Detected '_posts' directory outside custom `collections_dir`!" + Jekyll.logger.warn "", + "Please move '#{posts_at_root}' into the custom directory at " \ + "'#{site.in_source_dir(site.config["collections_dir"])}'" + false + end + + def deprecated_relative_permalinks(site) + if site.config["relative_permalinks"] + Jekyll::Deprecator.deprecation_message "Your site still uses relative permalinks, " \ + "which was removed in Jekyll v3.0.0." + true + end + end + + def conflicting_urls(site) + conflicting_urls = false + destination_map(site).each do |dest, paths| + next unless paths.size > 1 + + conflicting_urls = true + Jekyll.logger.warn "Conflict:", + "The following destination is shared by multiple files." + Jekyll.logger.warn "", "The written file may end up with unexpected contents." + Jekyll.logger.warn "", dest.to_s.cyan + paths.each { |path| Jekyll.logger.warn "", " - #{path}" } + Jekyll.logger.warn "" + end + conflicting_urls + end + + def fsnotify_buggy?(_site) + return true unless Utils::Platforms.osx? + + if Dir.pwd != `pwd`.strip + Jekyll.logger.error <<~STR + We have detected that there might be trouble using fsevent on your + operating system, you can read https://github.com/thibaudgg/rb-fsevent/wiki/no-fsevents-fired-(OSX-bug) + for possible workarounds or you can work around it immediately + with `--force-polling`. + STR + + false + end + + true + end + + def urls_only_differ_by_case(site) + urls_only_differ_by_case = false + urls = case_insensitive_urls(site.pages + site.docs_to_write, site.dest) + urls.each_value do |real_urls| + next unless real_urls.uniq.size > 1 + + urls_only_differ_by_case = true + Jekyll.logger.warn "Warning:", "The following URLs only differ by case. On a " \ + "case-insensitive file system one of the URLs will be " \ + "overwritten by the other: #{real_urls.join(", ")}" + end + urls_only_differ_by_case + end + + def proper_site_url?(site) + url = site.config["url"] + [ + url_exists?(url), + url_valid?(url), + url_absolute(url), + ].all? + end + + private + + def destination_map(site) + {}.tap do |result| + site.each_site_file do |thing| + next if allow_used_permalink?(thing) + + dest_path = thing.destination(site.dest) + (result[dest_path] ||= []) << thing.path + end + end + end + + def allow_used_permalink?(item) + defined?(JekyllRedirectFrom) && item.is_a?(JekyllRedirectFrom::RedirectPage) + end + + def case_insensitive_urls(things, destination) + things.each_with_object({}) do |thing, memo| + dest = thing.destination(destination) + (memo[dest.downcase] ||= []) << dest + end + end + + def url_exists?(url) + return true unless url.nil? || url.empty? + + Jekyll.logger.warn "Warning:", "You didn't set an URL in the config file, you may " \ + "encounter problems with some plugins." + false + end + + def url_valid?(url) + Addressable::URI.parse(url) + true + # Addressable::URI#parse only raises a TypeError + # https://github.com/sporkmonger/addressable/blob/0a0e96acb17225f9b1c9cab0bad332b448934c9a/lib/addressable/uri.rb#L103 + rescue TypeError + Jekyll.logger.warn "Warning:", "The site URL does not seem to be valid, " \ + "check the value of `url` in your config file." + false + end + + def url_absolute(url) + return true if url.is_a?(String) && Addressable::URI.parse(url).absolute? + + Jekyll.logger.warn "Warning:", "Your site URL does not seem to be absolute, " \ + "check the value of `url` in your config file." + false + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb new file mode 100644 index 0000000..90403df --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/help.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Jekyll + module Commands + class Help < Command + class << self + def init_with_program(prog) + prog.command(:help) do |c| + c.syntax "help [subcommand]" + c.description "Show the help message, optionally for a given subcommand." + + c.action do |args, _| + cmd = (args.first || "").to_sym + if args.empty? + Jekyll.logger.info prog.to_s + elsif prog.has_command? cmd + Jekyll.logger.info prog.commands[cmd].to_s + else + invalid_command(prog, cmd) + abort + end + end + end + end + + def invalid_command(prog, cmd) + Jekyll.logger.error "Error:", + "Hmm... we don't know what the '#{cmd}' command is." + Jekyll.logger.info "Valid commands:", prog.commands.keys.join(", ") + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb new file mode 100644 index 0000000..161a3dd --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +require "erb" + +module Jekyll + module Commands + class New < Command + class << self + def init_with_program(prog) + prog.command(:new) do |c| + c.syntax "new PATH" + c.description "Creates a new Jekyll site scaffold in PATH" + + c.option "force", "--force", "Force creation even if PATH already exists" + c.option "blank", "--blank", "Creates scaffolding but with empty files" + c.option "skip-bundle", "--skip-bundle", "Skip 'bundle install'" + + c.action do |args, options| + Jekyll::Commands::New.process(args, options) + end + end + end + + def process(args, options = {}) + raise ArgumentError, "You must specify a path." if args.empty? + + new_blog_path = File.expand_path(args.join(" "), Dir.pwd) + FileUtils.mkdir_p new_blog_path + if preserve_source_location?(new_blog_path, options) + Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty." + Jekyll.logger.abort_with "", "Ensure #{new_blog_path} is empty or else try again " \ + "with `--force` to proceed and overwrite any files." + end + + if options["blank"] + create_blank_site new_blog_path + else + create_site new_blog_path + end + + after_install(new_blog_path, options) + end + + def blank_template + File.expand_path("../../blank_template", __dir__) + end + + def create_blank_site(path) + FileUtils.cp_r blank_template + "/.", path + FileUtils.chmod_R "u+w", path + + Dir.chdir(path) do + FileUtils.mkdir(%w(_data _drafts _includes _posts)) + end + end + + def scaffold_post_content + ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result + end + + # Internal: Gets the filename of the sample post to be created + # + # Returns the filename of the sample post, as a String + def initialized_post_name + "_posts/#{Time.now.strftime("%Y-%m-%d")}-welcome-to-jekyll.markdown" + end + + private + + def gemfile_contents + <<~RUBY + source "https://rubygems.org" + # Hello! This is where you manage which Jekyll version is used to run. + # When you want to use a different version, change it below, save the + # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: + # + # bundle exec jekyll serve + # + # This will help ensure the proper Jekyll version is running. + # Happy Jekylling! + gem "jekyll", "~> #{Jekyll::VERSION}" + # This is the default theme for new Jekyll sites. You may change this to anything you like. + gem "minima", "~> 2.5" + # If you want to use GitHub Pages, remove the "gem "jekyll"" above and + # uncomment the line below. To upgrade, run `bundle update github-pages`. + # gem "github-pages", group: :jekyll_plugins + # If you have any plugins, put them here! + group :jekyll_plugins do + gem "jekyll-feed", "~> 0.12" + end + + # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem + # and associated library. + platforms :mingw, :x64_mingw, :mswin, :jruby do + gem "tzinfo", ">= 1", "< 3" + gem "tzinfo-data" + end + + # Performance-booster for watching directories on Windows + gem "wdm", "~> 0.1", :platforms => [:mingw, :x64_mingw, :mswin] + + # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem + # do not have a Java counterpart. + gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] + RUBY + end + + def create_site(new_blog_path) + create_sample_files new_blog_path + + File.write(File.expand_path(initialized_post_name, new_blog_path), scaffold_post_content) + + File.write(File.expand_path("Gemfile", new_blog_path), gemfile_contents) + end + + def preserve_source_location?(path, options) + !options["force"] && !Dir["#{path}/**/*"].empty? + end + + def create_sample_files(path) + FileUtils.cp_r site_template + "/.", path + FileUtils.chmod_R "u+w", path + FileUtils.rm File.expand_path(scaffold_path, path) + end + + def site_template + File.expand_path("../../site_template", __dir__) + end + + def scaffold_path + "_posts/0000-00-00-welcome-to-jekyll.markdown.erb" + end + + # After a new blog has been created, print a success notification and + # then automatically execute bundle install from within the new blog dir + # unless the user opts to generate a blank blog or skip 'bundle install'. + + def after_install(path, options = {}) + unless options["blank"] || options["skip-bundle"] + begin + require "bundler" + bundle_install path + rescue LoadError + Jekyll.logger.info "Could not load Bundler. Bundle install skipped." + end + end + + Jekyll.logger.info "New jekyll site installed in #{path.cyan}." + Jekyll.logger.info "Bundle install skipped." if options["skip-bundle"] + end + + def bundle_install(path) + Jekyll.logger.info "Running bundle install in #{path.cyan}..." + Dir.chdir(path) do + exe = Gem.bin_path("bundler", "bundle") + process, output = Jekyll::Utils::Exec.run("ruby", exe, "install") + + output.to_s.each_line do |line| + Jekyll.logger.info("Bundler:".green, line.strip) unless line.to_s.empty? + end + + raise SystemExit unless process.success? + end + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb new file mode 100644 index 0000000..3419d17 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/new_theme.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require "erb" + +module Jekyll + module Commands + class NewTheme < Jekyll::Command + class << self + def init_with_program(prog) + prog.command(:"new-theme") do |c| + c.syntax "new-theme NAME" + c.description "Creates a new Jekyll theme scaffold" + c.option "code_of_conduct", "-c", "--code-of-conduct", + "Include a Code of Conduct. (defaults to false)" + + c.action do |args, opts| + Jekyll::Commands::NewTheme.process(args, opts) + end + end + end + + def process(args, opts) + if !args || args.empty? + raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name." + end + + new_theme_name = args.join("_") + theme = Jekyll::ThemeBuilder.new(new_theme_name, opts) + Jekyll.logger.abort_with "Conflict:", "#{theme.path} already exists." if theme.path.exist? + + theme.create! + Jekyll.logger.info "Your new Jekyll theme, #{theme.name.cyan}, " \ + "is ready for you in #{theme.path.to_s.cyan}!" + Jekyll.logger.info "For help getting started, read #{theme.path}/README.md." + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb new file mode 100644 index 0000000..6abd893 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve.rb @@ -0,0 +1,372 @@ +# frozen_string_literal: true + +module Jekyll + module Commands + class Serve < Command + # Similar to the pattern in Utils::ThreadEvent except we are maintaining the + # state of @running instead of just signaling an event. We have to maintain this + # state since Serve is just called via class methods instead of an instance + # being created each time. + @mutex = Mutex.new + @run_cond = ConditionVariable.new + @running = false + + class << self + COMMAND_OPTIONS = { + "ssl_cert" => ["--ssl-cert [CERT]", "X.509 (SSL) certificate."], + "host" => ["host", "-H", "--host [HOST]", "Host to bind to"], + "open_url" => ["-o", "--open-url", "Launch your site in a browser"], + "detach" => ["-B", "--detach", + "Run the server in the background",], + "ssl_key" => ["--ssl-key [KEY]", "X.509 (SSL) Private Key."], + "port" => ["-P", "--port [PORT]", "Port to listen on"], + "show_dir_listing" => ["--show-dir-listing", + "Show a directory listing instead of loading " \ + "your index file.",], + "skip_initial_build" => ["skip_initial_build", "--skip-initial-build", + "Skips the initial site build which occurs before " \ + "the server is started.",], + "livereload" => ["-l", "--livereload", + "Use LiveReload to automatically refresh browsers",], + "livereload_ignore" => ["--livereload-ignore GLOB1[,GLOB2[,...]]", + Array, + "Files for LiveReload to ignore. " \ + "Remember to quote the values so your shell " \ + "won't expand them",], + "livereload_min_delay" => ["--livereload-min-delay [SECONDS]", + "Minimum reload delay",], + "livereload_max_delay" => ["--livereload-max-delay [SECONDS]", + "Maximum reload delay",], + "livereload_port" => ["--livereload-port [PORT]", Integer, + "Port for LiveReload to listen on",], + }.freeze + + DIRECTORY_INDEX = %w( + index.htm + index.html + index.rhtml + index.xht + index.xhtml + index.cgi + index.xml + index.json + ).freeze + + LIVERELOAD_PORT = 35_729 + LIVERELOAD_DIR = File.join(__dir__, "serve", "livereload_assets") + + attr_reader :mutex, :run_cond, :running + alias_method :running?, :running + + def init_with_program(prog) + prog.command(:serve) do |cmd| + cmd.description "Serve your site locally" + cmd.syntax "serve [options]" + cmd.alias :server + cmd.alias :s + + add_build_options(cmd) + COMMAND_OPTIONS.each do |key, val| + cmd.option key, *val + end + + cmd.action do |_, opts| + opts["serving"] = true + opts["watch"] = true unless opts.key?("watch") + + # Set the reactor to nil so any old reactor will be GCed. + # We can't unregister a hook so while running tests we don't want to + # inadvertently keep using a reactor created by a previous test. + @reload_reactor = nil + + config = configuration_from_options(opts) + config["url"] = default_url(config) if Jekyll.env == "development" + + process_with_graceful_fail(cmd, config, Build, Serve) + end + end + end + + # + + def process(opts) + opts = configuration_from_options(opts) + destination = opts["destination"] + if opts["livereload"] + opts["livereload_port"] ||= LIVERELOAD_PORT + validate_options(opts) + register_reload_hooks(opts) + end + setup(destination) + + start_up_webrick(opts, destination) + end + + def shutdown + @server.shutdown if running? + end + + # Perform logical validation of CLI options + + private + + def validate_options(opts) + if opts["livereload"] + if opts["detach"] + Jekyll.logger.warn "Warning:", "--detach and --livereload are mutually exclusive. " \ + "Choosing --livereload" + opts["detach"] = false + end + if opts["ssl_cert"] || opts["ssl_key"] + # This is not technically true. LiveReload works fine over SSL, but + # EventMachine's SSL support in Windows requires building the gem's + # native extensions against OpenSSL and that proved to be a process + # so tedious that expecting users to do it is a non-starter. + Jekyll.logger.abort_with "Error:", "LiveReload does not support SSL" + end + unless opts["watch"] + # Using livereload logically implies you want to watch the files + opts["watch"] = true + end + elsif %w(livereload_min_delay + livereload_max_delay + livereload_ignore + livereload_port).any? { |o| opts[o] } + Jekyll.logger.abort_with "--livereload-min-delay, --livereload-max-delay, " \ + "--livereload-ignore, and --livereload-port require " \ + "the --livereload option." + end + end + + def register_reload_hooks(opts) + require_relative "serve/live_reload_reactor" + @reload_reactor = LiveReloadReactor.new + + Jekyll::Hooks.register(:site, :post_render) do |site| + @changed_pages = [] + site.each_site_file do |item| + @changed_pages << item if site.regenerator.regenerate?(item) + end + end + + # A note on ignoring files: LiveReload errs on the side of reloading when it + # comes to the message it gets. If, for example, a page is ignored but a CSS + # file linked in the page isn't, the page will still be reloaded if the CSS + # file is contained in the message sent to LiveReload. Additionally, the + # path matching is very loose so that a message to reload "/" will always + # lead the page to reload since every page starts with "/". + Jekyll::Hooks.register(:site, :post_write) do + if @changed_pages && @reload_reactor && @reload_reactor.running? + ignore, @changed_pages = @changed_pages.partition do |p| + Array(opts["livereload_ignore"]).any? do |filter| + File.fnmatch(filter, p.relative_path) + end + end + Jekyll.logger.debug "LiveReload:", "Ignoring #{ignore.map(&:relative_path)}" + @reload_reactor.reload(@changed_pages) + end + @changed_pages = nil + end + end + + # Do a base pre-setup of WEBRick so that everything is in place + # when we get ready to party, checking for an setting up an error page + # and making sure our destination exists. + # + # rubocop:disable Security/IoMethods + def setup(destination) + require_relative "serve/servlet" + + FileUtils.mkdir_p(destination) + if File.exist?(File.join(destination, "404.html")) + WEBrick::HTTPResponse.class_eval do + def create_error_page + @header["Content-Type"] = "text/html; charset=UTF-8" + @body = IO.read(File.join(@config[:DocumentRoot], "404.html")) + end + end + end + end + # rubocop:enable Security/IoMethods + + def webrick_opts(opts) + opts = { + :JekyllOptions => opts, + :DoNotReverseLookup => true, + :MimeTypes => mime_types, + :MimeTypesCharset => mime_types_charset, + :DocumentRoot => opts["destination"], + :StartCallback => start_callback(opts["detach"]), + :StopCallback => stop_callback(opts["detach"]), + :BindAddress => opts["host"], + :Port => opts["port"], + :DirectoryIndex => DIRECTORY_INDEX, + } + + opts[:DirectoryIndex] = [] if opts[:JekyllOptions]["show_dir_listing"] + + enable_ssl(opts) + enable_logging(opts) + opts + end + + def start_up_webrick(opts, destination) + @reload_reactor.start(opts) if opts["livereload"] + + @server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") } + @server.mount(opts["baseurl"].to_s, Servlet, destination, file_handler_opts) + + Jekyll.logger.info "Server address:", server_address(@server, opts) + launch_browser @server, opts if opts["open_url"] + boot_or_detach @server, opts + end + + # Recreate NondisclosureName under utf-8 circumstance + def file_handler_opts + WEBrick::Config::FileHandler.merge( + :FancyIndexing => true, + :NondisclosureName => [ + ".ht*", "~*", + ] + ) + end + + def server_address(server, options = {}) + format_url( + server.config[:SSLEnable], + server.config[:BindAddress], + server.config[:Port], + options["baseurl"] + ) + end + + def format_url(ssl_enabled, address, port, baseurl = nil) + format("%s://%
s:%i%s", + :prefix => ssl_enabled ? "https" : "http", + :address => address, + :port => port, + :baseurl => baseurl ? "#{baseurl}/" : "") + end + + def default_url(opts) + config = configuration_from_options(opts) + format_url( + config["ssl_cert"] && config["ssl_key"], + config["host"] == "127.0.0.1" ? "localhost" : config["host"], + config["port"] + ) + end + + def launch_browser(server, opts) + address = server_address(server, opts) + return system "start", address if Utils::Platforms.windows? + return system "xdg-open", address if Utils::Platforms.linux? + return system "open", address if Utils::Platforms.osx? + + Jekyll.logger.error "Refusing to launch browser. Platform launcher unknown." + end + + # Keep in our area with a thread or detach the server as requested + # by the user. This method determines what we do based on what you + # ask us to do. + def boot_or_detach(server, opts) + if opts["detach"] + pid = Process.fork do + # Detach the process from controlling terminal + $stdin.reopen("/dev/null", "r") + $stdout.reopen("/dev/null", "w") + $stderr.reopen("/dev/null", "w") + server.start + end + + Process.detach(pid) + Jekyll.logger.info "Server detached with pid '#{pid}'.", + "Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server." + + # Exit without running `at_exit` inherited by the forked process. + Process.exit! 0 + else + t = Thread.new { server.start } + trap("INT") { server.shutdown } + t.join + end + end + + # Make the stack verbose if the user requests it. + def enable_logging(opts) + opts[:AccessLog] = [] + level = WEBrick::Log.const_get(opts[:JekyllOptions]["verbose"] ? :DEBUG : :WARN) + opts[:Logger] = WEBrick::Log.new($stdout, level) + end + + # Add SSL to the stack if the user triggers --enable-ssl and they + # provide both types of certificates commonly needed. Raise if they + # forget to add one of the certificates. + def enable_ssl(opts) + cert, key, src = + opts[:JekyllOptions].values_at("ssl_cert", "ssl_key", "source") + + return if cert.nil? && key.nil? + raise "Missing --ssl_cert or --ssl_key. Both are required." unless cert && key + + require "openssl" + require "webrick/https" + + opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(read_file(src, cert)) + begin + opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(read_file(src, key)) + rescue StandardError + if defined?(OpenSSL::PKey::EC) + opts[:SSLPrivateKey] = OpenSSL::PKey::EC.new(read_file(src, key)) + else + raise + end + end + opts[:SSLEnable] = true + end + + def start_callback(detached) + unless detached + proc do + mutex.synchronize do + # Block until EventMachine reactor starts + @reload_reactor&.started_event&.wait + @running = true + Jekyll.logger.info("Server running...", "press ctrl-c to stop.") + @run_cond.broadcast + end + end + end + end + + def stop_callback(detached) + unless detached + proc do + mutex.synchronize do + unless @reload_reactor.nil? + @reload_reactor.stop + @reload_reactor.stopped_event.wait + end + @running = false + @run_cond.broadcast + end + end + end + end + + def mime_types + file = File.expand_path("../mime.types", __dir__) + WEBrick::HTTPUtils.load_mime_types(file) + end + + def mime_types_charset + SafeYAML.load_file(File.expand_path("serve/mime_types_charset.json", __dir__)) + end + + def read_file(source_dir, file_path) + File.read(Jekyll.sanitized_path(source_dir, file_path)) + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb new file mode 100644 index 0000000..78f9408 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/live_reload_reactor.rb @@ -0,0 +1,119 @@ +# frozen_string_literal: true + +require "em-websocket" + +require_relative "websockets" + +module Jekyll + module Commands + class Serve + class LiveReloadReactor + attr_reader :started_event, :stopped_event, :thread + + def initialize + @websockets = [] + @connections_count = 0 + @started_event = Utils::ThreadEvent.new + @stopped_event = Utils::ThreadEvent.new + end + + def stop + # There is only one EventMachine instance per Ruby process so stopping + # it here will stop the reactor thread we have running. + EM.stop if EM.reactor_running? + Jekyll.logger.debug "LiveReload Server:", "halted" + end + + def running? + EM.reactor_running? + end + + def handle_websockets_event(websocket) + websocket.onopen { |handshake| connect(websocket, handshake) } + websocket.onclose { disconnect(websocket) } + websocket.onmessage { |msg| print_message(msg) } + websocket.onerror { |error| log_error(error) } + end + + def start(opts) + @thread = Thread.new do + # Use epoll if the kernel supports it + EM.epoll + EM.run do + EM.error_handler { |e| log_error(e) } + + EM.start_server( + opts["host"], + opts["livereload_port"], + HttpAwareConnection, + opts + ) do |ws| + handle_websockets_event(ws) + end + + # Notify blocked threads that EventMachine has started or shutdown + EM.schedule { @started_event.set } + EM.add_shutdown_hook { @stopped_event.set } + + Jekyll.logger.info "LiveReload address:", + "http://#{opts["host"]}:#{opts["livereload_port"]}" + end + end + @thread.abort_on_exception = true + end + + # For a description of the protocol see + # http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol + def reload(pages) + pages.each do |p| + json_message = JSON.dump( + :command => "reload", + :path => p.url, + :liveCSS => true + ) + + Jekyll.logger.debug "LiveReload:", "Reloading URL #{p.url.inspect}" + @websockets.each { |ws| ws.send(json_message) } + end + end + + private + + def connect(websocket, handshake) + @connections_count += 1 + if @connections_count == 1 + message = "Browser connected" + message += " over SSL/TLS" if handshake.secure? + Jekyll.logger.info "LiveReload:", message + end + websocket.send( + JSON.dump( + :command => "hello", + :protocols => ["http://livereload.com/protocols/official-7"], + :serverName => "jekyll" + ) + ) + + @websockets << websocket + end + + def disconnect(websocket) + @websockets.delete(websocket) + end + + def print_message(json_message) + msg = JSON.parse(json_message) + # Not sure what the 'url' command even does in LiveReload. The spec is silent + # on its purpose. + Jekyll.logger.info "LiveReload:", "Browser URL: #{msg["url"]}" if msg["command"] == "url" + end + + def log_error(error) + Jekyll.logger.error "LiveReload experienced an error. " \ + "Run with --trace for more information." + raise error + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js new file mode 100644 index 0000000..eee60ec --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/livereload_assets/livereload.js @@ -0,0 +1,1183 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o tag"); + return; + } + } + this.reloader = new Reloader(this.window, this.console, Timer); + this.connector = new Connector(this.options, this.WebSocket, Timer, { + connecting: (function(_this) { + return function() {}; + })(this), + socketConnected: (function(_this) { + return function() {}; + })(this), + connected: (function(_this) { + return function(protocol) { + var _base; + if (typeof (_base = _this.listeners).connect === "function") { + _base.connect(); + } + _this.log("LiveReload is connected to " + _this.options.host + ":" + _this.options.port + " (protocol v" + protocol + ")."); + return _this.analyze(); + }; + })(this), + error: (function(_this) { + return function(e) { + if (e instanceof ProtocolError) { + if (typeof console !== "undefined" && console !== null) { + return console.log("" + e.message + "."); + } + } else { + if (typeof console !== "undefined" && console !== null) { + return console.log("LiveReload internal error: " + e.message); + } + } + }; + })(this), + disconnected: (function(_this) { + return function(reason, nextDelay) { + var _base; + if (typeof (_base = _this.listeners).disconnect === "function") { + _base.disconnect(); + } + switch (reason) { + case 'cannot-connect': + return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + ", will retry in " + nextDelay + " sec."); + case 'broken': + return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + ", reconnecting in " + nextDelay + " sec."); + case 'handshake-timeout': + return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake timeout), will retry in " + nextDelay + " sec."); + case 'handshake-failed': + return _this.log("LiveReload cannot connect to " + _this.options.host + ":" + _this.options.port + " (handshake failed), will retry in " + nextDelay + " sec."); + case 'manual': + break; + case 'error': + break; + default: + return _this.log("LiveReload disconnected from " + _this.options.host + ":" + _this.options.port + " (" + reason + "), reconnecting in " + nextDelay + " sec."); + } + }; + })(this), + message: (function(_this) { + return function(message) { + switch (message.command) { + case 'reload': + return _this.performReload(message); + case 'alert': + return _this.performAlert(message); + } + }; + })(this) + }); + this.initialized = true; + } + + LiveReload.prototype.on = function(eventName, handler) { + return this.listeners[eventName] = handler; + }; + + LiveReload.prototype.log = function(message) { + return this.console.log("" + message); + }; + + LiveReload.prototype.performReload = function(message) { + var _ref, _ref1; + this.log("LiveReload received reload request: " + (JSON.stringify(message, null, 2))); + return this.reloader.reload(message.path, { + liveCSS: (_ref = message.liveCSS) != null ? _ref : true, + liveImg: (_ref1 = message.liveImg) != null ? _ref1 : true, + originalPath: message.originalPath || '', + overrideURL: message.overrideURL || '', + serverURL: "http://" + this.options.host + ":" + this.options.port + }); + }; + + LiveReload.prototype.performAlert = function(message) { + return alert(message.message); + }; + + LiveReload.prototype.shutDown = function() { + var _base; + if (!this.initialized) { + return; + } + this.connector.disconnect(); + this.log("LiveReload disconnected."); + return typeof (_base = this.listeners).shutdown === "function" ? _base.shutdown() : void 0; + }; + + LiveReload.prototype.hasPlugin = function(identifier) { + return !!this.pluginIdentifiers[identifier]; + }; + + LiveReload.prototype.addPlugin = function(pluginClass) { + var plugin; + if (!this.initialized) { + return; + } + if (this.hasPlugin(pluginClass.identifier)) { + return; + } + this.pluginIdentifiers[pluginClass.identifier] = true; + plugin = new pluginClass(this.window, { + _livereload: this, + _reloader: this.reloader, + _connector: this.connector, + console: this.console, + Timer: Timer, + generateCacheBustUrl: (function(_this) { + return function(url) { + return _this.reloader.generateCacheBustUrl(url); + }; + })(this) + }); + this.plugins.push(plugin); + this.reloader.addPlugin(plugin); + }; + + LiveReload.prototype.analyze = function() { + var plugin, pluginData, pluginsData, _i, _len, _ref; + if (!this.initialized) { + return; + } + if (!(this.connector.protocol >= 7)) { + return; + } + pluginsData = {}; + _ref = this.plugins; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + plugin = _ref[_i]; + pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === "function" ? plugin.analyze() : void 0) || {}; + pluginData.version = plugin.constructor.version; + } + this.connector.sendCommand({ + command: 'info', + plugins: pluginsData, + url: this.window.location.href + }); + }; + + return LiveReload; + + })(); + +}).call(this); + +},{"./connector":1,"./options":5,"./reloader":7,"./timer":9}],5:[function(require,module,exports){ +(function() { + var Options; + + exports.Options = Options = (function() { + function Options() { + this.https = false; + this.host = null; + this.port = 35729; + this.snipver = null; + this.ext = null; + this.extver = null; + this.mindelay = 1000; + this.maxdelay = 60000; + this.handshake_timeout = 5000; + } + + Options.prototype.set = function(name, value) { + if (typeof value === 'undefined') { + return; + } + if (!isNaN(+value)) { + value = +value; + } + return this[name] = value; + }; + + return Options; + + })(); + + Options.extract = function(document) { + var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len1, _ref, _ref1; + _ref = document.getElementsByTagName('script'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + element = _ref[_i]; + if ((src = element.src) && (m = src.match(/^[^:]+:\/\/(.*)\/z?livereload\.js(?:\?(.*))?$/))) { + options = new Options(); + options.https = src.indexOf("https") === 0; + if (mm = m[1].match(/^([^\/:]+)(?::(\d+))?$/)) { + options.host = mm[1]; + if (mm[2]) { + options.port = parseInt(mm[2], 10); + } + } + if (m[2]) { + _ref1 = m[2].split('&'); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + pair = _ref1[_j]; + if ((keyAndValue = pair.split('=')).length > 1) { + options.set(keyAndValue[0].replace(/-/g, '_'), keyAndValue.slice(1).join('=')); + } + } + } + return options; + } + } + return null; + }; + +}).call(this); + +},{}],6:[function(require,module,exports){ +(function() { + var PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + exports.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6'; + + exports.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7'; + + exports.ProtocolError = ProtocolError = (function() { + function ProtocolError(reason, data) { + this.message = "LiveReload protocol error (" + reason + ") after receiving data: \"" + data + "\"."; + } + + return ProtocolError; + + })(); + + exports.Parser = Parser = (function() { + function Parser(handlers) { + this.handlers = handlers; + this.reset(); + } + + Parser.prototype.reset = function() { + return this.protocol = null; + }; + + Parser.prototype.process = function(data) { + var command, e, message, options, _ref; + try { + if (this.protocol == null) { + if (data.match(/^!!ver:([\d.]+)$/)) { + this.protocol = 6; + } else if (message = this._parseMessage(data, ['hello'])) { + if (!message.protocols.length) { + throw new ProtocolError("no protocols specified in handshake message"); + } else if (__indexOf.call(message.protocols, PROTOCOL_7) >= 0) { + this.protocol = 7; + } else if (__indexOf.call(message.protocols, PROTOCOL_6) >= 0) { + this.protocol = 6; + } else { + throw new ProtocolError("no supported protocols found"); + } + } + return this.handlers.connected(this.protocol); + } else if (this.protocol === 6) { + message = JSON.parse(data); + if (!message.length) { + throw new ProtocolError("protocol 6 messages must be arrays"); + } + command = message[0], options = message[1]; + if (command !== 'refresh') { + throw new ProtocolError("unknown protocol 6 command"); + } + return this.handlers.message({ + command: 'reload', + path: options.path, + liveCSS: (_ref = options.apply_css_live) != null ? _ref : true + }); + } else { + message = this._parseMessage(data, ['reload', 'alert']); + return this.handlers.message(message); + } + } catch (_error) { + e = _error; + if (e instanceof ProtocolError) { + return this.handlers.error(e); + } else { + throw e; + } + } + }; + + Parser.prototype._parseMessage = function(data, validCommands) { + var e, message, _ref; + try { + message = JSON.parse(data); + } catch (_error) { + e = _error; + throw new ProtocolError('unparsable JSON', data); + } + if (!message.command) { + throw new ProtocolError('missing "command" key', data); + } + if (_ref = message.command, __indexOf.call(validCommands, _ref) < 0) { + throw new ProtocolError("invalid command '" + message.command + "', only valid commands are: " + (validCommands.join(', ')) + ")", data); + } + return message; + }; + + return Parser; + + })(); + +}).call(this); + +},{}],7:[function(require,module,exports){ +(function() { + var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl; + + splitUrl = function(url) { + var hash, index, params; + if ((index = url.indexOf('#')) >= 0) { + hash = url.slice(index); + url = url.slice(0, index); + } else { + hash = ''; + } + if ((index = url.indexOf('?')) >= 0) { + params = url.slice(index); + url = url.slice(0, index); + } else { + params = ''; + } + return { + url: url, + params: params, + hash: hash + }; + }; + + pathFromUrl = function(url) { + var path; + url = splitUrl(url).url; + if (url.indexOf('file://') === 0) { + path = url.replace(/^file:\/\/(localhost)?/, ''); + } else { + path = url.replace(/^([^:]+:)?\/\/([^:\/]+)(:\d*)?\//, '/'); + } + return decodeURIComponent(path); + }; + + pickBestMatch = function(path, objects, pathFunc) { + var bestMatch, object, score, _i, _len; + bestMatch = { + score: 0 + }; + for (_i = 0, _len = objects.length; _i < _len; _i++) { + object = objects[_i]; + score = numberOfMatchingSegments(path, pathFunc(object)); + if (score > bestMatch.score) { + bestMatch = { + object: object, + score: score + }; + } + } + if (bestMatch.score > 0) { + return bestMatch; + } else { + return null; + } + }; + + numberOfMatchingSegments = function(path1, path2) { + var comps1, comps2, eqCount, len; + path1 = path1.replace(/^\/+/, '').toLowerCase(); + path2 = path2.replace(/^\/+/, '').toLowerCase(); + if (path1 === path2) { + return 10000; + } + comps1 = path1.split('/').reverse(); + comps2 = path2.split('/').reverse(); + len = Math.min(comps1.length, comps2.length); + eqCount = 0; + while (eqCount < len && comps1[eqCount] === comps2[eqCount]) { + ++eqCount; + } + return eqCount; + }; + + pathsMatch = function(path1, path2) { + return numberOfMatchingSegments(path1, path2) > 0; + }; + + IMAGE_STYLES = [ + { + selector: 'background', + styleNames: ['backgroundImage'] + }, { + selector: 'border', + styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage'] + } + ]; + + exports.Reloader = Reloader = (function() { + function Reloader(window, console, Timer) { + this.window = window; + this.console = console; + this.Timer = Timer; + this.document = this.window.document; + this.importCacheWaitPeriod = 200; + this.plugins = []; + } + + Reloader.prototype.addPlugin = function(plugin) { + return this.plugins.push(plugin); + }; + + Reloader.prototype.analyze = function(callback) { + return results; + }; + + Reloader.prototype.reload = function(path, options) { + var plugin, _base, _i, _len, _ref; + this.options = options; + if ((_base = this.options).stylesheetReloadTimeout == null) { + _base.stylesheetReloadTimeout = 15000; + } + _ref = this.plugins; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + plugin = _ref[_i]; + if (plugin.reload && plugin.reload(path, options)) { + return; + } + } + if (options.liveCSS) { + if (path.match(/\.css$/i)) { + if (this.reloadStylesheet(path)) { + return; + } + } + } + if (options.liveImg) { + if (path.match(/\.(jpe?g|png|gif)$/i)) { + this.reloadImages(path); + return; + } + } + return this.reloadPage(); + }; + + Reloader.prototype.reloadPage = function() { + return this.window.document.location.reload(); + }; + + Reloader.prototype.reloadImages = function(path) { + var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results; + expando = this.generateUniqueString(); + _ref = this.document.images; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + img = _ref[_i]; + if (pathsMatch(path, pathFromUrl(img.src))) { + img.src = this.generateCacheBustUrl(img.src, expando); + } + } + if (this.document.querySelectorAll) { + for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) { + _ref1 = IMAGE_STYLES[_j], selector = _ref1.selector, styleNames = _ref1.styleNames; + _ref2 = this.document.querySelectorAll("[style*=" + selector + "]"); + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + img = _ref2[_k]; + this.reloadStyleImages(img.style, styleNames, path, expando); + } + } + } + if (this.document.styleSheets) { + _ref3 = this.document.styleSheets; + _results = []; + for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { + styleSheet = _ref3[_l]; + _results.push(this.reloadStylesheetImages(styleSheet, path, expando)); + } + return _results; + } + }; + + Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) { + var e, rule, rules, styleNames, _i, _j, _len, _len1; + try { + rules = styleSheet != null ? styleSheet.cssRules : void 0; + } catch (_error) { + e = _error; + } + if (!rules) { + return; + } + for (_i = 0, _len = rules.length; _i < _len; _i++) { + rule = rules[_i]; + switch (rule.type) { + case CSSRule.IMPORT_RULE: + this.reloadStylesheetImages(rule.styleSheet, path, expando); + break; + case CSSRule.STYLE_RULE: + for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) { + styleNames = IMAGE_STYLES[_j].styleNames; + this.reloadStyleImages(rule.style, styleNames, path, expando); + } + break; + case CSSRule.MEDIA_RULE: + this.reloadStylesheetImages(rule, path, expando); + } + } + }; + + Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) { + var newValue, styleName, value, _i, _len; + for (_i = 0, _len = styleNames.length; _i < _len; _i++) { + styleName = styleNames[_i]; + value = style[styleName]; + if (typeof value === 'string') { + newValue = value.replace(/\burl\s*\(([^)]*)\)/, (function(_this) { + return function(match, src) { + if (pathsMatch(path, pathFromUrl(src))) { + return "url(" + (_this.generateCacheBustUrl(src, expando)) + ")"; + } else { + return match; + } + }; + })(this)); + if (newValue !== value) { + style[styleName] = newValue; + } + } + } + }; + + Reloader.prototype.reloadStylesheet = function(path) { + var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1; + links = (function() { + var _i, _len, _ref, _results; + _ref = this.document.getElementsByTagName('link'); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + link = _ref[_i]; + if (link.rel.match(/^stylesheet$/i) && !link.__LiveReload_pendingRemoval) { + _results.push(link); + } + } + return _results; + }).call(this); + imported = []; + _ref = this.document.getElementsByTagName('style'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + style = _ref[_i]; + if (style.sheet) { + this.collectImportedStylesheets(style, style.sheet, imported); + } + } + for (_j = 0, _len1 = links.length; _j < _len1; _j++) { + link = links[_j]; + this.collectImportedStylesheets(link, link.sheet, imported); + } + if (this.window.StyleFix && this.document.querySelectorAll) { + _ref1 = this.document.querySelectorAll('style[data-href]'); + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + style = _ref1[_k]; + links.push(style); + } + } + this.console.log("LiveReload found " + links.length + " LINKed stylesheets, " + imported.length + " @imported stylesheets"); + match = pickBestMatch(path, links.concat(imported), (function(_this) { + return function(l) { + return pathFromUrl(_this.linkHref(l)); + }; + })(this)); + if (match) { + if (match.object.rule) { + this.console.log("LiveReload is reloading imported stylesheet: " + match.object.href); + this.reattachImportedRule(match.object); + } else { + this.console.log("LiveReload is reloading stylesheet: " + (this.linkHref(match.object))); + this.reattachStylesheetLink(match.object); + } + } else { + this.console.log("LiveReload will reload all stylesheets because path '" + path + "' did not match any specific one"); + for (_l = 0, _len3 = links.length; _l < _len3; _l++) { + link = links[_l]; + this.reattachStylesheetLink(link); + } + } + return true; + }; + + Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) { + var e, index, rule, rules, _i, _len; + try { + rules = styleSheet != null ? styleSheet.cssRules : void 0; + } catch (_error) { + e = _error; + } + if (rules && rules.length) { + for (index = _i = 0, _len = rules.length; _i < _len; index = ++_i) { + rule = rules[index]; + switch (rule.type) { + case CSSRule.CHARSET_RULE: + continue; + case CSSRule.IMPORT_RULE: + result.push({ + link: link, + rule: rule, + index: index, + href: rule.href + }); + this.collectImportedStylesheets(link, rule.styleSheet, result); + break; + default: + break; + } + } + } + }; + + Reloader.prototype.waitUntilCssLoads = function(clone, func) { + var callbackExecuted, executeCallback, poll; + callbackExecuted = false; + executeCallback = (function(_this) { + return function() { + if (callbackExecuted) { + return; + } + callbackExecuted = true; + return func(); + }; + })(this); + clone.onload = (function(_this) { + return function() { + _this.console.log("LiveReload: the new stylesheet has finished loading"); + _this.knownToSupportCssOnLoad = true; + return executeCallback(); + }; + })(this); + if (!this.knownToSupportCssOnLoad) { + (poll = (function(_this) { + return function() { + if (clone.sheet) { + _this.console.log("LiveReload is polling until the new CSS finishes loading..."); + return executeCallback(); + } else { + return _this.Timer.start(50, poll); + } + }; + })(this))(); + } + return this.Timer.start(this.options.stylesheetReloadTimeout, executeCallback); + }; + + Reloader.prototype.linkHref = function(link) { + return link.href || link.getAttribute('data-href'); + }; + + Reloader.prototype.reattachStylesheetLink = function(link) { + var clone, parent; + if (link.__LiveReload_pendingRemoval) { + return; + } + link.__LiveReload_pendingRemoval = true; + if (link.tagName === 'STYLE') { + clone = this.document.createElement('link'); + clone.rel = 'stylesheet'; + clone.media = link.media; + clone.disabled = link.disabled; + } else { + clone = link.cloneNode(false); + } + clone.href = this.generateCacheBustUrl(this.linkHref(link)); + parent = link.parentNode; + if (parent.lastChild === link) { + parent.appendChild(clone); + } else { + parent.insertBefore(clone, link.nextSibling); + } + return this.waitUntilCssLoads(clone, (function(_this) { + return function() { + var additionalWaitingTime; + if (/AppleWebKit/.test(navigator.userAgent)) { + additionalWaitingTime = 5; + } else { + additionalWaitingTime = 200; + } + return _this.Timer.start(additionalWaitingTime, function() { + var _ref; + if (!link.parentNode) { + return; + } + link.parentNode.removeChild(link); + clone.onreadystatechange = null; + return (_ref = _this.window.StyleFix) != null ? _ref.link(clone) : void 0; + }); + }; + })(this)); + }; + + Reloader.prototype.reattachImportedRule = function(_arg) { + var href, index, link, media, newRule, parent, rule, tempLink; + rule = _arg.rule, index = _arg.index, link = _arg.link; + parent = rule.parentStyleSheet; + href = this.generateCacheBustUrl(rule.href); + media = rule.media.length ? [].join.call(rule.media, ', ') : ''; + newRule = "@import url(\"" + href + "\") " + media + ";"; + rule.__LiveReload_newHref = href; + tempLink = this.document.createElement("link"); + tempLink.rel = 'stylesheet'; + tempLink.href = href; + tempLink.__LiveReload_pendingRemoval = true; + if (link.parentNode) { + link.parentNode.insertBefore(tempLink, link); + } + return this.Timer.start(this.importCacheWaitPeriod, (function(_this) { + return function() { + if (tempLink.parentNode) { + tempLink.parentNode.removeChild(tempLink); + } + if (rule.__LiveReload_newHref !== href) { + return; + } + parent.insertRule(newRule, index); + parent.deleteRule(index + 1); + rule = parent.cssRules[index]; + rule.__LiveReload_newHref = href; + return _this.Timer.start(_this.importCacheWaitPeriod, function() { + if (rule.__LiveReload_newHref !== href) { + return; + } + parent.insertRule(newRule, index); + return parent.deleteRule(index + 1); + }); + }; + })(this)); + }; + + Reloader.prototype.generateUniqueString = function() { + return 'livereload=' + Date.now(); + }; + + Reloader.prototype.generateCacheBustUrl = function(url, expando) { + var hash, oldParams, originalUrl, params, _ref; + if (expando == null) { + expando = this.generateUniqueString(); + } + _ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params; + if (this.options.overrideURL) { + if (url.indexOf(this.options.serverURL) < 0) { + originalUrl = url; + url = this.options.serverURL + this.options.overrideURL + "?url=" + encodeURIComponent(url); + this.console.log("LiveReload is overriding source URL " + originalUrl + " with " + url); + } + } + params = oldParams.replace(/(\?|&)livereload=(\d+)/, function(match, sep) { + return "" + sep + expando; + }); + if (params === oldParams) { + if (oldParams.length === 0) { + params = "?" + expando; + } else { + params = "" + oldParams + "&" + expando; + } + } + return url + params + hash; + }; + + return Reloader; + + })(); + +}).call(this); + +},{}],8:[function(require,module,exports){ +(function() { + var CustomEvents, LiveReload, k; + + CustomEvents = require('./customevents'); + + LiveReload = window.LiveReload = new (require('./livereload').LiveReload)(window); + + for (k in window) { + if (k.match(/^LiveReloadPlugin/)) { + LiveReload.addPlugin(window[k]); + } + } + + LiveReload.addPlugin(require('./less')); + + LiveReload.on('shutdown', function() { + return delete window.LiveReload; + }); + + LiveReload.on('connect', function() { + return CustomEvents.fire(document, 'LiveReloadConnect'); + }); + + LiveReload.on('disconnect', function() { + return CustomEvents.fire(document, 'LiveReloadDisconnect'); + }); + + CustomEvents.bind(document, 'LiveReloadShutDown', function() { + return LiveReload.shutDown(); + }); + +}).call(this); + +},{"./customevents":2,"./less":3,"./livereload":4}],9:[function(require,module,exports){ +(function() { + var Timer; + + exports.Timer = Timer = (function() { + function Timer(func) { + this.func = func; + this.running = false; + this.id = null; + this._handler = (function(_this) { + return function() { + _this.running = false; + _this.id = null; + return _this.func(); + }; + })(this); + } + + Timer.prototype.start = function(timeout) { + if (this.running) { + clearTimeout(this.id); + } + this.id = setTimeout(this._handler, timeout); + return this.running = true; + }; + + Timer.prototype.stop = function() { + if (this.running) { + clearTimeout(this.id); + this.running = false; + return this.id = null; + } + }; + + return Timer; + + })(); + + Timer.start = function(timeout, func) { + return setTimeout(func, timeout); + }; + +}).call(this); + +},{}]},{},[8]); diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json new file mode 100644 index 0000000..017469b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/mime_types_charset.json @@ -0,0 +1,71 @@ +{ + "application/javascript": "UTF-8", + "application/json": "UTF-8", + "application/manifest+json": "UTF-8", + "application/vnd.syncml+xml": "UTF-8", + "application/vnd.syncml.dm+wbxml": "UTF-8", + "application/vnd.syncml.dm+xml": "UTF-8", + "application/vnd.syncml.dmddf+xml": "UTF-8", + "application/vnd.wap.wbxml": "UTF-8", + "text/cache-manifest": "UTF-8", + "text/calendar": "UTF-8", + "text/coffeescript": "UTF-8", + "text/css": "UTF-8", + "text/csv": "UTF-8", + "text/html": "UTF-8", + "text/jade": "UTF-8", + "text/jsx": "UTF-8", + "text/less": "UTF-8", + "text/markdown": "UTF-8", + "text/mathml": "UTF-8", + "text/mdx": "UTF-8", + "text/n3": "UTF-8", + "text/plain": "UTF-8", + "text/prs.lines.tag": "UTF-8", + "text/richtext": "UTF-8", + "text/sgml": "UTF-8", + "text/shex": "UTF-8", + "text/slim": "UTF-8", + "text/spdx": "UTF-8", + "text/stylus": "UTF-8", + "text/tab-separated-values": "UTF-8", + "text/troff": "UTF-8", + "text/turtle": "UTF-8", + "text/uri-list": "UTF-8", + "text/vcard": "UTF-8", + "text/vnd.curl": "UTF-8", + "text/vnd.curl.dcurl": "UTF-8", + "text/vnd.curl.mcurl": "UTF-8", + "text/vnd.curl.scurl": "UTF-8", + "text/vnd.familysearch.gedcom": "UTF-8", + "text/vnd.fly": "UTF-8", + "text/vnd.fmi.flexstor": "UTF-8", + "text/vnd.graphviz": "UTF-8", + "text/vnd.in3d.3dml": "UTF-8", + "text/vnd.in3d.spot": "UTF-8", + "text/vnd.sun.j2me.app-descriptor": "UTF-8", + "text/vnd.wap.wml": "UTF-8", + "text/vnd.wap.wmlscript": "UTF-8", + "text/vtt": "UTF-8", + "text/x-asm": "UTF-8", + "text/x-c": "UTF-8", + "text/x-component": "UTF-8", + "text/x-fortran": "UTF-8", + "text/x-handlebars-template": "UTF-8", + "text/x-java-source": "UTF-8", + "text/x-lua": "UTF-8", + "text/x-markdown": "UTF-8", + "text/x-nfo": "UTF-8", + "text/x-opml": "UTF-8", + "text/x-pascal": "UTF-8", + "text/x-processing": "UTF-8", + "text/x-sass": "UTF-8", + "text/x-scss": "UTF-8", + "text/x-setext": "UTF-8", + "text/x-sfv": "UTF-8", + "text/x-suse-ymp": "UTF-8", + "text/x-uuencode": "UTF-8", + "text/x-vcalendar": "UTF-8", + "text/x-vcard": "UTF-8", + "text/yaml": "UTF-8" +} diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb new file mode 100644 index 0000000..c8895e5 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/servlet.rb @@ -0,0 +1,206 @@ +# frozen_string_literal: true + +require "webrick" + +module Jekyll + module Commands + class Serve + # This class is used to determine if the Servlet should modify a served file + # to insert the LiveReload script tags + class SkipAnalyzer + BAD_USER_AGENTS = [%r!MSIE!].freeze + + def self.skip_processing?(request, response, options) + new(request, response, options).skip_processing? + end + + def initialize(request, response, options) + @options = options + @request = request + @response = response + end + + def skip_processing? + !html? || chunked? || inline? || bad_browser? + end + + def chunked? + @response["Transfer-Encoding"] == "chunked" + end + + def inline? + @response["Content-Disposition"].to_s.start_with?("inline") + end + + def bad_browser? + BAD_USER_AGENTS.any? { |pattern| pattern.match?(@request["User-Agent"]) } + end + + def html? + @response["Content-Type"].to_s.include?("text/html") + end + end + + # This class inserts the LiveReload script tags into HTML as it is served + class BodyProcessor + HEAD_TAG_REGEX = %r!|!.freeze + + attr_reader :content_length, :new_body, :livereload_added + + def initialize(body, options) + @body = body + @options = options + @processed = false + end + + def processed? + @processed + end + + # rubocop:disable Metrics/MethodLength + def process! + @new_body = [] + # @body will usually be a File object but Strings occur in rare cases + if @body.respond_to?(:each) + begin + @body.each { |line| @new_body << line.to_s } + ensure + @body.close + end + else + @new_body = @body.lines + end + + @content_length = 0 + @livereload_added = false + + @new_body.each do |line| + if !@livereload_added && line[" + document.write( + ' + TEMPLATE + end + + def livereload_args + # XHTML standard requires ampersands to be encoded as entities when in + # attributes. See http://stackoverflow.com/a/2190292 + src = "" + if @options["livereload_min_delay"] + src += "&mindelay=#{@options["livereload_min_delay"]}" + end + if @options["livereload_max_delay"] + src += "&maxdelay=#{@options["livereload_max_delay"]}" + end + src += "&port=#{@options["livereload_port"]}" if @options["livereload_port"] + src + end + end + + class Servlet < WEBrick::HTTPServlet::FileHandler + DEFAULTS = { + "Cache-Control" => "private, max-age=0, proxy-revalidate, " \ + "no-store, no-cache, must-revalidate", + }.freeze + + def initialize(server, root, callbacks) + # So we can access them easily. + @jekyll_opts = server.config[:JekyllOptions] + @mime_types_charset = server.config[:MimeTypesCharset] + set_defaults + super + end + + def search_index_file(req, res) + super || + search_file(req, res, ".html") || + search_file(req, res, ".xhtml") + end + + # Add the ability to tap file.html the same way that Nginx does on our + # Docker images (or on GitHub Pages.) The difference is that we might end + # up with a different preference on which comes first. + + def search_file(req, res, basename) + # /file.* > /file/index.html > /file.html + super || + super(req, res, "#{basename}.html") || + super(req, res, "#{basename}.xhtml") + end + + # rubocop:disable Naming/MethodName + def do_GET(req, res) + rtn = super + + if @jekyll_opts["livereload"] + return rtn if SkipAnalyzer.skip_processing?(req, res, @jekyll_opts) + + processor = BodyProcessor.new(res.body, @jekyll_opts) + processor.process! + res.body = processor.new_body + res.content_length = processor.content_length.to_s + + if processor.livereload_added + # Add a header to indicate that the page content has been modified + res["X-Rack-LiveReload"] = "1" + end + end + + conditionally_inject_charset(res) + res.header.merge!(@headers) + rtn + end + # rubocop:enable Naming/MethodName + + private + + # Inject charset based on Jekyll config only if our mime-types database contains + # the charset metadata. + # + # Refer `script/vendor-mimes` in the repository for further details. + def conditionally_inject_charset(res) + typ = res.header["content-type"] + return unless @mime_types_charset.key?(typ) + return if %r!;\s*charset=!.match?(typ) + + res.header["content-type"] = "#{typ}; charset=#{@jekyll_opts["encoding"]}" + end + + def set_defaults + hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {}) + DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash| + hash[key] = val unless hash.key?(key) + end + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb new file mode 100644 index 0000000..6aa522c --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/commands/serve/websockets.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require "http/parser" + +module Jekyll + module Commands + class Serve + # The LiveReload protocol requires the server to serve livereload.js over HTTP + # despite the fact that the protocol itself uses WebSockets. This custom connection + # class addresses the dual protocols that the server needs to understand. + class HttpAwareConnection < EventMachine::WebSocket::Connection + attr_reader :reload_body, :reload_size + + def initialize(_opts) + # If EventMachine SSL support on Windows ever gets better, the code below will + # set up the reactor to handle SSL + # + # @ssl_enabled = opts["ssl_cert"] && opts["ssl_key"] + # if @ssl_enabled + # em_opts[:tls_options] = { + # :private_key_file => Jekyll.sanitized_path(opts["source"], opts["ssl_key"]), + # :cert_chain_file => Jekyll.sanitized_path(opts["source"], opts["ssl_cert"]) + # } + # em_opts[:secure] = true + # end + + # This is too noisy even for --verbose, but uncomment if you need it for + # a specific WebSockets issue. Adding ?LR-verbose=true onto the URL will + # enable logging on the client side. + # em_opts[:debug] = true + + em_opts = {} + super(em_opts) + + reload_file = File.join(Serve.singleton_class::LIVERELOAD_DIR, "livereload.js") + + @reload_body = File.read(reload_file) + @reload_size = @reload_body.bytesize + end + + # rubocop:disable Metrics/MethodLength + def dispatch(data) + parser = Http::Parser.new + parser << data + + # WebSockets requests will have a Connection: Upgrade header + if parser.http_method != "GET" || parser.upgrade? + super + elsif parser.request_url.start_with?("/livereload.js") + headers = [ + "HTTP/1.1 200 OK", + "Content-Type: application/javascript", + "Content-Length: #{reload_size}", + "", + "", + ].join("\r\n") + send_data(headers) + + # stream_file_data would free us from keeping livereload.js in memory + # but JRuby blocks on that call and never returns + send_data(reload_body) + close_connection_after_writing + else + body = "This port only serves livereload.js over HTTP.\n" + headers = [ + "HTTP/1.1 400 Bad Request", + "Content-Type: text/plain", + "Content-Length: #{body.bytesize}", + "", + "", + ].join("\r\n") + send_data(headers) + send_data(body) + close_connection_after_writing + end + end + # rubocop:enable Metrics/MethodLength + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/configuration.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/configuration.rb new file mode 100644 index 0000000..9b2fbff --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/configuration.rb @@ -0,0 +1,313 @@ +# frozen_string_literal: true + +module Jekyll + class Configuration < Hash + # Default options. Overridden by values in _config.yml. + # Strings rather than symbols are used for compatibility with YAML. + DEFAULTS = { + # Where things are + "source" => Dir.pwd, + "destination" => File.join(Dir.pwd, "_site"), + "collections_dir" => "", + "cache_dir" => ".jekyll-cache", + "plugins_dir" => "_plugins", + "layouts_dir" => "_layouts", + "data_dir" => "_data", + "includes_dir" => "_includes", + "collections" => {}, + + # Handling Reading + "safe" => false, + "include" => [".htaccess"], + "exclude" => [], + "keep_files" => [".git", ".svn"], + "encoding" => "utf-8", + "markdown_ext" => "markdown,mkdown,mkdn,mkd,md", + "strict_front_matter" => false, + + # Filtering Content + "show_drafts" => nil, + "limit_posts" => 0, + "future" => false, + "unpublished" => false, + + # Plugins + "whitelist" => [], + "plugins" => [], + + # Conversion + "markdown" => "kramdown", + "highlighter" => "rouge", + "lsi" => false, + "excerpt_separator" => "\n\n", + "incremental" => false, + + # Serving + "detach" => false, # default to not detaching the server + "port" => "4000", + "host" => "127.0.0.1", + "baseurl" => nil, # this mounts at /, i.e. no subdirectory + "show_dir_listing" => false, + + # Output Configuration + "permalink" => "date", + "paginate_path" => "/page:num", + "timezone" => nil, # use the local timezone + + "quiet" => false, + "verbose" => false, + "defaults" => [], + + "liquid" => { + "error_mode" => "warn", + "strict_filters" => false, + "strict_variables" => false, + }, + + "kramdown" => { + "auto_ids" => true, + "toc_levels" => (1..6).to_a, + "entity_output" => "as_char", + "smart_quotes" => "lsquo,rsquo,ldquo,rdquo", + "input" => "GFM", + "hard_wrap" => false, + "guess_lang" => true, + "footnote_nr" => 1, + "show_warnings" => false, + }, + }.each_with_object(Configuration.new) { |(k, v), hsh| hsh[k] = v.freeze }.freeze + + class << self + # Static: Produce a Configuration ready for use in a Site. + # It takes the input, fills in the defaults where values do not exist. + # + # user_config - a Hash or Configuration of overrides. + # + # Returns a Configuration filled with defaults. + def from(user_config) + Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys) + .add_default_collections.add_default_excludes + end + end + + # Public: Turn all keys into string + # + # Return a copy of the hash where all its keys are strings + def stringify_keys + each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v } + end + + def get_config_value_with_override(config_key, override) + override[config_key] || self[config_key] || DEFAULTS[config_key] + end + + # Public: Directory of the Jekyll source folder + # + # override - the command-line options hash + # + # Returns the path to the Jekyll source directory + def source(override) + get_config_value_with_override("source", override) + end + + def quiet(override = {}) + get_config_value_with_override("quiet", override) + end + alias_method :quiet?, :quiet + + def verbose(override = {}) + get_config_value_with_override("verbose", override) + end + alias_method :verbose?, :verbose + + def safe_load_file(filename) + case File.extname(filename) + when %r!\.toml!i + Jekyll::External.require_with_graceful_fail("tomlrb") unless defined?(Tomlrb) + Tomlrb.load_file(filename) + when %r!\.ya?ml!i + SafeYAML.load_file(filename) || {} + else + raise ArgumentError, + "No parser for '#{filename}' is available. Use a .y(a)ml or .toml file instead." + end + end + + # Public: Generate list of configuration files from the override + # + # override - the command-line options hash + # + # Returns an Array of config files + def config_files(override) + # Adjust verbosity quickly + Jekyll.logger.adjust_verbosity( + :quiet => quiet?(override), + :verbose => verbose?(override) + ) + + # Get configuration from /_config.yml or / + config_files = override["config"] + if config_files.to_s.empty? + default = %w(yml yaml toml).find(-> { "yml" }) do |ext| + File.exist?(Jekyll.sanitized_path(source(override), "_config.#{ext}")) + end + config_files = Jekyll.sanitized_path(source(override), "_config.#{default}") + @default_config_file = true + end + Array(config_files) + end + + # Public: Read configuration and return merged Hash + # + # file - the path to the YAML file to be read in + # + # Returns this configuration, overridden by the values in the file + def read_config_file(file) + file = File.expand_path(file) + next_config = safe_load_file(file) + + unless next_config.is_a?(Hash) + raise ArgumentError, "Configuration file: (INVALID) #{file}".yellow + end + + Jekyll.logger.info "Configuration file:", file + next_config + rescue SystemCallError + if @default_config_file ||= nil + Jekyll.logger.warn "Configuration file:", "none" + {} + else + Jekyll.logger.error "Fatal:", "The configuration file '#{file}' could not be found." + raise LoadError, "The Configuration file '#{file}' could not be found." + end + end + + # Public: Read in a list of configuration files and merge with this hash + # + # files - the list of configuration file paths + # + # Returns the full configuration, with the defaults overridden by the values in the + # configuration files + def read_config_files(files) + configuration = clone + + begin + files.each do |config_file| + next if config_file.nil? || config_file.empty? + + new_config = read_config_file(config_file) + configuration = Utils.deep_merge_hashes(configuration, new_config) + end + rescue ArgumentError => e + Jekyll.logger.warn "WARNING:", "Error reading configuration. Using defaults (and options)." + warn e + end + + configuration.validate.add_default_collections + end + + # Public: Split a CSV string into an array containing its values + # + # csv - the string of comma-separated values + # + # Returns an array of the values contained in the CSV + def csv_to_array(csv) + csv.split(",").map(&:strip) + end + + # Public: Ensure the proper options are set in the configuration + # + # Returns the configuration Hash + def validate + config = clone + + check_plugins(config) + check_include_exclude(config) + + config + end + + def add_default_collections + config = clone + + # It defaults to `{}`, so this is only if someone sets it to null manually. + return config if config["collections"].nil? + + # Ensure we have a hash. + if config["collections"].is_a?(Array) + config["collections"] = config["collections"].each_with_object({}) do |collection, hash| + hash[collection] = {} + end + end + + config["collections"] = Utils.deep_merge_hashes( + { "posts" => {} }, config["collections"] + ).tap do |collections| + collections["posts"]["output"] = true + if config["permalink"] + collections["posts"]["permalink"] ||= style_to_permalink(config["permalink"]) + end + end + + config + end + + DEFAULT_EXCLUDES = %w( + .sass-cache .jekyll-cache + gemfiles Gemfile Gemfile.lock + node_modules + vendor/bundle/ vendor/cache/ vendor/gems/ vendor/ruby/ + ).freeze + + def add_default_excludes + config = clone + return config if config["exclude"].nil? + + config["exclude"].concat(DEFAULT_EXCLUDES).uniq! + config + end + + private + + STYLE_TO_PERMALINK = { + :none => "/:categories/:title:output_ext", + :date => "/:categories/:year/:month/:day/:title:output_ext", + :ordinal => "/:categories/:year/:y_day/:title:output_ext", + :pretty => "/:categories/:year/:month/:day/:title/", + :weekdate => "/:categories/:year/W:week/:short_day/:title:output_ext", + }.freeze + + private_constant :STYLE_TO_PERMALINK + + def style_to_permalink(permalink_style) + STYLE_TO_PERMALINK[permalink_style.to_sym] || permalink_style.to_s + end + + def check_include_exclude(config) + %w(include exclude).each do |option| + next unless config.key?(option) + next if config[option].is_a?(Array) + + raise Jekyll::Errors::InvalidConfigurationError, + "'#{option}' should be set as an array, but was: #{config[option].inspect}." + end + end + + # Private: Checks if the `plugins` config is a String + # + # config - the config hash + # + # Raises a Jekyll::Errors::InvalidConfigurationError if the config `plugins` + # is not an Array. + def check_plugins(config) + return unless config.key?("plugins") + return if config["plugins"].is_a?(Array) + + Jekyll.logger.error "'plugins' should be set as an array of gem-names, but was: " \ + "#{config["plugins"].inspect}. Use 'plugins_dir' instead to set " \ + "the directory for your non-gemified Ruby plugins." + raise Jekyll::Errors::InvalidConfigurationError, + "'plugins' should be set as an array, but was: #{config["plugins"].inspect}." + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converter.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converter.rb new file mode 100644 index 0000000..3cb74de --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converter.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Jekyll + class Converter < Plugin + # Public: Get or set the highlighter prefix. When an argument is specified, + # the prefix will be set. If no argument is specified, the current prefix + # will be returned. + # + # highlighter_prefix - The String prefix (default: nil). + # + # Returns the String prefix. + def self.highlighter_prefix(highlighter_prefix = nil) + unless defined?(@highlighter_prefix) && highlighter_prefix.nil? + @highlighter_prefix = highlighter_prefix + end + @highlighter_prefix + end + + # Public: Get or set the highlighter suffix. When an argument is specified, + # the suffix will be set. If no argument is specified, the current suffix + # will be returned. + # + # highlighter_suffix - The String suffix (default: nil). + # + # Returns the String suffix. + def self.highlighter_suffix(highlighter_suffix = nil) + unless defined?(@highlighter_suffix) && highlighter_suffix.nil? + @highlighter_suffix = highlighter_suffix + end + @highlighter_suffix + end + + # Initialize the converter. + # + # Returns an initialized Converter. + def initialize(config = {}) + @config = config + end + + # Get the highlighter prefix. + # + # Returns the String prefix. + def highlighter_prefix + self.class.highlighter_prefix + end + + # Get the highlighter suffix. + # + # Returns the String suffix. + def highlighter_suffix + self.class.highlighter_suffix + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb new file mode 100644 index 0000000..7579b33 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/identity.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Jekyll + module Converters + # Identity converter. Returns same content as given. + # For more info on converters see https://jekyllrb.com/docs/plugins/converters/ + class Identity < Converter + safe true + + priority :lowest + + # Public: Does the given extension match this converter's list of acceptable extensions? + # Takes one argument: the file's extension (including the dot). + # + # _ext - The String extension to check (not relevant here) + # + # Returns true since it always matches. + def matches(_ext) + true + end + + # Public: The extension to be given to the output file (including the dot). + # + # ext - The String extension or original file. + # + # Returns The String output file extension. + def output_ext(ext) + ext + end + + # Logic to do the content conversion. + # + # content - String content of file (without front matter). + # + # Returns a String of the converted content. + def convert(content) + content + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb new file mode 100644 index 0000000..da1f1ce --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module Jekyll + module Converters + # Markdown converter. + # For more info on converters see https://jekyllrb.com/docs/plugins/converters/ + class Markdown < Converter + highlighter_prefix "\n" + highlighter_suffix "\n" + safe true + + def setup + return if @setup ||= false + + unless (@parser = get_processor) + if @config["safe"] + Jekyll.logger.warn "Build Warning:", "Custom processors are not loaded in safe mode" + end + + Jekyll.logger.error "Markdown processor:", + "#{@config["markdown"].inspect} is not a valid Markdown processor." + Jekyll.logger.error "", "Available processors are: #{valid_processors.join(", ")}" + Jekyll.logger.error "" + raise Errors::FatalException, "Invalid Markdown processor given: #{@config["markdown"]}" + end + + @cache = Jekyll::Cache.new("Jekyll::Converters::Markdown") + @setup = true + end + + # RuboCop does not allow reader methods to have names starting with `get_` + # To ensure compatibility, this check has been disabled on this method + # + # rubocop:disable Naming/AccessorMethodName + def get_processor + case @config["markdown"].downcase + when "kramdown" then KramdownParser.new(@config) + else + custom_processor + end + end + # rubocop:enable Naming/AccessorMethodName + + # Public: Provides you with a list of processors comprised of the ones we support internally + # and the ones that you have provided to us (if they're whitelisted for use in safe mode). + # + # Returns an array of symbols. + def valid_processors + [:kramdown] + third_party_processors + end + + # Public: A list of processors that you provide via plugins. + # + # Returns an array of symbols + def third_party_processors + self.class.constants - [:KramdownParser, :PRIORITIES] + end + + # Does the given extension match this converter's list of acceptable extensions? + # Takes one argument: the file's extension (including the dot). + # + # ext - The String extension to check. + # + # Returns true if it matches, false otherwise. + def matches(ext) + extname_list.include?(ext.downcase) + end + + # Public: The extension to be given to the output file (including the dot). + # + # ext - The String extension or original file. + # + # Returns The String output file extension. + def output_ext(_ext) + ".html" + end + + # Logic to do the content conversion. + # + # content - String content of file (without front matter). + # + # Returns a String of the converted content. + def convert(content) + setup + @cache.getset(content) do + @parser.convert(content) + end + end + + def extname_list + @extname_list ||= @config["markdown_ext"].split(",").map! { |e| ".#{e.downcase}" } + end + + private + + def custom_processor + converter_name = @config["markdown"] + self.class.const_get(converter_name).new(@config) if custom_class_allowed?(converter_name) + end + + # Private: Determine whether a class name is an allowed custom + # markdown class name. + # + # parser_name - the name of the parser class + # + # Returns true if the parser name contains only alphanumeric characters and is defined + # within Jekyll::Converters::Markdown + def custom_class_allowed?(parser_name) + parser_name !~ %r![^A-Za-z0-9_]! && self.class.constants.include?(parser_name.to_sym) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb new file mode 100644 index 0000000..1e6a1de --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/markdown/kramdown_parser.rb @@ -0,0 +1,197 @@ +# frozen_string_literal: true + +module Kramdown + # A Kramdown::Document subclass meant to optimize memory usage from initializing + # a kramdown document for parsing. + # + # The optimization is by using the same options Hash (and its derivatives) for + # converting all Markdown documents in a Jekyll site. + class JekyllDocument < Document + class << self + attr_reader :options, :parser + + # The implementation is basically the core logic in +Kramdown::Document#initialize+ + # + # rubocop:disable Naming/MemoizedInstanceVariableName + def setup(options) + @cache ||= {} + + # reset variables on a subsequent set up with a different options Hash + unless @cache[:id] == options.hash + @options = @parser = nil + @cache[:id] = options.hash + end + + @options ||= Options.merge(options).freeze + @parser ||= begin + parser_name = (@options[:input] || "kramdown").to_s + parser_name = parser_name[0..0].upcase + parser_name[1..-1] + try_require("parser", parser_name) + + if Parser.const_defined?(parser_name) + Parser.const_get(parser_name) + else + raise Kramdown::Error, "kramdown has no parser to handle the specified " \ + "input format: #{@options[:input]}" + end + end + end + # rubocop:enable Naming/MemoizedInstanceVariableName + + private + + def try_require(type, name) + require "kramdown/#{type}/#{Utils.snake_case(name)}" + rescue LoadError + false + end + end + + def initialize(source, options = {}) + JekyllDocument.setup(options) + + @options = JekyllDocument.options + @root, @warnings = JekyllDocument.parser.parse(source, @options) + end + + # Use Kramdown::Converter::Html class to convert this document into HTML. + # + # The implementation is basically an optimized version of core logic in + # +Kramdown::Document#method_missing+ from kramdown-2.1.0. + def to_html + output, warnings = Kramdown::Converter::Html.convert(@root, @options) + @warnings.concat(warnings) + output + end + end +end + +# + +module Jekyll + module Converters + class Markdown + class KramdownParser + CODERAY_DEFAULTS = { + "css" => "style", + "bold_every" => 10, + "line_numbers" => "inline", + "line_number_start" => 1, + "tab_width" => 4, + "wrap" => "div", + }.freeze + + def initialize(config) + @main_fallback_highlighter = config["highlighter"] || "rouge" + @config = config["kramdown"] || {} + @highlighter = nil + setup + load_dependencies + end + + # Setup and normalize the configuration: + # * Create Kramdown if it doesn't exist. + # * Set syntax_highlighter, detecting enable_coderay and merging + # highlighter if none. + # * Merge kramdown[coderay] into syntax_highlighter_opts stripping coderay_. + # * Make sure `syntax_highlighter_opts` exists. + + def setup + @config["syntax_highlighter"] ||= highlighter + @config["syntax_highlighter_opts"] ||= {} + @config["syntax_highlighter_opts"]["default_lang"] ||= "plaintext" + @config["syntax_highlighter_opts"]["guess_lang"] = @config["guess_lang"] + @config["coderay"] ||= {} # XXX: Legacy. + modernize_coderay_config + end + + def convert(content) + document = Kramdown::JekyllDocument.new(content, @config) + html_output = document.to_html + if @config["show_warnings"] + document.warnings.each do |warning| + Jekyll.logger.warn "Kramdown warning:", warning + end + end + html_output + end + + private + + def load_dependencies + require "kramdown-parser-gfm" if @config["input"] == "GFM" + + if highlighter == "coderay" + Jekyll::External.require_with_graceful_fail("kramdown-syntax-coderay") + end + + # `mathjax` engine is bundled within kramdown-2.x and will be handled by + # kramdown itself. + if (math_engine = @config["math_engine"]) && math_engine != "mathjax" + Jekyll::External.require_with_graceful_fail("kramdown-math-#{math_engine}") + end + end + + # config[kramdown][syntax_highlighter] > + # config[kramdown][enable_coderay] > + # config[highlighter] + # Where `enable_coderay` is now deprecated because Kramdown + # supports Rouge now too. + def highlighter + return @highlighter if @highlighter + + if @config["syntax_highlighter"] + return @highlighter = @config[ + "syntax_highlighter" + ] + end + + @highlighter = if @config.key?("enable_coderay") && @config["enable_coderay"] + Jekyll::Deprecator.deprecation_message( + "You are using 'enable_coderay', " \ + "use syntax_highlighter: coderay in your configuration file." + ) + + "coderay" + else + @main_fallback_highlighter + end + end + + def strip_coderay_prefix(hash) + hash.each_with_object({}) do |(key, val), hsh| + cleaned_key = key.to_s.delete_prefix("coderay_") + + if key != cleaned_key + Jekyll::Deprecator.deprecation_message( + "You are using '#{key}'. Normalizing to #{cleaned_key}." + ) + end + + hsh[cleaned_key] = val + end + end + + # If our highlighter is CodeRay we go in to merge the CodeRay defaults + # with your "coderay" key if it's there, deprecating it in the + # process of you using it. + def modernize_coderay_config + unless @config["coderay"].empty? + Jekyll::Deprecator.deprecation_message( + "You are using 'kramdown.coderay' in your configuration, " \ + "please use 'syntax_highlighter_opts' instead." + ) + + @config["syntax_highlighter_opts"] = begin + strip_coderay_prefix( + @config["syntax_highlighter_opts"] \ + .merge(CODERAY_DEFAULTS) \ + .merge(@config["coderay"]) + ) + end + end + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb new file mode 100644 index 0000000..606afdc --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/converters/smartypants.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Kramdown + module Parser + class SmartyPants < Kramdown::Parser::Kramdown + def initialize(source, options) + super + @block_parsers = [:block_html, :content] + @span_parsers = [:smart_quotes, :html_entity, :typographic_syms, :span_html] + end + + def parse_content + add_text @src.scan(%r!\A.*\n!) + end + define_parser(:content, %r!\A!) + end + end +end + +module Jekyll + module Converters + # SmartyPants converter. + # For more info on converters see https://jekyllrb.com/docs/plugins/converters/ + class SmartyPants < Converter + safe true + priority :low + + def initialize(config) + Jekyll::External.require_with_graceful_fail "kramdown" unless defined?(Kramdown) + @config = config["kramdown"].dup || {} + @config[:input] = :SmartyPants + end + + # Does the given extension match this converter's list of acceptable extensions? + # Takes one argument: the file's extension (including the dot). + # + # ext - The String extension to check. + # + # Returns true if it matches, false otherwise. + def matches(_ext) + false + end + + # Public: The extension to be given to the output file (including the dot). + # + # ext - The String extension or original file. + # + # Returns The String output file extension. + def output_ext(_ext) + nil + end + + # Logic to do the content conversion. + # + # content - String content of file (without front matter). + # + # Returns a String of the converted content. + def convert(content) + document = Kramdown::Document.new(content, @config) + html_output = document.to_html.chomp + if @config["show_warnings"] + document.warnings.each do |warning| + Jekyll.logger.warn "Kramdown warning:", warning.sub(%r!^Warning:\s+!, "") + end + end + html_output + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/convertible.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/convertible.rb new file mode 100644 index 0000000..b9f7a93 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/convertible.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true + +# Convertible provides methods for converting a pagelike item +# from a certain type of markup into actual content +# +# Requires +# self.site -> Jekyll::Site +# self.content +# self.content= +# self.data= +# self.ext= +# self.output= +# self.name +# self.path +# self.type -> :page, :post or :draft + +module Jekyll + module Convertible + # Returns the contents as a String. + def to_s + content || "" + end + + # Whether the file is published or not, as indicated in YAML front-matter + def published? + !(data.key?("published") && data["published"] == false) + end + + # Read the YAML frontmatter. + # + # base - The String path to the dir containing the file. + # name - The String filename of the file. + # opts - optional parameter to File.read, default at site configs + # + # Returns nothing. + # rubocop:disable Metrics/AbcSize + def read_yaml(base, name, opts = {}) + filename = @path || site.in_source_dir(base, name) + Jekyll.logger.debug "Reading:", relative_path + + begin + self.content = File.read(filename, **Utils.merged_file_read_opts(site, opts)) + if content =~ Document::YAML_FRONT_MATTER_REGEXP + self.content = Regexp.last_match.post_match + self.data = SafeYAML.load(Regexp.last_match(1)) + end + rescue Psych::SyntaxError => e + Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}" + raise e if site.config["strict_front_matter"] + rescue StandardError => e + Jekyll.logger.warn "Error reading file #{filename}: #{e.message}" + raise e if site.config["strict_front_matter"] + end + + self.data ||= {} + + validate_data! filename + validate_permalink! filename + + self.data + end + # rubocop:enable Metrics/AbcSize + + def validate_data!(filename) + unless self.data.is_a?(Hash) + raise Errors::InvalidYAMLFrontMatterError, + "Invalid YAML front matter in #{filename}" + end + end + + def validate_permalink!(filename) + if self.data["permalink"] == "" + raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}" + end + end + + # Transform the contents based on the content type. + # + # Returns the transformed contents. + def transform + renderer.convert(content) + end + + # Determine the extension depending on content_type. + # + # Returns the String extension for the output file. + # e.g. ".html" for an HTML output file. + def output_ext + renderer.output_ext + end + + # Determine which converter to use based on this convertible's + # extension. + # + # Returns the Converter instance. + def converters + renderer.converters + end + + # Render Liquid in the content + # + # content - the raw Liquid content to render + # payload - the payload for Liquid + # info - the info for Liquid + # + # Returns the converted content + def render_liquid(content, payload, info, path) + renderer.render_liquid(content, payload, info, path) + end + + # Convert this Convertible's data to a Hash suitable for use by Liquid. + # + # Returns the Hash representation of this Convertible. + def to_liquid(attrs = nil) + further_data = \ + (attrs || self.class::ATTRIBUTES_FOR_LIQUID).each_with_object({}) do |attribute, hsh| + hsh[attribute] = send(attribute) + end + + Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data) + end + + # The type of a document, + # i.e., its classname downcase'd and to_sym'd. + # + # Returns the type of self. + def type + :pages if is_a?(Page) + end + + # returns the owner symbol for hook triggering + def hook_owner + :pages if is_a?(Page) + end + + # Determine whether the document is an asset file. + # Asset files include CoffeeScript files and Sass/SCSS files. + # + # Returns true if the extname belongs to the set of extensions + # that asset files use. + def asset_file? + sass_file? || coffeescript_file? + end + + # Determine whether the document is a Sass file. + # + # Returns true if extname == .sass or .scss, false otherwise. + def sass_file? + Jekyll::Document::SASS_FILE_EXTS.include?(ext) + end + + # Determine whether the document is a CoffeeScript file. + # + # Returns true if extname == .coffee, false otherwise. + def coffeescript_file? + ext == ".coffee" + end + + # Determine whether the file should be rendered with Liquid. + # + # Returns true if the file has Liquid Tags or Variables, false otherwise. + def render_with_liquid? + return false if data["render_with_liquid"] == false + + Jekyll::Utils.has_liquid_construct?(content) + end + + # Determine whether the file should be placed into layouts. + # + # Returns false if the document is an asset file or if the front matter + # specifies `layout: none` + def place_in_layout? + !(asset_file? || no_layout?) + end + + # Checks if the layout specified in the document actually exists + # + # layout - the layout to check + # + # Returns true if the layout is invalid, false if otherwise + def invalid_layout?(layout) + !data["layout"].nil? && layout.nil? && !(is_a? Jekyll::Excerpt) + end + + # Recursively render layouts + # + # layouts - a list of the layouts + # payload - the payload for Liquid + # info - the info for Liquid + # + # Returns nothing + def render_all_layouts(layouts, payload, info) + renderer.layouts = layouts + self.output = renderer.place_in_layouts(output, payload, info) + ensure + @renderer = nil # this will allow the modifications above to disappear + end + + # Add any necessary layouts to this convertible document. + # + # payload - The site payload Drop or Hash. + # layouts - A Hash of {"name" => "layout"}. + # + # Returns nothing. + def do_layout(payload, layouts) + self.output = renderer.tap do |doc_renderer| + doc_renderer.layouts = layouts + doc_renderer.payload = payload + end.run + + Jekyll.logger.debug "Post-Render Hooks:", relative_path + Jekyll::Hooks.trigger hook_owner, :post_render, self + ensure + @renderer = nil # this will allow the modifications above to disappear + end + + # Write the generated page file to the destination directory. + # + # dest - The String path to the destination dir. + # + # Returns nothing. + def write(dest) + path = destination(dest) + FileUtils.mkdir_p(File.dirname(path)) + Jekyll.logger.debug "Writing:", path + File.write(path, output, :mode => "wb") + Jekyll::Hooks.trigger hook_owner, :post_write, self + end + + # Accessor for data properties by Liquid. + # + # property - The String name of the property to retrieve. + # + # Returns the String value or nil if the property isn't included. + def [](property) + if self.class::ATTRIBUTES_FOR_LIQUID.include?(property) + send(property) + else + data[property] + end + end + + def renderer + @renderer ||= Jekyll::Renderer.new(site, self) + end + + private + + def defaults + @defaults ||= site.frontmatter_defaults.all(relative_path, type) + end + + def no_layout? + data["layout"] == "none" + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb new file mode 100644 index 0000000..4ecb656 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/deprecator.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Jekyll + module Deprecator + extend self + + def process(args) + arg_is_present? args, "--server", "The --server command has been replaced by the \ + 'serve' subcommand." + arg_is_present? args, "--serve", "The --serve command has been replaced by the \ + 'serve' subcommand." + arg_is_present? args, "--no-server", "To build Jekyll without launching a server, \ + use the 'build' subcommand." + arg_is_present? args, "--auto", "The switch '--auto' has been replaced with \ + '--watch'." + arg_is_present? args, "--no-auto", "To disable auto-replication, simply leave off \ + the '--watch' switch." + arg_is_present? args, "--pygments", "The 'pygments' settings has been removed in \ + favour of 'highlighter'." + arg_is_present? args, "--paginate", "The 'paginate' setting can only be set in \ + your config files." + arg_is_present? args, "--url", "The 'url' setting can only be set in your \ + config files." + no_subcommand(args) + end + + def no_subcommand(args) + unless args.empty? || + args.first !~ %r(!/^--/!) || %w(--help --version).include?(args.first) + deprecation_message "Jekyll now uses subcommands instead of just switches. \ + Run `jekyll help` to find out more." + abort + end + end + + def arg_is_present?(args, deprecated_argument, message) + deprecation_message(message) if args.include?(deprecated_argument) + end + + def deprecation_message(message) + Jekyll.logger.warn "Deprecation:", message + end + + def defaults_deprecate_type(old, current) + Jekyll.logger.warn "Defaults:", "The '#{old}' type has become '#{current}'." + Jekyll.logger.warn "Defaults:", "Please update your front-matter defaults to use \ + 'type: #{current}'." + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/document.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/document.rb new file mode 100644 index 0000000..2e39024 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/document.rb @@ -0,0 +1,543 @@ +# frozen_string_literal: true + +module Jekyll + class Document + include Comparable + extend Forwardable + + attr_reader :path, :site, :extname, :collection, :type + attr_accessor :content, :output + + def_delegator :self, :read_post_data, :post_read + + YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m.freeze + DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze + DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze + + SASS_FILE_EXTS = %w(.sass .scss).freeze + YAML_FILE_EXTS = %w(.yaml .yml).freeze + + # + + # Class-wide cache to stash and retrieve regexp to detect "super-directories" + # of a particular Jekyll::Document object. + # + # dirname - The *special directory* for the Document. + # e.g. "_posts" or "_drafts" for Documents from the `site.posts` collection. + def self.superdirs_regex(dirname) + @superdirs_regex ||= {} + @superdirs_regex[dirname] ||= %r!#{dirname}.*! + end + + # + + # Create a new Document. + # + # path - the path to the file + # relations - a hash with keys :site and :collection, the values of which + # are the Jekyll::Site and Jekyll::Collection to which this + # Document belong. + # + # Returns nothing. + def initialize(path, relations = {}) + @site = relations[:site] + @path = path + @extname = File.extname(path) + @collection = relations[:collection] + @type = @collection.label.to_sym + + @has_yaml_header = nil + + if draft? + categories_from_path("_drafts") + else + categories_from_path(collection.relative_directory) + end + + data.default_proc = proc do |_, key| + site.frontmatter_defaults.find(relative_path, type, key) + end + + trigger_hooks(:post_init) + end + + # Fetch the Document's data. + # + # Returns a Hash containing the data. An empty hash is returned if + # no data was read. + def data + @data ||= {} + end + + # Merge some data in with this document's data. + # + # Returns the merged data. + def merge_data!(other, source: "YAML front matter") + merge_categories!(other) + Utils.deep_merge_hashes!(data, other) + merge_date!(source) + data + end + + # Returns the document date. If metadata is not present then calculates it + # based on Jekyll::Site#time or the document file modification time. + # + # Return document date string. + def date + data["date"] ||= (draft? ? source_file_mtime : site.time) + end + + # Return document file modification time in the form of a Time object. + # + # Return document file modification Time object. + def source_file_mtime + File.mtime(path) + end + + # Returns whether the document is a draft. This is only the case if + # the document is in the 'posts' collection but in a different + # directory than '_posts'. + # + # Returns whether the document is a draft. + def draft? + data["draft"] ||= relative_path.index(collection.relative_directory).nil? && + collection.label == "posts" + end + + # The path to the document, relative to the collections_dir. + # + # Returns a String path which represents the relative path from the collections_dir + # to this document. + def relative_path + @relative_path ||= path.sub("#{site.collections_path}/", "") + end + + # The output extension of the document. + # + # Returns the output extension + def output_ext + renderer.output_ext + end + + # The base filename of the document, without the file extname. + # + # Returns the basename without the file extname. + def basename_without_ext + @basename_without_ext ||= File.basename(path, ".*") + end + + # The base filename of the document. + # + # Returns the base filename of the document. + def basename + @basename ||= File.basename(path) + end + + def renderer + @renderer ||= Jekyll::Renderer.new(site, self) + end + + # Produces a "cleaned" relative path. + # The "cleaned" relative path is the relative path without the extname + # and with the collection's directory removed as well. + # This method is useful when building the URL of the document. + # + # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`) + # + # Examples: + # When relative_path is "_methods/site/generate...md": + # cleaned_relative_path + # # => "/site/generate" + # + # Returns the cleaned relative path of the document. + def cleaned_relative_path + @cleaned_relative_path ||= + relative_path[0..-extname.length - 1] + .sub(collection.relative_directory, "") + .gsub(%r!\.*\z!, "") + end + + # Determine whether the document is a YAML file. + # + # Returns true if the extname is either .yml or .yaml, false otherwise. + def yaml_file? + YAML_FILE_EXTS.include?(extname) + end + + # Determine whether the document is an asset file. + # Asset files include CoffeeScript files and Sass/SCSS files. + # + # Returns true if the extname belongs to the set of extensions + # that asset files use. + def asset_file? + sass_file? || coffeescript_file? + end + + # Determine whether the document is a Sass file. + # + # Returns true if extname == .sass or .scss, false otherwise. + def sass_file? + SASS_FILE_EXTS.include?(extname) + end + + # Determine whether the document is a CoffeeScript file. + # + # Returns true if extname == .coffee, false otherwise. + def coffeescript_file? + extname == ".coffee" + end + + # Determine whether the file should be rendered with Liquid. + # + # Returns false if the document is either an asset file or a yaml file, + # or if the document doesn't contain any Liquid Tags or Variables, + # true otherwise. + def render_with_liquid? + return false if data["render_with_liquid"] == false + + !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content)) + end + + # Determine whether the file should be rendered with a layout. + # + # Returns true if the Front Matter specifies that `layout` is set to `none`. + def no_layout? + data["layout"] == "none" + end + + # Determine whether the file should be placed into layouts. + # + # Returns false if the document is set to `layouts: none`, or is either an + # asset file or a yaml file. Returns true otherwise. + def place_in_layout? + !(asset_file? || yaml_file? || no_layout?) + end + + # The URL template where the document would be accessible. + # + # Returns the URL template for the document. + def url_template + collection.url_template + end + + # Construct a Hash of key-value pairs which contain a mapping between + # a key in the URL template and the corresponding value for this document. + # + # Returns the Hash of key-value pairs for replacement in the URL. + def url_placeholders + @url_placeholders ||= Drops::UrlDrop.new(self) + end + + # The permalink for this Document. + # Permalink is set via the data Hash. + # + # Returns the permalink or nil if no permalink was set in the data. + def permalink + data && data.is_a?(Hash) && data["permalink"] + end + + # The computed URL for the document. See `Jekyll::URL#to_s` for more details. + # + # Returns the computed URL for the document. + def url + @url ||= URL.new( + :template => url_template, + :placeholders => url_placeholders, + :permalink => permalink + ).to_s + end + + def [](key) + data[key] + end + + # The full path to the output file. + # + # base_directory - the base path of the output directory + # + # Returns the full path to the output file of this document. + def destination(base_directory) + @destination ||= {} + @destination[base_directory] ||= begin + path = site.in_dest_dir(base_directory, URL.unescape_path(url)) + if url.end_with? "/" + path = File.join(path, "index.html") + else + path << output_ext unless path.end_with? output_ext + end + path + end + end + + # Write the generated Document file to the destination directory. + # + # dest - The String path to the destination dir. + # + # Returns nothing. + def write(dest) + path = destination(dest) + FileUtils.mkdir_p(File.dirname(path)) + Jekyll.logger.debug "Writing:", path + File.write(path, output, :mode => "wb") + + trigger_hooks(:post_write) + end + + # Whether the file is published or not, as indicated in YAML front-matter + # + # Returns 'false' if the 'published' key is specified in the + # YAML front-matter and is 'false'. Otherwise returns 'true'. + def published? + !(data.key?("published") && data["published"] == false) + end + + # Read in the file and assign the content and data based on the file contents. + # Merge the frontmatter of the file with the frontmatter default + # values + # + # Returns nothing. + def read(opts = {}) + Jekyll.logger.debug "Reading:", relative_path + + if yaml_file? + @data = SafeYAML.load_file(path) + else + begin + merge_defaults + read_content(**opts) + read_post_data + rescue StandardError => e + handle_read_error(e) + end + end + end + + # Create a Liquid-understandable version of this Document. + # + # Returns a Hash representing this Document's data. + def to_liquid + @to_liquid ||= Drops::DocumentDrop.new(self) + end + + # The inspect string for this document. + # Includes the relative path and the collection label. + # + # Returns the inspect string for this document. + def inspect + "#<#{self.class} #{relative_path} collection=#{collection.label}>" + end + + # The string representation for this document. + # + # Returns the content of the document + def to_s + output || content || "NO CONTENT" + end + + # Compare this document against another document. + # Comparison is a comparison between the 2 paths of the documents. + # + # Returns -1, 0, +1 or nil depending on whether this doc's path is less than, + # equal or greater than the other doc's path. See String#<=> for more details. + def <=>(other) + return nil unless other.respond_to?(:data) + + cmp = data["date"] <=> other.data["date"] + cmp = path <=> other.path if cmp.nil? || cmp.zero? + cmp + end + + # Determine whether this document should be written. + # Based on the Collection to which it belongs. + # + # True if the document has a collection and if that collection's #write? + # method returns true, and if the site's Publisher will publish the document. + # False otherwise. + # + # rubocop:disable Naming/MemoizedInstanceVariableName + def write? + return @write_p if defined?(@write_p) + + @write_p = collection&.write? && site.publisher.publish?(self) + end + # rubocop:enable Naming/MemoizedInstanceVariableName + + # The Document excerpt_separator, from the YAML Front-Matter or site + # default excerpt_separator value + # + # Returns the document excerpt_separator + def excerpt_separator + @excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s + end + + # Whether to generate an excerpt + # + # Returns true if the excerpt separator is configured. + def generate_excerpt? + !excerpt_separator.empty? + end + + def next_doc + pos = collection.docs.index { |post| post.equal?(self) } + collection.docs[pos + 1] if pos && pos < collection.docs.length - 1 + end + + def previous_doc + pos = collection.docs.index { |post| post.equal?(self) } + collection.docs[pos - 1] if pos && pos.positive? + end + + def trigger_hooks(hook_name, *args) + Jekyll::Hooks.trigger collection.label.to_sym, hook_name, self, *args if collection + Jekyll::Hooks.trigger :documents, hook_name, self, *args + end + + def id + @id ||= File.join(File.dirname(url), (data["slug"] || basename_without_ext).to_s) + end + + # Calculate related posts. + # + # Returns an Array of related Posts. + def related_posts + @related_posts ||= Jekyll::RelatedPosts.new(self).build + end + + # Override of method_missing to check in @data for the key. + def method_missing(method, *args, &blck) + if data.key?(method.to_s) + Jekyll::Deprecator.deprecation_message "Document##{method} is now a key in the #data hash." + Jekyll.logger.warn "", "Called by #{caller(1..1)[0]}." + data[method.to_s] + else + super + end + end + + def respond_to_missing?(method, *) + data.key?(method.to_s) || super + end + + # Add superdirectories of the special_dir to categories. + # In the case of es/_posts, 'es' is added as a category. + # In the case of _posts/es, 'es' is NOT added as a category. + # + # Returns nothing. + def categories_from_path(special_dir) + if relative_path.start_with?(special_dir) + superdirs = [] + else + superdirs = relative_path.sub(Document.superdirs_regex(special_dir), "") + superdirs = superdirs.split(File::SEPARATOR) + superdirs.reject! { |c| c.empty? || c == special_dir || c == basename } + end + + merge_data!({ "categories" => superdirs }, :source => "file path") + end + + def populate_categories + categories = Array(data["categories"]) + Utils.pluralized_array_from_hash( + data, "category", "categories" + ) + categories.map!(&:to_s) + categories.flatten! + categories.uniq! + + merge_data!({ "categories" => categories }) + end + + def populate_tags + tags = Utils.pluralized_array_from_hash(data, "tag", "tags") + tags.flatten! + + merge_data!({ "tags" => tags }) + end + + private + + def merge_categories!(other) + if other.key?("categories") && !other["categories"].nil? + other["categories"] = other["categories"].split if other["categories"].is_a?(String) + + if data["categories"].is_a?(Array) + other["categories"] = data["categories"] | other["categories"] + end + end + end + + def merge_date!(source) + if data.key?("date") + data["date"] = Utils.parse_date( + data["date"].to_s, + "Document '#{relative_path}' does not have a valid date in the #{source}." + ) + end + end + + def merge_defaults + defaults = @site.frontmatter_defaults.all(relative_path, type) + merge_data!(defaults, :source => "front matter defaults") unless defaults.empty? + end + + def read_content(**opts) + self.content = File.read(path, **Utils.merged_file_read_opts(site, opts)) + if content =~ YAML_FRONT_MATTER_REGEXP + self.content = Regexp.last_match.post_match + data_file = SafeYAML.load(Regexp.last_match(1)) + merge_data!(data_file, :source => "YAML front matter") if data_file + end + end + + def read_post_data + populate_title + populate_categories + populate_tags + generate_excerpt + end + + def handle_read_error(error) + if error.is_a? Psych::SyntaxError + Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{error.message}" + else + Jekyll.logger.error "Error:", "could not read file #{path}: #{error.message}" + end + + if site.config["strict_front_matter"] || error.is_a?(Jekyll::Errors::FatalException) + raise error + end + end + + def populate_title + if relative_path =~ DATE_FILENAME_MATCHER + date, slug, ext = Regexp.last_match.captures + modify_date(date) + elsif relative_path =~ DATELESS_FILENAME_MATCHER + slug, ext = Regexp.last_match.captures + end + # `slug` will be nil for documents without an extension since the regex patterns + # above tests for an extension as well. + # In such cases, assign `basename_without_ext` as the slug. + slug ||= basename_without_ext + + # slugs shouldn't end with a period + # `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`) + slug.gsub!(%r!\.*\z!, "") + + # Try to ensure the user gets a title. + data["title"] ||= Utils.titleize_slug(slug) + # Only overwrite slug & ext if they aren't specified. + data["slug"] ||= slug + data["ext"] ||= ext + end + + def modify_date(date) + if !data["date"] || data["date"].to_i == site.time.to_i + merge_data!({ "date" => date }, :source => "filename") + end + end + + def generate_excerpt + data["excerpt"] ||= Jekyll::Excerpt.new(self) if generate_excerpt? + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb new file mode 100644 index 0000000..4fe95a5 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/collection_drop.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class CollectionDrop < Drop + extend Forwardable + + mutable false + + delegate_method_as :write?, :output + delegate_methods :label, :docs, :files, :directory, :relative_directory + + private delegate_method_as :metadata, :fallback_data + + def to_s + docs.to_s + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb new file mode 100644 index 0000000..0cff374 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/document_drop.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class DocumentDrop < Drop + extend Forwardable + + NESTED_OBJECT_FIELD_BLACKLIST = %w( + content output excerpt next previous + ).freeze + + mutable false + + delegate_method_as :relative_path, :path + private delegate_method_as :data, :fallback_data + + delegate_methods :id, :output, :content, :to_s, :relative_path, :url, :date + data_delegators "title", "categories", "tags" + + def collection + @obj.collection.label + end + + def excerpt + fallback_data["excerpt"].to_s + end + + def name + fallback_data["name"] || @obj.basename + end + + def <=>(other) + return nil unless other.is_a? DocumentDrop + + cmp = self["date"] <=> other["date"] + cmp = self["path"] <=> other["path"] if cmp.nil? || cmp.zero? + cmp + end + + def previous + @obj.previous_doc.to_liquid + end + + def next + @obj.next_doc.to_liquid + end + + # Generate a Hash for use in generating JSON. + # This is useful if fields need to be cleared before the JSON can generate. + # + # state - the JSON::State object which determines the state of current processing. + # + # Returns a Hash ready for JSON generation. + def hash_for_json(state = nil) + to_h.tap do |hash| + if state && state.depth >= 2 + hash["previous"] = collapse_document(hash["previous"]) if hash["previous"] + hash["next"] = collapse_document(hash["next"]) if hash["next"] + end + end + end + + # Generate a Hash which breaks the recursive chain. + # Certain fields which are normally available are omitted. + # + # Returns a Hash with only non-recursive fields present. + def collapse_document(doc) + doc.keys.each_with_object({}) do |(key, _), result| + result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key) + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb new file mode 100644 index 0000000..b82c7b4 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/drop.rb @@ -0,0 +1,294 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class Drop < Liquid::Drop + include Enumerable + + NON_CONTENT_METHODS = [:fallback_data, :collapse_document].freeze + NON_CONTENT_METHOD_NAMES = NON_CONTENT_METHODS.map(&:to_s).freeze + private_constant :NON_CONTENT_METHOD_NAMES + + # A private stash to avoid repeatedly generating the setter method name string for + # a call to `Drops::Drop#[]=`. + # The keys of the stash below have a very high probability of being called upon during + # the course of various `Jekyll::Renderer#run` calls. + SETTER_KEYS_STASH = { + "content" => "content=", + "layout" => "layout=", + "page" => "page=", + "paginator" => "paginator=", + "highlighter_prefix" => "highlighter_prefix=", + "highlighter_suffix" => "highlighter_suffix=", + }.freeze + private_constant :SETTER_KEYS_STASH + + class << self + # Get or set whether the drop class is mutable. + # Mutability determines whether or not pre-defined fields may be + # overwritten. + # + # is_mutable - Boolean set mutability of the class (default: nil) + # + # Returns the mutability of the class + def mutable(is_mutable = nil) + @is_mutable = is_mutable || false + end + + def mutable? + @is_mutable + end + + # public delegation helper methods that calls onto Drop's instance + # variable `@obj`. + + # Generate private Drop instance_methods for each symbol in the given list. + # + # Returns nothing. + def private_delegate_methods(*symbols) + symbols.each { |symbol| private delegate_method(symbol) } + nil + end + + # Generate public Drop instance_methods for each symbol in the given list. + # + # Returns nothing. + def delegate_methods(*symbols) + symbols.each { |symbol| delegate_method(symbol) } + nil + end + + # Generate public Drop instance_method for given symbol that calls `@obj.`. + # + # Returns delegated method symbol. + def delegate_method(symbol) + define_method(symbol) { @obj.send(symbol) } + end + + # Generate public Drop instance_method named `delegate` that calls `@obj.`. + # + # Returns delegated method symbol. + def delegate_method_as(original, delegate) + define_method(delegate) { @obj.send(original) } + end + + # Generate public Drop instance_methods for each string entry in the given list. + # The generated method(s) access(es) `@obj`'s data hash. + # + # Returns nothing. + def data_delegators(*strings) + strings.each do |key| + data_delegator(key) if key.is_a?(String) + end + nil + end + + # Generate public Drop instance_methods for given string `key`. + # The generated method access(es) `@obj`'s data hash. + # + # Returns method symbol. + def data_delegator(key) + define_method(key.to_sym) { @obj.data[key] } + end + + # Array of stringified instance methods that do not end with the assignment operator. + # + # (.instance_methods always generates a new Array object so it can be mutated) + # + # Returns array of strings. + def getter_method_names + @getter_method_names ||= instance_methods.map!(&:to_s).tap do |list| + list.reject! { |item| item.end_with?("=") } + end + end + end + + # Create a new Drop + # + # obj - the Jekyll Site, Collection, or Document required by the + # drop. + # + # Returns nothing + def initialize(obj) + @obj = obj + end + + # Access a method in the Drop or a field in the underlying hash data. + # If mutable, checks the mutations first. Then checks the methods, + # and finally check the underlying hash (e.g. document front matter) + # if all the previous places didn't match. + # + # key - the string key whose value to fetch + # + # Returns the value for the given key, or nil if none exists + def [](key) + if self.class.mutable? && mutations.key?(key) + mutations[key] + elsif self.class.invokable? key + public_send key + else + fallback_data[key] + end + end + alias_method :invoke_drop, :[] + + # Set a field in the Drop. If mutable, sets in the mutations and + # returns. If not mutable, checks first if it's trying to override a + # Drop method and raises a DropMutationException if so. If not + # mutable and the key is not a method on the Drop, then it sets the + # key to the value in the underlying hash (e.g. document front + # matter) + # + # key - the String key whose value to set + # val - the Object to set the key's value to + # + # Returns the value the key was set to unless the Drop is not mutable + # and the key matches a method in which case it raises a + # DropMutationException. + def []=(key, val) + setter = SETTER_KEYS_STASH[key] || "#{key}=" + if respond_to?(setter) + public_send(setter, val) + elsif respond_to?(key.to_s) + if self.class.mutable? + mutations[key] = val + else + raise Errors::DropMutationException, "Key #{key} cannot be set in the drop." + end + else + fallback_data[key] = val + end + end + + # Generates a list of strings which correspond to content getter + # methods. + # + # Returns an Array of strings which represent method-specific keys. + def content_methods + @content_methods ||= \ + self.class.getter_method_names \ + - Jekyll::Drops::Drop.getter_method_names \ + - NON_CONTENT_METHOD_NAMES + end + + # Check if key exists in Drop + # + # key - the string key whose value to fetch + # + # Returns true if the given key is present + def key?(key) + return false if key.nil? + return true if self.class.mutable? && mutations.key?(key) + + respond_to?(key) || fallback_data.key?(key) + end + + # Generates a list of keys with user content as their values. + # This gathers up the Drop methods and keys of the mutations and + # underlying data hashes and performs a set union to ensure a list + # of unique keys for the Drop. + # + # Returns an Array of unique keys for content for the Drop. + def keys + (content_methods | + mutations.keys | + fallback_data.keys).flatten + end + + # Generate a Hash representation of the Drop by resolving each key's + # value. It includes Drop methods, mutations, and the underlying object's + # data. See the documentation for Drop#keys for more. + # + # Returns a Hash with all the keys and values resolved. + def to_h + keys.each_with_object({}) do |(key, _), result| + result[key] = self[key] + end + end + alias_method :to_hash, :to_h + + # Inspect the drop's keys and values through a JSON representation + # of its keys and values. + # + # Returns a pretty generation of the hash representation of the Drop. + def inspect + JSON.pretty_generate to_h + end + + # Generate a Hash for use in generating JSON. + # This is useful if fields need to be cleared before the JSON can generate. + # + # Returns a Hash ready for JSON generation. + def hash_for_json(*) + to_h + end + + # Generate a JSON representation of the Drop. + # + # state - the JSON::State object which determines the state of current processing. + # + # Returns a JSON representation of the Drop in a String. + def to_json(state = nil) + JSON.generate(hash_for_json(state), state) + end + + # Collects all the keys and passes each to the block in turn. + # + # block - a block which accepts one argument, the key + # + # Returns nothing. + def each_key(&block) + keys.each(&block) + end + + def each + each_key.each do |key| + yield key, self[key] + end + end + + def merge(other, &block) + dup.tap do |me| + if block.nil? + me.merge!(other) + else + me.merge!(other, block) + end + end + end + + def merge!(other) + other.each_key do |key| + if block_given? + self[key] = yield key, self[key], other[key] + else + if Utils.mergable?(self[key]) && Utils.mergable?(other[key]) + self[key] = Utils.deep_merge_hashes(self[key], other[key]) + next + end + + self[key] = other[key] unless other[key].nil? + end + end + end + + # Imitate Hash.fetch method in Drop + # + # Returns value if key is present in Drop, otherwise returns default value + # KeyError is raised if key is not present and no default value given + def fetch(key, default = nil, &block) + return self[key] if key?(key) + raise KeyError, %(key not found: "#{key}") if default.nil? && block.nil? + return yield(key) unless block.nil? + + default unless default.nil? + end + + private + + def mutations + @mutations ||= {} + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb new file mode 100644 index 0000000..82d3cdf --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/excerpt_drop.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class ExcerptDrop < DocumentDrop + def layout + @obj.doc.data["layout"] + end + + def date + @obj.doc.date + end + + def excerpt + nil + end + + def name + @obj.doc.data["name"] || @obj.doc.basename + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb new file mode 100644 index 0000000..63187cc --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/jekyll_drop.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class JekyllDrop < Liquid::Drop + class << self + def global + @global ||= JekyllDrop.new + end + end + + def version + Jekyll::VERSION + end + + def environment + Jekyll.env + end + + def to_h + @to_h ||= { + "version" => version, + "environment" => environment, + } + end + + def to_json(state = nil) + JSON.generate(to_h, state) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb new file mode 100644 index 0000000..cc3c60f --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/site_drop.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class SiteDrop < Drop + extend Forwardable + + mutable false + + delegate_method_as :site_data, :data + delegate_methods :time, :pages, :static_files, :tags, :categories + + private delegate_method_as :config, :fallback_data + + def [](key) + if key != "posts" && @obj.collections.key?(key) + @obj.collections[key].docs + else + super(key) + end + end + + def key?(key) + (key != "posts" && @obj.collections.key?(key)) || super + end + + def posts + @site_posts ||= @obj.posts.docs.sort { |a, b| b <=> a } + end + + def html_pages + @site_html_pages ||= @obj.pages.select do |page| + page.html? || page.url.end_with?("/") + end + end + + def collections + @site_collections ||= @obj.collections.values.sort_by(&:label).map(&:to_liquid) + end + + # `Site#documents` cannot be memoized so that `Site#docs_to_write` can access the + # latest state of the attribute. + # + # Since this method will be called after `Site#pre_render` hook, the `Site#documents` + # array shouldn't thereafter change and can therefore be safely memoized to prevent + # additional computation of `Site#documents`. + def documents + @documents ||= @obj.documents + end + + # `{{ site.related_posts }}` is how posts can get posts related to + # them, either through LSI if it's enabled, or through the most + # recent posts. + # We should remove this in 4.0 and switch to `{{ post.related_posts }}`. + def related_posts + return nil unless @current_document.is_a?(Jekyll::Document) + + @current_document.related_posts + end + attr_writer :current_document + + # return nil for `{{ site.config }}` even if --config was passed via CLI + def config; end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb new file mode 100644 index 0000000..d00973b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/static_file_drop.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class StaticFileDrop < Drop + extend Forwardable + delegate_methods :name, :extname, :modified_time, :basename + delegate_method_as :relative_path, :path + delegate_method_as :type, :collection + + private delegate_method_as :data, :fallback_data + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb new file mode 100644 index 0000000..dd5b281 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/theme_drop.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class ThemeDrop < Drop + delegate_method_as :runtime_dependencies, :dependencies + + def root + @root ||= ENV["JEKYLL_ENV"] == "development" ? @obj.root : "" + end + + def authors + @authors ||= gemspec.authors.join(", ") + end + + def version + @version ||= gemspec.version.to_s + end + + def description + @description ||= gemspec.description || gemspec.summary + end + + def metadata + @metadata ||= gemspec.metadata + end + + private + + def gemspec + @gemspec ||= @obj.send(:gemspec) + end + + def fallback_data + @fallback_data ||= {} + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb new file mode 100644 index 0000000..709ad71 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/unified_payload_drop.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class UnifiedPayloadDrop < Drop + mutable true + + attr_accessor :content, :page, :layout, :paginator, + :highlighter_prefix, :highlighter_suffix + + def jekyll + JekyllDrop.global + end + + def site + @site_drop ||= SiteDrop.new(@obj) + end + + def theme + @theme_drop ||= ThemeDrop.new(@obj.theme) if @obj.theme + end + + private + + def fallback_data + @fallback_data ||= {} + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb new file mode 100644 index 0000000..de58c95 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/drops/url_drop.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true + +module Jekyll + module Drops + class UrlDrop < Drop + extend Forwardable + + mutable false + + delegate_method :output_ext + delegate_method_as :cleaned_relative_path, :path + + def collection + @obj.collection.label + end + + def name + Utils.slugify(@obj.basename_without_ext) + end + + def title + Utils.slugify(@obj.data["slug"], :mode => "pretty", :cased => true) || + Utils.slugify(@obj.basename_without_ext, :mode => "pretty", :cased => true) + end + + def slug + Utils.slugify(@obj.data["slug"]) || Utils.slugify(@obj.basename_without_ext) + end + + def categories + category_set = Set.new + Array(@obj.data["categories"]).each do |category| + category_set << category.to_s.downcase + end + category_set.to_a.join("/") + end + + # Similar to output from #categories, but each category will be downcased and + # all non-alphanumeric characters of the category replaced with a hyphen. + def slugified_categories + Array(@obj.data["categories"]).each_with_object(Set.new) do |category, set| + set << Utils.slugify(category.to_s) + end.to_a.join("/") + end + + # CCYY + def year + @obj.date.strftime("%Y") + end + + # MM: 01..12 + def month + @obj.date.strftime("%m") + end + + # DD: 01..31 + def day + @obj.date.strftime("%d") + end + + # hh: 00..23 + def hour + @obj.date.strftime("%H") + end + + # mm: 00..59 + def minute + @obj.date.strftime("%M") + end + + # ss: 00..59 + def second + @obj.date.strftime("%S") + end + + # D: 1..31 + def i_day + @obj.date.strftime("%-d") + end + + # M: 1..12 + def i_month + @obj.date.strftime("%-m") + end + + # MMM: Jan..Dec + def short_month + @obj.date.strftime("%b") + end + + # MMMM: January..December + def long_month + @obj.date.strftime("%B") + end + + # YY: 00..99 + def short_year + @obj.date.strftime("%y") + end + + # CCYYw, ISO week year + # may differ from CCYY for the first days of January and last days of December + def w_year + @obj.date.strftime("%G") + end + + # WW: 01..53 + # %W and %U do not comply with ISO 8601-1 + def week + @obj.date.strftime("%V") + end + + # d: 1..7 (Monday..Sunday) + def w_day + @obj.date.strftime("%u") + end + + # dd: Mon..Sun + def short_day + @obj.date.strftime("%a") + end + + # ddd: Monday..Sunday + def long_day + @obj.date.strftime("%A") + end + + # DDD: 001..366 + def y_day + @obj.date.strftime("%j") + end + + private + + def fallback_data + @fallback_data ||= {} + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb new file mode 100644 index 0000000..4e70a5d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/entry_filter.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +module Jekyll + class EntryFilter + attr_reader :site + + SPECIAL_LEADING_CHAR_REGEX = %r!\A#{Regexp.union([".", "_", "#", "~"])}!o.freeze + + def initialize(site, base_directory = nil) + @site = site + @base_directory = derive_base_directory( + @site, base_directory.to_s.dup + ) + end + + def base_directory + @base_directory.to_s + end + + def derive_base_directory(site, base_dir) + base_dir[site.source] = "" if base_dir.start_with?(site.source) + base_dir + end + + def relative_to_source(entry) + File.join( + base_directory, entry + ) + end + + def filter(entries) + entries.reject do |e| + # Reject this entry if it is just a "dot" representation. + # e.g.: '.', '..', '_movies/.', 'music/..', etc + next true if e.end_with?(".") + + # Check if the current entry is explicitly included and cache the result + included = included?(e) + + # Reject current entry if it is excluded but not explicitly included as well. + next true if excluded?(e) && !included + + # Reject current entry if it is a symlink. + next true if symlink?(e) + + # Do not reject current entry if it is explicitly included. + next false if included + + # Reject current entry if it is special or a backup file. + special?(e) || backup?(e) + end + end + + def included?(entry) + glob_include?(site.include, entry) || + glob_include?(site.include, File.basename(entry)) + end + + def special?(entry) + SPECIAL_LEADING_CHAR_REGEX.match?(entry) || + SPECIAL_LEADING_CHAR_REGEX.match?(File.basename(entry)) + end + + def backup?(entry) + entry.end_with?("~") + end + + def excluded?(entry) + glob_include?(site.exclude - site.include, relative_to_source(entry)).tap do |excluded| + if excluded + Jekyll.logger.debug( + "EntryFilter:", + "excluded #{relative_to_source(entry)}" + ) + end + end + end + + # -- + # Check if a file is a symlink. + # NOTE: This can be converted to allowing even in safe, + # since we use Pathutil#in_path? now. + # -- + def symlink?(entry) + site.safe && File.symlink?(entry) && symlink_outside_site_source?(entry) + end + + # -- + # Check if given path is outside of current site's configured source directory. + # -- + def symlink_outside_site_source?(entry) + !File.realpath(entry).start_with?(site.in_source_dir) + end + + # Check if an entry matches a specific pattern. + # Returns true if path matches against any glob pattern, else false. + def glob_include?(enumerator, entry) + entry_with_source = PathManager.join(site.source, entry) + entry_is_directory = File.directory?(entry_with_source) + + enumerator.any? do |pattern| + case pattern + when String + pattern_with_source = PathManager.join(site.source, pattern) + + File.fnmatch?(pattern_with_source, entry_with_source) || + entry_with_source.start_with?(pattern_with_source) || + (pattern_with_source == "#{entry_with_source}/" if entry_is_directory) + when Regexp + pattern.match?(entry_with_source) + else + false + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/errors.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/errors.rb new file mode 100644 index 0000000..8d659e8 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/errors.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Jekyll + module Errors + FatalException = Class.new(::RuntimeError) + + InvalidThemeName = Class.new(FatalException) + + DropMutationException = Class.new(FatalException) + InvalidPermalinkError = Class.new(FatalException) + InvalidYAMLFrontMatterError = Class.new(FatalException) + MissingDependencyException = Class.new(FatalException) + + InvalidDateError = Class.new(FatalException) + InvalidPostNameError = Class.new(FatalException) + PostURLError = Class.new(FatalException) + InvalidURLError = Class.new(FatalException) + InvalidConfigurationError = Class.new(FatalException) + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb new file mode 100644 index 0000000..6318520 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/excerpt.rb @@ -0,0 +1,200 @@ +# frozen_string_literal: true + +module Jekyll + class Excerpt + extend Forwardable + + attr_accessor :content, :doc, :ext + attr_writer :output + + def_delegators :@doc, + :site, :name, :ext, :extname, + :collection, :related_posts, :type, + :coffeescript_file?, :yaml_file?, + :url, :next_doc, :previous_doc + + private :coffeescript_file?, :yaml_file? + + # Initialize this Excerpt instance. + # + # doc - The Document. + # + # Returns the new Excerpt. + def initialize(doc) + self.doc = doc + self.content = extract_excerpt(doc.content) + end + + # Fetch YAML front-matter data from related doc, without layout key + # + # Returns Hash of doc data + def data + @data ||= doc.data.dup + @data.delete("layout") + @data.delete("excerpt") + @data + end + + def trigger_hooks(*); end + + # 'Path' of the excerpt. + # + # Returns the path for the doc this excerpt belongs to with #excerpt appended + def path + File.join(doc.path, "#excerpt") + end + + # 'Relative Path' of the excerpt. + # + # Returns the relative_path for the doc this excerpt belongs to with #excerpt appended + def relative_path + @relative_path ||= File.join(doc.relative_path, "#excerpt") + end + + # Check if excerpt includes a string + # + # Returns true if the string passed in + def include?(something) + output&.include?(something) || content.include?(something) + end + + # The UID for this doc (useful in feeds). + # e.g. /2008/11/05/my-awesome-doc + # + # Returns the String UID. + def id + "#{doc.id}#excerpt" + end + + def to_s + output || content + end + + def to_liquid + Jekyll::Drops::ExcerptDrop.new(self) + end + + # Returns the shorthand String identifier of this doc. + def inspect + "<#{self.class} id=#{id}>" + end + + def output + @output ||= Renderer.new(doc.site, self, site.site_payload).run + end + + def place_in_layout? + false + end + + def render_with_liquid? + return false if data["render_with_liquid"] == false + + !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content)) + end + + protected + + # Internal: Extract excerpt from the content + # + # By default excerpt is your first paragraph of a doc: everything before + # the first two new lines: + # + # --- + # title: Example + # --- + # + # First paragraph with [link][1]. + # + # Second paragraph. + # + # [1]: http://example.com/ + # + # This is fairly good option for Markdown and Textile files. But might cause + # problems for HTML docs (which is quite unusual for Jekyll). If default + # excerpt delimiter is not good for you, you might want to set your own via + # configuration option `excerpt_separator`. For example, following is a good + # alternative for HTML docs: + # + # # file: _config.yml + # excerpt_separator: "" + # + # Notice that all markdown-style link references will be appended to the + # excerpt. So the example doc above will have this excerpt source: + # + # First paragraph with [link][1]. + # + # [1]: http://example.com/ + # + # Excerpts are rendered same time as content is rendered. + # + # Returns excerpt String + + LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze + MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze + + def extract_excerpt(doc_content) + head, _, tail = doc_content.to_s.partition(doc.excerpt_separator) + return head if tail.empty? + + head = sanctify_liquid_tags(head) if head.include?("{%") + definitions = extract_markdown_link_reference_definitions(head, tail) + return head if definitions.empty? + + head << "\n\n" << definitions.join("\n") + end + + private + + # append appropriate closing tag(s) (for each Liquid block), to the `head` if the + # partitioning resulted in leaving the closing tag somewhere in the `tail` partition. + def sanctify_liquid_tags(head) + modified = false + tag_names = head.scan(LIQUID_TAG_REGEX) + tag_names.flatten! + tag_names.reverse_each do |tag_name| + next unless liquid_block?(tag_name) + next if endtag_regex_stash(tag_name).match?(head) + + modified = true + head << "\n{% end#{tag_name} %}" + end + + print_build_warning if modified + head + end + + def extract_markdown_link_reference_definitions(head, tail) + [].tap do |definitions| + tail.scan(MKDWN_LINK_REF_REGEX).each do |segments| + definitions << segments.join if head.include?(segments[0]) + end + end + end + + def endtag_regex_stash(tag_name) + @endtag_regex_stash ||= {} + @endtag_regex_stash[tag_name] ||= %r!{%-?\s*end#{tag_name}.*?\s*-?%}!m + end + + def liquid_block?(tag_name) + return false unless tag_name.is_a?(String) + return false unless Liquid::Template.tags[tag_name] + + Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block) + rescue NoMethodError + Jekyll.logger.error "Error:", + "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed." + raise + end + + def print_build_warning + Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!" + Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator " \ + "#{doc.excerpt_separator.inspect}." + Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag." + Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the" + Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory." + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/external.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/external.rb new file mode 100644 index 0000000..b484160 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/external.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Jekyll + module External + class << self + # + # Gems that, if installed, should be loaded. + # Usually contain subcommands. + # + def blessed_gems + %w( + jekyll-compose + jekyll-docs + jekyll-import + ) + end + + # + # Require a gem or file if it's present, otherwise silently fail. + # + # names - a string gem name or array of gem names + # + def require_if_present(names) + Array(names).each do |name| + require name + rescue LoadError + Jekyll.logger.debug "Couldn't load #{name}. Skipping." + yield(name, version_constraint(name)) if block_given? + false + end + end + + # + # The version constraint required to activate a given gem. + # Usually the gem version requirement is "> 0," because any version + # will do. In the case of jekyll-docs, however, we require the exact + # same version as Jekyll. + # + # Returns a String version constraint in a parseable form for + # RubyGems. + def version_constraint(gem_name) + return "= #{Jekyll::VERSION}" if gem_name.to_s.eql?("jekyll-docs") + + "> 0" + end + + # + # Require a gem or gems. If it's not present, show a very nice error + # message that explains everything and is much more helpful than the + # normal LoadError. + # + # names - a string gem name or array of gem names + # + def require_with_graceful_fail(names) + Array(names).each do |name| + Jekyll.logger.debug "Requiring:", name.to_s + require name + rescue LoadError => e + Jekyll.logger.error "Dependency Error:", <<~MSG + Yikes! It looks like you don't have #{name} or one of its dependencies installed. + In order to use Jekyll as currently configured, you'll need to install this gem. + + If you've run Jekyll with `bundle exec`, ensure that you have included the #{name} + gem in your Gemfile as well. + + The full error message from Ruby is: '#{e.message}' + + If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/! + MSG + raise Jekyll::Errors::MissingDependencyException, name + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters.rb new file mode 100644 index 0000000..7a79eec --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters.rb @@ -0,0 +1,540 @@ +# frozen_string_literal: true + +require_all "jekyll/filters" + +module Jekyll + module Filters + include URLFilters + include GroupingFilters + include DateFilters + + # Convert a Markdown string into HTML output. + # + # input - The Markdown String to convert. + # + # Returns the HTML formatted String. + def markdownify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::Markdown + ).convert(input.to_s) + end + + # Convert quotes into smart quotes. + # + # input - The String to convert. + # + # Returns the smart-quotified String. + def smartify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::SmartyPants + ).convert(input.to_s) + end + + # Convert a Sass string into CSS output. + # + # input - The Sass String to convert. + # + # Returns the CSS formatted String. + def sassify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::Sass + ).convert(input) + end + + # Convert a Scss string into CSS output. + # + # input - The Scss String to convert. + # + # Returns the CSS formatted String. + def scssify(input) + @context.registers[:site].find_converter_instance( + Jekyll::Converters::Scss + ).convert(input) + end + + # Slugify a filename or title. + # + # input - The filename or title to slugify. + # mode - how string is slugified + # + # Returns the given filename or title as a lowercase URL String. + # See Utils.slugify for more detail. + def slugify(input, mode = nil) + Utils.slugify(input, :mode => mode) + end + + # XML escape a string for use. Replaces any special characters with + # appropriate HTML entity replacements. + # + # input - The String to escape. + # + # Examples + # + # xml_escape('foo "bar" ') + # # => "foo "bar" <baz>" + # + # Returns the escaped String. + def xml_escape(input) + input.to_s.encode(:xml => :attr).gsub(%r!\A"|"\Z!, "") + end + + # CGI escape a string for use in a URL. Replaces any special characters + # with appropriate %XX replacements. + # + # input - The String to escape. + # + # Examples + # + # cgi_escape('foo,bar;baz?') + # # => "foo%2Cbar%3Bbaz%3F" + # + # Returns the escaped String. + def cgi_escape(input) + CGI.escape(input) + end + + # URI escape a string. + # + # input - The String to escape. + # + # Examples + # + # uri_escape('foo, bar \\baz?') + # # => "foo,%20bar%20%5Cbaz?" + # + # Returns the escaped String. + def uri_escape(input) + Addressable::URI.normalize_component(input) + end + + # Replace any whitespace in the input string with a single space + # + # input - The String on which to operate. + # + # Returns the formatted String + def normalize_whitespace(input) + input.to_s.gsub(%r!\s+!, " ").tap(&:strip!) + end + + # Count the number of words in the input string. + # + # input - The String on which to operate. + # + # Returns the Integer word count. + def number_of_words(input, mode = nil) + cjk_charset = '\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}' + cjk_regex = %r![#{cjk_charset}]!o + word_regex = %r![^#{cjk_charset}\s]+!o + + case mode + when "cjk" + input.scan(cjk_regex).length + input.scan(word_regex).length + when "auto" + cjk_count = input.scan(cjk_regex).length + cjk_count.zero? ? input.split.length : cjk_count + input.scan(word_regex).length + else + input.split.length + end + end + + # Join an array of things into a string by separating with commas and the + # word "and" for the last one. + # + # array - The Array of Strings to join. + # connector - Word used to connect the last 2 items in the array + # + # Examples + # + # array_to_sentence_string(["apples", "oranges", "grapes"]) + # # => "apples, oranges, and grapes" + # + # Returns the formatted String. + def array_to_sentence_string(array, connector = "and") + case array.length + when 0 + "" + when 1 + array[0].to_s + when 2 + "#{array[0]} #{connector} #{array[1]}" + else + "#{array[0...-1].join(", ")}, #{connector} #{array[-1]}" + end + end + + # Convert the input into json string + # + # input - The Array or Hash to be converted + # + # Returns the converted json string + def jsonify(input) + as_liquid(input).to_json + end + + # Filter an array of objects + # + # input - the object array. + # property - the property within each object to filter by. + # value - the desired value. + # Cannot be an instance of Array nor Hash since calling #to_s on them returns + # their `#inspect` string object. + # + # Returns the filtered array of objects + def where(input, property, value) + return input if !property || value.is_a?(Array) || value.is_a?(Hash) + return input unless input.respond_to?(:select) + + input = input.values if input.is_a?(Hash) + input_id = input.hash + + # implement a hash based on method parameters to cache the end-result + # for given parameters. + @where_filter_cache ||= {} + @where_filter_cache[input_id] ||= {} + @where_filter_cache[input_id][property] ||= {} + + # stash or retrieve results to return + @where_filter_cache[input_id][property][value] ||= input.select do |object| + compare_property_vs_target(item_property(object, property), value) + end.to_a + end + + # Filters an array of objects against an expression + # + # input - the object array + # variable - the variable to assign each item to in the expression + # expression - a Liquid comparison expression passed in as a string + # + # Returns the filtered array of objects + def where_exp(input, variable, expression) + return input unless input.respond_to?(:select) + + input = input.values if input.is_a?(Hash) # FIXME + + condition = parse_condition(expression) + @context.stack do + input.select do |object| + @context[variable] = object + condition.evaluate(@context) + end + end || [] + end + + # Search an array of objects and returns the first object that has the queried attribute + # with the given value or returns nil otherwise. + # + # input - the object array. + # property - the property within each object to search by. + # value - the desired value. + # Cannot be an instance of Array nor Hash since calling #to_s on them returns + # their `#inspect` string object. + # + # Returns the found object or nil + # + # rubocop:disable Metrics/CyclomaticComplexity + def find(input, property, value) + return input if !property || value.is_a?(Array) || value.is_a?(Hash) + return input unless input.respond_to?(:find) + + input = input.values if input.is_a?(Hash) + input_id = input.hash + + # implement a hash based on method parameters to cache the end-result for given parameters. + @find_filter_cache ||= {} + @find_filter_cache[input_id] ||= {} + @find_filter_cache[input_id][property] ||= {} + + # stash or retrieve results to return + # Since `enum.find` can return nil or false, we use a placeholder string "<__NO MATCH__>" + # to validate caching. + result = @find_filter_cache[input_id][property][value] ||= input.find do |object| + compare_property_vs_target(item_property(object, property), value) + end || "<__NO MATCH__>" + + return nil if result == "<__NO MATCH__>" + + result + end + # rubocop:enable Metrics/CyclomaticComplexity + + # Searches an array of objects against an expression and returns the first object for which + # the expression evaluates to true, or returns nil otherwise. + # + # input - the object array + # variable - the variable to assign each item to in the expression + # expression - a Liquid comparison expression passed in as a string + # + # Returns the found object or nil + def find_exp(input, variable, expression) + return input unless input.respond_to?(:find) + + input = input.values if input.is_a?(Hash) + + condition = parse_condition(expression) + @context.stack do + input.find do |object| + @context[variable] = object + condition.evaluate(@context) + end + end + end + + # Convert the input into integer + # + # input - the object string + # + # Returns the integer value + def to_integer(input) + return 1 if input == true + return 0 if input == false + + input.to_i + end + + # Sort an array of objects + # + # input - the object array + # property - property within each object to filter by + # nils ('first' | 'last') - nils appear before or after non-nil values + # + # Returns the filtered array of objects + def sort(input, property = nil, nils = "first") + raise ArgumentError, "Cannot sort a null object." if input.nil? + + if property.nil? + input.sort + else + case nils + when "first" + order = - 1 + when "last" + order = + 1 + else + raise ArgumentError, "Invalid nils order: " \ + "'#{nils}' is not a valid nils order. It must be 'first' or 'last'." + end + + sort_input(input, property, order) + end + end + + def pop(array, num = 1) + return array unless array.is_a?(Array) + + num = Liquid::Utils.to_integer(num) + new_ary = array.dup + new_ary.pop(num) + new_ary + end + + def push(array, input) + return array unless array.is_a?(Array) + + new_ary = array.dup + new_ary.push(input) + new_ary + end + + def shift(array, num = 1) + return array unless array.is_a?(Array) + + num = Liquid::Utils.to_integer(num) + new_ary = array.dup + new_ary.shift(num) + new_ary + end + + def unshift(array, input) + return array unless array.is_a?(Array) + + new_ary = array.dup + new_ary.unshift(input) + new_ary + end + + def sample(input, num = 1) + return input unless input.respond_to?(:sample) + + num = Liquid::Utils.to_integer(num) rescue 1 + if num == 1 + input.sample + else + input.sample(num) + end + end + + # Convert an object into its String representation for debugging + # + # input - The Object to be converted + # + # Returns a String representation of the object. + def inspect(input) + xml_escape(input.inspect) + end + + private + + # Sort the input Enumerable by the given property. + # If the property doesn't exist, return the sort order respective of + # which item doesn't have the property. + # We also utilize the Schwartzian transform to make this more efficient. + def sort_input(input, property, order) + input.map { |item| [item_property(item, property), item] } + .sort! do |a_info, b_info| + a_property = a_info.first + b_property = b_info.first + + if !a_property.nil? && b_property.nil? + - order + elsif a_property.nil? && !b_property.nil? + + order + else + a_property <=> b_property || a_property.to_s <=> b_property.to_s + end + end + .map!(&:last) + end + + # `where` filter helper + # + def compare_property_vs_target(property, target) + case target + when NilClass + return true if property.nil? + when Liquid::Expression::MethodLiteral # `empty` or `blank` + target = target.to_s + return true if property == target || Array(property).join == target + else + target = target.to_s + if property.is_a? String + return true if property == target + else + Array(property).each do |prop| + return true if prop.to_s == target + end + end + end + + false + end + + def item_property(item, property) + @item_property_cache ||= @context.registers[:site].filter_cache[:item_property] ||= {} + @item_property_cache[property] ||= {} + @item_property_cache[property][item] ||= begin + property = property.to_s + property = if item.respond_to?(:to_liquid) + read_liquid_attribute(item.to_liquid, property) + elsif item.respond_to?(:data) + item.data[property] + else + item[property] + end + + parse_sort_input(property) + end + end + + def read_liquid_attribute(liquid_data, property) + return liquid_data[property] unless property.include?(".") + + property.split(".").reduce(liquid_data) do |data, key| + data.respond_to?(:[]) && data[key] + end + rescue TypeError => e + msg = if liquid_data.is_a?(Array) + "Error accessing object (#{liquid_data.to_s[0...20]}) with given key. Expected an " \ + "integer but got #{property.inspect} instead." + else + e.message + end + raise e, msg + end + + FLOAT_LIKE = %r!\A\s*-?(?:\d+\.?\d*|\.\d+)\s*\Z!.freeze + INTEGER_LIKE = %r!\A\s*-?\d+\s*\Z!.freeze + private_constant :FLOAT_LIKE, :INTEGER_LIKE + + # return numeric values as numbers for proper sorting + def parse_sort_input(property) + stringified = property.to_s + return property.to_i if INTEGER_LIKE.match?(stringified) + return property.to_f if FLOAT_LIKE.match?(stringified) + + property + end + + def as_liquid(item) + case item + when Hash + item.each_with_object({}) { |(k, v), result| result[as_liquid(k)] = as_liquid(v) } + when Array + item.map { |i| as_liquid(i) } + else + if item.respond_to?(:to_liquid) + liquidated = item.to_liquid + # prevent infinite recursion for simple types (which return `self`) + if liquidated == item + item + else + as_liquid(liquidated) + end + else + item + end + end + end + + # ----------- The following set of code was *adapted* from Liquid::If + # ----------- ref: https://github.com/Shopify/liquid/blob/ffb0ace30315bbcf3548a0383fab531452060ae8/lib/liquid/tags/if.rb#L84-L107 + + # Parse a string to a Liquid Condition + def parse_condition(exp) + parser = Liquid::Parser.new(exp) + condition = parse_binary_comparison(parser) + + parser.consume(:end_of_string) + condition + end + + # Generate a Liquid::Condition object from a Liquid::Parser object additionally processing + # the parsed expression based on whether the expression consists of binary operations with + # Liquid operators `and` or `or` + # + # - parser: an instance of Liquid::Parser + # + # Returns an instance of Liquid::Condition + def parse_binary_comparison(parser) + condition = parse_comparison(parser) + first_condition = condition + while (binary_operator = parser.id?("and") || parser.id?("or")) + child_condition = parse_comparison(parser) + condition.send(binary_operator, child_condition) + condition = child_condition + end + first_condition + end + + # Generates a Liquid::Condition object from a Liquid::Parser object based on whether the parsed + # expression involves a "comparison" operator (e.g. <, ==, >, !=, etc) + # + # - parser: an instance of Liquid::Parser + # + # Returns an instance of Liquid::Condition + def parse_comparison(parser) + left_operand = Liquid::Expression.parse(parser.expression) + operator = parser.consume?(:comparison) + + # No comparison-operator detected. Initialize a Liquid::Condition using only left operand + return Liquid::Condition.new(left_operand) unless operator + + # Parse what remained after extracting the left operand and the `:comparison` operator + # and initialize a Liquid::Condition object using the operands and the comparison-operator + Liquid::Condition.new(left_operand, operator, Liquid::Expression.parse(parser.expression)) + end + end +end + +Liquid::Template.register_filter( + Jekyll::Filters +) diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb new file mode 100644 index 0000000..966b49b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/date_filters.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +module Jekyll + module Filters + module DateFilters + # Format a date in short format e.g. "27 Jan 2011". + # Ordinal format is also supported, in both the UK + # (e.g. "27th Jan 2011") and US ("e.g. Jan 27th, 2011") formats. + # UK format is the default. + # + # date - the Time to format. + # type - if "ordinal" the returned String will be in ordinal format + # style - if "US" the returned String will be in US format. + # Otherwise it will be in UK format. + # + # Returns the formatting String. + def date_to_string(date, type = nil, style = nil) + stringify_date(date, "%b", type, style) + end + + # Format a date in long format e.g. "27 January 2011". + # Ordinal format is also supported, in both the UK + # (e.g. "27th January 2011") and US ("e.g. January 27th, 2011") formats. + # UK format is the default. + # + # date - the Time to format. + # type - if "ordinal" the returned String will be in ordinal format + # style - if "US" the returned String will be in US format. + # Otherwise it will be in UK format. + # + # Returns the formatted String. + def date_to_long_string(date, type = nil, style = nil) + stringify_date(date, "%B", type, style) + end + + # Format a date for use in XML. + # + # date - The Time to format. + # + # Examples + # + # date_to_xmlschema(Time.now) + # # => "2011-04-24T20:34:46+08:00" + # + # Returns the formatted String. + def date_to_xmlschema(date) + return date if date.to_s.empty? + + time(date).xmlschema + end + + # Format a date according to RFC-822 + # + # date - The Time to format. + # + # Examples + # + # date_to_rfc822(Time.now) + # # => "Sun, 24 Apr 2011 12:34:46 +0000" + # + # Returns the formatted String. + def date_to_rfc822(date) + return date if date.to_s.empty? + + time(date).rfc822 + end + + private + + # month_type: Notations that evaluate to 'Month' via `Time#strftime` ("%b", "%B") + # type: nil (default) or "ordinal" + # style: nil (default) or "US" + # + # Returns a stringified date or the empty input. + def stringify_date(date, month_type, type = nil, style = nil) + return date if date.to_s.empty? + + time = time(date) + if type == "ordinal" + day = time.day + ordinal_day = "#{day}#{ordinal(day)}" + return time.strftime("#{month_type} #{ordinal_day}, %Y") if style == "US" + + return time.strftime("#{ordinal_day} #{month_type} %Y") + end + time.strftime("%d #{month_type} %Y") + end + + def ordinal(number) + return "th" if (11..13).cover?(number) + + case number % 10 + when 1 then "st" + when 2 then "nd" + when 3 then "rd" + else "th" + end + end + + def time(input) + date = Liquid::Utils.to_date(input) + unless date.respond_to?(:to_time) + raise Errors::InvalidDateError, + "Invalid Date: '#{input.inspect}' is not a valid datetime." + end + date.to_time.dup.localtime + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb new file mode 100644 index 0000000..c9cdc65 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/grouping_filters.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Jekyll + module Filters + module GroupingFilters + # Group an array of items by a property + # + # input - the inputted Enumerable + # property - the property + # + # Returns an array of Hashes, each looking something like this: + # {"name" => "larry" + # "items" => [...] } # all the items where `property` == "larry" + def group_by(input, property) + if groupable?(input) + groups = input.group_by { |item| item_property(item, property).to_s } + grouped_array(groups) + else + input + end + end + + # Group an array of items by an expression + # + # input - the object array + # variable - the variable to assign each item to in the expression + # expression -a Liquid comparison expression passed in as a string + # + # Returns the filtered array of objects + def group_by_exp(input, variable, expression) + return input unless groupable?(input) + + parsed_expr = parse_expression(expression) + @context.stack do + groups = input.group_by do |item| + @context[variable] = item + parsed_expr.render(@context) + end + grouped_array(groups) + end + end + + private + + def parse_expression(str) + Liquid::Variable.new(str, Liquid::ParseContext.new) + end + + def groupable?(element) + element.respond_to?(:group_by) + end + + def grouped_array(groups) + groups.each_with_object([]) do |item, array| + array << { + "name" => item.first, + "items" => item.last, + "size" => item.last.size, + } + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb new file mode 100644 index 0000000..aa28c5a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/filters/url_filters.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +module Jekyll + module Filters + module URLFilters + # Produces an absolute URL based on site.url and site.baseurl. + # + # input - the URL to make absolute. + # + # Returns the absolute URL as a String. + def absolute_url(input) + return if input.nil? + + cache = if input.is_a?(String) + (@context.registers[:site].filter_cache[:absolute_url] ||= {}) + else + (@context.registers[:cached_absolute_url] ||= {}) + end + cache[input] ||= compute_absolute_url(input) + + # Duplicate cached string so that the cached value is never mutated by + # a subsequent filter. + cache[input].dup + end + + # Produces a URL relative to the domain root based on site.baseurl + # unless it is already an absolute url with an authority (host). + # + # input - the URL to make relative to the domain root + # + # Returns a URL relative to the domain root as a String. + def relative_url(input) + return if input.nil? + + cache = if input.is_a?(String) + (@context.registers[:site].filter_cache[:relative_url] ||= {}) + else + (@context.registers[:cached_relative_url] ||= {}) + end + cache[input] ||= compute_relative_url(input) + + # Duplicate cached string so that the cached value is never mutated by + # a subsequent filter. + cache[input].dup + end + + # Strips trailing `/index.html` from URLs to create pretty permalinks + # + # input - the URL with a possible `/index.html` + # + # Returns a URL with the trailing `/index.html` removed + def strip_index(input) + return if input.nil? || input.to_s.empty? + + input.sub(%r!/index\.html?$!, "/") + end + + private + + def compute_absolute_url(input) + input = input.url if input.respond_to?(:url) + return input if Addressable::URI.parse(input.to_s).absolute? + + site = @context.registers[:site] + site_url = site.config["url"] + return relative_url(input) if site_url.nil? || site_url == "" + + Addressable::URI.parse( + site_url.to_s + relative_url(input) + ).normalize.to_s + end + + def compute_relative_url(input) + input = input.url if input.respond_to?(:url) + return input if Addressable::URI.parse(input.to_s).absolute? + + parts = [sanitized_baseurl, input] + Addressable::URI.parse( + parts.map! { |part| ensure_leading_slash(part.to_s) }.join + ).normalize.to_s + end + + def sanitized_baseurl + site = @context.registers[:site] + baseurl = site.config["baseurl"] + return "" if baseurl.nil? + + baseurl.to_s.chomp("/") + end + + def ensure_leading_slash(input) + return input if input.nil? || input.empty? || input.start_with?("/") + + "/#{input}" + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb new file mode 100644 index 0000000..5ad896b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/frontmatter_defaults.rb @@ -0,0 +1,238 @@ +# frozen_string_literal: true + +module Jekyll + # This class handles custom defaults for YAML frontmatter settings. + # These are set in _config.yml and apply both to internal use (e.g. layout) + # and the data available to liquid. + # + # It is exposed via the frontmatter_defaults method on the site class. + class FrontmatterDefaults + # Initializes a new instance. + def initialize(site) + @site = site + end + + def reset + @glob_cache = {} if @glob_cache + end + + def update_deprecated_types(set) + return set unless set.key?("scope") && set["scope"].key?("type") + + set["scope"]["type"] = + case set["scope"]["type"] + when "page" + Deprecator.defaults_deprecate_type("page", "pages") + "pages" + when "post" + Deprecator.defaults_deprecate_type("post", "posts") + "posts" + when "draft" + Deprecator.defaults_deprecate_type("draft", "drafts") + "drafts" + else + set["scope"]["type"] + end + + set + end + + def ensure_time!(set) + return set unless set.key?("values") && set["values"].key?("date") + return set if set["values"]["date"].is_a?(Time) + + set["values"]["date"] = Utils.parse_date( + set["values"]["date"], + "An invalid date format was found in a front-matter default set: #{set}" + ) + set + end + + # Finds a default value for a given setting, filtered by path and type + # + # path - the path (relative to the source) of the page, + # post or :draft the default is used in + # type - a symbol indicating whether a :page, + # a :post or a :draft calls this method + # + # Returns the default value or nil if none was found + def find(path, type, setting) + value = nil + old_scope = nil + + matching_sets(path, type).each do |set| + if set["values"].key?(setting) && has_precedence?(old_scope, set["scope"]) + value = set["values"][setting] + old_scope = set["scope"] + end + end + value + end + + # Collects a hash with all default values for a page or post + # + # path - the relative path of the page or post + # type - a symbol indicating the type (:post, :page or :draft) + # + # Returns a hash with all default values (an empty hash if there are none) + def all(path, type) + defaults = {} + old_scope = nil + matching_sets(path, type).each do |set| + if has_precedence?(old_scope, set["scope"]) + defaults = Utils.deep_merge_hashes(defaults, set["values"]) + old_scope = set["scope"] + else + defaults = Utils.deep_merge_hashes(set["values"], defaults) + end + end + defaults + end + + private + + # Checks if a given default setting scope matches the given path and type + # + # scope - the hash indicating the scope, as defined in _config.yml + # path - the path to check for + # type - the type (:post, :page or :draft) to check for + # + # Returns true if the scope applies to the given type and path + def applies?(scope, path, type) + applies_type?(scope, type) && applies_path?(scope, path) + end + + def applies_path?(scope, path) + rel_scope_path = scope["path"] + return true if !rel_scope_path.is_a?(String) || rel_scope_path.empty? + + sanitized_path = sanitize_path(path) + + if rel_scope_path.include?("*") + glob_scope(sanitized_path, rel_scope_path) + else + path_is_subpath?(sanitized_path, strip_collections_dir(rel_scope_path)) + end + end + + def glob_scope(sanitized_path, rel_scope_path) + site_source = Pathname.new(@site.source) + abs_scope_path = site_source.join(rel_scope_path).to_s + + glob_cache(abs_scope_path).each do |scope_path| + scope_path = Pathname.new(scope_path).relative_path_from(site_source).to_s + scope_path = strip_collections_dir(scope_path) + Jekyll.logger.debug "Globbed Scope Path:", scope_path + return true if path_is_subpath?(sanitized_path, scope_path) + end + false + end + + def glob_cache(path) + @glob_cache ||= {} + @glob_cache[path] ||= Dir.glob(path) + end + + def path_is_subpath?(path, parent_path) + path.start_with?(parent_path) + end + + def strip_collections_dir(path) + collections_dir = @site.config["collections_dir"] + slashed_coll_dir = collections_dir.empty? ? "/" : "#{collections_dir}/" + return path if collections_dir.empty? || !path.to_s.start_with?(slashed_coll_dir) + + path.sub(slashed_coll_dir, "") + end + + # Determines whether the scope applies to type. + # The scope applies to the type if: + # 1. no 'type' is specified + # 2. the 'type' in the scope is the same as the type asked about + # + # scope - the Hash defaults set being asked about application + # type - the type of the document being processed / asked about + # its defaults. + # + # Returns true if either of the above conditions are satisfied, + # otherwise returns false + def applies_type?(scope, type) + !scope.key?("type") || type&.to_sym.eql?(scope["type"].to_sym) + end + + # Checks if a given set of default values is valid + # + # set - the default value hash, as defined in _config.yml + # + # Returns true if the set is valid and can be used in this class + def valid?(set) + set.is_a?(Hash) && set["values"].is_a?(Hash) + end + + # Determines if a new scope has precedence over an old one + # + # old_scope - the old scope hash, or nil if there's none + # new_scope - the new scope hash + # + # Returns true if the new scope has precedence over the older + # rubocop: disable Naming/PredicateName + def has_precedence?(old_scope, new_scope) + return true if old_scope.nil? + + new_path = sanitize_path(new_scope["path"]) + old_path = sanitize_path(old_scope["path"]) + + if new_path.length != old_path.length + new_path.length >= old_path.length + elsif new_scope.key?("type") + true + else + !old_scope.key? "type" + end + end + # rubocop: enable Naming/PredicateName + + # Collects a list of sets that match the given path and type + # + # Returns an array of hashes + def matching_sets(path, type) + @matched_set_cache ||= {} + @matched_set_cache[path] ||= {} + @matched_set_cache[path][type] ||= valid_sets.select do |set| + !set.key?("scope") || applies?(set["scope"], path, type) + end + end + + # Returns a list of valid sets + # + # This is not cached to allow plugins to modify the configuration + # and have their changes take effect + # + # Returns an array of hashes + def valid_sets + sets = @site.config["defaults"] + return [] unless sets.is_a?(Array) + + sets.map do |set| + if valid?(set) + ensure_time!(update_deprecated_types(set)) + else + Jekyll.logger.warn "Defaults:", "An invalid front-matter default set was found:" + Jekyll.logger.warn set.to_s + nil + end + end.tap(&:compact!) + end + + # Sanitizes the given path by removing a leading slash + def sanitize_path(path) + if path.nil? || path.empty? + "" + elsif path.start_with?("/") + path.gsub(%r!\A/|(?<=[^/])\z!, "") + else + path + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/generator.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/generator.rb new file mode 100644 index 0000000..649715f --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/generator.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Jekyll + Generator = Class.new(Plugin) +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/hooks.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/hooks.rb new file mode 100644 index 0000000..482d802 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/hooks.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module Jekyll + module Hooks + DEFAULT_PRIORITY = 20 + + # compatibility layer for octopress-hooks users + PRIORITY_MAP = { + :low => 10, + :normal => 20, + :high => 30, + }.freeze + + # initial empty hooks + @registry = { + :site => { + :after_init => [], + :after_reset => [], + :post_read => [], + :pre_render => [], + :post_render => [], + :post_write => [], + }, + :pages => { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + }, + :posts => { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + }, + :documents => { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + }, + :clean => { + :on_obsolete => [], + }, + } + + # map of all hooks and their priorities + @hook_priority = {} + + NotAvailable = Class.new(RuntimeError) + Uncallable = Class.new(RuntimeError) + + # register hook(s) to be called later, public API + def self.register(owners, event, priority: DEFAULT_PRIORITY, &block) + Array(owners).each do |owner| + register_one(owner, event, priority_value(priority), &block) + end + end + + # Ensure the priority is a Fixnum + def self.priority_value(priority) + return priority if priority.is_a?(Integer) + + PRIORITY_MAP[priority] || DEFAULT_PRIORITY + end + + # register a single hook to be called later, internal API + def self.register_one(owner, event, priority, &block) + @registry[owner] ||= { + :post_init => [], + :pre_render => [], + :post_convert => [], + :post_render => [], + :post_write => [], + } + + unless @registry[owner][event] + raise NotAvailable, "Invalid hook. #{owner} supports only the following hooks " \ + "#{@registry[owner].keys.inspect}" + end + + raise Uncallable, "Hooks must respond to :call" unless block.respond_to? :call + + insert_hook owner, event, priority, &block + end + + def self.insert_hook(owner, event, priority, &block) + @hook_priority[block] = [-priority, @hook_priority.size] + @registry[owner][event] << block + end + + # interface for Jekyll core components to trigger hooks + def self.trigger(owner, event, *args) + # proceed only if there are hooks to call + hooks = @registry.dig(owner, event) + return if hooks.nil? || hooks.empty? + + # sort and call hooks according to priority and load order + hooks.sort_by { |h| @hook_priority[h] }.each do |hook| + hook.call(*args) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb new file mode 100644 index 0000000..179ddb0 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/inclusion.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Jekyll + class Inclusion + attr_reader :site, :name, :path + private :site + + def initialize(site, base, name) + @site = site + @name = name + @path = PathManager.join(base, name) + end + + def render(context) + @template ||= site.liquid_renderer.file(path).parse(content) + @template.render!(context) + rescue Liquid::Error => e + e.template_name = path + e.markup_context = "included " if e.markup_context.nil? + raise e + end + + def content + @content ||= File.read(path, **site.file_read_opts) + end + + def inspect + "#{self.class} #{path.inspect}" + end + alias_method :to_s, :inspect + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/layout.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/layout.rb new file mode 100644 index 0000000..af3ea71 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/layout.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Jekyll + class Layout + include Convertible + + attr_accessor :content, # content of layout + :data, # the Hash that holds the metadata for this layout + :ext # extension of layout + + attr_reader :name, # name of layout + :path, # path to layout + :site, # the Site object + :relative_path # path to layout relative to its base + + # Initialize a new Layout. + # + # site - The Site. + # base - The String path to the source. + # name - The String filename of the post file. + def initialize(site, base, name) + @site = site + @base = base + @name = name + + if site.theme && site.theme.layouts_path.eql?(base) + @base_dir = site.theme.root + @path = site.in_theme_dir(base, name) + else + @base_dir = site.source + @path = site.in_source_dir(base, name) + end + @relative_path = @path.sub(@base_dir, "") + + self.data = {} + + process(name) + read_yaml(base, name) + end + + # Extract information from the layout filename. + # + # name - The String filename of the layout file. + # + # Returns nothing. + def process(name) + self.ext = File.extname(name) + end + + # Returns the object as a debug String. + def inspect + "#<#{self.class} @path=#{@path.inspect}>" + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb new file mode 100644 index 0000000..87e06ef --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_extensions.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Jekyll + module LiquidExtensions + # Lookup a Liquid variable in the given context. + # + # context - the Liquid context in question. + # variable - the variable name, as a string. + # + # Returns the value of the variable in the context + # or the variable name if not found. + def lookup_variable(context, variable) + lookup = context + + variable.split(".").each do |value| + lookup = lookup[value] + end + + lookup || variable + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb new file mode 100644 index 0000000..7655e04 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require_relative "liquid_renderer/file" +require_relative "liquid_renderer/table" + +module Jekyll + class LiquidRenderer + def initialize(site) + @site = site + Liquid::Template.error_mode = @site.config["liquid"]["error_mode"].to_sym + reset + end + + def reset + @stats = {} + @cache = {} + end + + def file(filename) + filename = normalize_path(filename) + LiquidRenderer::File.new(self, filename).tap do + @stats[filename] ||= new_profile_hash + end + end + + def increment_bytes(filename, bytes) + @stats[filename][:bytes] += bytes + end + + def increment_time(filename, time) + @stats[filename][:time] += time + end + + def increment_count(filename) + @stats[filename][:count] += 1 + end + + def stats_table(num_of_rows = 50) + LiquidRenderer::Table.new(@stats).to_s(num_of_rows) + end + + def self.format_error(error, path) + "#{error.message} in #{path}" + end + + # A persistent cache to store and retrieve parsed templates based on the filename + # via `LiquidRenderer::File#parse` + # + # It is emptied when `self.reset` is called. + def cache + @cache ||= {} + end + + private + + def normalize_path(filename) + @normalize_path ||= {} + @normalize_path[filename] ||= begin + theme_dir = @site.theme&.root + case filename + when %r!\A(#{Regexp.escape(@site.source)}/)(?.*)!io + Regexp.last_match(:rest) + when %r!(/gems/.*)*/gems/(?[^/]+)(?.*)!, + %r!(?[^/]+/lib)(?.*)! + "#{Regexp.last_match(:dirname)}#{Regexp.last_match(:rest)}" + when theme_dir && %r!\A#{Regexp.escape(theme_dir)}/(?.*)!io + PathManager.join(@site.theme.basename, Regexp.last_match(:rest)) + when %r!\A/(.*)! + Regexp.last_match(1) + else + filename + end + end + end + + def new_profile_hash + Hash.new { |hash, key| hash[key] = 0 } + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb new file mode 100644 index 0000000..146c416 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/file.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module Jekyll + class LiquidRenderer + class File + def initialize(renderer, filename) + @renderer = renderer + @filename = filename + end + + def parse(content) + measure_time do + @renderer.cache[@filename] ||= Liquid::Template.parse(content, :line_numbers => true) + end + @template = @renderer.cache[@filename] + + self + end + + def render(*args) + reset_template_assigns + + measure_time do + measure_bytes do + measure_counts do + @template.render(*args) + end + end + end + end + + # This method simply 'rethrows any error' before attempting to render the template. + def render!(*args) + reset_template_assigns + + measure_time do + measure_bytes do + measure_counts do + @template.render!(*args) + end + end + end + end + + def warnings + @template.warnings + end + + private + + # clear assigns to `Liquid::Template` instance prior to rendering since + # `Liquid::Template` instances are cached in Jekyll 4. + def reset_template_assigns + @template.instance_assigns.clear + end + + def measure_counts + @renderer.increment_count(@filename) + yield + end + + def measure_bytes + yield.tap do |str| + @renderer.increment_bytes(@filename, str.bytesize) + end + end + + def measure_time + before = Time.now + yield + ensure + after = Time.now + @renderer.increment_time(@filename, after - before) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb new file mode 100644 index 0000000..2d06a26 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/liquid_renderer/table.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Jekyll + class LiquidRenderer + class Table + GAUGES = [:count, :bytes, :time].freeze + + def initialize(stats) + @stats = stats + end + + def to_s(num_of_rows = 50) + Jekyll::Profiler.tabulate(data_for_table(num_of_rows)) + end + + private + + def data_for_table(num_of_rows) + sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] } + sorted = sorted.slice(0, num_of_rows) + + table = [header_labels] + sorted.each do |filename, file_stats| + row = [] + row << filename + row << file_stats[:count].to_s + row << format_bytes(file_stats[:bytes]) + row << format("%.3f", file_stats[:time]) + table << row + end + + table + end + + def header_labels + GAUGES.map { |gauge| gauge.to_s.capitalize }.unshift("Filename") + end + + def format_bytes(bytes) + bytes /= 1024.0 + format("%.2fK", bytes) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb new file mode 100644 index 0000000..6ddfa4a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/log_adapter.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true + +module Jekyll + class LogAdapter + attr_reader :writer, :messages, :level + + LOG_LEVELS = { + :debug => ::Logger::DEBUG, + :info => ::Logger::INFO, + :warn => ::Logger::WARN, + :error => ::Logger::ERROR, + }.freeze + + # Public: Create a new instance of a log writer + # + # writer - Logger compatible instance + # log_level - (optional, symbol) the log level + # + # Returns nothing + def initialize(writer, level = :info) + @messages = [] + @writer = writer + self.log_level = level + end + + # Public: Set the log level on the writer + # + # level - (symbol) the log level + # + # Returns nothing + def log_level=(level) + writer.level = level if level.is_a?(Integer) && level.between?(0, 3) + writer.level = LOG_LEVELS[level] || + raise(ArgumentError, "unknown log level") + @level = level + end + + def adjust_verbosity(options = {}) + # Quiet always wins. + if options[:quiet] + self.log_level = :error + elsif options[:verbose] + self.log_level = :debug + end + debug "Logging at level:", LOG_LEVELS.key(writer.level).to_s + debug "Jekyll Version:", Jekyll::VERSION + end + + # Public: Print a debug message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def debug(topic, message = nil, &block) + write(:debug, topic, message, &block) + end + + # Public: Print a message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def info(topic, message = nil, &block) + write(:info, topic, message, &block) + end + + # Public: Print a message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def warn(topic, message = nil, &block) + write(:warn, topic, message, &block) + end + + # Public: Print an error message + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns nothing + def error(topic, message = nil, &block) + write(:error, topic, message, &block) + end + + # Public: Print an error message and immediately abort the process + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail (can be omitted) + # + # Returns nothing + def abort_with(topic, message = nil, &block) + error(topic, message, &block) + abort + end + + # Internal: Build a topic method + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # message - the message detail + # + # Returns the formatted message + def message(topic, message = nil) + raise ArgumentError, "block or message, not both" if block_given? && message + + message = yield if block_given? + message = message.to_s.gsub(%r!\s+!, " ") + topic = formatted_topic(topic, block_given?) + out = topic + message + messages << out + out + end + + # Internal: Format the topic + # + # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc. + # colon - + # + # Returns the formatted topic statement + def formatted_topic(topic, colon = false) + "#{topic}#{colon ? ": " : " "}".rjust(20) + end + + # Internal: Check if the message should be written given the log level. + # + # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error + # + # Returns whether the message should be written. + def write_message?(level_of_message) + LOG_LEVELS.fetch(level) <= LOG_LEVELS.fetch(level_of_message) + end + + # Internal: Log a message. + # + # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error + # topic - the String topic or full message + # message - the String message (optional) + # block - a block containing the message (optional) + # + # Returns false if the message was not written, otherwise returns the value of calling + # the appropriate writer method, e.g. writer.info. + def write(level_of_message, topic, message = nil, &block) + return false unless write_message?(level_of_message) + + writer.public_send(level_of_message, message(topic, message, &block)) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/mime.types b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/mime.types new file mode 100644 index 0000000..10f713c --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/mime.types @@ -0,0 +1,940 @@ +# Woah there. Do not edit this file directly. +# This file is generated automatically by script/vendor-mimes. + +application/andrew-inset ez +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +application/atomdeleted+xml atomdeleted +application/atomsvc+xml atomsvc +application/atsc-dwd+xml dwd +application/atsc-held+xml held +application/atsc-rsat+xml rsat +application/bdoc bdoc +application/calendar+xml xcs +application/ccxml+xml ccxml +application/cdfx+xml cdfx +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +application/cpl+xml cpl +application/cu-seeme cu +application/dash+xml mpd +application/dash-patch+xml mpp +application/davmount+xml davmount +application/docbook+xml dbk +application/dssc+der dssc +application/dssc+xml xdssc +application/ecmascript ecma es +application/emma+xml emma +application/emotionml+xml emotionml +application/epub+zip epub +application/exi exi +application/express exp +application/fdt+xml fdt +application/font-tdpfr pfr +application/geo+json geojson +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +application/gzip gz +application/hjson hjson +application/hyperstudio stk +application/inkml+xml ink inkml +application/ipfix ipfix +application/its+xml its +application/java-archive ear jar war +application/java-serialized-object ser +application/java-vm class +application/javascript js mjs +application/json json map +application/json5 json5 +application/jsonml+json jsonml +application/ld+json jsonld +application/lgr+xml lgr +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/mads+xml mads +application/manifest+json webmanifest +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma mb nb +application/mathml+xml mathml +application/mbox mbox +application/media-policy-dataset+xml mpf +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +application/mmt-aei+xml maei +application/mmt-usd+xml musd +application/mods+xml mods +application/mp21 m21 mp21 +application/mp4 m4p mp4s +application/msword doc dot +application/mxf mxf +application/n-quads nq +application/n-triples nt +application/node cjs +application/octet-stream bin bpk buffer deb deploy dist distz dll dmg dms dump elc exe img iso lrf mar msi msm msp pkg so +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onepkg onetmp onetoc onetoc2 +application/oxps oxps +application/p2p-overlay+xml relo +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-keys asc +application/pgp-signature sig +application/pics-rules prf +application/pkcs10 p10 +application/pkcs7-mime p7c p7m +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/postscript ai eps ps +application/provenance+xml provx +application/prs.cww cww +application/pskc+xml pskcxml +application/raml+yaml raml +application/rdf+xml owl rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +application/rls-services+xml rs +application/route-apd+xml rapd +application/route-s-tsid+xml sls +application/route-usd+xml rusd +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/senml+xml senmlx +application/sensml+xml sensmlx +application/set-payment-initiation setpay +application/set-registration-initiation setreg +application/shf+xml shf +application/sieve sieve siv +application/smil+xml smi smil +application/sparql-query rq +application/sparql-results+xml srx +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +application/swid+xml swidtag +application/tei+xml tei teicorpus +application/thraud+xml tfi +application/timestamped-data tsd +application/toml toml +application/trig trig +application/ttml+xml ttml +application/ubjson ubj +application/urc-ressheet+xml rsheet +application/urc-targetdesc+xml td +application/vnd.1000minds.decision-model+xml 1km +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp acutc atc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.age age +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.keynote key +application/vnd.apple.mpegurl m3u8 +application/vnd.apple.numbers numbers +application/vnd.apple.pages pages +application/vnd.apple.pkpass pkpass +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +application/vnd.balsamiq.bmml+xml bmml +application/vnd.blueice.multipass mpm +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.citationstyles.style+xml csl +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4d c4f c4g c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.cups-ppd ppd +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dbf dbf +application/vnd.dece.data uvd uvf uvvd uvvf +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvvx uvx +application/vnd.dece.zip uvvz uvz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +application/vnd.dvb.service svc +application/vnd.dynageo geo +application/vnd.ecowin.chart mag +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.eszigno3+xml es3 et3 +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed dataless seed +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.framemaker book fm frame maker +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +application/vnd.gmx gmx +application/vnd.google-apps.document gdoc +application/vnd.google-apps.presentation gslides +application/vnd.google-apps.spreadsheet gsheet +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp list3820 listafp +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktr ktz +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skd skm skp skt +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.mapbox-vector-tile mvt +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xla xlc xlm xls xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-officetheme thmx +application/vnd.ms-outlook msg +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +application/vnd.ms-powerpoint pot pps ppt +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +application/vnd.ms-project mpt +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wcm wdb wks wps +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf nitf ntf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.olpc-sugar xo +application/vnd.oma.dd2+xml dd2 +application/vnd.openblox.game+xml obgx +application/vnd.openofficeorg.extension oxt +application/vnd.openstreetmap.data+xml osm +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.osgeo.mapguide.package mgp +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +application/vnd.palm oprc pdb pqa +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.picsel efif +application/vnd.pmi.widget wg +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.quark.quarkxpress qwd qwt qxb qxd qxl qxt +application/vnd.rar rar +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +application/vnd.sailingtracker.track st +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +application/vnd.smart.teacher teacher +application/vnd.software602.filler.form+xml fo +application/vnd.solent.sdkm+xml sdkd sdkm +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +application/vnd.sun.wadl+xml wadl +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.sus-calendar sus susp +application/vnd.svd svd +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.syncml.dmddf+xml ddf +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap cap dmp pcap +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.vcx vcx +application/vnd.visio vsd vss vst vsw +application/vnd.visionary vis +application/vnd.vsf vsf +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wt.stf stf +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/wasm wasm +application/watcherinfo+xml wif +application/widget wgt +application/winhlp hlp +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +application/x-arj arj +application/x-authorware-bin aab u32 vox x32 +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 boz bz2 +application/x-cbr cb7 cba cbr cbt cbz +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-chrome-extension crx +application/x-cocoa cco +application/x-conference nsc +application/x-cpio cpio +application/x-csh csh +application/x-debian-package udeb +application/x-dgc-compressed dgc +application/x-director cct cst cxt dcr dir dxr fgd swa w3d +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +application/x-font-ghostscript gsf +application/x-font-linux-psf psf +application/x-font-pcf pcf +application/x-font-snf snf +application/x-font-type1 afm pfa pfb pfm +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +application/x-hdf hdf +application/x-httpd-php php +application/x-install-instructions install +application/x-java-archive-diff jardiff +application/x-java-jnlp-file jnlp +application/x-keepass2 kdbx +application/x-latex latex +application/x-lua-bytecode luac +application/x-lzh-compressed lha lzh +application/x-makeself run +application/x-mie mie +application/x-mobipocket-ebook mobi prc +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload bat com +application/x-msmediaview m13 m14 mvb +application/x-msmetafile emf emz wmf +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf cdf nc +application/x-ns-proxy-autoconfig pac +application/x-nzb nzb +application/x-perl pl pm +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-redhat-package-manager rpm +application/x-research-info-systems ris +application/x-sea sea +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl tk +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texi texinfo +application/x-tgif obj +application/x-ustar ustar +application/x-virtualbox-hdd hdd +application/x-virtualbox-ova ova +application/x-virtualbox-ovf ovf +application/x-virtualbox-vbox vbox +application/x-virtualbox-vbox-extpack vbox-extpack +application/x-virtualbox-vdi vdi +application/x-virtualbox-vhd vhd +application/x-virtualbox-vmdk vmdk +application/x-wais-source src +application/x-web-app-manifest+json webapp +application/x-x509-ca-cert crt der pem +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +application/xaml+xml xaml +application/xcap-att+xml xav +application/xcap-caps+xml xca +application/xcap-diff+xml xdf +application/xcap-el+xml xel +application/xcap-ns+xml xns +application/xenc+xml xenc +application/xhtml+xml xht xhtml +application/xml rng xml xsd xsl +application/xml-dtd dtd +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvm xvml +application/yang yang +application/yin+xml yin +application/zip zip +audio/3gpp 3gpp +audio/adpcm adp +audio/amr amr +audio/basic au snd +audio/midi kar mid midi rmi +audio/mobile-xmf mxmf +audio/mp3 mp3 +audio/mp4 m4a mp4a +audio/mpeg m2a m3a mp2 mp2a mpga +audio/ogg oga ogg opus spx +audio/s3m s3m +audio/silk sil +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.rip rip +audio/wav wav +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aifc aiff +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ra ram +audio/x-pn-realaudio-plugin rmp +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +chemical/x-xyz xyz +font/collection ttc +font/otf otf +font/ttf ttf +font/woff woff +font/woff2 woff2 +image/aces exr +image/apng apng +image/avci avci +image/avcs avcs +image/avif avif +image/bmp bmp +image/cgm cgm +image/dicom-rle drle +image/fits fits +image/g3fax g3 +image/gif gif +image/heic heic +image/heic-sequence heics +image/heif heif +image/heif-sequence heifs +image/hej2k hej2 +image/hsj2 hsj2 +image/ief ief +image/jls jls +image/jp2 jp2 jpg2 +image/jpeg jpe jpeg jpg +image/jph jph +image/jphc jhc +image/jpm jpm +image/jpx jpf jpx +image/jxr jxr +image/jxra jxra +image/jxrs jxrs +image/jxs jxs +image/jxsc jxsc +image/jxsi jxsi +image/jxss jxss +image/ktx ktx +image/ktx2 ktx2 +image/png png +image/prs.btif btif +image/prs.pti pti +image/sgi sgi +image/svg+xml svg svgz +image/t38 t38 +image/tiff tif tiff +image/tiff-fx tfx +image/vnd.adobe.photoshop psd +image/vnd.airzip.accelerator.azv azv +image/vnd.dece.graphic uvg uvi uvvg uvvi +image/vnd.djvu djv djvu +image/vnd.dvb.subtitle sub +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.microsoft.icon ico +image/vnd.ms-dds dds +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +image/vnd.pco.b16 b16 +image/vnd.tencent.tap tap +image/vnd.valve.source.texture vtf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/vnd.zbrush.pcx pcx +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fh4 fh5 fh7 fhc +image/x-jng jng +image/x-mrsid-image sid +image/x-pict pct pic +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/disposition-notification disposition-notification +message/global u8msg +message/global-delivery-status u8dsn +message/global-disposition-notification u8mdn +message/global-headers u8hdr +message/rfc822 eml mime +message/vnd.wfa.wsc wsc +model/3mf 3mf +model/gltf+json gltf +model/gltf-binary glb +model/iges iges igs +model/mesh mesh msh silo +model/mtl mtl +model/step+xml stpx +model/step+zip stpz +model/step-xml+zip stpxz +model/vnd.collada+xml dae +model/vnd.dwf dwf +model/vnd.gdl gdl +model/vnd.gtw gtw +model/vnd.mts mts +model/vnd.opengex ogex +model/vnd.parasolid.transmit.binary x_b +model/vnd.parasolid.transmit.text x_t +model/vnd.sap.vds vds +model/vnd.usdz+zip usdz +model/vnd.valve.source.compiled-map bsp +model/vnd.vtu vtu +model/vrml vrml wrl +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +text/cache-manifest appcache manifest +text/calendar ics ifb +text/coffeescript coffee litcoffee +text/css css +text/csv csv +text/html htm html shtml +text/jade jade +text/jsx jsx +text/less less +text/markdown markdown md +text/mathml mml +text/mdx mdx +text/n3 n3 +text/plain conf def in ini list log text txt +text/prs.lines.tag dsc +text/richtext rtx +text/sgml sgm sgml +text/shex shex +text/slim slim slm +text/spdx spdx +text/stylus styl stylus +text/tab-separated-values tsv +text/troff man me ms roff t tr +text/turtle ttl +text/uri-list uri uris urls +text/vcard vcard +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.mcurl mcurl +text/vnd.curl.scurl scurl +text/vnd.familysearch.gedcom ged +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.sun.j2me.app-descriptor jad +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/vtt vtt +text/x-asm asm s +text/x-c c cc cpp cxx dic h hh +text/x-component htc +text/x-fortran f f77 f90 for +text/x-handlebars-template hbs +text/x-java-source java +text/x-lua lua +text/x-markdown mkd +text/x-nfo nfo +text/x-opml opml +text/x-pascal p pas +text/x-processing pde +text/x-sass sass +text/x-scss scss +text/x-setext etx +text/x-sfv sfv +text/x-suse-ymp ymp +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +text/yaml yaml yml +video/3gpp 3gp +video/3gpp2 3g2 +video/h261 h261 +video/h263 h263 +video/h264 h264 +video/iso.segment m4s +video/jpeg jpgv +video/jpm jpgm +video/mj2 mj2 mjp2 +video/mp2t ts +video/mp4 mp4 mp4v mpg4 +video/mpeg m1v m2v mpe mpeg mpg +video/ogg ogv +video/quicktime mov qt +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +video/vnd.dvb.file dvb +video/vnd.fvt fvt +video/vnd.mpegurl m4u mxu +video/vnd.ms-playready.media.pyv pyv +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mk3d mks mkv +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice \ No newline at end of file diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page.rb new file mode 100644 index 0000000..64821a8 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page.rb @@ -0,0 +1,215 @@ +# frozen_string_literal: true + +module Jekyll + class Page + include Convertible + + attr_writer :dir + attr_accessor :basename, :content, :data, :ext, :name, :output, :pager, :site + + alias_method :extname, :ext + + # Attributes for Liquid templates + ATTRIBUTES_FOR_LIQUID = %w( + content + dir + excerpt + name + path + url + ).freeze + + # A set of extensions that are considered HTML or HTML-like so we + # should not alter them, this includes .xhtml through XHTM5. + + HTML_EXTENSIONS = %w( + .html + .xhtml + .htm + ).freeze + + # Initialize a new Page. + # + # site - The Site object. + # base - The String path to the source. + # dir - The String path between the source and the file. + # name - The String filename of the file. + def initialize(site, base, dir, name) + @site = site + @base = base + @dir = dir + @name = name + @path = if site.in_theme_dir(base) == base # we're in a theme + site.in_theme_dir(base, dir, name) + else + site.in_source_dir(base, dir, name) + end + + process(name) + read_yaml(PathManager.join(base, dir), name) + generate_excerpt if site.config["page_excerpts"] + + data.default_proc = proc do |_, key| + site.frontmatter_defaults.find(relative_path, type, key) + end + + Jekyll::Hooks.trigger :pages, :post_init, self + end + + # The generated directory into which the page will be placed + # upon generation. This is derived from the permalink or, if + # permalink is absent, will be '/' + # + # Returns the String destination directory. + def dir + url.end_with?("/") ? url : url_dir + end + + # The full path and filename of the post. Defined in the YAML of the post + # body. + # + # Returns the String permalink or nil if none has been set. + def permalink + data.nil? ? nil : data["permalink"] + end + + # The template of the permalink. + # + # Returns the template String. + def template + if !html? + "/:path/:basename:output_ext" + elsif index? + "/:path/" + else + Utils.add_permalink_suffix("/:path/:basename", site.permalink_style) + end + end + + # The generated relative url of this page. e.g. /about.html. + # + # Returns the String url. + def url + @url ||= URL.new( + :template => template, + :placeholders => url_placeholders, + :permalink => permalink + ).to_s + end + + # Returns a hash of URL placeholder names (as symbols) mapping to the + # desired placeholder replacements. For details see "url.rb" + def url_placeholders + { + :path => @dir, + :basename => basename, + :output_ext => output_ext, + } + end + + # Extract information from the page filename. + # + # name - The String filename of the page file. + # + # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`) + # Returns nothing. + def process(name) + return unless name + + self.ext = File.extname(name) + self.basename = name[0..-ext.length - 1].gsub(%r!\.*\z!, "") + end + + # Add any necessary layouts to this post + # + # layouts - The Hash of {"name" => "layout"}. + # site_payload - The site payload Hash. + # + # Returns String rendered page. + def render(layouts, site_payload) + site_payload["page"] = to_liquid + site_payload["paginator"] = pager.to_liquid + + do_layout(site_payload, layouts) + end + + # The path to the source file + # + # Returns the path to the source file + def path + data.fetch("path") { relative_path } + end + + # The path to the page source file, relative to the site source + def relative_path + @relative_path ||= PathManager.join(@dir, @name).delete_prefix("/") + end + + # Obtain destination path. + # + # dest - The String path to the destination dir. + # + # Returns the destination file path String. + def destination(dest) + @destination ||= {} + @destination[dest] ||= begin + path = site.in_dest_dir(dest, URL.unescape_path(url)) + path = File.join(path, "index") if url.end_with?("/") + path << output_ext unless path.end_with? output_ext + path + end + end + + # Returns the object as a debug String. + def inspect + "#<#{self.class} @relative_path=#{relative_path.inspect}>" + end + + # Returns the Boolean of whether this Page is HTML or not. + def html? + HTML_EXTENSIONS.include?(output_ext) + end + + # Returns the Boolean of whether this Page is an index file or not. + def index? + basename == "index" + end + + def trigger_hooks(hook_name, *args) + Jekyll::Hooks.trigger :pages, hook_name, self, *args + end + + def write? + true + end + + def excerpt_separator + @excerpt_separator ||= (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s + end + + def excerpt + return @excerpt if defined?(@excerpt) + + @excerpt = data["excerpt"] ? data["excerpt"].to_s : nil + end + + def generate_excerpt? + !excerpt_separator.empty? && instance_of?(Jekyll::Page) && html? + end + + private + + def generate_excerpt + return unless generate_excerpt? + + data["excerpt"] ||= Jekyll::PageExcerpt.new(self) + end + + def url_dir + @url_dir ||= begin + value = File.dirname(url) + value.end_with?("/") ? value : "#{value}/" + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb new file mode 100644 index 0000000..dd79fca --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_excerpt.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Jekyll + class PageExcerpt < Excerpt + attr_reader :doc + alias_method :id, :relative_path + + EXCERPT_ATTRIBUTES = (Page::ATTRIBUTES_FOR_LIQUID - %w(excerpt)).freeze + private_constant :EXCERPT_ATTRIBUTES + + def to_liquid + @to_liquid ||= doc.to_liquid(EXCERPT_ATTRIBUTES) + end + + def render_with_liquid? + return false if data["render_with_liquid"] == false + + Jekyll::Utils.has_liquid_construct?(content) + end + + def inspect + "#<#{self.class} id=#{id.inspect}>" + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb new file mode 100644 index 0000000..e314f97 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/page_without_a_file.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Jekyll + # A Jekyll::Page subclass to handle processing files without reading it to + # determine the page-data and page-content based on Front Matter delimiters. + # + # The class instance is basically just a bare-bones entity with just + # attributes "dir", "name", "path", "url" defined on it. + class PageWithoutAFile < Page + def read_yaml(*) + @data ||= {} + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb new file mode 100644 index 0000000..5d97522 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/path_manager.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Jekyll + # A singleton class that caches frozen instances of path strings returned from its methods. + # + # NOTE: + # This class exists because `File.join` allocates an Array and returns a new String on every + # call using **the same arguments**. Caching the result means reduced memory usage. + # However, the caches are never flushed so that they can be used even when a site is + # regenerating. The results are frozen to deter mutation of the cached string. + # + # Therefore, employ this class only for situations where caching the result is necessary + # for performance reasons. + # + class PathManager + # This class cannot be initialized from outside + private_class_method :new + + class << self + # Wraps `File.join` to cache the frozen result. + # Reassigns `nil`, empty strings and empty arrays to a frozen empty string beforehand. + # + # Returns a frozen string. + def join(base, item) + base = "" if base.nil? || base.empty? + item = "" if item.nil? || item.empty? + @join ||= {} + @join[base] ||= {} + @join[base][item] ||= File.join(base, item).freeze + end + + # Ensures the questionable path is prefixed with the base directory + # and prepends the questionable path with the base directory if false. + # + # Returns a frozen string. + def sanitized_path(base_directory, questionable_path) + @sanitized_path ||= {} + @sanitized_path[base_directory] ||= {} + @sanitized_path[base_directory][questionable_path] ||= if questionable_path.nil? + base_directory.freeze + else + sanitize_and_join( + base_directory, questionable_path + ).freeze + end + end + + private + + def sanitize_and_join(base_directory, questionable_path) + clean_path = if questionable_path.start_with?("~") + questionable_path.dup.insert(0, "/") + else + questionable_path + end + clean_path = File.expand_path(clean_path, "/") + return clean_path if clean_path.eql?(base_directory) + + # remove any remaining extra leading slashes not stripped away by calling + # `File.expand_path` above. + clean_path.squeeze!("/") + return clean_path if clean_path.start_with?(slashed_dir_cache(base_directory)) + + clean_path.sub!(%r!\A\w:/!, "/") + join(base_directory, clean_path) + end + + def slashed_dir_cache(base_directory) + @slashed_dir_cache ||= {} + @slashed_dir_cache[base_directory] ||= base_directory.sub(%r!\z!, "/") + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin.rb new file mode 100644 index 0000000..1157e12 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +module Jekyll + class Plugin + PRIORITIES = { + :low => -10, + :highest => 100, + :lowest => -100, + :normal => 0, + :high => 10, + }.freeze + + # + + def self.inherited(const) + catch_inheritance(const) do |const_| + catch_inheritance(const_) + end + end + + # + + def self.catch_inheritance(const) + const.define_singleton_method :inherited do |const_| + (@children ||= Set.new).add const_ + yield const_ if block_given? + end + end + + # + + def self.descendants + @children ||= Set.new + out = @children.map(&:descendants) + out << self unless superclass == Plugin + Set.new(out).flatten + end + + # Get or set the priority of this plugin. When called without an + # argument it returns the priority. When an argument is given, it will + # set the priority. + # + # priority - The Symbol priority (default: nil). Valid options are: + # :lowest, :low, :normal, :high, :highest + # + # Returns the Symbol priority. + def self.priority(priority = nil) + @priority ||= nil + @priority = priority if priority && PRIORITIES.key?(priority) + @priority || :normal + end + + # Get or set the safety of this plugin. When called without an argument + # it returns the safety. When an argument is given, it will set the + # safety. + # + # safe - The Boolean safety (default: nil). + # + # Returns the safety Boolean. + def self.safe(safe = nil) + @safe = safe unless defined?(@safe) && safe.nil? + @safe || false + end + + # Spaceship is priority [higher -> lower] + # + # other - The class to be compared. + # + # Returns -1, 0, 1. + def self.<=>(other) + PRIORITIES[other.priority] <=> PRIORITIES[priority] + end + + # Spaceship is priority [higher -> lower] + # + # other - The class to be compared. + # + # Returns -1, 0, 1. + def <=>(other) + self.class <=> other.class + end + + # Initialize a new plugin. This should be overridden by the subclass. + # + # config - The Hash of configuration options. + # + # Returns a new instance. + def initialize(config = {}) + # no-op for default + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb new file mode 100644 index 0000000..810a2fa --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/plugin_manager.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +module Jekyll + class PluginManager + attr_reader :site + + # Create an instance of this class. + # + # site - the instance of Jekyll::Site we're concerned with + # + # Returns nothing + def initialize(site) + @site = site + end + + # Require all the plugins which are allowed. + # + # Returns nothing + def conscientious_require + require_theme_deps if site.theme + require_plugin_files + require_gems + deprecation_checks + end + + # Require each of the gem plugins specified. + # + # Returns nothing. + def require_gems + Jekyll::External.require_with_graceful_fail( + site.gems.select { |plugin| plugin_allowed?(plugin) } + ) + end + + # Require each of the runtime_dependencies specified by the theme's gemspec. + # + # Returns false only if no dependencies have been specified, otherwise nothing. + def require_theme_deps + return false unless site.theme.runtime_dependencies + + site.theme.runtime_dependencies.each do |dep| + next if dep.name == "jekyll" + + External.require_with_graceful_fail(dep.name) if plugin_allowed?(dep.name) + end + end + + def self.require_from_bundler + if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] && gemfile_exists? + require "bundler" + + Bundler.setup + required_gems = Bundler.require(:jekyll_plugins) + message = "Required #{required_gems.map(&:name).join(", ")}" + Jekyll.logger.debug("PluginManager:", message) + ENV["JEKYLL_NO_BUNDLER_REQUIRE"] = "true" + + true + else + false + end + end + + # Check for the existence of a Gemfile. + # + # Returns true if a Gemfile exists in the places bundler will look + def self.gemfile_exists? + File.file?("Gemfile") || (ENV["BUNDLE_GEMFILE"] && File.file?(ENV["BUNDLE_GEMFILE"])) + end + + # Check whether a gem plugin is allowed to be used during this build. + # + # plugin_name - the name of the plugin + # + # Returns true if the plugin name is in the whitelist or if the site is not + # in safe mode. + def plugin_allowed?(plugin_name) + !site.safe || whitelist.include?(plugin_name) + end + + # Build an array of allowed plugin gem names. + # + # Returns an array of strings, each string being the name of a gem name + # that is allowed to be used. + def whitelist + @whitelist ||= [site.config["whitelist"]].flatten + end + + # Require all .rb files if safe mode is off + # + # Returns nothing. + def require_plugin_files + unless site.safe + plugins_path.each do |plugin_search_path| + plugin_files = Utils.safe_glob(plugin_search_path, File.join("**", "*.rb")) + Jekyll::External.require_with_graceful_fail(plugin_files) + end + end + end + + # Public: Setup the plugin search path + # + # Returns an Array of plugin search paths + def plugins_path + if site.config["plugins_dir"].eql? Jekyll::Configuration::DEFAULTS["plugins_dir"] + [site.in_source_dir(site.config["plugins_dir"])] + else + Array(site.config["plugins_dir"]).map { |d| File.expand_path(d) } + end + end + + def deprecation_checks + pagination_included = (site.config["plugins"] || []).include?("jekyll-paginate") || + defined?(Jekyll::Paginate) + if site.config["paginate"] && !pagination_included + Jekyll::Deprecator.deprecation_message <<~MSG + You appear to have pagination turned on, but you haven't included the `jekyll-paginate` + gem. Ensure you have `plugins: [jekyll-paginate]` in your configuration file. + MSG + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/profiler.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/profiler.rb new file mode 100644 index 0000000..f5dbfb1 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/profiler.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Jekyll + class Profiler + TERMINAL_TABLE_STYLES = { + :alignment => :right, + :border_top => false, + :border_bottom => false, + }.freeze + private_constant :TERMINAL_TABLE_STYLES + + def self.tabulate(table_rows) + require "terminal-table" + + rows = table_rows.dup + header = rows.shift + output = +"\n" + + table = Terminal::Table.new do |t| + t << header + t << :separator + rows.each { |row| t << row } + t.style = TERMINAL_TABLE_STYLES + t.align_column(0, :left) + end + + output << table.to_s << "\n" + end + + def initialize(site) + @site = site + end + + def profile_process + profile_data = { "PHASE" => "TIME" } + + [:reset, :read, :generate, :render, :cleanup, :write].each do |method| + start_time = Time.now + @site.send(method) + end_time = (Time.now - start_time).round(4) + profile_data[method.to_s.upcase] = format("%.4f", end_time) + end + + Jekyll.logger.info "\nBuild Process Summary:" + Jekyll.logger.info Profiler.tabulate(Array(profile_data)) + + Jekyll.logger.info "\nSite Render Stats:" + @site.print_stats + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/publisher.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/publisher.rb new file mode 100644 index 0000000..26fe4a3 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/publisher.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + class Publisher + def initialize(site) + @site = site + end + + def publish?(thing) + can_be_published?(thing) && !hidden_in_the_future?(thing) + end + + def hidden_in_the_future?(thing) + thing.respond_to?(:date) && !@site.future && thing.date.to_i > @site.time.to_i + end + + private + + def can_be_published?(thing) + thing.data.fetch("published", true) || @site.unpublished + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/reader.rb new file mode 100644 index 0000000..5d15177 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/reader.rb @@ -0,0 +1,209 @@ +# frozen_string_literal: true + +module Jekyll + class Reader + attr_reader :site + + def initialize(site) + @site = site + end + + # Read Site data from disk and load it into internal data structures. + # + # Returns nothing. + def read + @site.layouts = LayoutReader.new(site).read + read_directories + read_included_excludes + sort_files! + CollectionReader.new(site).read + ThemeAssetsReader.new(site).read + read_data + end + + # Read and merge the data files. + # If a theme is specified and it contains data, it will be read. + # Site data will overwrite theme data with the same key using the + # semantics of Utils.deep_merge_hashes. + # + # Returns nothing. + def read_data + @site.data = DataReader.new(site).read(site.config["data_dir"]) + return unless site.theme&.data_path + + theme_data = DataReader.new( + site, + :in_source_dir => site.method(:in_theme_dir) + ).read(site.theme.data_path) + @site.data = Jekyll::Utils.deep_merge_hashes(theme_data, @site.data) + end + + # Sorts posts, pages, and static files. + def sort_files! + site.collections.each_value { |c| c.docs.sort! } + site.pages.sort_by!(&:name) + site.static_files.sort_by!(&:relative_path) + end + + # Recursively traverse directories to find pages and static files + # that will become part of the site according to the rules in + # filter_entries. + # + # dir - The String relative path of the directory to read. Default: ''. + # + # Returns nothing. + def read_directories(dir = "") + base = site.in_source_dir(dir) + + return unless File.directory?(base) + + dot_dirs = [] + dot_pages = [] + dot_static_files = [] + + dot = Dir.chdir(base) { filter_entries(Dir.entries("."), base) } + dot.each do |entry| + file_path = @site.in_source_dir(base, entry) + if File.directory?(file_path) + dot_dirs << entry + elsif Utils.has_yaml_header?(file_path) + dot_pages << entry + else + dot_static_files << entry + end + end + + retrieve_posts(dir) + retrieve_dirs(base, dir, dot_dirs) + retrieve_pages(dir, dot_pages) + retrieve_static_files(dir, dot_static_files) + end + + # Retrieves all the posts(posts/drafts) from the given directory + # and add them to the site and sort them. + # + # dir - The String representing the directory to retrieve the posts from. + # + # Returns nothing. + def retrieve_posts(dir) + return if outside_configured_directory?(dir) + + site.posts.docs.concat(post_reader.read_posts(dir)) + site.posts.docs.concat(post_reader.read_drafts(dir)) if site.show_drafts + end + + # Recursively traverse directories with the read_directories function. + # + # base - The String representing the site's base directory. + # dir - The String representing the directory to traverse down. + # dot_dirs - The Array of subdirectories in the dir. + # + # Returns nothing. + def retrieve_dirs(_base, dir, dot_dirs) + dot_dirs.each do |file| + dir_path = site.in_source_dir(dir, file) + rel_path = PathManager.join(dir, file) + @site.reader.read_directories(rel_path) unless @site.dest.chomp("/") == dir_path + end + end + + # Retrieve all the pages from the current directory, + # add them to the site and sort them. + # + # dir - The String representing the directory retrieve the pages from. + # dot_pages - The Array of pages in the dir. + # + # Returns nothing. + def retrieve_pages(dir, dot_pages) + site.pages.concat(PageReader.new(site, dir).read(dot_pages)) + end + + # Retrieve all the static files from the current directory, + # add them to the site and sort them. + # + # dir - The directory retrieve the static files from. + # dot_static_files - The static files in the dir. + # + # Returns nothing. + def retrieve_static_files(dir, dot_static_files) + site.static_files.concat(StaticFileReader.new(site, dir).read(dot_static_files)) + end + + # Filter out any files/directories that are hidden or backup files (start + # with "." or "#" or end with "~"), or contain site content (start with "_"), + # or are excluded in the site configuration, unless they are web server + # files such as '.htaccess'. + # + # entries - The Array of String file/directory entries to filter. + # base_directory - The string representing the optional base directory. + # + # Returns the Array of filtered entries. + def filter_entries(entries, base_directory = nil) + EntryFilter.new(site, base_directory).filter(entries) + end + + # Read the entries from a particular directory for processing + # + # dir - The String representing the relative path of the directory to read. + # subfolder - The String representing the directory to read. + # + # Returns the list of entries to process + def get_entries(dir, subfolder) + base = site.in_source_dir(dir, subfolder) + return [] unless File.exist?(base) + + entries = Dir.chdir(base) { filter_entries(Dir["**/*"], base) } + entries.delete_if { |e| File.directory?(site.in_source_dir(base, e)) } + end + + private + + # Internal + # + # Determine if the directory is supposed to contain posts and drafts. + # If the user has defined a custom collections_dir, then attempt to read + # posts and drafts only from within that directory. + # + # Returns true if a custom collections_dir has been set but current directory lies + # outside that directory. + def outside_configured_directory?(dir) + collections_dir = site.config["collections_dir"] + !collections_dir.empty? && !dir.start_with?("/#{collections_dir}") + end + + # Create a single PostReader instance to retrieve drafts and posts from all valid + # directories in current site. + def post_reader + @post_reader ||= PostReader.new(site) + end + + def read_included_excludes + entry_filter = EntryFilter.new(site) + + site.include.each do |entry| + entry_path = site.in_source_dir(entry) + next if File.directory?(entry_path) + next if entry_filter.symlink?(entry_path) + + read_included_file(entry_path) if File.file?(entry_path) + end + end + + def read_included_file(entry_path) + if Utils.has_yaml_header?(entry_path) + conditionally_generate_entry(entry_path, site.pages, PageReader) + else + conditionally_generate_entry(entry_path, site.static_files, StaticFileReader) + end + end + + def conditionally_generate_entry(entry_path, container, reader) + return if container.find { |item| site.in_source_dir(item.relative_path) == entry_path } + + dir, files = File.split(entry_path) + dir.sub!(site.source, "") + files = Array(files) + container.concat(reader.new(site, dir).read(files)) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb new file mode 100644 index 0000000..6d18275 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/collection_reader.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Jekyll + class CollectionReader + SPECIAL_COLLECTIONS = %w(posts data).freeze + + attr_reader :site, :content + + def initialize(site) + @site = site + @content = {} + end + + # Read in all collections specified in the configuration + # + # Returns nothing. + def read + site.collections.each_value do |collection| + collection.read unless SPECIAL_COLLECTIONS.include?(collection.label) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb new file mode 100644 index 0000000..80b57bd --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/data_reader.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +module Jekyll + class DataReader + attr_reader :site, :content + + def initialize(site, in_source_dir: nil) + @site = site + @content = {} + @entry_filter = EntryFilter.new(site) + @in_source_dir = in_source_dir || @site.method(:in_source_dir) + @source_dir = @in_source_dir.call("/") + end + + # Read all the files in and adds them to @content + # + # dir - The String relative path of the directory to read. + # + # Returns @content, a Hash of the .yaml, .yml, + # .json, and .csv files in the base directory + def read(dir) + base = @in_source_dir.call(dir) + read_data_to(base, @content) + @content + end + + # Read and parse all .yaml, .yml, .json, .csv and .tsv + # files under and add them to the variable. + # + # dir - The string absolute path of the directory to read. + # data - The variable to which data will be added. + # + # Returns nothing + def read_data_to(dir, data) + return unless File.directory?(dir) && !@entry_filter.symlink?(dir) + + entries = Dir.chdir(dir) do + Dir["*.{yaml,yml,json,csv,tsv}"] + Dir["*"].select { |fn| File.directory?(fn) } + end + + entries.each do |entry| + path = @in_source_dir.call(dir, entry) + next if @entry_filter.symlink?(path) + + if File.directory?(path) + read_data_to(path, data[sanitize_filename(entry)] = {}) + else + key = sanitize_filename(File.basename(entry, ".*")) + data[key] = read_data_file(path) + end + end + end + + # Determines how to read a data file. + # + # Returns the contents of the data file. + def read_data_file(path) + Jekyll.logger.debug "Reading:", path.sub(@source_dir, "") + + case File.extname(path).downcase + when ".csv" + CSV.read(path, **csv_config).map { |row| convert_row(row) } + when ".tsv" + CSV.read(path, **tsv_config).map { |row| convert_row(row) } + else + SafeYAML.load_file(path) + end + end + + def sanitize_filename(name) + name.gsub(%r![^\w\s-]+|(?<=^|\b\s)\s+(?=$|\s?\b)!, "") + .gsub(%r!\s+!, "_") + end + + private + + # @return [Hash] + def csv_config + @csv_config ||= read_config("csv_reader") + end + + # @return [Hash] + def tsv_config + @tsv_config ||= read_config("tsv_reader", { :col_sep => "\t" }) + end + + # @param config_key [String] + # @param overrides [Hash] + # @return [Hash] + # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/csv/rdoc/CSV.html#Converters + def read_config(config_key, overrides = {}) + reader_config = config[config_key] || {} + + defaults = { + :converters => reader_config.fetch("csv_converters", []).map(&:to_sym), + :headers => reader_config.fetch("headers", true), + :encoding => reader_config.fetch("encoding", config["encoding"]), + } + + defaults.merge(overrides) + end + + def config + @config ||= site.config + end + + # @param row [Array, CSV::Row] + # @return [Array, Hash] + def convert_row(row) + row.instance_of?(CSV::Row) ? row.to_hash : row + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb new file mode 100644 index 0000000..981867b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/layout_reader.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Jekyll + class LayoutReader + attr_reader :site + + def initialize(site) + @site = site + @layouts = {} + end + + def read + layout_entries.each do |layout_file| + @layouts[layout_name(layout_file)] = \ + Layout.new(site, layout_directory, layout_file) + end + + theme_layout_entries.each do |layout_file| + @layouts[layout_name(layout_file)] ||= \ + Layout.new(site, theme_layout_directory, layout_file) + end + + @layouts + end + + def layout_directory + @layout_directory ||= site.in_source_dir(site.config["layouts_dir"]) + end + + def theme_layout_directory + @theme_layout_directory ||= site.theme.layouts_path if site.theme + end + + private + + def layout_entries + entries_in layout_directory + end + + def theme_layout_entries + theme_layout_directory ? entries_in(theme_layout_directory) : [] + end + + def entries_in(dir) + entries = [] + within(dir) do + entries = EntryFilter.new(site).filter(Dir["**/*.*"]) + end + entries + end + + def layout_name(file) + file.split(".")[0..-2].join(".") + end + + def within(directory) + return unless File.exist?(directory) + + Dir.chdir(directory) { yield } + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb new file mode 100644 index 0000000..e72f767 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/page_reader.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Jekyll + class PageReader + attr_reader :site, :dir, :unfiltered_content + + def initialize(site, dir) + @site = site + @dir = dir + @unfiltered_content = [] + end + + # Create a new `Jekyll::Page` object for each entry in a given array. + # + # files - An array of file names inside `@dir` + # + # Returns an array of publishable `Jekyll::Page` objects. + def read(files) + files.each do |page| + @unfiltered_content << Page.new(@site, @site.source, @dir, page) + end + @unfiltered_content.select { |page| site.publisher.publish?(page) } + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb new file mode 100644 index 0000000..25c5f98 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/post_reader.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Jekyll + class PostReader + attr_reader :site, :unfiltered_content + + def initialize(site) + @site = site + end + + # Read all the files in //_drafts and create a new + # Document object with each one. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_drafts(dir) + read_publishable(dir, "_drafts", Document::DATELESS_FILENAME_MATCHER) + end + + # Read all the files in //_posts and create a new Document + # object with each one. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_posts(dir) + read_publishable(dir, "_posts", Document::DATE_FILENAME_MATCHER) + end + + # Read all the files in // and create a new + # Document object with each one insofar as it matches the regexp matcher. + # + # dir - The String relative path of the directory to read. + # + # Returns nothing. + def read_publishable(dir, magic_dir, matcher) + read_content(dir, magic_dir, matcher) + .tap { |docs| docs.each(&:read) } + .select { |doc| processable?(doc) } + end + + # Read all the content files from //magic_dir + # and return them with the type klass. + # + # dir - The String relative path of the directory to read. + # magic_dir - The String relative directory to , + # looks for content here. + # klass - The return type of the content. + # + # Returns klass type of content files + def read_content(dir, magic_dir, matcher) + @site.reader.get_entries(dir, magic_dir).map do |entry| + next unless matcher.match?(entry) + + path = @site.in_source_dir(File.join(dir, magic_dir, entry)) + Document.new(path, + :site => @site, + :collection => @site.posts) + end.tap(&:compact!) + end + + private + + def processable?(doc) + if doc.content.nil? + Jekyll.logger.debug "Skipping:", "Content in #{doc.relative_path} is nil" + false + elsif !doc.content.valid_encoding? + Jekyll.logger.debug "Skipping:", "#{doc.relative_path} is not valid UTF-8" + false + else + publishable?(doc) + end + end + + def publishable?(doc) + site.publisher.publish?(doc).tap do |will_publish| + if !will_publish && site.publisher.hidden_in_the_future?(doc) + Jekyll.logger.warn "Skipping:", "#{doc.relative_path} has a future date" + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb new file mode 100644 index 0000000..5c8a677 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/static_file_reader.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Jekyll + class StaticFileReader + attr_reader :site, :dir, :unfiltered_content + + def initialize(site, dir) + @site = site + @dir = dir + @unfiltered_content = [] + end + + # Create a new StaticFile object for every entry in a given list of basenames. + # + # files - an array of file basenames. + # + # Returns an array of static files. + def read(files) + files.each do |file| + @unfiltered_content << StaticFile.new(@site, @site.source, @dir, file) + end + @unfiltered_content + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb new file mode 100644 index 0000000..b20a3a0 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/readers/theme_assets_reader.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Jekyll + class ThemeAssetsReader + attr_reader :site + + def initialize(site) + @site = site + end + + def read + return unless site.theme&.assets_path + + Find.find(site.theme.assets_path) do |path| + next if File.directory?(path) + + if File.symlink?(path) + Jekyll.logger.warn "Theme reader:", "Ignored symlinked asset: #{path}" + else + read_theme_asset(path) + end + end + end + + private + + def read_theme_asset(path) + base = site.theme.root + dir = File.dirname(path.sub("#{site.theme.root}/", "")) + name = File.basename(path) + + if Utils.has_yaml_header?(path) + append_unless_exists site.pages, + Jekyll::Page.new(site, base, dir, name) + else + append_unless_exists site.static_files, + Jekyll::StaticFile.new(site, base, "/#{dir}", name) + end + end + + def append_unless_exists(haystack, new_item) + if haystack.any? { |file| file.relative_path == new_item.relative_path } + Jekyll.logger.debug "Theme:", + "Ignoring #{new_item.relative_path} in theme due to existing file " \ + "with that path in site." + return + end + + haystack << new_item + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb new file mode 100644 index 0000000..88c6a81 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/regenerator.rb @@ -0,0 +1,195 @@ +# frozen_string_literal: true + +module Jekyll + class Regenerator + attr_reader :site, :metadata, :cache + attr_accessor :disabled + private :disabled, :disabled= + + def initialize(site) + @site = site + + # Read metadata from file + read_metadata + + # Initialize cache to an empty hash + clear_cache + end + + # Checks if a renderable object needs to be regenerated + # + # Returns a boolean. + def regenerate?(document) + return true if disabled + + case document + when Page + regenerate_page?(document) + when Document + regenerate_document?(document) + else + source_path = document.respond_to?(:path) ? document.path : nil + dest_path = document.destination(@site.dest) if document.respond_to?(:destination) + source_modified_or_dest_missing?(source_path, dest_path) + end + end + + # Add a path to the metadata + # + # Returns true, also on failure. + def add(path) + return true unless File.exist?(path) + + metadata[path] = { + "mtime" => File.mtime(path), + "deps" => [], + } + cache[path] = true + end + + # Force a path to regenerate + # + # Returns true. + def force(path) + cache[path] = true + end + + # Clear the metadata and cache + # + # Returns nothing + def clear + @metadata = {} + clear_cache + end + + # Clear just the cache + # + # Returns nothing + def clear_cache + @cache = {} + end + + # Checks if the source has been modified or the + # destination is missing + # + # returns a boolean + def source_modified_or_dest_missing?(source_path, dest_path) + modified?(source_path) || (dest_path && !File.exist?(dest_path)) + end + + # Checks if a path's (or one of its dependencies) + # mtime has changed + # + # Returns a boolean. + def modified?(path) + return true if disabled? + + # objects that don't have a path are always regenerated + return true if path.nil? + + # Check for path in cache + return cache[path] if cache.key? path + + if metadata[path] + # If we have seen this file before, + # check if it or one of its dependencies has been modified + existing_file_modified?(path) + else + # If we have not seen this file before, add it to the metadata and regenerate it + add(path) + end + end + + # Add a dependency of a path + # + # Returns nothing. + def add_dependency(path, dependency) + return if metadata[path].nil? || disabled + + unless metadata[path]["deps"].include? dependency + metadata[path]["deps"] << dependency + add(dependency) unless metadata.include?(dependency) + end + regenerate? dependency + end + + # Write the metadata to disk + # + # Returns nothing. + def write_metadata + unless disabled? + Jekyll.logger.debug "Writing Metadata:", ".jekyll-metadata" + File.binwrite(metadata_file, Marshal.dump(metadata)) + end + end + + # Produce the absolute path of the metadata file + # + # Returns the String path of the file. + def metadata_file + @metadata_file ||= site.in_source_dir(".jekyll-metadata") + end + + # Check if metadata has been disabled + # + # Returns a Boolean (true for disabled, false for enabled). + def disabled? + self.disabled = !site.incremental? if disabled.nil? + disabled + end + + private + + # Read metadata from the metadata file, if no file is found, + # initialize with an empty hash + # + # Returns the read metadata. + def read_metadata + @metadata = + if !disabled? && File.file?(metadata_file) + content = File.binread(metadata_file) + + begin + Marshal.load(content) + rescue TypeError + SafeYAML.load(content) + rescue ArgumentError => e + Jekyll.logger.warn("Failed to load #{metadata_file}: #{e}") + {} + end + else + {} + end + end + + def regenerate_page?(document) + document.asset_file? || document.data["regenerate"] || + source_modified_or_dest_missing?( + site.in_source_dir(document.relative_path), document.destination(@site.dest) + ) + end + + def regenerate_document?(document) + !document.write? || document.data["regenerate"] || + source_modified_or_dest_missing?( + document.path, document.destination(@site.dest) + ) + end + + def existing_file_modified?(path) + # If one of this file dependencies have been modified, + # set the regeneration bit for both the dependency and the file to true + metadata[path]["deps"].each do |dependency| + return cache[dependency] = cache[path] = true if modified?(dependency) + end + + if File.exist?(path) && metadata[path]["mtime"].eql?(File.mtime(path)) + # If this file has not been modified, set the regeneration bit to false + cache[path] = false + else + # If it has been modified, set it to true + add(path) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb new file mode 100644 index 0000000..98fc488 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/related_posts.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Jekyll + class RelatedPosts + class << self + attr_accessor :lsi + end + + attr_reader :post, :site + + def initialize(post) + @post = post + @site = post.site + Jekyll::External.require_with_graceful_fail("classifier-reborn") if site.lsi + end + + def build + return [] unless site.posts.docs.size > 1 + + if site.lsi + build_index + lsi_related_posts + else + most_recent_posts + end + end + + def build_index + self.class.lsi ||= begin + lsi = ClassifierReborn::LSI.new(:auto_rebuild => false) + Jekyll.logger.info("Populating LSI...") + + site.posts.docs.each do |x| + lsi.add_item(x) + end + + Jekyll.logger.info("Rebuilding index...") + lsi.build_index + Jekyll.logger.info("") + lsi + end + end + + def lsi_related_posts + self.class.lsi.find_related(post, 11) + end + + def most_recent_posts + @most_recent_posts ||= (site.posts.docs.last(11).reverse! - [post]).first(10) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/renderer.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/renderer.rb new file mode 100644 index 0000000..c365a0d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/renderer.rb @@ -0,0 +1,263 @@ +# frozen_string_literal: true + +module Jekyll + class Renderer + attr_reader :document, :site + attr_writer :layouts, :payload + + def initialize(site, document, site_payload = nil) + @site = site + @document = document + @payload = site_payload + @layouts = nil + end + + # Fetches the payload used in Liquid rendering. + # It can be written with #payload=(new_payload) + # Falls back to site.site_payload if no payload is set. + # + # Returns a Jekyll::Drops::UnifiedPayloadDrop + def payload + @payload ||= site.site_payload + end + + # The list of layouts registered for this Renderer. + # It can be written with #layouts=(new_layouts) + # Falls back to site.layouts if no layouts are registered. + # + # Returns a Hash of String => Jekyll::Layout identified + # as basename without the extension name. + def layouts + @layouts || site.layouts + end + + # Determine which converters to use based on this document's + # extension. + # + # Returns Array of Converter instances. + def converters + @converters ||= site.converters.select { |c| c.matches(document.extname) }.tap(&:sort!) + end + + # Determine the extname the outputted file should have + # + # Returns String the output extname including the leading period. + def output_ext + @output_ext ||= (permalink_ext || converter_output_ext) + end + + # Prepare payload and render the document + # + # Returns String rendered document output + def run + Jekyll.logger.debug "Rendering:", document.relative_path + + assign_pages! + assign_current_document! + assign_highlighter_options! + assign_layout_data! + + Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path + document.trigger_hooks(:pre_render, payload) + + render_document + end + + # Render the document. + # + # Returns String rendered document output + # rubocop: disable Metrics/AbcSize, Metrics/MethodLength + def render_document + info = { + :registers => { :site => site, :page => payload["page"] }, + :strict_filters => liquid_options["strict_filters"], + :strict_variables => liquid_options["strict_variables"], + } + + output = document.content + if document.render_with_liquid? + Jekyll.logger.debug "Rendering Liquid:", document.relative_path + output = render_liquid(output, payload, info, document.path) + end + + Jekyll.logger.debug "Rendering Markup:", document.relative_path + output = convert(output.to_s) + document.content = output + + Jekyll.logger.debug "Post-Convert Hooks:", document.relative_path + document.trigger_hooks(:post_convert) + output = document.content + + if document.place_in_layout? + Jekyll.logger.debug "Rendering Layout:", document.relative_path + output = place_in_layouts(output, payload, info) + end + + output + end + # rubocop: enable Metrics/AbcSize, Metrics/MethodLength + + # Convert the document using the converters which match this renderer's document. + # + # Returns String the converted content. + def convert(content) + converters.reduce(content) do |output, converter| + converter.convert output + rescue StandardError => e + Jekyll.logger.error "Conversion error:", + "#{converter.class} encountered an error while " \ + "converting '#{document.relative_path}':" + Jekyll.logger.error("", e.to_s) + raise e + end + end + + # Render the given content with the payload and info + # + # content - + # payload - + # info - + # path - (optional) the path to the file, for use in ex + # + # Returns String the content, rendered by Liquid. + def render_liquid(content, payload, info, path = nil) + template = site.liquid_renderer.file(path).parse(content) + template.warnings.each do |e| + Jekyll.logger.warn "Liquid Warning:", + LiquidRenderer.format_error(e, path || document.relative_path) + end + template.render!(payload, info) + # rubocop: disable Lint/RescueException + rescue Exception => e + Jekyll.logger.error "Liquid Exception:", + LiquidRenderer.format_error(e, path || document.relative_path) + raise e + end + # rubocop: enable Lint/RescueException + + # Checks if the layout specified in the document actually exists + # + # layout - the layout to check + # + # Returns Boolean true if the layout is invalid, false if otherwise + def invalid_layout?(layout) + !document.data["layout"].nil? && layout.nil? && !(document.is_a? Jekyll::Excerpt) + end + + # Render layouts and place document content inside. + # + # Returns String rendered content + def place_in_layouts(content, payload, info) + output = content.dup + layout = layouts[document.data["layout"].to_s] + validate_layout(layout) + + used = Set.new([layout]) + + # Reset the payload layout data to ensure it starts fresh for each page. + payload["layout"] = nil + + while layout + output = render_layout(output, layout, info) + add_regenerator_dependencies(layout) + + next unless (layout = site.layouts[layout.data["layout"]]) + break if used.include?(layout) + + used << layout + end + output + end + + private + + # Checks if the layout specified in the document actually exists + # + # layout - the layout to check + # Returns nothing + def validate_layout(layout) + return unless invalid_layout?(layout) + + Jekyll.logger.warn "Build Warning:", "Layout '#{document.data["layout"]}' requested " \ + "in #{document.relative_path} does not exist." + end + + # Render layout content into document.output + # + # Returns String rendered content + def render_layout(output, layout, info) + payload["content"] = output + payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {}) + + render_liquid( + layout.content, + payload, + info, + layout.path + ) + end + + def add_regenerator_dependencies(layout) + return unless document.write? + + site.regenerator.add_dependency( + site.in_source_dir(document.path), + layout.path + ) + end + + # Set page content to payload and assign pager if document has one. + # + # Returns nothing + def assign_pages! + payload["page"] = document.to_liquid + payload["paginator"] = (document.pager.to_liquid if document.respond_to?(:pager)) + end + + # Set related posts to payload if document is a post. + # + # Returns nothing + def assign_current_document! + payload["site"].current_document = document + end + + # Set highlighter prefix and suffix + # + # Returns nothing + def assign_highlighter_options! + payload["highlighter_prefix"] = converters.first.highlighter_prefix + payload["highlighter_suffix"] = converters.first.highlighter_suffix + end + + def assign_layout_data! + layout = layouts[document.data["layout"]] + payload["layout"] = Utils.deep_merge_hashes(layout.data, payload["layout"] || {}) if layout + end + + def permalink_ext + document_permalink = document.permalink + if document_permalink && !document_permalink.end_with?("/") + permalink_ext = File.extname(document_permalink) + permalink_ext unless permalink_ext.empty? + end + end + + def converter_output_ext + if output_exts.size == 1 + output_exts.last + else + output_exts[-2] + end + end + + def output_exts + @output_exts ||= converters.map do |c| + c.output_ext(document.extname) + end.tap(&:compact!) + end + + def liquid_options + @liquid_options ||= site.config["liquid"] + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb new file mode 100644 index 0000000..adec4cc --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb @@ -0,0 +1,576 @@ +# frozen_string_literal: true + +module Jekyll + class Site + attr_accessor :baseurl, :converters, :data, :drafts, :exclude, + :file_read_opts, :future, :gems, :generators, :highlighter, + :include, :inclusions, :keep_files, :layouts, :limit_posts, + :lsi, :pages, :permalink_style, :plugin_manager, :plugins, + :reader, :safe, :show_drafts, :static_files, :theme, :time, + :unpublished + + attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths, + :liquid_renderer, :profiler, :regenerator, :source + + # Public: Initialize a new Site. + # + # config - A Hash containing site configuration details. + def initialize(config) + # Source and destination may not be changed after the site has been created. + @source = File.expand_path(config["source"]).freeze + @dest = File.expand_path(config["destination"]).freeze + + self.config = config + + @cache_dir = in_source_dir(config["cache_dir"]) + @filter_cache = {} + + @reader = Reader.new(self) + @profiler = Profiler.new(self) + @regenerator = Regenerator.new(self) + @liquid_renderer = LiquidRenderer.new(self) + + Jekyll.sites << self + + reset + setup + + Jekyll::Hooks.trigger :site, :after_init, self + end + + # Public: Set the site's configuration. This handles side-effects caused by + # changing values in the configuration. + # + # config - a Jekyll::Configuration, containing the new configuration. + # + # Returns the new configuration. + def config=(config) + @config = config.clone + + %w(safe lsi highlighter baseurl exclude include future unpublished + show_drafts limit_posts keep_files).each do |opt| + send(:"#{opt}=", config[opt]) + end + + # keep using `gems` to avoid breaking change + self.gems = config["plugins"] + + configure_cache + configure_plugins + configure_theme + configure_include_paths + configure_file_read_opts + + self.permalink_style = config["permalink"].to_sym + + # Read in a _config.yml from the current theme-gem at the very end. + @config = load_theme_configuration(config) if theme + @config + end + + # Public: Read, process, and write this Site to output. + # + # Returns nothing. + def process + return profiler.profile_process if config["profile"] + + reset + read + generate + render + cleanup + write + end + + def print_stats + Jekyll.logger.info @liquid_renderer.stats_table + end + + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength + # + # Reset Site details. + # + # Returns nothing + def reset + self.time = if config["time"] + Utils.parse_date(config["time"].to_s, "Invalid time in _config.yml.") + else + Time.now + end + self.layouts = {} + self.inclusions = {} + self.pages = [] + self.static_files = [] + self.data = {} + @post_attr_hash = {} + @site_data = nil + @collections = nil + @documents = nil + @docs_to_write = nil + @regenerator.clear_cache + @liquid_renderer.reset + @site_cleaner = nil + frontmatter_defaults.reset + + raise ArgumentError, "limit_posts must be a non-negative number" if limit_posts.negative? + + Jekyll::Cache.clear_if_config_changed config + Jekyll::Hooks.trigger :site, :after_reset, self + nil + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/AbcSize + + # Load necessary libraries, plugins, converters, and generators. + # + # Returns nothing. + def setup + ensure_not_in_dest + + plugin_manager.conscientious_require + + self.converters = instantiate_subclasses(Jekyll::Converter) + self.generators = instantiate_subclasses(Jekyll::Generator) + end + + # Check that the destination dir isn't the source dir or a directory + # parent to the source dir. + def ensure_not_in_dest + dest_pathname = Pathname.new(dest) + Pathname.new(source).ascend do |path| + if path == dest_pathname + raise Errors::FatalException, + "Destination directory cannot be or contain the Source directory." + end + end + end + + # The list of collections and their corresponding Jekyll::Collection instances. + # If config['collections'] is set, a new instance is created + # for each item in the collection, a new hash is returned otherwise. + # + # Returns a Hash containing collection name-to-instance pairs. + def collections + @collections ||= collection_names.each_with_object({}) do |name, hsh| + hsh[name] = Jekyll::Collection.new(self, name) + end + end + + # The list of collection names. + # + # Returns an array of collection names from the configuration, + # or an empty array if the `collections` key is not set. + def collection_names + case config["collections"] + when Hash + config["collections"].keys + when Array + config["collections"] + when nil + [] + else + raise ArgumentError, "Your `collections` key must be a hash or an array." + end + end + + # Read Site data from disk and load it into internal data structures. + # + # Returns nothing. + def read + reader.read + limit_posts! + Jekyll::Hooks.trigger :site, :post_read, self + nil + end + + # Run each of the Generators. + # + # Returns nothing. + def generate + generators.each do |generator| + start = Time.now + generator.generate(self) + Jekyll.logger.debug "Generating:", + "#{generator.class} finished in #{Time.now - start} seconds." + end + nil + end + + # Render the site to the destination. + # + # Returns nothing. + def render + relative_permalinks_are_deprecated + + payload = site_payload + + Jekyll::Hooks.trigger :site, :pre_render, self, payload + + render_docs(payload) + render_pages(payload) + + Jekyll::Hooks.trigger :site, :post_render, self, payload + nil + end + + # Remove orphaned files and empty directories in destination. + # + # Returns nothing. + def cleanup + site_cleaner.cleanup! + nil + end + + # Write static files, pages, and posts. + # + # Returns nothing. + def write + Jekyll::Commands::Doctor.conflicting_urls(self) + each_site_file do |item| + item.write(dest) if regenerator.regenerate?(item) + end + regenerator.write_metadata + Jekyll::Hooks.trigger :site, :post_write, self + nil + end + + def posts + collections["posts"] ||= Collection.new(self, "posts") + end + + # Construct a Hash of Posts indexed by the specified Post attribute. + # + # post_attr - The String name of the Post attribute. + # + # Examples + # + # post_attr_hash('categories') + # # => { 'tech' => [, ], + # # 'ruby' => [] } + # + # Returns the Hash: { attr => posts } where + # attr - One of the values for the requested attribute. + # posts - The Array of Posts with the given attr value. + def post_attr_hash(post_attr) + # Build a hash map based on the specified post attribute ( post attr => + # array of posts ) then sort each array in reverse order. + @post_attr_hash[post_attr] ||= begin + hash = Hash.new { |h, key| h[key] = [] } + posts.docs.each do |p| + p.data[post_attr]&.each { |t| hash[t] << p } + end + hash.each_value { |posts| posts.sort!.reverse! } + hash + end + end + + def tags + post_attr_hash("tags") + end + + def categories + post_attr_hash("categories") + end + + # Prepare site data for site payload. The method maintains backward compatibility + # if the key 'data' is already used in _config.yml. + # + # Returns the Hash to be hooked to site.data. + def site_data + @site_data ||= (config["data"] || data) + end + + # The Hash payload containing site-wide data. + # + # Returns the Hash: { "site" => data } where data is a Hash with keys: + # "time" - The Time as specified in the configuration or the + # current time if none was specified. + # "posts" - The Array of Posts, sorted chronologically by post date + # and then title. + # "pages" - The Array of all Pages. + # "html_pages" - The Array of HTML Pages. + # "categories" - The Hash of category values and Posts. + # See Site#post_attr_hash for type info. + # "tags" - The Hash of tag values and Posts. + # See Site#post_attr_hash for type info. + def site_payload + Drops::UnifiedPayloadDrop.new self + end + alias_method :to_liquid, :site_payload + + # Get the implementation class for the given Converter. + # Returns the Converter instance implementing the given Converter. + # klass - The Class of the Converter to fetch. + def find_converter_instance(klass) + @find_converter_instance ||= {} + @find_converter_instance[klass] ||= converters.find do |converter| + converter.instance_of?(klass) + end || \ + raise("No Converters found for #{klass}") + end + + # klass - class or module containing the subclasses. + # Returns array of instances of subclasses of parameter. + # Create array of instances of the subclasses of the class or module + # passed in as argument. + + def instantiate_subclasses(klass) + klass.descendants.select { |c| !safe || c.safe }.tap do |result| + result.sort! + result.map! { |c| c.new(config) } + end + end + + # Warns the user if permanent links are relative to the parent + # directory. As this is a deprecated function of Jekyll. + # + # Returns + def relative_permalinks_are_deprecated + if config["relative_permalinks"] + Jekyll.logger.abort_with "Since v3.0, permalinks for pages " \ + "in subfolders must be relative to the " \ + "site source directory, not the parent " \ + "directory. Check https://jekyllrb.com/docs/upgrading/ " \ + "for more info." + end + end + + # Get the to be written documents + # + # Returns an Array of Documents which should be written + def docs_to_write + documents.select(&:write?) + end + + # Get the to be written static files + # + # Returns an Array of StaticFiles which should be written + def static_files_to_write + static_files.select(&:write?) + end + + # Get all the documents + # + # Returns an Array of all Documents + def documents + collections.each_with_object(Set.new) do |(_, collection), set| + set.merge(collection.docs).merge(collection.files) + end.to_a + end + + def each_site_file + pages.each { |page| yield page } + static_files.each { |file| yield(file) if file.write? } + collections.each_value { |coll| coll.docs.each { |doc| yield(doc) if doc.write? } } + end + + # Returns the FrontmatterDefaults or creates a new FrontmatterDefaults + # if it doesn't already exist. + # + # Returns The FrontmatterDefaults + def frontmatter_defaults + @frontmatter_defaults ||= FrontmatterDefaults.new(self) + end + + # Whether to perform a full rebuild without incremental regeneration + # + # Returns a Boolean: true for a full rebuild, false for normal build + def incremental?(override = {}) + override["incremental"] || config["incremental"] + end + + # Returns the publisher or creates a new publisher if it doesn't + # already exist. + # + # Returns The Publisher + def publisher + @publisher ||= Publisher.new(self) + end + + # Public: Prefix a given path with the source directory. + # + # paths - (optional) path elements to a file or directory within the + # source directory + # + # Returns a path which is prefixed with the source directory. + def in_source_dir(*paths) + paths.reduce(source) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the theme directory. + # + # paths - (optional) path elements to a file or directory within the + # theme directory + # + # Returns a path which is prefixed with the theme root directory. + def in_theme_dir(*paths) + return nil unless theme + + paths.reduce(theme.root) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the destination directory. + # + # paths - (optional) path elements to a file or directory within the + # destination directory + # + # Returns a path which is prefixed with the destination directory. + def in_dest_dir(*paths) + paths.reduce(dest) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: Prefix a given path with the cache directory. + # + # paths - (optional) path elements to a file or directory within the + # cache directory + # + # Returns a path which is prefixed with the cache directory. + def in_cache_dir(*paths) + paths.reduce(cache_dir) do |base, path| + Jekyll.sanitized_path(base, path) + end + end + + # Public: The full path to the directory that houses all the collections registered + # with the current site. + # + # Returns the source directory or the absolute path to the custom collections_dir + def collections_path + dir_str = config["collections_dir"] + @collections_path ||= dir_str.empty? ? source : in_source_dir(dir_str) + end + + # Public + # + # Returns the object as a debug String. + def inspect + "#<#{self.class} @source=#{@source}>" + end + + private + + def load_theme_configuration(config) + return config if config["ignore_theme_config"] == true + + theme_config_file = in_theme_dir("_config.yml") + return config unless File.exist?(theme_config_file) + + # Bail out if the theme_config_file is a symlink file irrespective of safe mode + return config if File.symlink?(theme_config_file) + + theme_config = SafeYAML.load_file(theme_config_file) + return config unless theme_config.is_a?(Hash) + + Jekyll.logger.info "Theme Config file:", theme_config_file + + # theme_config should not be overriding Jekyll's defaults + theme_config.delete_if { |key, _| Configuration::DEFAULTS.key?(key) } + + # Override theme_config with existing config and return the result. + # Additionally ensure we return a `Jekyll::Configuration` instance instead of a Hash. + Utils.deep_merge_hashes(theme_config, config) + .each_with_object(Jekyll::Configuration.new) do |(key, value), conf| + conf[key] = value + end + end + + # Limits the current posts; removes the posts which exceed the limit_posts + # + # Returns nothing + def limit_posts! + if limit_posts.positive? + limit = [posts.docs.length, limit_posts].min + posts.docs = posts.docs[-limit, limit] + end + end + + # Returns the Cleaner or creates a new Cleaner if it doesn't + # already exist. + # + # Returns The Cleaner + def site_cleaner + @site_cleaner ||= Cleaner.new(self) + end + + def hide_cache_dir_from_git + @cache_gitignore_path ||= in_source_dir(config["cache_dir"], ".gitignore") + return if File.exist?(@cache_gitignore_path) + + cache_dir_path = in_source_dir(config["cache_dir"]) + FileUtils.mkdir_p(cache_dir_path) unless File.directory?(cache_dir_path) + + File.open(@cache_gitignore_path, "wb") do |file| + file.puts("# ignore everything in this directory\n*") + end + end + + # Disable Marshaling cache to disk in Safe Mode + def configure_cache + Jekyll::Cache.cache_dir = in_source_dir(config["cache_dir"], "Jekyll/Cache") + if safe || config["disable_disk_cache"] + Jekyll::Cache.disable_disk_cache! + else + hide_cache_dir_from_git + end + end + + def configure_plugins + self.plugin_manager = Jekyll::PluginManager.new(self) + self.plugins = plugin_manager.plugins_path + end + + def configure_theme + self.theme = nil + return if config["theme"].nil? + + self.theme = + if config["theme"].is_a?(String) + Jekyll::Theme.new(config["theme"]) + else + Jekyll.logger.warn "Theme:", "value of 'theme' in config should be String to use " \ + "gem-based themes, but got #{config["theme"].class}" + nil + end + end + + def configure_include_paths + @includes_load_paths = Array(in_source_dir(config["includes_dir"].to_s)) + @includes_load_paths << theme.includes_path if theme&.includes_path + end + + def configure_file_read_opts + self.file_read_opts = {} + file_read_opts[:encoding] = config["encoding"] if config["encoding"] + self.file_read_opts = Jekyll::Utils.merged_file_read_opts(self, {}) + end + + def render_docs(payload) + collections.each_value do |collection| + collection.docs.each do |document| + render_regenerated(document, payload) + end + end + end + + def render_pages(payload) + pages.each do |page| + render_regenerated(page, payload) + end + end + + def render_regenerated(document, payload) + return unless regenerator.regenerate?(document) + + document.renderer.payload = payload + document.output = document.renderer.run + document.trigger_hooks(:post_render) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/static_file.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/static_file.rb new file mode 100644 index 0000000..13479b0 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/static_file.rb @@ -0,0 +1,203 @@ +# frozen_string_literal: true + +module Jekyll + class StaticFile + extend Forwardable + + attr_reader :relative_path, :extname, + :type, # Returns the type of the collection if present, nil otherwise. + :name + + def_delegator :to_liquid, :to_json, :to_json + + class << self + # The cache of last modification times [path] -> mtime. + def mtimes + @mtimes ||= {} + end + + def reset_cache + @mtimes = nil + end + end + + # Initialize a new StaticFile. + # + # site - The Site. + # base - The String path to the . + # dir - The String path between and the file. + # name - The String filename of the file. + # rubocop: disable Metrics/ParameterLists + def initialize(site, base, dir, name, collection = nil) + @site = site + @base = base + @dir = dir + @name = name + @collection = collection + @relative_path = File.join(*[@dir, @name].compact) + @extname = File.extname(@name) + @type = @collection&.label&.to_sym + end + # rubocop: enable Metrics/ParameterLists + + # Returns source file path. + def path + @path ||= if !@collection.nil? && !@site.config["collections_dir"].empty? + File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact) + else + File.join(*[@base, @dir, @name].compact) + end + end + + # Obtain destination path. + # + # dest - The String path to the destination dir. + # + # Returns destination file path. + def destination(dest) + @destination ||= {} + @destination[dest] ||= @site.in_dest_dir(dest, Jekyll::URL.unescape_path(url)) + end + + def destination_rel_dir + if @collection + File.dirname(url) + else + @dir + end + end + + def modified_time + @modified_time ||= File.stat(path).mtime + end + + # Returns last modification time for this file. + def mtime + modified_time.to_i + end + + # Is source path modified? + # + # Returns true if modified since last write. + def modified? + self.class.mtimes[path] != mtime + end + + # Whether to write the file to the filesystem + # + # Returns true unless the defaults for the destination path from + # _config.yml contain `published: false`. + def write? + publishable = defaults.fetch("published", true) + return publishable unless @collection + + publishable && @collection.write? + end + + # Write the static file to the destination directory (if modified). + # + # dest - The String path to the destination dir. + # + # Returns false if the file was not modified since last time (no-op). + def write(dest) + dest_path = destination(dest) + return false if File.exist?(dest_path) && !modified? + + self.class.mtimes[path] = mtime + + FileUtils.mkdir_p(File.dirname(dest_path)) + FileUtils.rm(dest_path) if File.exist?(dest_path) + copy_file(dest_path) + + true + end + + def data + @data ||= @site.frontmatter_defaults.all(relative_path, type) + end + + def to_liquid + @to_liquid ||= Drops::StaticFileDrop.new(self) + end + + # Generate "basename without extension" and strip away any trailing periods. + # NOTE: `String#gsub` removes all trailing periods (in comparison to `String#chomp`) + def basename + @basename ||= File.basename(name, extname).gsub(%r!\.*\z!, "") + end + + def placeholders + { + :collection => @collection.label, + :path => cleaned_relative_path, + :output_ext => "", + :name => basename, + :title => "", + } + end + + # Similar to Jekyll::Document#cleaned_relative_path. + # Generates a relative path with the collection's directory removed when applicable + # and additionally removes any multiple periods in the string. + # + # NOTE: `String#gsub!` removes all trailing periods (in comparison to `String#chomp!`) + # + # Examples: + # When `relative_path` is "_methods/site/my-cool-avatar...png": + # cleaned_relative_path + # # => "/site/my-cool-avatar" + # + # Returns the cleaned relative path of the static file. + def cleaned_relative_path + @cleaned_relative_path ||= begin + cleaned = relative_path[0..-extname.length - 1] + cleaned.gsub!(%r!\.*\z!, "") + cleaned.sub!(@collection.relative_directory, "") if @collection + cleaned + end + end + + # Applies a similar URL-building technique as Jekyll::Document that takes + # the collection's URL template into account. The default URL template can + # be overridden in the collection's configuration in _config.yml. + def url + @url ||= begin + base = if @collection.nil? + cleaned_relative_path + else + Jekyll::URL.new( + :template => @collection.url_template, + :placeholders => placeholders + ) + end.to_s.chomp("/") + base << extname + end + end + + # Returns the front matter defaults defined for the file's URL and/or type + # as defined in _config.yml. + def defaults + @defaults ||= @site.frontmatter_defaults.all url, type + end + + # Returns a debug string on inspecting the static file. + # Includes only the relative path of the object. + def inspect + "#<#{self.class} @relative_path=#{relative_path.inspect}>" + end + + private + + def copy_file(dest_path) + if @site.safe || Jekyll.env == "production" + FileUtils.cp(path, dest_path) + else + FileUtils.copy_entry(path, dest_path) + end + + unless File.symlink?(dest_path) + File.utime(self.class.mtimes[path], self.class.mtimes[path], dest_path) + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb new file mode 100644 index 0000000..10e5a0b --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/stevenson.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Jekyll + class Stevenson < ::Logger + def initialize + formatter = proc do |_, _, _, msg| + msg.to_s + end + super($stdout, :formatter => formatter) + end + + def add(severity, message = nil, progname = nil) + severity ||= UNKNOWN + @logdev = logdevice(severity) + + return true if @logdev.nil? || severity < @level + + progname ||= @progname + if message.nil? + if block_given? + message = yield + else + message = progname + progname = @progname + end + end + @logdev.puts( + format_message(format_severity(severity), Time.now, progname, message) + ) + true + end + + # Log a +WARN+ message + def warn(progname = nil, &block) + add(WARN, nil, progname.yellow, &block) + end + + # Log an +ERROR+ message + def error(progname = nil, &block) + add(ERROR, nil, progname.red, &block) + end + + def close + # No LogDevice in use + end + + private + + def logdevice(severity) + if severity > INFO + $stderr + else + $stdout + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb new file mode 100644 index 0000000..fcea81f --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/highlight.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class HighlightBlock < Liquid::Block + include Liquid::StandardFilters + + # The regular expression syntax checker. Start with the language specifier. + # Follow that by zero or more space separated options that take one of three + # forms: name, name=value, or name="" + # + # is a space-separated list of numbers + SYNTAX = %r!^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$!.freeze + + def initialize(tag_name, markup, tokens) + super + if markup.strip =~ SYNTAX + @lang = Regexp.last_match(1).downcase + @highlight_options = parse_options(Regexp.last_match(2)) + else + raise SyntaxError, <<~MSG + Syntax Error in tag 'highlight' while parsing the following markup: + + #{markup} + + Valid syntax: highlight [linenos] [mark_lines="3 4 5"] + + See https://jekyllrb.com/docs/liquid/tags/#code-snippet-highlighting for more details. + MSG + end + end + + LEADING_OR_TRAILING_LINE_TERMINATORS = %r!\A(\n|\r)+|(\n|\r)+\z!.freeze + + def render(context) + prefix = context["highlighter_prefix"] || "" + suffix = context["highlighter_suffix"] || "" + code = super.to_s.gsub(LEADING_OR_TRAILING_LINE_TERMINATORS, "") + + output = + case context.registers[:site].highlighter + when "rouge" + render_rouge(code) + when "pygments" + render_pygments(code, context) + else + render_codehighlighter(code) + end + + rendered_output = add_code_tag(output) + prefix + rendered_output + suffix + end + + private + + OPTIONS_REGEX = %r!(?:\w="[^"]*"|\w=\w|\w)+!.freeze + + def parse_options(input) + options = {} + return options if input.empty? + + # Split along 3 possible forms -- key="", key=value, or key + input.scan(OPTIONS_REGEX) do |opt| + key, value = opt.split("=") + # If a quoted list, convert to array + if value&.include?('"') + value.delete!('"') + value = value.split + end + options[key.to_sym] = value || true + end + + options[:linenos] = "inline" if options[:linenos] == true + options + end + + def render_pygments(code, _context) + Jekyll.logger.warn "Warning:", "Highlight Tag no longer supports rendering with Pygments." + Jekyll.logger.warn "", "Using the default highlighter, Rouge, instead." + render_rouge(code) + end + + def render_rouge(code) + require "rouge" + formatter = Rouge::Formatters::HTML.new + formatter = line_highlighter_formatter(formatter) if @highlight_options[:mark_lines] + formatter = table_formatter(formatter) if @highlight_options[:linenos] + + lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText + formatter.format(lexer.lex(code)) + end + + def line_highlighter_formatter(formatter) + Rouge::Formatters::HTMLLineHighlighter.new( + formatter, + :highlight_lines => mark_lines + ) + end + + def mark_lines + value = @highlight_options[:mark_lines] + return value.map(&:to_i) if value.is_a?(Array) + + raise SyntaxError, "Syntax Error for mark_lines declaration. Expected a " \ + "double-quoted list of integers." + end + + def table_formatter(formatter) + Rouge::Formatters::HTMLTable.new( + formatter, + :css_class => "highlight", + :gutter_class => "gutter", + :code_class => "code" + ) + end + + def render_codehighlighter(code) + h(code).strip + end + + def add_code_tag(code) + code_attrs = %(class="language-#{@lang.tr("+", "-")}" data-lang="#{@lang}") + %(
#{code.chomp}
) + end + end + end +end + +Liquid::Template.register_tag("highlight", Jekyll::Tags::HighlightBlock) diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb new file mode 100644 index 0000000..6960952 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/include.rb @@ -0,0 +1,275 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class IncludeTag < Liquid::Tag + VALID_SYNTAX = %r! + ([\w-]+)\s*=\s* + (?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w.-]+)) + !x.freeze + VARIABLE_SYNTAX = %r! + (?[^{]*(\{\{\s*[\w\-.]+\s*(\|.*)?\}\}[^\s{}]*)+) + (?.*) + !mx.freeze + + FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze + VALID_FILENAME_CHARS = %r!^[\w/.\-()+~\#@]+$!.freeze + INVALID_SEQUENCES = %r![./]{2,}!.freeze + + def initialize(tag_name, markup, tokens) + super + markup = markup.strip + matched = markup.match(VARIABLE_SYNTAX) + if matched + @file = matched["variable"].strip + @params = matched["params"].strip + else + @file, @params = markup.split(%r!\s+!, 2) + end + validate_params if @params + @tag_name = tag_name + end + + def syntax_example + "{% #{@tag_name} file.ext param='value' param2='value' %}" + end + + def parse_params(context) + params = {} + @params.scan(VALID_SYNTAX) do |key, d_quoted, s_quoted, variable| + value = if d_quoted + d_quoted.include?('\\"') ? d_quoted.gsub('\\"', '"') : d_quoted + elsif s_quoted + s_quoted.include?("\\'") ? s_quoted.gsub("\\'", "'") : s_quoted + elsif variable + context[variable] + end + + params[key] = value + end + params + end + + def validate_file_name(file) + if INVALID_SEQUENCES.match?(file) || !VALID_FILENAME_CHARS.match?(file) + raise ArgumentError, <<~MSG + Invalid syntax for include tag. File contains invalid characters or sequences: + + #{file} + + Valid syntax: + + #{syntax_example} + + MSG + end + end + + def validate_params + unless FULL_VALID_SYNTAX.match?(@params) + raise ArgumentError, <<~MSG + Invalid syntax for include tag: + + #{@params} + + Valid syntax: + + #{syntax_example} + + MSG + end + end + + # Grab file read opts in the context + def file_read_opts(context) + context.registers[:site].file_read_opts + end + + # Render the variable if required + def render_variable(context) + Liquid::Template.parse(@file).render(context) if VARIABLE_SYNTAX.match?(@file) + end + + def tag_includes_dirs(context) + context.registers[:site].includes_load_paths.freeze + end + + def locate_include_file(context, file, safe) + includes_dirs = tag_includes_dirs(context) + includes_dirs.each do |dir| + path = PathManager.join(dir, file) + return path if valid_include_file?(path, dir.to_s, safe) + end + raise IOError, could_not_locate_message(file, includes_dirs, safe) + end + + def render(context) + site = context.registers[:site] + + file = render_variable(context) || @file + validate_file_name(file) + + path = locate_include_file(context, file, site.safe) + return unless path + + add_include_to_dependency(site, path, context) + + partial = load_cached_partial(path, context) + + context.stack do + context["include"] = parse_params(context) if @params + begin + partial.render!(context) + rescue Liquid::Error => e + e.template_name = path + e.markup_context = "included " if e.markup_context.nil? + raise e + end + end + end + + def add_include_to_dependency(site, path, context) + if context.registers[:page]&.key?("path") + site.regenerator.add_dependency( + site.in_source_dir(context.registers[:page]["path"]), + path + ) + end + end + + def load_cached_partial(path, context) + context.registers[:cached_partials] ||= {} + cached_partial = context.registers[:cached_partials] + + if cached_partial.key?(path) + cached_partial[path] + else + unparsed_file = context.registers[:site] + .liquid_renderer + .file(path) + begin + cached_partial[path] = unparsed_file.parse(read_file(path, context)) + rescue Liquid::Error => e + e.template_name = path + e.markup_context = "included " if e.markup_context.nil? + raise e + end + end + end + + def valid_include_file?(path, dir, safe) + !outside_site_source?(path, dir, safe) && File.file?(path) + end + + def outside_site_source?(path, dir, safe) + safe && !realpath_prefixed_with?(path, dir) + end + + def realpath_prefixed_with?(path, dir) + File.exist?(path) && File.realpath(path).start_with?(dir) + rescue StandardError + false + end + + # This method allows to modify the file content by inheriting from the class. + def read_file(file, context) + File.read(file, **file_read_opts(context)) + end + + private + + def could_not_locate_message(file, includes_dirs, safe) + message = "Could not locate the included file '#{file}' in any of #{includes_dirs}. " \ + "Ensure it exists in one of those directories and" + message + if safe + " is not a symlink as those are not allowed in safe mode." + else + ", if it is a symlink, does not point outside your site source." + end + end + end + + # Do not inherit from this class. + # TODO: Merge into the `Jekyll::Tags::IncludeTag` in v5.0 + class OptimizedIncludeTag < IncludeTag + def render(context) + @site ||= context.registers[:site] + + file = render_variable(context) || @file + validate_file_name(file) + + @site.inclusions[file] ||= locate_include_file(file) + inclusion = @site.inclusions[file] + + add_include_to_dependency(inclusion, context) if @site.config["incremental"] + + context.stack do + context["include"] = parse_params(context) if @params + inclusion.render(context) + end + end + + private + + def locate_include_file(file) + @site.includes_load_paths.each do |dir| + path = PathManager.join(dir, file) + return Inclusion.new(@site, dir, file) if valid_include_file?(path, dir) + end + raise IOError, could_not_locate_message(file, @site.includes_load_paths, @site.safe) + end + + def valid_include_file?(path, dir) + File.file?(path) && !outside_scope?(path, dir) + end + + def outside_scope?(path, dir) + @site.safe && !realpath_prefixed_with?(path, dir) + end + + def realpath_prefixed_with?(path, dir) + File.realpath(path).start_with?(dir) + rescue StandardError + false + end + + def add_include_to_dependency(inclusion, context) + page = context.registers[:page] + return unless page&.key?("path") + + absolute_path = \ + if page["collection"] + @site.in_source_dir(@site.config["collections_dir"], page["path"]) + else + @site.in_source_dir(page["path"]) + end + + @site.regenerator.add_dependency(absolute_path, inclusion.path) + end + end + + class IncludeRelativeTag < IncludeTag + def tag_includes_dirs(context) + Array(page_path(context)).freeze + end + + def page_path(context) + page, site = context.registers.values_at(:page, :site) + return site.source unless page + + site.in_source_dir File.dirname(resource_path(page, site)) + end + + private + + def resource_path(page, site) + path = page["path"] + path = File.join(site.config["collections_dir"], path) if page["collection"] + path.delete_suffix("/#excerpt") + end + end + end +end + +Liquid::Template.register_tag("include", Jekyll::Tags::OptimizedIncludeTag) +Liquid::Template.register_tag("include_relative", Jekyll::Tags::IncludeRelativeTag) diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb new file mode 100644 index 0000000..c986b5a --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/link.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class Link < Liquid::Tag + include Jekyll::Filters::URLFilters + + class << self + def tag_name + name.split("::").last.downcase + end + end + + def initialize(tag_name, relative_path, tokens) + super + + @relative_path = relative_path.strip + end + + def render(context) + @context = context + site = context.registers[:site] + relative_path = Liquid::Template.parse(@relative_path).render(context) + relative_path_with_leading_slash = PathManager.join("", relative_path) + + site.each_site_file do |item| + return relative_url(item) if item.relative_path == relative_path + # This takes care of the case for static files that have a leading / + return relative_url(item) if item.relative_path == relative_path_with_leading_slash + end + + raise ArgumentError, <<~MSG + Could not find document '#{relative_path}' in tag '#{self.class.tag_name}'. + + Make sure the document exists and the path is correct. + MSG + end + end + end +end + +Liquid::Template.register_tag(Jekyll::Tags::Link.tag_name, Jekyll::Tags::Link) diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb new file mode 100644 index 0000000..7774d37 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/tags/post_url.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module Jekyll + module Tags + class PostComparer + MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze + + attr_reader :path, :date, :slug, :name + + def initialize(name) + @name = name + + all, @path, @date, @slug = *name.sub(%r!^/!, "").match(MATCHER) + unless all + raise Jekyll::Errors::InvalidPostNameError, + "'#{name}' does not contain valid date and/or title." + end + + basename_pattern = "#{date}-#{Regexp.escape(slug)}\\.[^.]+" + @name_regex = %r!^_posts/#{path}#{basename_pattern}|^#{path}_posts/?#{basename_pattern}! + end + + def post_date + @post_date ||= Utils.parse_date( + date, + "'#{date}' does not contain valid date and/or title." + ) + end + + def ==(other) + other.relative_path.match(@name_regex) + end + + def deprecated_equality(other) + slug == post_slug(other) && + post_date.year == other.date.year && + post_date.month == other.date.month && + post_date.day == other.date.day + end + + private + + # Construct the directory-aware post slug for a Jekyll::Post + # + # other - the Jekyll::Post + # + # Returns the post slug with the subdirectory (relative to _posts) + def post_slug(other) + path = other.basename.split("/")[0...-1].join("/") + if path.nil? || path == "" + other.data["slug"] + else + "#{path}/#{other.data["slug"]}" + end + end + end + + class PostUrl < Liquid::Tag + include Jekyll::Filters::URLFilters + + def initialize(tag_name, post, tokens) + super + @orig_post = post.strip + begin + @post = PostComparer.new(@orig_post) + rescue StandardError => e + raise Jekyll::Errors::PostURLError, <<~MSG + Could not parse name of post "#{@orig_post}" in tag 'post_url'. + Make sure the post exists and the name is correct. + #{e.class}: #{e.message} + MSG + end + end + + def render(context) + @context = context + site = context.registers[:site] + + site.posts.docs.each do |document| + return relative_url(document) if @post == document + end + + # New matching method did not match, fall back to old method + # with deprecation warning if this matches + + site.posts.docs.each do |document| + next unless @post.deprecated_equality document + + Jekyll::Deprecator.deprecation_message( + "A call to '{% post_url #{@post.name} %}' did not match a post using the new " \ + "matching method of checking name (path-date-slug) equality. Please make sure " \ + "that you change this tag to match the post's name exactly." + ) + return relative_url(document) + end + + raise Jekyll::Errors::PostURLError, <<~MSG + Could not find post "#{@orig_post}" in tag 'post_url'. + Make sure the post exists and the name is correct. + MSG + end + end + end +end + +Liquid::Template.register_tag("post_url", Jekyll::Tags::PostUrl) diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme.rb new file mode 100644 index 0000000..a3f2a94 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +module Jekyll + class Theme + extend Forwardable + attr_reader :name + + def_delegator :gemspec, :version, :version + + def initialize(name) + @name = name.downcase.strip + Jekyll.logger.debug "Theme:", name + Jekyll.logger.debug "Theme source:", root + end + + def root + # Must use File.realpath to resolve symlinks created by rbenv + # Otherwise, Jekyll.sanitized path with prepend the unresolved root + @root ||= File.realpath(gemspec.full_gem_path) + rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP + raise "Path #{gemspec.full_gem_path} does not exist, is not accessible or includes " \ + "a symbolic link loop" + end + + # The name of theme directory + def basename + @basename ||= File.basename(root) + end + + def includes_path + @includes_path ||= path_for "_includes" + end + + def layouts_path + @layouts_path ||= path_for "_layouts" + end + + def sass_path + @sass_path ||= path_for "_sass" + end + + def assets_path + @assets_path ||= path_for "assets" + end + + def data_path + @data_path ||= path_for "_data" + end + + def runtime_dependencies + gemspec.runtime_dependencies + end + + private + + def path_for(folder) + path = realpath_for(folder) + path if path && File.directory?(path) + end + + def realpath_for(folder) + # This resolves all symlinks for the theme subfolder and then ensures that the directory + # remains inside the theme root. This prevents the use of symlinks for theme subfolders to + # escape the theme root. + # However, symlinks are allowed to point to other directories within the theme. + Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s))) + rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e + log_realpath_exception(e, folder) + nil + end + + def log_realpath_exception(err, folder) + return if err.is_a?(Errno::ENOENT) + + case err + when Errno::EACCES + Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible." + when Errno::ELOOP + Jekyll.logger.error "Theme error:", "Directory '#{folder}' includes a symbolic link loop." + end + end + + def gemspec + @gemspec ||= Gem::Specification.find_by_name(name) + rescue Gem::LoadError + raise Jekyll::Errors::MissingDependencyException, + "The #{name} theme could not be found." + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb new file mode 100644 index 0000000..b03abbf --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/theme_builder.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +module Jekyll + class ThemeBuilder + SCAFFOLD_DIRECTORIES = %w( + assets _data _layouts _includes _sass + ).freeze + + attr_reader :name, :path, :code_of_conduct + + def initialize(theme_name, opts) + @name = theme_name.to_s.tr(" ", "_").squeeze("_") + @path = Pathname.new(File.expand_path(name, Dir.pwd)) + @code_of_conduct = !!opts["code_of_conduct"] + end + + def create! + create_directories + create_starter_files + create_gemspec + create_accessories + initialize_git_repo + end + + def user_name + @user_name ||= `git config user.name`.chomp + end + + def user_email + @user_email ||= `git config user.email`.chomp + end + + private + + def root + @root ||= Pathname.new(File.expand_path("../", __dir__)) + end + + def template_file(filename) + [ + root.join("theme_template", "#{filename}.erb"), + root.join("theme_template", filename.to_s), + ].find(&:exist?) + end + + def template(filename) + erb.render(template_file(filename).read) + end + + def erb + @erb ||= ERBRenderer.new(self) + end + + def mkdir_p(directories) + Array(directories).each do |directory| + full_path = path.join(directory) + Jekyll.logger.info "create", full_path.to_s + FileUtils.mkdir_p(full_path) + end + end + + def write_file(filename, contents) + full_path = path.join(filename) + Jekyll.logger.info "create", full_path.to_s + File.write(full_path, contents) + end + + def create_directories + mkdir_p(SCAFFOLD_DIRECTORIES) + end + + def create_starter_files + %w(page post default).each do |layout| + write_file("_layouts/#{layout}.html", template("_layouts/#{layout}.html")) + end + end + + def create_gemspec + write_file("Gemfile", template("Gemfile")) + write_file("#{name}.gemspec", template("theme.gemspec")) + end + + def create_accessories + accessories = %w(README.md LICENSE.txt) + accessories << "CODE_OF_CONDUCT.md" if code_of_conduct + accessories.each do |filename| + write_file(filename, template(filename)) + end + end + + def initialize_git_repo + Jekyll.logger.info "initialize", path.join(".git").to_s + Dir.chdir(path.to_s) { `git init` } + write_file(".gitignore", template("gitignore")) + end + + class ERBRenderer + extend Forwardable + + def_delegator :@theme_builder, :name, :theme_name + def_delegator :@theme_builder, :user_name, :user_name + def_delegator :@theme_builder, :user_email, :user_email + + def initialize(theme_builder) + @theme_builder = theme_builder + end + + def jekyll_version_with_minor + Jekyll::VERSION.split(".").take(2).join(".") + end + + def theme_directories + SCAFFOLD_DIRECTORIES + end + + def render(contents) + ERB.new(contents).result binding + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/url.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/url.rb new file mode 100644 index 0000000..aeb2ac0 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/url.rb @@ -0,0 +1,167 @@ +# frozen_string_literal: true + +# Public: Methods that generate a URL for a resource such as a Post or a Page. +# +# Examples +# +# URL.new({ +# :template => /:categories/:title.html", +# :placeholders => {:categories => "ruby", :title => "something"} +# }).to_s +# +module Jekyll + class URL + # options - One of :permalink or :template must be supplied. + # :template - The String used as template for URL generation, + # for example "/:path/:basename:output_ext", where + # a placeholder is prefixed with a colon. + # :placeholders - A hash containing the placeholders which will be + # replaced when used inside the template. E.g. + # { "year" => Time.now.strftime("%Y") } would replace + # the placeholder ":year" with the current year. + # :permalink - If supplied, no URL will be generated from the + # template. Instead, the given permalink will be + # used as URL. + def initialize(options) + @template = options[:template] + @placeholders = options[:placeholders] || {} + @permalink = options[:permalink] + + if (@template || @permalink).nil? + raise ArgumentError, "One of :template or :permalink must be supplied." + end + end + + # The generated relative URL of the resource + # + # Returns the String URL + def to_s + sanitize_url(generated_permalink || generated_url) + end + + # Generates a URL from the permalink + # + # Returns the _unsanitized String URL + def generated_permalink + (@generated_permalink ||= generate_url(@permalink)) if @permalink + end + + # Generates a URL from the template + # + # Returns the unsanitized String URL + def generated_url + @generated_url ||= generate_url(@template) + end + + # Internal: Generate the URL by replacing all placeholders with their + # respective values in the given template + # + # Returns the unsanitized String URL + def generate_url(template) + if @placeholders.is_a? Drops::UrlDrop + generate_url_from_drop(template) + else + generate_url_from_hash(template) + end + end + + def generate_url_from_hash(template) + @placeholders.inject(template) do |result, token| + break result if result.index(":").nil? + + if token.last.nil? + # Remove leading "/" to avoid generating urls with `//` + result.gsub("/:#{token.first}", "") + else + result.gsub(":#{token.first}", self.class.escape_path(token.last)) + end + end + end + + # We include underscores in keys to allow for 'i_month' and so forth. + # This poses a problem for keys which are followed by an underscore + # but the underscore is not part of the key, e.g. '/:month_:day'. + # That should be :month and :day, but our key extraction regexp isn't + # smart enough to know that so we have to make it an explicit + # possibility. + def possible_keys(key) + if key.end_with?("_") + [key, key.chomp("_")] + else + [key] + end + end + + def generate_url_from_drop(template) + template.gsub(%r!:([a-z_]+)!) do |match| + name = Regexp.last_match(1) + pool = name.end_with?("_") ? [name, name.chomp!("_")] : [name] + + winner = pool.find { |key| @placeholders.key?(key) } + if winner.nil? + raise NoMethodError, + "The URL template doesn't have #{pool.join(" or ")} keys. " \ + "Check your permalink template!" + end + + value = @placeholders[winner] + value = "" if value.nil? + replacement = self.class.escape_path(value) + + match.sub!(":#{winner}", replacement) + end + end + + # Returns a sanitized String URL, stripping "../../" and multiples of "/", + # as well as the beginning "/" so we can enforce and ensure it. + def sanitize_url(str) + "/#{str}".gsub("..", "/").tap do |result| + result.gsub!("./", "") + result.squeeze!("/") + end + end + + # Escapes a path to be a valid URL path segment + # + # path - The path to be escaped. + # + # Examples: + # + # URL.escape_path("/a b") + # # => "/a%20b" + # + # Returns the escaped path. + def self.escape_path(path) + return path if path.empty? || %r!^[a-zA-Z0-9./-]+$!.match?(path) + + # Because URI.escape doesn't escape "?", "[" and "]" by default, + # specify unsafe string (except unreserved, sub-delims, ":", "@" and "/"). + # + # URI path segment is defined in RFC 3986 as follows: + # segment = *pchar + # pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + # pct-encoded = "%" HEXDIG HEXDIG + # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + # / "*" / "+" / "," / ";" / "=" + Addressable::URI.encode(path).encode("utf-8").sub("#", "%23") + end + + # Unescapes a URL path segment + # + # path - The path to be unescaped. + # + # Examples: + # + # URL.unescape_path("/a%20b") + # # => "/a b" + # + # Returns the unescaped path. + def self.unescape_path(path) + path = path.encode("utf-8") + return path unless path.include?("%") + + Addressable::URI.unencode(path) + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils.rb new file mode 100644 index 0000000..2a96527 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils.rb @@ -0,0 +1,371 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + extend self + autoload :Ansi, "jekyll/utils/ansi" + autoload :Exec, "jekyll/utils/exec" + autoload :Internet, "jekyll/utils/internet" + autoload :Platforms, "jekyll/utils/platforms" + autoload :ThreadEvent, "jekyll/utils/thread_event" + autoload :WinTZ, "jekyll/utils/win_tz" + + # Constants for use in #slugify + SLUGIFY_MODES = %w(raw default pretty ascii latin).freeze + SLUGIFY_RAW_REGEXP = Regexp.new('\\s+').freeze + SLUGIFY_DEFAULT_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}]+").freeze + SLUGIFY_PRETTY_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}._~!$&'()+,;=@]+").freeze + SLUGIFY_ASCII_REGEXP = Regexp.new("[^[A-Za-z0-9]]+").freeze + + # Takes a slug and turns it into a simple title. + def titleize_slug(slug) + slug.split("-").map!(&:capitalize).join(" ") + end + + # Non-destructive version of deep_merge_hashes! See that method. + # + # Returns the merged hashes. + def deep_merge_hashes(master_hash, other_hash) + deep_merge_hashes!(master_hash.dup, other_hash) + end + + # Merges a master hash with another hash, recursively. + # + # master_hash - the "parent" hash whose values will be overridden + # other_hash - the other hash whose values will be persisted after the merge + # + # This code was lovingly stolen from some random gem: + # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html + # + # Thanks to whoever made it. + def deep_merge_hashes!(target, overwrite) + merge_values(target, overwrite) + merge_default_proc(target, overwrite) + duplicate_frozen_values(target) + + target + end + + def mergable?(value) + value.is_a?(Hash) || value.is_a?(Drops::Drop) + end + + def duplicable?(obj) + case obj + when nil, false, true, Symbol, Numeric + false + else + true + end + end + + # Read array from the supplied hash favouring the singular key + # and then the plural key, and handling any nil entries. + # + # hash - the hash to read from + # singular_key - the singular key + # plural_key - the plural key + # + # Returns an array + def pluralized_array_from_hash(hash, singular_key, plural_key) + array = [] + value = value_from_singular_key(hash, singular_key) + value ||= value_from_plural_key(hash, plural_key) + + array << value + array.flatten! + array.compact! + array + end + + def value_from_singular_key(hash, key) + hash[key] if hash.key?(key) || (hash.default_proc && hash[key]) + end + + def value_from_plural_key(hash, key) + if hash.key?(key) || (hash.default_proc && hash[key]) + val = hash[key] + case val + when String + val.split + when Array + val.compact + end + end + end + + def transform_keys(hash) + result = {} + hash.each_key do |key| + result[yield(key)] = hash[key] + end + result + end + + # Apply #to_sym to all keys in the hash + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with symbolized keys + def symbolize_hash_keys(hash) + transform_keys(hash) { |key| key.to_sym rescue key } + end + + # Apply #to_s to all keys in the Hash + # + # hash - the hash to which to apply this transformation + # + # Returns a new hash with stringified keys + def stringify_hash_keys(hash) + transform_keys(hash) { |key| key.to_s rescue key } + end + + # Parse a date/time and throw an error if invalid + # + # input - the date/time to parse + # msg - (optional) the error message to show the user + # + # Returns the parsed date if successful, throws a FatalException + # if not + def parse_date(input, msg = "Input could not be parsed.") + @parse_date_cache ||= {} + @parse_date_cache[input] ||= Time.parse(input).localtime + rescue ArgumentError + raise Errors::InvalidDateError, "Invalid date '#{input}': #{msg}" + end + + # Determines whether a given file has + # + # Returns true if the YAML front matter is present. + # rubocop: disable Naming/PredicateName + def has_yaml_header?(file) + File.open(file, "rb", &:readline).match? %r!\A---\s*\r?\n! + rescue EOFError + false + end + + # Determine whether the given content string contains Liquid Tags or Variables + # + # Returns true is the string contains sequences of `{%` or `{{` + def has_liquid_construct?(content) + return false if content.nil? || content.empty? + + content.include?("{%") || content.include?("{{") + end + # rubocop: enable Naming/PredicateName + + # Slugify a filename or title. + # + # string - the filename or title to slugify + # mode - how string is slugified + # cased - whether to replace all uppercase letters with their + # lowercase counterparts + # + # When mode is "none", return the given string. + # + # When mode is "raw", return the given string, + # with every sequence of spaces characters replaced with a hyphen. + # + # When mode is "default" or nil, non-alphabetic characters are + # replaced with a hyphen too. + # + # When mode is "pretty", some non-alphabetic characters (._~!$&'()+,;=@) + # are not replaced with hyphen. + # + # When mode is "ascii", some everything else except ASCII characters + # a-z (lowercase), A-Z (uppercase) and 0-9 (numbers) are not replaced with hyphen. + # + # When mode is "latin", the input string is first preprocessed so that + # any letters with accents are replaced with the plain letter. Afterwards, + # it follows the "default" mode of operation. + # + # If cased is true, all uppercase letters in the result string are + # replaced with their lowercase counterparts. + # + # Examples: + # slugify("The _config.yml file") + # # => "the-config-yml-file" + # + # slugify("The _config.yml file", "pretty") + # # => "the-_config.yml-file" + # + # slugify("The _config.yml file", "pretty", true) + # # => "The-_config.yml file" + # + # slugify("The _config.yml file", "ascii") + # # => "the-config-yml-file" + # + # slugify("The _config.yml file", "latin") + # # => "the-config-yml-file" + # + # Returns the slugified string. + def slugify(string, mode: nil, cased: false) + mode ||= "default" + return nil if string.nil? + + unless SLUGIFY_MODES.include?(mode) + return cased ? string : string.downcase + end + + # Drop accent marks from latin characters. Everything else turns to ? + if mode == "latin" + I18n.config.available_locales = :en if I18n.config.available_locales.empty? + string = I18n.transliterate(string) + end + + slug = replace_character_sequence_with_hyphen(string, :mode => mode) + + # Remove leading/trailing hyphen + slug.gsub!(%r!^-|-$!i, "") + + slug.downcase! unless cased + Jekyll.logger.warn("Warning:", "Empty `slug` generated for '#{string}'.") if slug.empty? + slug + end + + # Add an appropriate suffix to template so that it matches the specified + # permalink style. + # + # template - permalink template without trailing slash or file extension + # permalink_style - permalink style, either built-in or custom + # + # The returned permalink template will use the same ending style as + # specified in permalink_style. For example, if permalink_style contains a + # trailing slash (or is :pretty, which indirectly has a trailing slash), + # then so will the returned template. If permalink_style has a trailing + # ":output_ext" (or is :none, :date, or :ordinal) then so will the returned + # template. Otherwise, template will be returned without modification. + # + # Examples: + # add_permalink_suffix("/:basename", :pretty) + # # => "/:basename/" + # + # add_permalink_suffix("/:basename", :date) + # # => "/:basename:output_ext" + # + # add_permalink_suffix("/:basename", "/:year/:month/:title/") + # # => "/:basename/" + # + # add_permalink_suffix("/:basename", "/:year/:month/:title") + # # => "/:basename" + # + # Returns the updated permalink template + def add_permalink_suffix(template, permalink_style) + template = template.dup + + case permalink_style + when :pretty + template << "/" + when :date, :ordinal, :none + template << ":output_ext" + else + template << "/" if permalink_style.to_s.end_with?("/") + template << ":output_ext" if permalink_style.to_s.end_with?(":output_ext") + end + + template + end + + # Work the same way as Dir.glob but separating the input into two parts + # ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act + # as a pattern. + # + # For example, Dir.glob("path[/*") always returns an empty array, + # because the method fails to find the closing pattern to '[' which is ']' + # + # Examples: + # safe_glob("path[", "*") + # # => ["path[/file1", "path[/file2"] + # + # safe_glob("path", "*", File::FNM_DOTMATCH) + # # => ["path/.", "path/..", "path/file1"] + # + # safe_glob("path", ["**", "*"]) + # # => ["path[/file1", "path[/folder/file2"] + # + # dir - the dir where glob will be executed under + # (the dir will be included to each result) + # patterns - the patterns (or the pattern) which will be applied under the dir + # flags - the flags which will be applied to the pattern + # + # Returns matched paths + def safe_glob(dir, patterns, flags = 0) + return [] unless Dir.exist?(dir) + + pattern = File.join(Array(patterns)) + return [dir] if pattern.empty? + + Dir.chdir(dir) do + Dir.glob(pattern, flags).map { |f| File.join(dir, f) } + end + end + + # Returns merged option hash for File.read of self.site (if exists) + # and a given param + def merged_file_read_opts(site, opts) + merged = (site ? site.file_read_opts : {}).merge(opts) + + # always use BOM when reading UTF-encoded files + if merged[:encoding]&.downcase&.start_with?("utf-") + merged[:encoding] = "bom|#{merged[:encoding]}" + end + if merged["encoding"]&.downcase&.start_with?("utf-") + merged["encoding"] = "bom|#{merged["encoding"]}" + end + + merged + end + + private + + def merge_values(target, overwrite) + target.merge!(overwrite) do |_key, old_val, new_val| + if new_val.nil? + old_val + elsif mergable?(old_val) && mergable?(new_val) + deep_merge_hashes(old_val, new_val) + else + new_val + end + end + end + + def merge_default_proc(target, overwrite) + if target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil? + target.default_proc = overwrite.default_proc + end + end + + def duplicate_frozen_values(target) + target.each do |key, val| + target[key] = val.dup if val.frozen? && duplicable?(val) + end + end + + # Replace each character sequence with a hyphen. + # + # See Utils#slugify for a description of the character sequence specified + # by each mode. + def replace_character_sequence_with_hyphen(string, mode: "default") + replaceable_char = + case mode + when "raw" + SLUGIFY_RAW_REGEXP + when "pretty" + # "._~!$&'()+,;=@" is human readable (not URI-escaped) in URL + # and is allowed in both extN and NTFS. + SLUGIFY_PRETTY_REGEXP + when "ascii" + # For web servers not being able to handle Unicode, the safe + # method is to ditch anything else but latin letters and numeric + # digits. + SLUGIFY_ASCII_REGEXP + else + SLUGIFY_DEFAULT_REGEXP + end + + # Strip according to the mode + string.gsub(replaceable_char, "-") + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb new file mode 100644 index 0000000..00d1b1d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/ansi.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module Ansi + extend self + + ESCAPE = format("%c", 27) + MATCH = %r!#{ESCAPE}\[(?:\d+)(?:;\d+)*(j|k|m|s|u|A|B|G)|\e\(B\e\[m!ix.freeze + COLORS = { + :red => 31, + :green => 32, + :black => 30, + :magenta => 35, + :yellow => 33, + :white => 37, + :blue => 34, + :cyan => 36, + }.freeze + + # Strip ANSI from the current string. It also strips cursor stuff, + # well some of it, and it also strips some other stuff that a lot of + # the other ANSI strippers don't. + + def strip(str) + str.gsub MATCH, "" + end + + # + + def has?(str) + !!(str =~ MATCH) + end + + # Reset the color back to the default color so that you do not leak any + # colors when you move onto the next line. This is probably normally + # used as part of a wrapper so that we don't leak colors. + + def reset(str = "") + @ansi_reset ||= format("%c[0m", 27) + "#{@ansi_reset}#{str}" + end + + # SEE: `self::COLORS` for a list of methods. They are mostly + # standard base colors supported by pretty much any xterm-color, we do + # not need more than the base colors so we do not include them. + # Actually... if I'm honest we don't even need most of the + # base colors. + + COLORS.each do |color, num| + define_method color do |str| + "#{format("%c", 27)}[#{num}m#{str}#{reset}" + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb new file mode 100644 index 0000000..5838ecb --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/exec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "open3" + +module Jekyll + module Utils + module Exec + extend self + + # Runs a program in a sub-shell. + # + # *args - a list of strings containing the program name and arguments + # + # Returns a Process::Status and a String of output in an array in + # that order. + def run(*args) + stdin, stdout, stderr, process = Open3.popen3(*args) + out = stdout.read.strip + err = stderr.read.strip + + [stdin, stdout, stderr].each(&:close) + [process.value, out + err] + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb new file mode 100644 index 0000000..945267f --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/internet.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module Internet + # Public: Determine whether the present device has a connection to + # the Internet. This allows plugin writers which require the outside + # world to have a neat fallback mechanism for offline building. + # + # Example: + # if Internet.connected? + # Typhoeus.get("https://pages.github.com/versions.json") + # else + # Jekyll.logger.warn "Warning:", "Version check has been disabled." + # Jekyll.logger.warn "", "Connect to the Internet to enable it." + # nil + # end + # + # Returns true if a DNS call can successfully be made, or false if not. + + module_function + + def connected? + !dns("example.com").nil? + end + + def dns(domain) + require "resolv" + Resolv::DNS.open do |resolver| + resolver.getaddress(domain) + end + rescue Resolv::ResolvError, Resolv::ResolvTimeout + nil + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb new file mode 100644 index 0000000..a6c6da9 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/platforms.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module Platforms + extend self + + def jruby? + RUBY_ENGINE == "jruby" + end + + def mri? + RUBY_ENGINE == "ruby" + end + + def windows? + vanilla_windows? || bash_on_windows? + end + + # Not a Windows Subsystem for Linux (WSL) + def vanilla_windows? + rbconfig_host.match?(%r!mswin|mingw|cygwin!) && proc_version.empty? + end + alias_method :really_windows?, :vanilla_windows? + + # Determine if Windows Subsystem for Linux (WSL) + def bash_on_windows? + linux_os? && microsoft_proc_version? + end + + def linux? + linux_os? && !microsoft_proc_version? + end + + def osx? + rbconfig_host.match?(%r!darwin|mac os!) + end + + def unix? + rbconfig_host.match?(%r!solaris|bsd!) + end + + private + + def proc_version + @proc_version ||= \ + begin + File.read("/proc/version").downcase + rescue Errno::ENOENT, Errno::EACCES + "" + end + end + + def rbconfig_host + @rbconfig_host ||= RbConfig::CONFIG["host_os"].downcase + end + + def linux_os? + rbconfig_host.include?("linux") + end + + def microsoft_proc_version? + proc_version.include?("microsoft") + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb new file mode 100644 index 0000000..801022e --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/thread_event.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + # Based on the pattern and code from + # https://emptysqua.re/blog/an-event-synchronization-primitive-for-ruby/ + class ThreadEvent + attr_reader :flag + + def initialize + @lock = Mutex.new + @cond = ConditionVariable.new + @flag = false + end + + def set + @lock.synchronize do + yield if block_given? + @flag = true + @cond.broadcast + end + end + + def wait + @lock.synchronize do + @cond.wait(@lock) unless @flag + end + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb new file mode 100644 index 0000000..ad277d3 --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/utils/win_tz.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Jekyll + module Utils + module WinTZ + extend self + + # Public: Calculate the Timezone for Windows when the config file has a defined + # 'timezone' key. + # + # timezone - the IANA Time Zone specified in "_config.yml" + # + # Returns a string that ultimately re-defines ENV["TZ"] in Windows + def calculate(timezone, now = Time.now) + External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo) + tz = TZInfo::Timezone.get(timezone) + + # + # Use period_for_utc and utc_total_offset instead of + # period_for and observed_utc_offset for compatibility with tzinfo v1. + offset = tz.period_for_utc(now.getutc).utc_total_offset + + # + # POSIX style definition reverses the offset sign. + # e.g. Eastern Standard Time (EST) that is 5Hrs. to the 'west' of Prime Meridian + # is denoted as: + # EST+5 (or) EST+05:00 + # Reference: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + sign = offset.positive? ? "-" : "+" + + rational_hours = offset.abs.to_r / 3600 + hours = rational_hours.to_i + minutes = ((rational_hours - hours) * 60).to_i + + # + # Format the hours and minutes as two-digit numbers. + time = format("%02d:%02d", :hours => hours, :minutes => minutes) + + Jekyll.logger.debug "Timezone:", "#{timezone} #{sign}#{time}" + # + # Note: The 3-letter-word below doesn't have a particular significance. + "WTZ#{sign}#{time}" + end + end + end +end diff --git a/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/version.rb b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/version.rb new file mode 100644 index 0000000..eff0d1d --- /dev/null +++ b/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Jekyll + VERSION = "4.4.1" +end -- cgit v1.2.3