jekyll-vitepress-theme 1.10.0 → 1.11.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 +4 -4
- data/assets/css/vitepress-overrides.css +1 -1
- data/lib/jekyll/vitepress_theme/hooks.rb +1 -20
- data/lib/jekyll/vitepress_theme/last_updated.rb +162 -0
- data/lib/jekyll/vitepress_theme/llms.rb +1 -2
- data/lib/jekyll/vitepress_theme/markdown_export.rb +2 -3
- data/lib/jekyll/vitepress_theme/seo.rb +9 -3
- data/lib/jekyll/vitepress_theme/version.rb +1 -1
- data/lib/jekyll-vitepress-theme.rb +1 -0
- metadata +8 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 31b1b2c1994a774599c9b5612781ac138dc561291572b97a4a2d3a96530618a6
|
|
4
|
+
data.tar.gz: 85fc67f3109b3e0c8a0964a98604c219c7fb418b4482580802aae6bc056f5adb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '099a79e03be5ea69bf4a6d60f5ec0d9c567439f54b75e777f00d2199fc8ca055b3a15bb9d751993f6544b6d2e363ef0d0615adb5d09b8965fa04b7a1cbcf0b9b'
|
|
7
|
+
data.tar.gz: 5b527894fd9d9a99c5e2521cc9c40aea76507136fa7125915ad10347c503b0bd9570e9d5ba4287d9b975541deac4c3e784141c59e555806fde0a15a43684a13d
|
|
@@ -3,7 +3,7 @@ require 'rouge'
|
|
|
3
3
|
|
|
4
4
|
module Jekyll
|
|
5
5
|
module VitePressTheme
|
|
6
|
-
# rubocop:disable Metrics/ModuleLength
|
|
6
|
+
# rubocop:disable-next Metrics/ModuleLength
|
|
7
7
|
module Sidebar
|
|
8
8
|
module_function
|
|
9
9
|
|
|
@@ -243,7 +243,6 @@ module Jekyll
|
|
|
243
243
|
)
|
|
244
244
|
end
|
|
245
245
|
end
|
|
246
|
-
# rubocop:enable Metrics/ModuleLength
|
|
247
246
|
|
|
248
247
|
module SearchIndex
|
|
249
248
|
module_function
|
|
@@ -319,24 +318,6 @@ module Jekyll
|
|
|
319
318
|
end
|
|
320
319
|
end
|
|
321
320
|
|
|
322
|
-
module LastUpdated
|
|
323
|
-
module_function
|
|
324
|
-
|
|
325
|
-
def source_file_time(site, path)
|
|
326
|
-
return nil unless path
|
|
327
|
-
|
|
328
|
-
source_path = if Pathname.new(path).absolute?
|
|
329
|
-
path
|
|
330
|
-
else
|
|
331
|
-
File.join(site.source, path)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
return nil unless File.file?(source_path)
|
|
335
|
-
|
|
336
|
-
File.mtime(source_path).utc
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
|
|
340
321
|
module RougeStyles
|
|
341
322
|
module_function
|
|
342
323
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
module Jekyll
|
|
7
|
+
module VitePressTheme
|
|
8
|
+
# Dates each page by the last commit that touched its source file, read
|
|
9
|
+
# from one `git log` pass per build. Files Git cannot date reliably
|
|
10
|
+
# (untracked, locally modified, outside the repository, or older than a
|
|
11
|
+
# shallow clone's history) use their modification time instead.
|
|
12
|
+
module LastUpdated
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
FIELD_SEPARATOR = "\x1e"
|
|
16
|
+
|
|
17
|
+
# Git's view of the files under a site source: commit times keyed by
|
|
18
|
+
# real path, plus the paths whose working copy differs from HEAD.
|
|
19
|
+
class GitIndex
|
|
20
|
+
def self.empty
|
|
21
|
+
new({}, [])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(times, modified)
|
|
25
|
+
@times = times
|
|
26
|
+
@modified = modified.to_h { |path| [path, true] }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def time_for(path)
|
|
30
|
+
return nil if @modified.key?(path)
|
|
31
|
+
|
|
32
|
+
@times[path]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def source_file_time(site, path)
|
|
37
|
+
source_path = resolved_source_path(site, path)
|
|
38
|
+
return nil unless source_path
|
|
39
|
+
|
|
40
|
+
git_index(site).time_for(source_path) || File.mtime(source_path).utc
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The last commit date alone, or nil where Git cannot date the file.
|
|
44
|
+
# For uses such as the sitemap, where a build-time file timestamp
|
|
45
|
+
# would claim a change that never happened.
|
|
46
|
+
def commit_time(site, path)
|
|
47
|
+
source_path = resolved_source_path(site, path)
|
|
48
|
+
source_path && git_index(site).time_for(source_path)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def resolved_source_path(site, path)
|
|
52
|
+
return nil unless path
|
|
53
|
+
|
|
54
|
+
source_path = Pathname.new(path).absolute? ? path : File.join(site.source, path)
|
|
55
|
+
return nil unless File.file?(source_path)
|
|
56
|
+
|
|
57
|
+
File.realpath(source_path)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def git_index(site)
|
|
61
|
+
@git_indexes ||= {}
|
|
62
|
+
@git_indexes[site] ||= build_git_index(site.source)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def reset(site)
|
|
66
|
+
@git_indexes&.delete(site)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build_git_index(source)
|
|
70
|
+
source = File.realpath(source)
|
|
71
|
+
root = repository_root(source)
|
|
72
|
+
return GitIndex.empty unless root
|
|
73
|
+
|
|
74
|
+
pathspec = relative_pathspec(source, root)
|
|
75
|
+
boundaries = shallow_boundaries(root)
|
|
76
|
+
warn_shallow if boundaries.any?
|
|
77
|
+
|
|
78
|
+
GitIndex.new(commit_times(root, pathspec, boundaries), modified_paths(root, pathspec))
|
|
79
|
+
rescue SystemCallError, ArgumentError => e
|
|
80
|
+
Jekyll.logger.debug('jekyll-vitepress-theme', "Git dates unavailable: #{e.message}")
|
|
81
|
+
GitIndex.empty
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def repository_root(source)
|
|
85
|
+
root = git(source, 'rev-parse', '--show-toplevel').to_s.strip
|
|
86
|
+
root.empty? ? nil : File.realpath(root)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def relative_pathspec(source, root)
|
|
90
|
+
Pathname.new(source).relative_path_from(Pathname.new(root)).to_s
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def commit_times(root, pathspec, boundaries)
|
|
94
|
+
log = git(root, 'log', '--no-renames', "--format=#{FIELD_SEPARATOR}%H %ct", '--name-only', '-z', '--', pathspec)
|
|
95
|
+
return {} unless log
|
|
96
|
+
|
|
97
|
+
log.split(FIELD_SEPARATOR).each_with_object({}) do |entry, times|
|
|
98
|
+
sha, time, files = parse_log_entry(entry)
|
|
99
|
+
next if files.empty? || boundaries.include?(sha)
|
|
100
|
+
|
|
101
|
+
files.each do |file|
|
|
102
|
+
path = File.join(root, file)
|
|
103
|
+
times[path] = time if times[path].nil? || time > times[path]
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def parse_log_entry(entry)
|
|
109
|
+
header, files = entry.split("\0", 2)
|
|
110
|
+
sha, timestamp = header.to_s.split
|
|
111
|
+
return [sha, nil, []] if files.nil?
|
|
112
|
+
|
|
113
|
+
[sha, Time.at(Integer(timestamp)).utc, files.delete_prefix("\n").split("\0").reject(&:empty?)]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def modified_paths(root, pathspec)
|
|
117
|
+
status = git(root, 'status', '--porcelain=v1', '-z', '--untracked-files=no', '--', pathspec)
|
|
118
|
+
return [] unless status
|
|
119
|
+
|
|
120
|
+
entries = status.split("\0")
|
|
121
|
+
paths = []
|
|
122
|
+
until entries.empty?
|
|
123
|
+
entry = entries.shift
|
|
124
|
+
paths << File.join(root, entry[3..])
|
|
125
|
+
entries.shift if entry.start_with?('R', 'C')
|
|
126
|
+
end
|
|
127
|
+
paths
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def shallow_boundaries(root)
|
|
131
|
+
return [] unless git(root, 'rev-parse', '--is-shallow-repository')&.strip == 'true'
|
|
132
|
+
|
|
133
|
+
shallow_file = git(root, 'rev-parse', '--git-path', 'shallow')&.strip
|
|
134
|
+
return [] unless shallow_file
|
|
135
|
+
|
|
136
|
+
shallow_file = File.expand_path(shallow_file, root)
|
|
137
|
+
return [] unless File.file?(shallow_file)
|
|
138
|
+
|
|
139
|
+
File.read(shallow_file).split
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def warn_shallow
|
|
143
|
+
Jekyll.logger.warn(
|
|
144
|
+
'jekyll-vitepress-theme',
|
|
145
|
+
'Shallow Git clone: pages last changed before the clone\'s history use their file ' \
|
|
146
|
+
'modification time for "Last updated". Fetch the full history (fetch-depth: 0) for accurate dates.'
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def git(directory, *args)
|
|
151
|
+
output, status = Open3.capture2('git', '-C', directory, *args, err: File::NULL)
|
|
152
|
+
status.success? ? output : nil
|
|
153
|
+
rescue SystemCallError
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
Jekyll::Hooks.register :site, :after_reset do |site|
|
|
161
|
+
Jekyll::VitePressTheme::LastUpdated.reset(site)
|
|
162
|
+
end
|
|
@@ -4,7 +4,7 @@ module Jekyll
|
|
|
4
4
|
module VitePressTheme
|
|
5
5
|
# Generates the proposed llms.txt index and its full-text companion from
|
|
6
6
|
# the same canonical, indexable content used by the theme's SEO layer.
|
|
7
|
-
# rubocop:disable Metrics/AbcSize, Metrics/ModuleLength
|
|
7
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/ModuleLength
|
|
8
8
|
module LLMS
|
|
9
9
|
module_function
|
|
10
10
|
|
|
@@ -231,6 +231,5 @@ module Jekyll
|
|
|
231
231
|
value.is_a?(Hash) ? value : {}
|
|
232
232
|
end
|
|
233
233
|
end
|
|
234
|
-
# rubocop:enable Metrics/AbcSize, Metrics/ModuleLength
|
|
235
234
|
end
|
|
236
235
|
end
|
|
@@ -11,7 +11,7 @@ module Jekyll
|
|
|
11
11
|
# the exported .md files, and llms-full.txt all share it. Fenced code
|
|
12
12
|
# blocks and code spans pass through untouched, and a page without HTML
|
|
13
13
|
# comes back unchanged.
|
|
14
|
-
# rubocop:disable Metrics/AbcSize, Metrics/ModuleLength
|
|
14
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/ModuleLength
|
|
15
15
|
module MarkdownExport
|
|
16
16
|
module_function
|
|
17
17
|
|
|
@@ -277,7 +277,7 @@ module Jekyll
|
|
|
277
277
|
def dedent(text)
|
|
278
278
|
lines = text.split("\n", -1)
|
|
279
279
|
indents = lines.drop(1).reject { |line| line.strip.empty? || line.match?(/\A[ \t]*#{BLOCK_CODE_PATTERN.source}/) }
|
|
280
|
-
|
|
280
|
+
.map { |line| line[/\A[ \t]*/].length }
|
|
281
281
|
indent = indents.min.to_i
|
|
282
282
|
return text if indent.zero?
|
|
283
283
|
|
|
@@ -632,6 +632,5 @@ module Jekyll
|
|
|
632
632
|
nil
|
|
633
633
|
end
|
|
634
634
|
end
|
|
635
|
-
# rubocop:enable Metrics/AbcSize, Metrics/ModuleLength
|
|
636
635
|
end
|
|
637
636
|
end
|
|
@@ -10,7 +10,7 @@ module Jekyll
|
|
|
10
10
|
# Generates the metadata shared by the HTML head, sitemap, and robots.txt.
|
|
11
11
|
# Keeping those outputs on one canonical URL resolver prevents contradictory
|
|
12
12
|
# indexing signals across theme consumers.
|
|
13
|
-
# rubocop:disable Metrics/AbcSize, Metrics/ModuleLength
|
|
13
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/ModuleLength
|
|
14
14
|
module SEO
|
|
15
15
|
module_function
|
|
16
16
|
|
|
@@ -388,7 +388,7 @@ module Jekyll
|
|
|
388
388
|
metadata = item.data['_seo']
|
|
389
389
|
next unless sitemap_candidate?(item, metadata)
|
|
390
390
|
|
|
391
|
-
last_modified = metadata['date_modified']
|
|
391
|
+
last_modified = metadata['date_modified'] || source_modified(item)
|
|
392
392
|
last_modified ||= metadata['date_published'] if posts_document?(item)
|
|
393
393
|
[metadata['canonical_url'], last_modified]
|
|
394
394
|
end
|
|
@@ -408,6 +408,13 @@ module Jekyll
|
|
|
408
408
|
XML
|
|
409
409
|
end
|
|
410
410
|
|
|
411
|
+
# Front matter first, then the last commit that touched the page's
|
|
412
|
+
# source file. Never a build-time file timestamp, which would mark every
|
|
413
|
+
# page as changed on each build.
|
|
414
|
+
def source_modified(item)
|
|
415
|
+
xml_time(item.data['last_updated_at'] || LastUpdated.commit_time(item.site, item.path))
|
|
416
|
+
end
|
|
417
|
+
|
|
411
418
|
def robots_txt(site, config, site_url)
|
|
412
419
|
index = config.fetch('index', true) != false
|
|
413
420
|
lines = ['User-agent: *', index ? 'Allow: /' : 'Disallow: /']
|
|
@@ -588,6 +595,5 @@ module Jekyll
|
|
|
588
595
|
CGI.escapeHTML(value.to_s)
|
|
589
596
|
end
|
|
590
597
|
end
|
|
591
|
-
# rubocop:enable Metrics/AbcSize, Metrics/ModuleLength
|
|
592
598
|
end
|
|
593
599
|
end
|
|
@@ -3,4 +3,5 @@ require_relative 'jekyll/vitepress_theme/version'
|
|
|
3
3
|
require_relative 'jekyll/vitepress_theme/markdown_export'
|
|
4
4
|
require_relative 'jekyll/vitepress_theme/seo'
|
|
5
5
|
require_relative 'jekyll/vitepress_theme/llms'
|
|
6
|
+
require_relative 'jekyll/vitepress_theme/last_updated'
|
|
6
7
|
require_relative 'jekyll/vitepress_theme/hooks'
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-vitepress-theme
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carmine Paolino
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: cgi
|
|
@@ -56,20 +55,20 @@ dependencies:
|
|
|
56
55
|
requirements:
|
|
57
56
|
- - ">="
|
|
58
57
|
- !ruby/object:Gem::Version
|
|
59
|
-
version: '
|
|
58
|
+
version: '4.1'
|
|
60
59
|
- - "<"
|
|
61
60
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: '
|
|
61
|
+
version: '6.0'
|
|
63
62
|
type: :runtime
|
|
64
63
|
prerelease: false
|
|
65
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
65
|
requirements:
|
|
67
66
|
- - ">="
|
|
68
67
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: '
|
|
68
|
+
version: '4.1'
|
|
70
69
|
- - "<"
|
|
71
70
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '
|
|
71
|
+
version: '6.0'
|
|
73
72
|
description: Jekyll VitePress Theme brings VitePress-style documentation UX, search,
|
|
74
73
|
structured metadata, and Jekyll-native extensions to Ruby static sites.
|
|
75
74
|
email:
|
|
@@ -177,6 +176,7 @@ files:
|
|
|
177
176
|
- assets/vendor/turbo.js
|
|
178
177
|
- lib/jekyll-vitepress-theme.rb
|
|
179
178
|
- lib/jekyll/vitepress_theme/hooks.rb
|
|
179
|
+
- lib/jekyll/vitepress_theme/last_updated.rb
|
|
180
180
|
- lib/jekyll/vitepress_theme/llms.rb
|
|
181
181
|
- lib/jekyll/vitepress_theme/markdown_export.rb
|
|
182
182
|
- lib/jekyll/vitepress_theme/seo.rb
|
|
@@ -192,7 +192,6 @@ metadata:
|
|
|
192
192
|
documentation_uri: https://jekyll-vitepress.dev
|
|
193
193
|
bug_tracker_uri: https://github.com/crmne/jekyll-vitepress-theme/issues
|
|
194
194
|
funding_uri: https://github.com/sponsors/crmne
|
|
195
|
-
post_install_message:
|
|
196
195
|
rdoc_options: []
|
|
197
196
|
require_paths:
|
|
198
197
|
- lib
|
|
@@ -207,8 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
207
206
|
- !ruby/object:Gem::Version
|
|
208
207
|
version: '0'
|
|
209
208
|
requirements: []
|
|
210
|
-
rubygems_version: 3.
|
|
211
|
-
signing_key:
|
|
209
|
+
rubygems_version: 3.6.9
|
|
212
210
|
specification_version: 4
|
|
213
211
|
summary: A polished, SEO-ready VitePress-style documentation theme for Jekyll.
|
|
214
212
|
test_files: []
|