jekyll-carve 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28da599466525fea6bbc65a8c6143d8579241a20f1838d6ccb0f9d0317ac3405
4
- data.tar.gz: f36f40e656e8d8ea3da71e207cbaeb61f7daf43b06f8ae7ef41f6d34dd9ad4f7
3
+ metadata.gz: 86256975160492f093658f4cde9291d34e1b343de95a42ec0e098d2ebb37a8c4
4
+ data.tar.gz: ec48c36fd313fe0fede2487ec12812c9684b5e4731fa3f6e60ad414fd9cdfd91
5
5
  SHA512:
6
- metadata.gz: 869155a13081b84dcbd811b2a6474a8e1df7b282924c3b187226c0b16e782d8180f46dfd3b9fa9348c9ed631c0d8b37f33381c7e41849ec6571052c2619cd85b
7
- data.tar.gz: 7fceaae2aee055d86faccc18445e2e5191dba2d9c3a74a73bd91ba1bffac31b531aa7fbcfce58da156379cb42f1f80214b9576a712d488f060e07cde018cd57b
6
+ metadata.gz: 5252c852e50fcc9240dbcbd47b734a8f1a269ff2d161966bde8d37cebf29219baf6778b08123a97791f098d82f7adec4196e3b02c8931e99e41f42d94e0694bb
7
+ data.tar.gz: 4981a39b6764c0c4b60399be7d4b3e0da50c701a8194a8e4369e87be52b2bbf59be62f93d80b85542400d74d20081540f324a0e96121c46783298145cc7eecf7
data/README.md CHANGED
@@ -176,6 +176,45 @@ resolve against.
176
176
  > will publish them. Exclude them in `_config.yml`, or keep them outside the
177
177
  > source and point `include_root` at the tree above both.
178
178
 
179
+ ### `carve.lint` - reporting what renders but is lost
180
+
181
+ Carve's linter reports constructs that parse and render, but not the way the
182
+ author meant: a block attribute that attaches to nothing, a link to an id no
183
+ heading has, an unclosed code fence. Turn it on to see them as build warnings:
184
+
185
+ ```yaml
186
+ carve:
187
+ lint: true
188
+ ```
189
+
190
+ ```
191
+ Carve lint: guide/intro.crv:7:1: unattached-block-attribute: This block attribute reaches no block: ...
192
+ ```
193
+
194
+ Each warning names the page, the line and column in the file, and the rule id.
195
+ The line counts the front matter, so it matches your editor; a Liquid tag that
196
+ expands to several lines shifts the lines below it, since the linter reads the
197
+ page after Liquid. Pages still render.
198
+
199
+ To fail the build instead, use `strict`:
200
+
201
+ ```yaml
202
+ carve:
203
+ lint: strict
204
+ ```
205
+
206
+ Every page is linted and reported first, then `jekyll build` stops with an
207
+ error before writing the site.
208
+
209
+ The linter reads the same `carve.extensions` the pages render with. With
210
+ `carve.includes` on it also lints each included Carve file, and a finding there
211
+ names that file: `index.crv (parts/intro.crv:3:1): ...`. Include warnings such
212
+ as `include-unresolved` are logged once, by the include pass, but count toward
213
+ `strict`.
214
+
215
+ `carve.lint` needs carve-lang 0.1.11 or later, the first engine that exposes the
216
+ linter. That is why it is this gem's floor.
217
+
179
218
  ## Usage
180
219
 
181
220
  Create a page with a `.crv` extension. It MUST begin with Jekyll
@@ -197,6 +236,28 @@ This is /italic/ and *bold* text.
197
236
  Note Carve's inline syntax: `*...*` is **strong** (bold) and `/.../` is
198
237
  _emphasis_ (italic) - the opposite of Markdown.
199
238
 
239
+ ## Highlighting Carve code blocks
240
+
241
+ This plugin renders `.crv` pages. To highlight a ` ```carve ` block inside a
242
+ Markdown page, add [rouge-carve](https://github.com/markup-carve/rouge-carve),
243
+ which registers a Carve lexer with Rouge, Jekyll's default highlighter:
244
+
245
+ ```ruby
246
+ # Gemfile
247
+ group :jekyll_plugins do
248
+ gem "rouge-carve"
249
+ end
250
+ ```
251
+
252
+ Jekyll requires every gem in the `jekyll_plugins` group on its own. Without
253
+ that group, list it in `_config.yml` instead:
254
+
255
+ ```yaml
256
+ plugins:
257
+ - jekyll-carve
258
+ - rouge-carve
259
+ ```
260
+
200
261
  ## Important: Jekyll front matter vs. Carve frontmatter
201
262
 
202
263
  This is the one nuance to understand:
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module Carve
5
- VERSION = "0.1.3"
5
+ VERSION = "0.1.4"
6
6
  end
7
7
  end
data/lib/jekyll-carve.rb CHANGED
@@ -61,32 +61,46 @@ module Jekyll
61
61
  def convert(content)
62
62
  document = Rendering.current
63
63
  root = include_root
64
- if root.nil? || document.nil? || document.path.to_s.empty?
65
- return ::Carve.to_html(content.to_s,
66
- extensions: carve_extensions,
67
- symbols: carve_symbols)
68
- end
69
- # carve-lang added this entry point in 0.1.4; the floor stays lower for sites without includes.
70
- unless ::Carve.respond_to?(:to_html_with_includes)
71
- raise ArgumentError,
72
- "carve.includes: the installed carve-lang (#{::Carve::VERSION}) has no " \
73
- "to_html_with_includes; upgrade it to 0.1.4 or later, or set carve.includes: false"
74
- end
64
+ include_page = !(root.nil? || document.nil? || document.path.to_s.empty?)
65
+ html = render(content.to_s, document, include_page ? root : nil)
66
+ lint(content.to_s, document, include_page ? root : nil) if lint_mode
67
+ html
68
+ end
75
69
 
76
- begin
77
- result = ::Carve.to_html_with_includes(content.to_s,
78
- root: root,
79
- source_path: document.path,
80
- extensions: carve_extensions,
81
- symbols: carve_symbols)
82
- rescue ArgumentError => e
83
- # A relative root, or a page outside it. Both are decided by the
84
- # engine; what this adds is the key and the page to look at.
70
+ # How `carve.lint` is set: nil (off), :warn or :strict.
71
+ #
72
+ # `true` logs each finding as a build warning; `"strict"` also fails the
73
+ # build once every page has been linted.
74
+ def lint_mode
75
+ case (value = carve_config["lint"])
76
+ when nil, false then nil
77
+ when true then :warn
78
+ when "strict", :strict then :strict
79
+ else
85
80
  raise ArgumentError,
86
- "carve.include_root: #{document.relative_path || document.path}: #{e.message}"
81
+ "carve.lint: expected true, false or \"strict\", got #{value.inspect}"
87
82
  end
88
- report_includes(result, document, root)
89
- result[:value]
83
+ end
84
+
85
+ # Lint findings counted under `carve.lint: strict` since the last reset.
86
+ def lint_findings
87
+ @lint_findings ||= 0
88
+ end
89
+
90
+ # Fail the build when strict lint counted a finding.
91
+ #
92
+ # Called from the `:site, :post_render` hook below, so every page is
93
+ # linted and reported before the build stops.
94
+ def check_lint!
95
+ return unless lint_mode == :strict && lint_findings.positive?
96
+
97
+ raise Jekyll::Errors::FatalException,
98
+ "carve.lint: #{lint_findings} lint finding(s) under strict mode; see the warnings above"
99
+ end
100
+
101
+ # Drop the strict-mode count, so each build is judged on its own.
102
+ def reset_lint
103
+ @lint_findings = 0
90
104
  end
91
105
 
92
106
  # The containment root configured under `carve.include_root`, or nil when
@@ -172,6 +186,71 @@ module Jekyll
172
186
 
173
187
  private
174
188
 
189
+ def render(content, document, root)
190
+ if root.nil?
191
+ return ::Carve.to_html(content,
192
+ extensions: carve_extensions,
193
+ symbols: carve_symbols)
194
+ end
195
+ # carve-lang added this entry point in 0.1.4; the floor stays lower for sites without includes.
196
+ unless ::Carve.respond_to?(:to_html_with_includes)
197
+ raise ArgumentError,
198
+ "carve.includes: the installed carve-lang (#{::Carve::VERSION}) has no " \
199
+ "to_html_with_includes; upgrade it to 0.1.4 or later, or set carve.includes: false"
200
+ end
201
+
202
+ begin
203
+ result = ::Carve.to_html_with_includes(content,
204
+ root: root,
205
+ source_path: document.path,
206
+ extensions: carve_extensions,
207
+ symbols: carve_symbols)
208
+ rescue ArgumentError => e
209
+ # A relative root, or a page outside it. Both are decided by the
210
+ # engine; what this adds is the key and the page to look at.
211
+ raise ArgumentError,
212
+ "carve.include_root: #{document.relative_path || document.path}: #{e.message}"
213
+ end
214
+ report_includes(result, document, root)
215
+ result[:value]
216
+ end
217
+
218
+ # Log each lint finding as a build warning, located in the source file.
219
+ #
220
+ # Runs after rendering, so a bad include root is reported by the render
221
+ # path with its own message. With includes on, the include-* findings
222
+ # repeat the include warnings `report_includes` already logged, so they
223
+ # are counted but not logged twice.
224
+ def lint(content, document, root)
225
+ page = document && (document.relative_path || document.path).to_s
226
+ page = "(no page)" if page.nil? || page.empty?
227
+ options = { extensions: carve_extensions }
228
+ options.update(root: root, source_path: document.path) if root
229
+ findings = ::Carve.lint(content, **options)
230
+ offset = front_matter_lines(document)
231
+ findings.each do |finding|
232
+ next if root && finding[:rule].start_with?("include-")
233
+
234
+ where = if finding[:file]
235
+ "#{page} (#{finding[:file]}:#{finding[:line]}:#{finding[:column]})"
236
+ else
237
+ "#{page}:#{finding[:line] + offset}:#{finding[:column]}"
238
+ end
239
+ Jekyll.logger.warn "Carve lint:", "#{where}: #{finding[:rule]}: #{finding[:message]}"
240
+ end
241
+ @lint_findings = lint_findings + findings.size if lint_mode == :strict
242
+ end
243
+
244
+ # Lines of YAML front matter above the body, so a finding names the line
245
+ # in the file. Jekyll strips the front matter before `convert` sees it.
246
+ def front_matter_lines(document)
247
+ path = document&.path.to_s
248
+ return 0 if path.empty? || !File.file?(path)
249
+
250
+ match = Jekyll::Document::YAML_FRONT_MATTER_REGEXP.match(File.read(path, encoding: "bom|utf-8"))
251
+ match ? match[0].count("\n") : 0
252
+ end
253
+
175
254
  # Surface what expansion degraded, and record what it read.
176
255
  def report_includes(result, document, root)
177
256
  page = document.relative_path || document.path
@@ -379,6 +458,17 @@ end
379
458
  # BEFORE `setup`, and `setup` is what builds the converter list.
380
459
  Jekyll::Hooks.register :site, :after_reset do |site|
381
460
  Array(site.converters).each do |converter|
382
- converter.reset_symbols if converter.is_a?(Jekyll::Carve::Converter)
461
+ next unless converter.is_a?(Jekyll::Carve::Converter)
462
+
463
+ converter.reset_symbols
464
+ converter.reset_lint
465
+ end
466
+ end
467
+
468
+ # `carve.lint: strict` fails here, after every page was linted and before any
469
+ # output is written.
470
+ Jekyll::Hooks.register :site, :post_render do |site|
471
+ Array(site.converters).each do |converter|
472
+ converter.check_lint! if converter.is_a?(Jekyll::Carve::Converter)
383
473
  end
384
474
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-carve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - markup-carve
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-08 00:00:00.000000000 Z
11
+ date: 2026-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: carve-lang
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.1
19
+ version: 0.1.11
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: 0.2.0
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.1.1
29
+ version: 0.1.11
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: 0.2.0