jekyll-client-search 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +121 -0
- data/LICENSE +22 -0
- data/NOTICE +49 -0
- data/README.developer.md +204 -0
- data/README.md +948 -0
- data/assets/adapters/elasticlunr.js +59 -0
- data/assets/adapters/minisearch.js +57 -0
- data/assets/adapters/semantic.js +154 -0
- data/assets/client-search-base.js +294 -0
- data/assets/client-search-related.js +176 -0
- data/assets/includes/related-articles.html +36 -0
- data/assets/layouts/post-with-related.html +54 -0
- data/assets/query-embedders/ollama-api.js +63 -0
- data/assets/query-embedders/transformers-worker.js +130 -0
- data/assets/query-embedders/transformers.js +223 -0
- data/docs/assets/icon-256.png +0 -0
- data/docs/assets/icon.svg +133 -0
- data/lib/jekyll/client_search/configuration.rb +152 -0
- data/lib/jekyll/client_search/configuration_accessors.rb +48 -0
- data/lib/jekyll/client_search/document_builder.rb +66 -0
- data/lib/jekyll/client_search/embedder_config_page.rb +14 -0
- data/lib/jekyll/client_search/embedding_configuration.rb +95 -0
- data/lib/jekyll/client_search/generator.rb +134 -0
- data/lib/jekyll/client_search/index_cache.rb +82 -0
- data/lib/jekyll/client_search/live_search_configuration.rb +70 -0
- data/lib/jekyll/client_search/ollama_embedding_adapter.rb +59 -0
- data/lib/jekyll/client_search/query_embedder_configuration.rb +127 -0
- data/lib/jekyll/client_search/related_analyzer.rb +152 -0
- data/lib/jekyll/client_search/related_configuration.rb +103 -0
- data/lib/jekyll/client_search/related_page.rb +14 -0
- data/lib/jekyll/client_search/related_tag.rb +76 -0
- data/lib/jekyll/client_search/runtime_config_page.rb +30 -0
- data/lib/jekyll/client_search/search_index_page.rb +15 -0
- data/lib/jekyll/client_search/search_tag.rb +100 -0
- data/lib/jekyll/client_search/tasks.rb +137 -0
- data/lib/jekyll/client_search/version.rb +7 -0
- data/lib/jekyll/client_search.rb +25 -0
- data/lib/jekyll-client-search.rb +3 -0
- metadata +104 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module ClientSearch
|
|
5
|
+
# Generates browser runtime settings shared by all search adapters.
|
|
6
|
+
class RuntimeConfigPage < Jekyll::PageWithoutAFile
|
|
7
|
+
def initialize(site, configuration)
|
|
8
|
+
super(site, site.source, "assets", "search-runtime-config.js")
|
|
9
|
+
self.data = { "layout" => nil, "sitemap" => false }
|
|
10
|
+
defaults = {
|
|
11
|
+
"indexUrl" => index_url(site, configuration.output),
|
|
12
|
+
"liveSearch" => configuration.live_search_config
|
|
13
|
+
}
|
|
14
|
+
defaults["relatedUrl"] = index_url(site, configuration.related_output) if configuration.related_enabled?
|
|
15
|
+
json = JSON.generate(defaults)
|
|
16
|
+
self.content = "window.clientSearchConfig = (function (generated, existing) {" \
|
|
17
|
+
"var liveSearch = Object.assign({}, generated.liveSearch, existing.liveSearch || {});" \
|
|
18
|
+
"return Object.assign(generated, existing, { liveSearch: liveSearch });" \
|
|
19
|
+
"}(#{json}, window.clientSearchConfig || {}));\n"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def index_url(site, output)
|
|
25
|
+
parts = [site.baseurl, output].map { |part| part.to_s.gsub(%r{\A/+|/+$}, "") }.reject(&:empty?)
|
|
26
|
+
"/#{parts.join('/')}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module ClientSearch
|
|
5
|
+
# A Jekyll page that renders the search documents as JSON at the
|
|
6
|
+
# configured output path.
|
|
7
|
+
class SearchIndexPage < Jekyll::PageWithoutAFile
|
|
8
|
+
def initialize(site, output, documents)
|
|
9
|
+
super(site, site.source, File.dirname(output), File.basename(output))
|
|
10
|
+
self.data = { "layout" => nil, "sitemap" => false }
|
|
11
|
+
self.content = JSON.generate(documents)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module ClientSearch
|
|
5
|
+
# Liquid tag that renders the search form, status/results containers,
|
|
6
|
+
# and all runtime scripts in one line — config-driven so changing engines
|
|
7
|
+
# in _config.yml requires zero template changes.
|
|
8
|
+
#
|
|
9
|
+
# {% search_form %}
|
|
10
|
+
# {% search_form scripts_only %} — just scripts (custom form HTML)
|
|
11
|
+
# {% search_form no_scripts %} — just form HTML (user loads scripts)
|
|
12
|
+
#
|
|
13
|
+
# When client_search is disabled the tag renders nothing.
|
|
14
|
+
class SearchTag < Liquid::Tag
|
|
15
|
+
SYNTAX = /\A\s*(scripts_only|no_scripts)?\s*\z/
|
|
16
|
+
|
|
17
|
+
def initialize(tag_name, markup, tokens)
|
|
18
|
+
super
|
|
19
|
+
@markup = markup.to_s
|
|
20
|
+
unless (match = @markup.match(SYNTAX))
|
|
21
|
+
raise Liquid::SyntaxError,
|
|
22
|
+
"search_form: invalid syntax. Use {% search_form %}, " \
|
|
23
|
+
"{% search_form scripts_only %}, or {% search_form no_scripts %}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
@mode = match[1] || "full"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def render(context)
|
|
30
|
+
site = context.registers[:site]
|
|
31
|
+
config_hash = site&.config&.fetch("client_search", {})
|
|
32
|
+
return "" unless config_hash["enabled"] != false
|
|
33
|
+
|
|
34
|
+
configuration = Configuration.new(site)
|
|
35
|
+
baseurl = site.config["baseurl"].to_s.gsub(%r{\A/+|/+$}, "")
|
|
36
|
+
prefix = baseurl.empty? ? "" : "/#{baseurl}"
|
|
37
|
+
|
|
38
|
+
form_html = build_form
|
|
39
|
+
return form_html if @mode == "no_scripts"
|
|
40
|
+
|
|
41
|
+
scripts = build_scripts(configuration, prefix)
|
|
42
|
+
return scripts if @mode == "scripts_only"
|
|
43
|
+
|
|
44
|
+
"#{form_html}\n#{scripts}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def build_form
|
|
50
|
+
<<~HTML
|
|
51
|
+
<form id="search-form" role="search">
|
|
52
|
+
<label class="is-sr-only" for="search-query">Search</label>
|
|
53
|
+
<input id="search-query" type="search" name="q" placeholder="Search">
|
|
54
|
+
<button type="submit">Search</button>
|
|
55
|
+
</form>
|
|
56
|
+
<div id="search-status" aria-live="polite"></div>
|
|
57
|
+
<div id="search-results"></div>
|
|
58
|
+
HTML
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def build_scripts(configuration, prefix)
|
|
62
|
+
scripts = []
|
|
63
|
+
engine = engine_script(configuration)
|
|
64
|
+
scripts << engine if engine
|
|
65
|
+
scripts << "<script src=\"#{prefix}/assets/search-runtime-config.js\"></script>"
|
|
66
|
+
scripts.concat(embedder_scripts(configuration, prefix))
|
|
67
|
+
scripts << "<script src=\"#{prefix}/assets/client-search-base.js\"></script>"
|
|
68
|
+
scripts << "<script src=\"#{prefix}/assets/adapters/#{configuration.engine}.js\"></script>"
|
|
69
|
+
scripts.map { |script| " #{script}" }.join("\n")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def engine_script(configuration)
|
|
73
|
+
url = configuration.engine_url
|
|
74
|
+
return nil unless url
|
|
75
|
+
|
|
76
|
+
attrs = ["src=\"#{url}\""]
|
|
77
|
+
attrs << "crossorigin=\"#{configuration.engine_crossorigin}\"" if configuration.engine_crossorigin
|
|
78
|
+
attrs << "integrity=\"#{configuration.engine_sri}\"" if configuration.engine_sri
|
|
79
|
+
"<script #{attrs.join(' ')}></script>"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def embedder_scripts(configuration, prefix)
|
|
83
|
+
return [] unless semantic_with_embedder?(configuration)
|
|
84
|
+
|
|
85
|
+
scripts = ["<script src=\"#{prefix}/assets/search-embedder-config.js\"></script>"]
|
|
86
|
+
embedder_asset = configuration.query_embedder_asset
|
|
87
|
+
scripts << "<script src=\"#{prefix}/#{embedder_asset}\"></script>" if embedder_asset
|
|
88
|
+
scripts
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def semantic_with_embedder?(configuration)
|
|
92
|
+
configuration.engine == "semantic" &&
|
|
93
|
+
configuration.embedding_enabled? &&
|
|
94
|
+
configuration.query_embedder_type != "none"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Liquid::Template.register_tag("search_form", Jekyll::ClientSearch::SearchTag)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "rubygems"
|
|
5
|
+
|
|
6
|
+
module Jekyll
|
|
7
|
+
module ClientSearch
|
|
8
|
+
# Rake tasks for inspecting and installing reference files.
|
|
9
|
+
#
|
|
10
|
+
# Tasks:
|
|
11
|
+
# jekyll_client_search:reference_files — list gem reference files,
|
|
12
|
+
# diff against site copies, offer to update
|
|
13
|
+
# jekyll_client_search:install — copy reference files into the site's
|
|
14
|
+
# _layouts/ and _includes/ directories
|
|
15
|
+
module Tasks
|
|
16
|
+
REFERENCE_FILES = {
|
|
17
|
+
"assets/layouts/post-with-related.html" => "_layouts/post-with-related.html",
|
|
18
|
+
"assets/includes/related-articles.html" => "_includes/related-articles.html"
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def gem_root
|
|
23
|
+
spec = Gem::Specification.find_by_name("jekyll-client-search")
|
|
24
|
+
spec.gem_dir
|
|
25
|
+
rescue Gem::MissingSpecError
|
|
26
|
+
# Fall back to the development source directory
|
|
27
|
+
File.expand_path("../../..", __dir__)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def reference_files
|
|
31
|
+
REFERENCE_FILES
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def site_root
|
|
35
|
+
Dir.pwd
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def list_reference_files
|
|
39
|
+
puts "jekyll-client-search reference files:"
|
|
40
|
+
puts
|
|
41
|
+
reference_files.each do |gem_rel, site_rel|
|
|
42
|
+
gem_path = File.join(gem_root, gem_rel)
|
|
43
|
+
site_path = File.join(site_root, site_rel)
|
|
44
|
+
site_exists = File.exist?(site_path)
|
|
45
|
+
|
|
46
|
+
status = if !site_exists
|
|
47
|
+
"not installed"
|
|
48
|
+
elsif same_content?(gem_path, site_path)
|
|
49
|
+
"up to date"
|
|
50
|
+
else
|
|
51
|
+
"modified or outdated"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
puts " #{site_rel}"
|
|
55
|
+
puts " gem: #{gem_path}"
|
|
56
|
+
puts " site: #{site_path}"
|
|
57
|
+
puts " status: #{status}"
|
|
58
|
+
puts
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def diff_reference_files
|
|
63
|
+
reference_files.each do |gem_rel, site_rel|
|
|
64
|
+
gem_path = File.join(gem_root, gem_rel)
|
|
65
|
+
site_path = File.join(site_root, site_rel)
|
|
66
|
+
|
|
67
|
+
unless File.exist?(site_path)
|
|
68
|
+
puts "#{site_rel}: not installed (no diff)"
|
|
69
|
+
next
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if same_content?(gem_path, site_path)
|
|
73
|
+
puts "#{site_rel}: up to date"
|
|
74
|
+
else
|
|
75
|
+
puts "Diff for #{site_rel}:"
|
|
76
|
+
system("diff", "-u", site_path, gem_path)
|
|
77
|
+
puts
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def install_reference_files(overwrite: false)
|
|
83
|
+
installed = []
|
|
84
|
+
skipped = []
|
|
85
|
+
|
|
86
|
+
reference_files.each do |gem_rel, site_rel|
|
|
87
|
+
result = install_file(gem_rel, site_rel, overwrite: overwrite)
|
|
88
|
+
case result
|
|
89
|
+
when :installed then installed << site_rel
|
|
90
|
+
when :skipped then skipped << site_rel
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
{ installed: installed, skipped: skipped }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def install_file(gem_rel, site_rel, overwrite:)
|
|
98
|
+
gem_path = File.join(gem_root, gem_rel)
|
|
99
|
+
site_path = File.join(site_root, site_rel)
|
|
100
|
+
|
|
101
|
+
unless File.exist?(gem_path)
|
|
102
|
+
warn " WARNING: gem file missing: #{gem_path}"
|
|
103
|
+
return nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
return handle_existing(site_rel, gem_path, site_path) if File.exist?(site_path) && !overwrite
|
|
107
|
+
|
|
108
|
+
copy_file(gem_path, site_path, site_rel, overwrite)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def handle_existing(site_rel, gem_path, site_path)
|
|
112
|
+
if same_content?(gem_path, site_path)
|
|
113
|
+
puts " #{site_rel}: already up to date (skip)"
|
|
114
|
+
nil
|
|
115
|
+
else
|
|
116
|
+
puts " #{site_rel}: exists and differs (skip — use overwrite: true to replace)"
|
|
117
|
+
:skipped
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def copy_file(gem_path, site_path, site_rel, overwrite)
|
|
122
|
+
FileUtils.mkdir_p(File.dirname(site_path))
|
|
123
|
+
FileUtils.cp(gem_path, site_path)
|
|
124
|
+
action = overwrite ? "updated" : "installed"
|
|
125
|
+
puts " #{site_rel}: #{action}"
|
|
126
|
+
:installed
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def same_content?(path_a, path_b)
|
|
130
|
+
File.read(path_a) == File.read(path_b)
|
|
131
|
+
rescue Errno::ENOENT
|
|
132
|
+
false
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi/escape"
|
|
4
|
+
require "json"
|
|
5
|
+
require "jekyll"
|
|
6
|
+
require "pathname"
|
|
7
|
+
require "time"
|
|
8
|
+
require_relative "client_search/version"
|
|
9
|
+
require_relative "client_search/embedding_configuration"
|
|
10
|
+
require_relative "client_search/live_search_configuration"
|
|
11
|
+
require_relative "client_search/related_configuration"
|
|
12
|
+
require_relative "client_search/query_embedder_configuration"
|
|
13
|
+
require_relative "client_search/configuration_accessors"
|
|
14
|
+
require_relative "client_search/configuration"
|
|
15
|
+
require_relative "client_search/document_builder"
|
|
16
|
+
require_relative "client_search/search_index_page"
|
|
17
|
+
require_relative "client_search/runtime_config_page"
|
|
18
|
+
require_relative "client_search/related_analyzer"
|
|
19
|
+
require_relative "client_search/related_page"
|
|
20
|
+
require_relative "client_search/embedder_config_page"
|
|
21
|
+
require_relative "client_search/index_cache"
|
|
22
|
+
require_relative "client_search/ollama_embedding_adapter"
|
|
23
|
+
require_relative "client_search/generator"
|
|
24
|
+
require_relative "client_search/related_tag"
|
|
25
|
+
require_relative "client_search/search_tag"
|
metadata
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: jekyll-client-search
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Svend Gundestrup
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: jekyll
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '4.0'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '5.0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '4.0'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '5.0'
|
|
32
|
+
description: A Jekyll plugin that generates a configurable JSON search index with
|
|
33
|
+
pluggable browser runtime adapters for client-side JavaScript search engines.
|
|
34
|
+
email:
|
|
35
|
+
- svend@gundestrup.dk
|
|
36
|
+
executables: []
|
|
37
|
+
extensions: []
|
|
38
|
+
extra_rdoc_files: []
|
|
39
|
+
files:
|
|
40
|
+
- CHANGELOG.md
|
|
41
|
+
- LICENSE
|
|
42
|
+
- NOTICE
|
|
43
|
+
- README.developer.md
|
|
44
|
+
- README.md
|
|
45
|
+
- assets/adapters/elasticlunr.js
|
|
46
|
+
- assets/adapters/minisearch.js
|
|
47
|
+
- assets/adapters/semantic.js
|
|
48
|
+
- assets/client-search-base.js
|
|
49
|
+
- assets/client-search-related.js
|
|
50
|
+
- assets/includes/related-articles.html
|
|
51
|
+
- assets/layouts/post-with-related.html
|
|
52
|
+
- assets/query-embedders/ollama-api.js
|
|
53
|
+
- assets/query-embedders/transformers-worker.js
|
|
54
|
+
- assets/query-embedders/transformers.js
|
|
55
|
+
- docs/assets/icon-256.png
|
|
56
|
+
- docs/assets/icon.svg
|
|
57
|
+
- lib/jekyll-client-search.rb
|
|
58
|
+
- lib/jekyll/client_search.rb
|
|
59
|
+
- lib/jekyll/client_search/configuration.rb
|
|
60
|
+
- lib/jekyll/client_search/configuration_accessors.rb
|
|
61
|
+
- lib/jekyll/client_search/document_builder.rb
|
|
62
|
+
- lib/jekyll/client_search/embedder_config_page.rb
|
|
63
|
+
- lib/jekyll/client_search/embedding_configuration.rb
|
|
64
|
+
- lib/jekyll/client_search/generator.rb
|
|
65
|
+
- lib/jekyll/client_search/index_cache.rb
|
|
66
|
+
- lib/jekyll/client_search/live_search_configuration.rb
|
|
67
|
+
- lib/jekyll/client_search/ollama_embedding_adapter.rb
|
|
68
|
+
- lib/jekyll/client_search/query_embedder_configuration.rb
|
|
69
|
+
- lib/jekyll/client_search/related_analyzer.rb
|
|
70
|
+
- lib/jekyll/client_search/related_configuration.rb
|
|
71
|
+
- lib/jekyll/client_search/related_page.rb
|
|
72
|
+
- lib/jekyll/client_search/related_tag.rb
|
|
73
|
+
- lib/jekyll/client_search/runtime_config_page.rb
|
|
74
|
+
- lib/jekyll/client_search/search_index_page.rb
|
|
75
|
+
- lib/jekyll/client_search/search_tag.rb
|
|
76
|
+
- lib/jekyll/client_search/tasks.rb
|
|
77
|
+
- lib/jekyll/client_search/version.rb
|
|
78
|
+
homepage: https://github.com/gundestrup/jekyll-client-search
|
|
79
|
+
licenses:
|
|
80
|
+
- AGPL-3.0-or-later
|
|
81
|
+
metadata:
|
|
82
|
+
homepage_uri: https://github.com/gundestrup/jekyll-client-search
|
|
83
|
+
source_code_uri: https://github.com/gundestrup/jekyll-client-search/tree/main
|
|
84
|
+
changelog_uri: https://github.com/gundestrup/jekyll-client-search/blob/main/CHANGELOG.md
|
|
85
|
+
bug_tracker_uri: https://github.com/gundestrup/jekyll-client-search/issues
|
|
86
|
+
rubygems_mfa_required: 'true'
|
|
87
|
+
rdoc_options: []
|
|
88
|
+
require_paths:
|
|
89
|
+
- lib
|
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: 3.2.0
|
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
requirements: []
|
|
101
|
+
rubygems_version: 3.6.9
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: Build client-side search indexes for Jekyll sites
|
|
104
|
+
test_files: []
|