diff --git a/README.md b/README.md index 30c8cd41..243bdd00 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ Ruby wrapper for Rust's [comrak](https://github.com/kivikakk/comrak) crate. It passes all of the CommonMark test suite, and is therefore spec-complete. It also includes extensions to the CommonMark spec as documented in the [GitHub Flavored Markdown spec](http://github.github.com/gfm/), such as support for tables, strikethroughs, and autolinking. -For more information on available extensions, see [the documentation below](#extension-options). +> [!NOTE] +> By default, several extensions not in any spec have been enabled, for the sake of end user convenience when generating HTML. +> +> For more information on the available options and extensions, see [the documentation below](#options-and-plugins). ## Installation @@ -147,16 +150,16 @@ Commonmarker.to_html('"Hi *there*"', options:{ }) ``` -Note that there is a distinction in comrak for "parse" options and "render" options, which are represented in the tables below. +Note that there is a distinction in comrak for "parse" options and "render" options, which are represented in the tables below. As well, if you wish to disable any-non boolean option, pass in `nil`. ### Parse options -| Name | Description | Default | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| `smart` | Punctuation (quotes, full-stops and hyphens) are converted into 'smart' punctuation. | `false` | -| `default_info_string` | The default info string for fenced code blocks. | `""` | -| `relaxed_tasklist_matching` | Enables relaxing of the tasklist extension matching, allowing any non-space to be used for the "checked" state instead of only `x` and `X`. | `false` | -| `relaxed_autolinks` | Enable relaxing of the autolink extension parsing, allowing links to be recognized when in brackets, as well as permitting any url scheme. | `false` | +| Name | Description | Default | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `smart` | Punctuation (quotes, full-stops and hyphens) are converted into 'smart' punctuation. | `false` | +| `default_info_string` | The default info string for fenced code blocks. | `""` | +| `relaxed_tasklist_matching` | Enables relaxing of the tasklist extension matching, allowing any non-space to be used for the "checked" state instead of only `x` and `X`. | `false` | +| `relaxed_autolinks` | Enable relaxing of the autolink extension parsing, allowing links to be recognized when in brackets, as well as permitting any url scheme. | `false` | ### Render options @@ -187,7 +190,7 @@ Commonmarker.to_html('"Hi *there*"', options: { ### Extension options | Name | Description | Default | -| --------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------- | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------- | | `strikethrough` | Enables the [strikethrough extension](https://github.github.com/gfm/#strikethrough-extension-) from the GFM spec. | `true` | | `tagfilter` | Enables the [tagfilter extension](https://github.github.com/gfm/#disallowed-raw-html-extension-) from the GFM spec. | `true` | | `table` | Enables the [table extension](https://github.github.com/gfm/#tables-extension-) from the GFM spec. | `true` | diff --git a/lib/commonmarker/config.rb b/lib/commonmarker/config.rb index 0cc7841b..f419bb45 100644 --- a/lib/commonmarker/config.rb +++ b/lib/commonmarker/config.rb @@ -45,7 +45,7 @@ module Config underline: false, spoiler: false, greentext: false, - }, + }.freeze, format: [:html].freeze, }.freeze @@ -59,10 +59,6 @@ module Config class << self include Commonmarker::Utils - def merged_with_defaults(options) - Commonmarker::Config::OPTIONS.merge(process_options(options)) - end - def process_options(options) { parse: process_parse_options(options[:parse]), @@ -79,37 +75,30 @@ def process_plugins(plugins) end [:parse, :render, :extension].each do |type| - define_singleton_method :"process_#{type}_options" do |option| + define_singleton_method :"process_#{type}_options" do |options| Commonmarker::Config::OPTIONS[type].each_with_object({}) do |(key, value), hash| - if option.nil? # option not provided, go for the default + if options.nil? || !options.key?(key) # option not provided, use the default hash[key] = value next end - # option explicitly not included, remove it - next if option[key].nil? + if options[key].nil? # # option explicitly not included, remove it + options.delete(key) + next + end - hash[key] = fetch_kv(option, key, value, type) + hash[key] = fetch_kv(options, key, value, type) end end end - [:syntax_highlighter].each do |type| - define_singleton_method :"process_#{type}_plugin" do |plugin| - return if plugin.nil? # plugin explicitly nil, remove it + define_singleton_method :process_syntax_highlighter_plugin do |options| + return if options.nil? # plugin explicitly nil, remove it - Commonmarker::Config::PLUGINS[type].each_with_object({}) do |(key, value), hash| - if plugin.nil? # option not provided, go for the default - hash[key] = value - next - end + raise TypeError, "Expected a Hash for syntax_highlighter plugin, got #{options.class}" unless options.is_a?(Hash) + raise TypeError, "Expected a Hash for syntax_highlighter plugin, got nothing" if options.empty? - # option explicitly not included, remove it - next if plugin[key].nil? - - hash[key] = fetch_kv(plugin, key, value, type) - end - end + Commonmarker::Config::PLUGINS[:syntax_highlighter].merge(options) end end end diff --git a/lib/commonmarker/utils.rb b/lib/commonmarker/utils.rb index 974de948..56ad3270 100644 --- a/lib/commonmarker/utils.rb +++ b/lib/commonmarker/utils.rb @@ -6,16 +6,16 @@ module Commonmarker module Utils include Commonmarker::Constants - def fetch_kv(option, key, value, type) + def fetch_kv(options, key, value, type) value_klass = value.class - if Constants::BOOLS.include?(value) && BOOLS.include?(option[key]) - option[key] - elsif option[key].is_a?(value_klass) - option[key] + if Constants::BOOLS.include?(value) && BOOLS.include?(options[key]) + options[key] + elsif options[key].is_a?(value_klass) + options[key] else expected_type = Constants::BOOLS.include?(value) ? "Boolean" : value_klass.to_s - raise TypeError, "#{type} option `:#{key}` must be #{expected_type}; got #{option[key].class}" + raise TypeError, "#{type} option `:#{key}` must be #{expected_type}; got #{options[key].class}" end end end diff --git a/test/config_test.rb b/test/config_test.rb new file mode 100644 index 00000000..4771838e --- /dev/null +++ b/test/config_test.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require "test_helper" + +class ConfigTest < Minitest::Test + def test_process_options + user_config = { + parse: { + smart: true, + }, + render: { + unsafe: false, + }, + extension: { + autolink: false, + }, + } + processed_config = Commonmarker::Config.process_options(user_config) + + expected_config = [:parse, :render, :extension].each_with_object({}) do |type, hash| + hash[type] = Commonmarker::Config::OPTIONS[type].merge(user_config[type] || {}) + end + + assert_equal(expected_config, processed_config) + end + + def test_process_plugins + user_config = { + syntax_highlighter: { + path: "./themes", + }, + } + processed_config = Commonmarker::Config.process_plugins(user_config) + expected_config = [:syntax_highlighter].each_with_object({}) do |type, hash| + hash[type] = Commonmarker::Config::PLUGINS[type].merge(user_config[type]) + end + + assert_equal(expected_config, processed_config) + end + + def test_config_merges_directly + # hardbreaks work, the `\n` in between is rendered + assert_equal("
aaaa
\nbbbb
aaaa
\nbbbb
", "a", " | ", "", "c", " | ", "x"].each { |html| assert_includes(out, html) } assert_includes(out, "~~hi~~") end - Commonmarker.to_html(@markdown, options: { extension: { strikethrough: true } }).tap do |out| + Commonmarker.to_html(@markdown, options: { extension: { table: false, strikethrough: true } }).tap do |out| assert_includes(out, "| a") refute_includes(out, "~~hi~~") assert_includes(out, "
---|