gitlab-glfm-markdown 0.0.39-x86_64-linux-musl → 0.0.40-x86_64-linux-musl

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: 42637795847d612164394935442b2faf3fa0651bd3dd98caa387fa388f29d0d6
4
- data.tar.gz: 541cb50ff5dfddd6bae60a3f6f5aeb6aca707d720115aa4bf3850bd2a338ead9
3
+ metadata.gz: eb0088abff5e397bde9577a878cd2c825661abe6d2dc692e0a251fa9fcefae86
4
+ data.tar.gz: 5dd36aa2212ee06c4d1546dc4137753614561a660a67c7fd93bb7dd416b981d0
5
5
  SHA512:
6
- metadata.gz: daae2d2ef3209da8b8d870e8ffb560c1bfafb35557b3b16599fa103f93c7f8fb8ff369c8d504eea1f7beeadf1bff871f8b7a5029b8f0394cb3cae466725eecb6
7
- data.tar.gz: b56b594fddff880be8db81052a6e653871ccacfc6fff176cc5590b5a65010f956a28befe85e3052890c9221353a3c76d31f17965031a72825c6613294276a685
6
+ metadata.gz: f8ff221a2a371e4de120f7d93cb87ccd1f52670e19faa3e40cc79e0c71b4c26e70b6b04e60680d6d9102b00b068f0fa194114c7c18f8caa68f0e1c0f294eaee2
7
+ data.tar.gz: fa4678a099c510324ebd91d4533f0cfcf0495f8d81945d4d463850c564f8c14341bceea8c3abe24898cd46ad36dc751865644f94aee0cc4d082b3056b58d89cb
data/Cargo.lock CHANGED
@@ -221,9 +221,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
221
221
 
222
222
  [[package]]
223
223
  name = "comrak"
224
- version = "0.48.0"
224
+ version = "0.49.0"
225
225
  source = "registry+https://github.com/rust-lang/crates.io-index"
226
- checksum = "48bf2260aceee247c6c5639f5751dc635211895066d782d2a28fb87f2e0d5613"
226
+ checksum = "ab87129dce2f2d7e75e753b1df0e5093b27dec8fa5970b6eb51280faacb25bd6"
227
227
  dependencies = [
228
228
  "caseless",
229
229
  "emojis",
@@ -307,7 +307,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
307
307
 
308
308
  [[package]]
309
309
  name = "gitlab-glfm-markdown"
310
- version = "0.0.39"
310
+ version = "0.0.40"
311
311
  dependencies = [
312
312
  "clap",
313
313
  "comrak",
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Latest Release](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/badges/release.svg)](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/releases)
5
5
 
6
6
  Implements GLFM (as used by GitLab) using the Rust-based Markdown parser
7
- [Comrak](https://github.com/kivikakk/comrak) (0.48.0), providing a Ruby interface.
7
+ [Comrak](https://github.com/kivikakk/comrak) (0.49.0), providing a Ruby interface.
8
8
 
9
9
  This project is still in constant flux, so interfaces and functionality can change at any time.
10
10
 
@@ -221,9 +221,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
221
221
 
222
222
  [[package]]
223
223
  name = "comrak"
224
- version = "0.48.0"
224
+ version = "0.49.0"
225
225
  source = "registry+https://github.com/rust-lang/crates.io-index"
226
- checksum = "48bf2260aceee247c6c5639f5751dc635211895066d782d2a28fb87f2e0d5613"
226
+ checksum = "ab87129dce2f2d7e75e753b1df0e5093b27dec8fa5970b6eb51280faacb25bd6"
227
227
  dependencies = [
228
228
  "caseless",
229
229
  "emojis",
@@ -307,7 +307,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
307
307
 
308
308
  [[package]]
309
309
  name = "gitlab-glfm-markdown"
310
- version = "0.0.39"
310
+ version = "0.0.40"
311
311
  dependencies = [
312
312
  "clap",
313
313
  "comrak",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "gitlab-glfm-markdown"
3
- version = "0.0.39"
3
+ version = "0.0.40"
4
4
  edition = "2021"
5
5
  authors = ["digitalmoksha <bwalker@gitlab.com>", "Asherah Connor <aconnor@gitlab.com>"]
6
6
  description = "GitLab Flavored Markdown parser and formatter. 100% CommonMark-compatible. Experimental."
@@ -15,7 +15,7 @@ required-features = ["cli"]
15
15
 
16
16
  [dependencies]
17
17
  clap = { version = "=4.4.18", optional = true, features = ["derive", "string"] }
18
- comrak = { version = "0.48.0", default-features = false, features = ["shortcodes"] }
18
+ comrak = { version = "0.49.0", default-features = false, features = ["shortcodes"] }
19
19
  magnus = "0.8.2"
20
20
  rb-sys = { version = "0.9.117", default-features = false, features = ["stable-api-compiled-fallback"] }
21
21
  regex = "1.11.1"
@@ -2,8 +2,8 @@ use std::fmt::{self, Write};
2
2
  use std::sync::LazyLock;
3
3
 
4
4
  use comrak::html::{collect_text, format_node_default, render_sourcepos, ChildRendering, Context};
5
- use comrak::nodes::{AstNode, ListType, NodeHeading, NodeLink, NodeList, NodeValue};
6
- use comrak::{create_formatter, html, node_matches};
5
+ use comrak::nodes::{ListType, NodeHeading, NodeLink, NodeList, NodeTaskItem, NodeValue};
6
+ use comrak::{create_formatter, html, node_matches, Node};
7
7
  use regex::Regex;
8
8
 
9
9
  use crate::glfm::RenderOptions;
@@ -11,6 +11,7 @@ use crate::glfm::RenderOptions;
11
11
  static PLACEHOLDER_REGEX: LazyLock<Regex> =
12
12
  LazyLock::new(|| Regex::new(r"%\{(?:\w{1,30})}").unwrap());
13
13
 
14
+ #[derive(Default)]
14
15
  pub struct RenderUserData {
15
16
  pub default_html: bool,
16
17
  pub inapplicable_tasks: bool,
@@ -55,8 +56,8 @@ create_formatter!(CustomFormatter<RenderUserData>, {
55
56
  NodeValue::List(ref nl) => |context, node, entering| {
56
57
  return render_list(context, node, entering, nl);
57
58
  },
58
- NodeValue::TaskItem(symbol) => |context, node, entering| {
59
- return render_task_item(context, node, entering, symbol);
59
+ NodeValue::TaskItem(ref nti) => |context, node, entering| {
60
+ return render_task_item(context, node, entering, nti);
60
61
  },
61
62
  NodeValue::Escaped => |context, node, entering| {
62
63
  return render_escaped(context, node, entering);
@@ -66,9 +67,9 @@ create_formatter!(CustomFormatter<RenderUserData>, {
66
67
  },
67
68
  });
68
69
 
69
- fn render_text<'a>(
70
+ fn render_text(
70
71
  context: &mut Context<RenderUserData>,
71
- node: &'a AstNode<'a>,
72
+ node: Node<'_>,
72
73
  entering: bool,
73
74
  literal: &str,
74
75
  ) -> Result<ChildRendering, fmt::Error> {
@@ -99,9 +100,9 @@ fn render_text<'a>(
99
100
  Ok(ChildRendering::HTML)
100
101
  }
101
102
 
102
- fn render_link<'a>(
103
+ fn render_link(
103
104
  context: &mut Context<RenderUserData>,
104
- node: &'a AstNode<'a>,
105
+ node: Node<'_>,
105
106
  entering: bool,
106
107
  nl: &NodeLink,
107
108
  ) -> Result<ChildRendering, fmt::Error> {
@@ -148,9 +149,9 @@ fn render_link<'a>(
148
149
  Ok(ChildRendering::HTML)
149
150
  }
150
151
 
151
- fn render_image<'a>(
152
+ fn render_image(
152
153
  context: &mut Context<RenderUserData>,
153
- node: &'a AstNode<'a>,
154
+ node: Node<'_>,
154
155
  entering: bool,
155
156
  nl: &NodeLink,
156
157
  ) -> Result<ChildRendering, fmt::Error> {
@@ -202,9 +203,9 @@ fn render_image<'a>(
202
203
 
203
204
  // Overridden to use class `task-list` instead of `contains-task-list`
204
205
  // to align with GitLab class usage
205
- fn render_list<'a>(
206
+ fn render_list(
206
207
  context: &mut Context<RenderUserData>,
207
- node: &'a AstNode<'a>,
208
+ node: Node<'_>,
208
209
  entering: bool,
209
210
  nl: &NodeList,
210
211
  ) -> Result<ChildRendering, fmt::Error> {
@@ -239,87 +240,51 @@ fn render_list<'a>(
239
240
  Ok(ChildRendering::HTML)
240
241
  }
241
242
 
242
- // Overridden to detect inapplicable task list items
243
- fn render_task_item<'a>(
243
+ // Overridden to:
244
+ // 1. Detect inapplicable task list items; and,
245
+ // 2. Output checkbox sourcepos.
246
+ fn render_task_item(
244
247
  context: &mut Context<RenderUserData>,
245
- node: &'a AstNode<'a>,
248
+ node: Node<'_>,
246
249
  entering: bool,
247
- symbol: Option<char>,
250
+ nti: &NodeTaskItem,
248
251
  ) -> Result<ChildRendering, fmt::Error> {
249
- if !context.user.inapplicable_tasks {
250
- return html::format_node_default(context, node, entering);
251
- }
252
-
253
- let Some(symbol) = symbol else {
254
- return html::format_node_default(context, node, entering);
255
- };
256
-
257
- if symbol == 'x' || symbol == 'X' {
258
- return html::format_node_default(context, node, entering);
259
- }
260
-
261
- // We only proceed past this point if:
262
- //
263
- // * inapplicable_tasks is enabled; and,
264
- // * the symbol is present (the tasklist didn't contain a ' '), and isn't 'x' or 'X'.
265
- //
266
- // There are three possibilities remaining:
267
- //
268
- // * the symbol is '~': we write out an inapplicable task item.
269
- // * the symbol is a different Unicode whitespace: we write out an incomplete task item,
270
- // per Comrak.
271
- // * the symbol is something else: we write out the source Markdown that would've been entered,
272
- // to act like a non-match.
273
- //
274
- // TODO: have Comrak accept a list of acceptable tasklist symbols instead. :)
275
-
276
252
  let write_li = node
277
253
  .parent()
278
254
  .map(|p| node_matches!(p, NodeValue::List(_)))
279
255
  .unwrap_or_default();
280
256
 
281
- if entering {
282
- if symbol == '~' {
283
- context.cr()?;
284
- if write_li {
285
- context.write_str("<li")?;
286
- context.write_str(" class=\"inapplicable")?;
287
-
288
- if context.options.render.tasklist_classes {
289
- context.write_str(" task-list-item")?;
290
- }
291
- context.write_str("\"")?;
292
- html::render_sourcepos(context, node)?;
293
- context.write_str(">")?;
294
- }
295
- context.write_str("<input type=\"checkbox\"")?;
296
- if !write_li {
297
- html::render_sourcepos(context, node)?;
298
- }
299
- if context.options.render.tasklist_classes {
300
- context.write_str(" class=\"task-list-item-checkbox\"")?;
301
- }
257
+ if !entering {
258
+ if write_li {
259
+ context.write_str("</li>\n")?;
260
+ }
261
+ return Ok(ChildRendering::HTML);
262
+ }
302
263
 
303
- context.write_str(" data-inapplicable disabled=\"\"> ")?;
304
- } else if symbol.is_whitespace() {
305
- context.cr()?;
306
- if write_li {
307
- context.write_str("<li")?;
308
- if context.options.render.tasklist_classes {
309
- context.write_str(" class=\"task-list-item\"")?;
310
- }
311
- render_sourcepos(context, node)?;
312
- context.write_str(">")?;
313
- }
314
- context.write_str("<input type=\"checkbox\"")?;
315
- if !write_li {
316
- render_sourcepos(context, node)?;
317
- }
318
- if context.options.render.tasklist_classes {
319
- context.write_str(" class=\"task-list-item-checkbox\"")?;
320
- }
321
- context.write_str(" disabled=\"\" /> ")?;
322
- } else {
264
+ match nti.symbol {
265
+ Some('~') => {
266
+ render_task_item_with(
267
+ context,
268
+ node,
269
+ nti,
270
+ if context.user.inapplicable_tasks {
271
+ TaskItemState::Inapplicable
272
+ } else {
273
+ TaskItemState::Checked
274
+ },
275
+ write_li,
276
+ )?;
277
+ }
278
+ None => {
279
+ render_task_item_with(context, node, nti, TaskItemState::Unchecked, write_li)?;
280
+ }
281
+ Some(ws) if ws.is_whitespace() => {
282
+ render_task_item_with(context, node, nti, TaskItemState::Unchecked, write_li)?;
283
+ }
284
+ Some('x' | 'X') => {
285
+ render_task_item_with(context, node, nti, TaskItemState::Checked, write_li)?;
286
+ }
287
+ Some(symbol) => {
323
288
  context.cr()?;
324
289
  if write_li {
325
290
  context.write_str("<li")?;
@@ -333,16 +298,72 @@ fn render_task_item<'a>(
333
298
  context.escape(&symbol.to_string())?;
334
299
  context.write_str("] ")?;
335
300
  }
336
- } else if write_li {
337
- context.write_str("</li>\n")?;
338
301
  }
339
302
 
340
303
  Ok(ChildRendering::HTML)
341
304
  }
342
305
 
343
- fn render_escaped<'a>(
306
+ #[derive(PartialEq)]
307
+ enum TaskItemState {
308
+ Checked,
309
+ Unchecked,
310
+ Inapplicable,
311
+ }
312
+
313
+ fn render_task_item_with(
314
+ context: &mut Context<RenderUserData>,
315
+ node: Node<'_>,
316
+ nti: &NodeTaskItem,
317
+ state: TaskItemState,
318
+ write_li: bool,
319
+ ) -> fmt::Result {
320
+ context.cr()?;
321
+ if write_li {
322
+ context.write_str("<li")?;
323
+ if context.options.render.tasklist_classes {
324
+ context.write_str(" class=\"")?;
325
+ if state == TaskItemState::Inapplicable {
326
+ context.write_str("inapplicable ")?;
327
+ }
328
+ context.write_str("task-list-item\"")?;
329
+ }
330
+ render_sourcepos(context, node)?;
331
+ context.write_str(">")?;
332
+ }
333
+
334
+ context.write_str("<input type=\"checkbox\"")?;
335
+ if !write_li {
336
+ html::render_sourcepos(context, node)?;
337
+ }
338
+ if context.options.render.sourcepos {
339
+ write!(
340
+ context,
341
+ " data-checkbox-sourcepos=\"{:?}\"",
342
+ nti.symbol_sourcepos
343
+ )?;
344
+ }
345
+
346
+ if context.options.render.tasklist_classes {
347
+ context.write_str(" class=\"task-list-item-checkbox\"")?;
348
+ }
349
+
350
+ match state {
351
+ TaskItemState::Checked => {
352
+ context.write_str(" checked=\"\"")?;
353
+ }
354
+ TaskItemState::Unchecked => {}
355
+ TaskItemState::Inapplicable => {
356
+ context.write_str(" data-inapplicable")?;
357
+ }
358
+ }
359
+ context.write_str(" disabled=\"\" /> ")?;
360
+
361
+ Ok(())
362
+ }
363
+
364
+ fn render_escaped(
344
365
  context: &mut Context<RenderUserData>,
345
- node: &'a AstNode<'a>,
366
+ node: Node<'_>,
346
367
  entering: bool,
347
368
  ) -> Result<ChildRendering, fmt::Error> {
348
369
  if !context.options.render.escaped_char_spans {
@@ -353,7 +374,7 @@ fn render_escaped<'a>(
353
374
  .user
354
375
  .only_escape_chars
355
376
  .as_ref()
356
- .map_or(true, |only_escape_chars| {
377
+ .is_none_or(|only_escape_chars| {
357
378
  with_node_text_content(node, false, |content| {
358
379
  content.chars().count() == 1
359
380
  && only_escape_chars.contains(&content.chars().next().unwrap())
@@ -372,9 +393,9 @@ fn render_escaped<'a>(
372
393
  Ok(ChildRendering::HTML)
373
394
  }
374
395
 
375
- fn render_heading<'a>(
396
+ fn render_heading(
376
397
  context: &mut Context<RenderUserData>,
377
- node: &'a AstNode<'a>,
398
+ node: Node<'_>,
378
399
  entering: bool,
379
400
  nh: &NodeHeading,
380
401
  ) -> Result<ChildRendering, fmt::Error> {
@@ -415,7 +436,7 @@ fn render_heading<'a>(
415
436
 
416
437
  /// If the given node has a single text child, apply a function to the text content
417
438
  /// of that node. Otherwise, return the given default value.
418
- fn with_node_text_content<'a, U, F>(node: &'a AstNode<'a>, default: U, f: F) -> U
439
+ fn with_node_text_content<U, F>(node: Node<'_>, default: U, f: F) -> U
419
440
  where
420
441
  F: FnOnce(&str) -> U,
421
442
  {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GLFMMarkdown
4
- VERSION = '0.0.39'
4
+ VERSION = '0.0.40'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-glfm-markdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.39
4
+ version: 0.0.40
5
5
  platform: x86_64-linux-musl
6
6
  authors:
7
7
  - Brett Walker
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-11-14 00:00:00.000000000 Z
12
+ date: 2025-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rb_sys