gitlab-glfm-markdown 0.0.4 → 0.0.8

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.
data/LICENSE CHANGED
@@ -1,6 +1,13 @@
1
- The MIT License (MIT)
1
+ Copyright (c) 2011-present GitLab B.V.
2
2
 
3
- Copyright (c) 2022-present GitLab B.V.
3
+ Portions of this software are licensed as follows:
4
+
5
+ * All content residing under the "doc/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
6
+ * All content that resides under the "ee/" directory of this repository, if that directory exists, is licensed under the license defined in "ee/LICENSE".
7
+ * All content that resides under the "jh/" directory of this repository, if that directory exists, is licensed under the license defined in "jh/LICENSE".
8
+ * All client-side JavaScript (when served directly or after being compiled, arranged, augmented, or combined), is licensed under the "MIT Expat" license.
9
+ * All third party components incorporated into the GitLab Software are licensed under the original license provided by the owner of the applicable component.
10
+ * Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
4
11
 
5
12
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
13
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # GitLab Flavored Markdown
2
2
 
3
+ [![Pipeline status](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/badges/main/pipeline.svg)](https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/commits/main)
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
+
3
6
  Implements GLFM (as used by GitLab) using a Rust-based markdown parser.
4
7
 
5
8
  This project is currently EXPLORATORY, so anything and everything will change.
@@ -22,7 +25,7 @@ Try on command line:
22
25
  rake compile
23
26
  bin/console
24
27
 
25
- GLFMMarkdown.to_html('# header', options: {sourcepos: true})
28
+ GLFMMarkdown.to_html('# header', options: { glfm: true })
26
29
  ```
27
30
 
28
31
  ## Development
@@ -30,12 +33,32 @@ GLFMMarkdown.to_html('# header', options: {sourcepos: true})
30
33
  A command line executable can be built for debugging.
31
34
 
32
35
  ```
33
- cd ext/glfm_markdown
34
- cargo run --bin glfm_markdown -- --sourcepos
36
+ cargo run --bin glfm_markdown --features="cli" -- --help
37
+ cargo run --bin glfm_markdown --features="cli" -- --sourcepos
35
38
  ```
36
39
 
37
40
  There is a VSCode workspace that allows you to `Debug executable`
38
41
 
42
+ When developing another project locally and using `gitlab-glfm-markdown` by linking
43
+ directly to the gem's source directory, make sure that you're using the same version
44
+ of Ruby for the project and the gem. Otherwise you can see unexplained errors when
45
+ calling into the gem.
46
+
47
+ ### Releasing a new version
48
+
49
+ To release a new version:
50
+
51
+ 1. Update `lib/glfm_markdown/version.rb` with the version number.
52
+ 1. Update `CHANGELOG.md` with the changes in the release.
53
+ 1. Create a merge request and merge it to `master`.
54
+ 1. Push a new tag to the repository.
55
+
56
+ The new version with precompiled, native gems will automatically be
57
+ published to [RubyGems](https://rubygems.org/gems/gitlab-glfm-markdown) when the
58
+ pipeline for the tag completes.
59
+
39
60
  ## Contributing
40
61
 
41
62
  Bug reports and merge requests are welcome on GitLab at https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown.
63
+
64
+ Please refer to [CONTRIBUTING](CONTRIBUTING.md) for more details.
@@ -1,8 +1,9 @@
1
1
  [package]
2
2
  name = "glfm_markdown"
3
- version = "0.0.3"
3
+ version = "0.0.8"
4
4
  edition = "2021"
5
5
  authors = ["digitalmoksha <bwalker@gitlab.com>"]
6
+ description = "GitLab Flavored Markdown parser and formatter. 100% CommonMark-compatible. Experimental."
6
7
  publish = false
7
8
 
8
9
  [lib]
@@ -10,8 +11,13 @@ crate-type = ["cdylib"]
10
11
 
11
12
  [[bin]]
12
13
  name = "glfm_markdown"
14
+ required-features = ["cli"]
13
15
 
14
16
  [dependencies]
15
- magnus = { version = "0.4" }
16
- argparse = { version = ">= 0.2.1" }
17
- comrak = { git = "https://github.com/kivikakk/comrak.git" }
17
+ clap = { version = "4.0", optional = true, features = ["derive", "string"] }
18
+ comrak = { version = "0.20.0", default-features = false }
19
+ magnus = "0.6.2"
20
+ rb-sys = { version = "0.9.83", default-features = false, features = ["stable-api-compiled-fallback"] }
21
+
22
+ [features]
23
+ cli = ["clap", "comrak/syntect"]
@@ -3,4 +3,6 @@
3
3
  require 'mkmf'
4
4
  require 'rb_sys/mkmf'
5
5
 
6
- create_rust_makefile('glfm_markdown/glfm_markdown')
6
+ create_rust_makefile('glfm_markdown') do |r|
7
+ r.auto_install_rust_toolchain = false
8
+ end
@@ -1,6 +1,23 @@
1
1
  #[derive(Debug)]
2
2
  pub struct RenderOptions {
3
+ pub autolink: bool,
4
+ pub escape: bool,
5
+ pub description_lists: bool,
6
+ pub footnotes: bool,
7
+ pub full_info_string: bool,
8
+ pub github_pre_lang: bool,
9
+ pub hardbreaks: bool,
10
+ pub relaxed_autolinks: bool,
11
+ pub relaxed_tasklist_character: bool,
3
12
  pub sourcepos: bool,
13
+ pub smart: bool,
14
+ pub strikethrough: bool,
15
+ pub superscript: bool,
16
+ pub table: bool,
17
+ pub tagfilter: bool,
18
+ pub tasklist: bool,
19
+ pub unsafe_: bool,
20
+
4
21
  pub debug: bool,
5
22
  }
6
23
 
@@ -11,20 +28,25 @@ pub fn render(text: String, options: RenderOptions) -> String {
11
28
  fn render_comrak(text: String, options: RenderOptions) -> String {
12
29
  let mut comrak_options = comrak::ComrakOptions::default();
13
30
 
14
- comrak_options.extension.strikethrough = true;
15
- comrak_options.extension.table = true;
16
- comrak_options.extension.autolink = true;
17
- comrak_options.extension.tasklist = false;
18
- comrak_options.extension.footnotes = true;
31
+ comrak_options.extension.autolink = options.autolink;
32
+ comrak_options.extension.description_lists = options.description_lists;
33
+ comrak_options.extension.footnotes = options.footnotes;
34
+ comrak_options.extension.strikethrough = options.strikethrough;
35
+ comrak_options.extension.superscript = options.superscript;
36
+ comrak_options.extension.table = options.table;
37
+ comrak_options.extension.tagfilter = options.tagfilter;
38
+ comrak_options.extension.tasklist = options.tasklist;
19
39
 
20
- comrak_options.render.unsafe_ = true;
21
- comrak_options.render.github_pre_lang = true;
22
- comrak_options.render.full_info_string = true;
23
- comrak_options.render.hardbreaks = false;
40
+ comrak_options.render.escape = options.escape;
41
+ comrak_options.render.full_info_string = options.full_info_string;
42
+ comrak_options.render.github_pre_lang = options.github_pre_lang;
43
+ comrak_options.render.hardbreaks = options.hardbreaks;
24
44
  comrak_options.render.sourcepos = options.sourcepos;
45
+ comrak_options.render.unsafe_ = options.unsafe_;
25
46
 
26
- comrak_options.parse.smart = false;
27
- comrak_options.parse.relaxed_autolinks = false;
47
+ comrak_options.parse.relaxed_autolinks = options.relaxed_autolinks;
48
+ comrak_options.parse.relaxed_tasklist_matching = options.relaxed_tasklist_character;
49
+ comrak_options.parse.smart = options.smart;
28
50
 
29
51
  comrak::markdown_to_html(&text, &comrak_options)
30
52
  }
@@ -3,10 +3,33 @@ use magnus::{define_module, function, prelude::*, Error, RHash, Symbol};
3
3
  mod glfm;
4
4
  use glfm::{render, RenderOptions};
5
5
 
6
- pub fn render_to_html(text: String, options: RHash) -> String {
7
- let sourcepos: bool = options.lookup::<_, bool>(Symbol::new("sourcepos")).unwrap();
8
- let debug: bool = options.lookup::<_, bool>(Symbol::new("debug")).unwrap();
9
- let render_options = RenderOptions { sourcepos, debug };
6
+ /// Lookup symbol in provided `RHash`. Returns `false` if the key is not present
7
+ /// or value cannot be converted to a boolean.
8
+ fn get_opt(arg: &str, options: RHash) -> bool {
9
+ options.lookup(Symbol::new(arg)).unwrap_or_default()
10
+ }
11
+
12
+ pub fn render_to_html_rs(text: String, options: RHash) -> String {
13
+ let render_options = RenderOptions {
14
+ autolink: get_opt("autolink", options),
15
+ description_lists: get_opt("description_lists", options),
16
+ escape: get_opt("escape", options),
17
+ footnotes: get_opt("footnotes", options),
18
+ full_info_string: get_opt("full_info_string", options),
19
+ github_pre_lang: get_opt("github_pre_lang", options),
20
+ hardbreaks: get_opt("hardbreaks", options),
21
+ relaxed_autolinks: get_opt("relaxed_autolinks", options),
22
+ relaxed_tasklist_character: get_opt("relaxed_tasklist_character", options),
23
+ sourcepos: get_opt("sourcepos", options),
24
+ smart: get_opt("smart", options),
25
+ strikethrough: get_opt("strikethrough", options),
26
+ superscript: get_opt("superscript", options),
27
+ table: get_opt("table", options),
28
+ tagfilter: get_opt("tagfilter", options),
29
+ tasklist: get_opt("tasklist", options),
30
+ unsafe_: get_opt("unsafe", options),
31
+ debug: get_opt("debug", options),
32
+ };
10
33
 
11
34
  render(text, render_options)
12
35
  }
@@ -15,7 +38,7 @@ pub fn render_to_html(text: String, options: RHash) -> String {
15
38
  fn init() -> Result<(), Error> {
16
39
  let module = define_module("GLFMMarkdown")?;
17
40
 
18
- module.define_singleton_method("render_to_html", function!(render_to_html, 2))?;
41
+ module.define_singleton_method("render_to_html_rs", function!(render_to_html_rs, 2))?;
19
42
 
20
43
  Ok(())
21
44
  }
@@ -3,52 +3,132 @@ use glfm::{render, RenderOptions};
3
3
  use std::io::Read;
4
4
  use std::io::Write;
5
5
 
6
+ use clap::Parser;
7
+
8
+ #[derive(Parser, Debug)]
9
+ #[command(author, version, about, long_about = None)]
10
+ struct Args {
11
+ /// CommonMark file(s) to parse; or standard input if none passed
12
+ #[arg(value_name = "FILE")]
13
+ file: Option<String>,
14
+
15
+ /// Enable 'autolink' extension
16
+ #[arg(long)]
17
+ autolink: bool,
18
+
19
+ /// Enable 'description-lists' extension
20
+ #[arg(long)]
21
+ description_lists: bool,
22
+
23
+ /// Escape raw HTML instead of clobbering it
24
+ #[arg(long)]
25
+ escape: bool,
26
+
27
+ /// Enable 'footnotes' extension
28
+ #[arg(long)]
29
+ footnotes: bool,
30
+
31
+ /// Enable full info strings for code blocks
32
+ #[arg(long)]
33
+ full_info_string: bool,
34
+
35
+ /// Use GitHub-style <pre lang> for code blocks
36
+ #[arg(long)]
37
+ github_pre_lang: bool,
38
+
39
+ /// Treat newlines as hard line breaks
40
+ #[arg(long)]
41
+ hardbreaks: bool,
42
+
43
+ /// Write output to FILE instead of stdout
44
+ #[arg(short, long, value_name = "FILE")]
45
+ output: Option<String>,
46
+
47
+ /// Enable relaxing of autolink parsing, allowing links to be recognized when in brackets
48
+ #[arg(long)]
49
+ relaxed_autolinks: bool,
50
+
51
+ /// Enable relaxing which character is allowed in a tasklists
52
+ #[arg(long)]
53
+ relaxed_tasklist_character: bool,
54
+
55
+ /// Include source mappings in HTML attributes
56
+ #[arg(long)]
57
+ sourcepos: bool,
58
+
59
+ /// Use smart punctuation
60
+ #[arg(long)]
61
+ smart: bool,
62
+
63
+ /// Enable 'strikethrough' extension
64
+ #[arg(long)]
65
+ strikethrough: bool,
66
+
67
+ /// Enable 'superscript' extension
68
+ #[arg(long)]
69
+ superscript: bool,
70
+
71
+ /// Enable 'table' extension
72
+ #[arg(long)]
73
+ table: bool,
74
+
75
+ /// Enable 'tagfilter' extension
76
+ #[arg(long)]
77
+ tagfilter: bool,
78
+
79
+ /// Enable 'tasklist' extension
80
+ #[arg(long)]
81
+ tasklist: bool,
82
+
83
+ /// Allow raw HTML and dangerous URLs
84
+ #[arg(long = "unsafe")]
85
+ unsafe_: bool,
86
+
87
+ /// Show debug information
88
+ #[arg(long)]
89
+ debug: bool,
90
+ }
91
+
6
92
  fn main() {
7
- let mut input = "-".to_owned();
8
- let mut output = "-".to_owned();
9
- let mut sourcepos = false;
10
- let mut debug = false;
11
-
12
- {
13
- // this block limits scope of borrows by cli.refer() method
14
- let mut cli = argparse::ArgumentParser::new();
15
-
16
- cli.set_description("Gitlab Flavored Markdown. Experimental.");
17
-
18
- cli.refer(&mut input)
19
- .add_argument("file", argparse::Store, "File to read");
20
- cli.refer(&mut output)
21
- .add_option(&["-o", "--output"], argparse::Store, "File to write");
22
- cli.refer(&mut sourcepos).add_option(
23
- &["--sourcepos"],
24
- argparse::StoreTrue,
25
- "Include source mappings in HTML attributes.",
26
- );
27
- cli.refer(&mut debug).add_option(
28
- &["--debug"],
29
- argparse::StoreTrue,
30
- "Show debug information",
31
- );
32
-
33
- cli.parse_args_or_exit();
34
- }
35
-
36
- let vec = if input == "-" {
37
- let mut vec = Vec::new();
38
- std::io::stdin().read_to_end(&mut vec).unwrap();
39
- vec
40
- } else {
41
- std::fs::read(input).unwrap()
93
+ let mut s: Vec<u8> = Vec::with_capacity(2048);
94
+ let cli = Args::parse();
95
+
96
+ match cli.file {
97
+ None => {
98
+ std::io::stdin().read_to_end(&mut s).unwrap();
99
+ }
100
+ Some(fs) => {
101
+ s = std::fs::read(fs).unwrap();
102
+ }
42
103
  };
43
104
 
44
- let source = String::from_utf8_lossy(&vec);
45
- let options = RenderOptions { sourcepos, debug };
105
+ let source = String::from_utf8_lossy(&s);
106
+ let options = RenderOptions {
107
+ autolink: cli.autolink,
108
+ description_lists: cli.description_lists,
109
+ escape: cli.escape,
110
+ footnotes: cli.footnotes,
111
+ full_info_string: cli.full_info_string,
112
+ github_pre_lang: cli.github_pre_lang,
113
+ hardbreaks: cli.hardbreaks,
114
+ relaxed_autolinks: cli.relaxed_autolinks,
115
+ relaxed_tasklist_character: cli.relaxed_tasklist_character,
116
+ sourcepos: cli.sourcepos,
117
+ smart: cli.smart,
118
+ strikethrough: cli.strikethrough,
119
+ superscript: cli.superscript,
120
+ table: cli.table,
121
+ tagfilter: cli.tagfilter,
122
+ tasklist: cli.tasklist,
123
+ unsafe_: cli.unsafe_,
124
+ debug: cli.debug,
125
+ };
46
126
 
47
127
  let result = render(source.to_string(), options);
48
128
 
49
- if output == "-" {
50
- std::io::stdout().write_all(result.as_bytes()).unwrap();
129
+ if let Some(output_filename) = cli.output {
130
+ std::fs::write(output_filename, &result).unwrap();
51
131
  } else {
52
- std::fs::write(output, &result).unwrap();
53
- }
132
+ std::io::stdout().write_all(result.as_bytes()).unwrap();
133
+ };
54
134
  }
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ def load_rust_extension
4
+ ruby_version = /(\d+\.\d+)/.match(RUBY_VERSION)
5
+ require_relative "./#{ruby_version}/glfm_markdown"
6
+ rescue LoadError
7
+ require 'glfm_markdown/glfm_markdown'
8
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GLFMMarkdown
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.8'
5
5
  end
data/lib/glfm_markdown.rb CHANGED
@@ -1,17 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'glfm_markdown/version'
4
- require_relative 'glfm_markdown/glfm_markdown'
4
+ require_relative 'glfm_markdown/loader'
5
5
 
6
- DEFAULT_OPTIONS = {
6
+ load_rust_extension
7
+
8
+ GLFM_DEFAULT_OPTIONS = {
9
+ autolink: true,
10
+ footnotes: true,
11
+ full_info_string: true,
12
+ github_pre_lang: false,
13
+ hardbreaks: false,
14
+ relaxed_autolinks: false,
7
15
  sourcepos: true,
16
+ smart: false,
17
+ strikethrough: true,
18
+ table: true,
19
+ tagfilter: false,
20
+ tasklist: true,
21
+ unsafe: true,
22
+
8
23
  debug: false
9
24
  }.freeze
10
25
 
11
26
  module GLFMMarkdown
12
27
  class << self
13
- def to_html(text, options: {})
14
- render_to_html(text, DEFAULT_OPTIONS.merge(options))
28
+ def to_html(markdown, options: {})
29
+ raise TypeError, 'markdown must be a String' unless markdown.is_a?(String)
30
+ raise TypeError, 'markdown must be UTF-8 encoded' unless markdown.encoding.name == "UTF-8"
31
+ raise TypeError, 'options must be a Hash' unless options.is_a?(Hash)
32
+
33
+ default_options = options[:glfm] ? GLFM_DEFAULT_OPTIONS : {}
34
+ options = options.merge(unsafe: true) if options[:tagfilter]
35
+
36
+ render_to_html_rs(markdown, default_options.merge(options))
15
37
  end
16
38
  end
17
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-glfm-markdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Walker
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-08 00:00:00.000000000 Z
11
+ date: 2023-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.9'
27
27
  - !ruby/object:Gem::Dependency
28
- name: pry
28
+ name: pry-byebug
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.12.2
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.12.2
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.3'
83
- description: GLFM Markdown
83
+ description: Markdown processing for GitLab Flavored Markdown
84
84
  email:
85
85
  - bwalker@gitlab.com
86
86
  executables: []
@@ -97,13 +97,15 @@ files:
97
97
  - ext/glfm_markdown/src/lib.rs
98
98
  - ext/glfm_markdown/src/main.rs
99
99
  - lib/glfm_markdown.rb
100
+ - lib/glfm_markdown/loader.rb
100
101
  - lib/glfm_markdown/version.rb
101
102
  homepage: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown
102
- licenses: []
103
+ licenses:
104
+ - MIT
103
105
  metadata:
104
106
  homepage_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown
105
107
  source_code_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown
106
- changelog_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/blob/main/CHANGELOG.md
108
+ changelog_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-glfm-markdown/-/releases
107
109
  post_install_message:
108
110
  rdoc_options: []
109
111
  require_paths:
@@ -112,14 +114,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
112
114
  requirements:
113
115
  - - ">="
114
116
  - !ruby/object:Gem::Version
115
- version: 3.0.0
117
+ version: '2.7'
116
118
  required_rubygems_version: !ruby/object:Gem::Requirement
117
119
  requirements:
118
120
  - - ">="
119
121
  - !ruby/object:Gem::Version
120
- version: 3.2.33
122
+ version: '0'
121
123
  requirements: []
122
- rubygems_version: 3.4.10
124
+ rubygems_version: 3.3.26
123
125
  signing_key:
124
126
  specification_version: 4
125
127
  summary: GLFM Markdown