summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb
diff options
context:
space:
mode:
authorBenjamin Sanders <ben@Benjamins-MacBook-Pro.local>2025-10-11 10:34:24 -0400
committerBenjamin Sanders <ben@Benjamins-MacBook-Pro.local>2025-10-11 10:34:24 -0400
commit5571dc766e2143e39762ff0b47c41d1c2e154f4c (patch)
treef4f124d314a7e76c04484515aa0fd1f2e271a601 /vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb
parent359f3309c97fc894b63e0a295c76ab298504d635 (diff)
Vendor bundled gems for deployment
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/jekyll-4.4.1/lib/jekyll/site.rb576
1 files changed, 576 insertions, 0 deletions
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' => [<Post A>, <Post B>],
+ # # 'ruby' => [<Post B>] }
+ #
+ # 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