lib/jekyll/algolia/configurator.rb
# frozen_string_literal: true module Jekyll module Algolia # Single source of truth for access to configuration variables module Configurator include Jekyll::Algolia @config = {} # Algolia default values ALGOLIA_DEFAULTS = { 'extensions_to_index' => nil, 'files_to_exclude' => nil, 'nodes_to_index' => 'p', 'indexing_batch_size' => 1000, 'max_record_size' => 10_000, 'settings' => { # Searchable attributes 'searchableAttributes' => %w[ title headings unordered(content) collection,categories,tags ], # Custom Ranking 'customRanking' => [ 'desc(date)', 'desc(custom_ranking.heading)', 'asc(custom_ranking.position)' ], 'unretrievableAttributes' => [ 'custom_ranking' ], # Highlight 'attributesToHighlight' => %w[ title headings content html collection categories tags ], 'highlightPreTag' => '<em class="ais-Highlight">', 'highlightPostTag' => '</em>', # Snippet 'attributesToSnippet' => %w[ content:55 ], 'snippetEllipsisText' => '…', # Distinct 'distinct' => true, 'attributeForDistinct' => 'url', # Faceting 'attributesForFaceting' => %w[ type searchable(collection) searchable(categories) searchable(tags) searchable(title) ] } }.freeze # Public: Init the configurator with the Jekyll config # # config - The config passed by the `jekyll algolia` command. Default to # the default Jekyll config def self.init(config = nil) # Use the default Jekyll configuration if none specified. Silence the # warning about no config set Logger.silent { config = Jekyll.configuration } if config.nil? @config = config @config = disable_other_plugins(@config) self end # Public: Access to the global configuration object # # This is a method around @config so we can mock it in the tests def self.config @config end # Public: Get the value of a specific Jekyll configuration option # # key - Key to read # # Returns the value of this configuration option, nil otherwise def self.get(key) config[key] end # Public: Get the value of a specific Algolia configuration option, or # revert to the default value otherwise # # key - Algolia key to read # # Returns the value of this option, or the default value def self.algolia(key) config = get('algolia') || {} value = config[key] || ALGOLIA_DEFAULTS[key] # No value found but we have a method to define the default value if value.nil? && respond_to?("default_#{key}") value = send("default_#{key}") end value end # Public: Return the application id # # Will first try to read the ENV variable, and fallback to the one # configured in Jekyll config def self.application_id ENV['ALGOLIA_APPLICATION_ID'] || algolia('application_id') end # Public: Return the api key # # Will first try to read the ENV variable. Will otherwise try to read the # _algolia_api_key file in the Jekyll folder def self.api_key # Alway taking the ENV variable first return ENV['ALGOLIA_API_KEY'] if ENV['ALGOLIA_API_KEY'] # Reading from file on disk otherwise source_dir = get('source') if source_dir api_key_file = File.join(source_dir, '_algolia_api_key') if File.exist?(api_key_file) && File.size(api_key_file).positive? return File.open(api_key_file).read.strip end end nil end # Public: Return the index name # # Will first try to read the ENV variable, and fallback to the one # configured in Jekyll config def self.index_name ENV['ALGOLIA_INDEX_NAME'] || algolia('index_name') end # Public: Return the name of the index used to store the object ids def self.index_object_ids_name "#{index_name}_object_ids" end # Public: Get the index settings # # This will be a merge of default settings and the one defined in the # _config.yml file def self.settings user_settings = algolia('settings') || {} ALGOLIA_DEFAULTS['settings'].merge(user_settings) end # Public: Check that all credentials are set # # Returns true if everything is ok, false otherwise. Will display helpful # error messages for each missing credential def self.assert_valid_credentials checks = %w[application_id index_name api_key] checks.each do |check| if send(check.to_sym).nil? Logger.known_message("missing_#{check}") return false end end true end # Public: Setting a default values to index only html and markdown files # # Markdown files can have many different extensions. We keep the one # defined in the Jekyll config def self.default_extensions_to_index markdown_ext = get('markdown_ext') || '' ['html'] + markdown_ext.split(',') end # Public: Setting a default value to ignore index.html/index.md files in # the root # # Chances are high that the main page is not worthy of indexing (it can be # the list of the most recent posts or some landing page without much # content). We ignore it by default. # # User can still add it by manually specifying a `files_to_exclude` to an # empty array def self.default_files_to_exclude extensions_to_index.map do |extension| "index.#{extension}" end end # Public: Returns true if the command is run in verbose mode # # When set to true, more logs will be displayed def self.verbose? value = get('verbose') return true if value == true false end # Public: Returns true if the command is run in verbose mode # # When set to true, no indexing operations will be sent to the API def self.dry_run? value = get('dry_run') return true if value == true false end # Public: Returns true if the command should always update the settings # # When set to true, the index settings will always be updated, no matter # if they've been modified or not def self.force_settings? value = get('force_settings') return true if value == true false end # Public: Returns a list of extensions to index # # Will use default values or read the algolia.extensions_to_index key. # Accepts both an array or a comma-separated list def self.extensions_to_index extensions = algolia('extensions_to_index') return [] if extensions.nil? extensions = extensions.split(',') if extensions.is_a? String extensions end # Public: Disable features from other Jekyll plugins that might interfere # with the indexing def self.disable_other_plugins(config) # Disable archive pages from jekyll-archives config['jekyll-archives'] = nil # Disable tags from jekyll-tagging config['tag_page_dir'] = nil config['tag_page_layout'] = nil config end # Public: Check for any deprecated config option and warn the user def self.warn_of_deprecated_options # indexing_mode is no longer used return if algolia('indexing_mode').nil? # rubocop:disable Metrics/LineLength Logger.log('I:') Logger.log('W:[jekyll-algolia] You are using the algolia.indexing_mode option which has been deprecated in v1.1') Logger.log('I: Indexing is now always using an atomic diff algorithm.') Logger.log('I: This option is no longer necessary, you can remove it from your _config.yml') Logger.log('I:') # rubocop:enable Metrics/LineLength end end end end