qiita-markdown 0.44.1 → 1.0.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/.github/workflows/test.yml +2 -2
- data/.rubocop.yml +0 -4
- data/.rubocop_todo.yml +6 -44
- data/CHANGELOG.md +10 -0
- data/README.md +3 -1
- data/lib/qiita/markdown/filters/checkbox.rb +5 -1
- data/lib/qiita/markdown/filters/custom_block.rb +7 -6
- data/lib/qiita/markdown/filters/final_sanitizer.rb +8 -2
- data/lib/qiita/markdown/filters/heading_anchor.rb +44 -0
- data/lib/qiita/markdown/filters/html_toc.rb +67 -0
- data/lib/qiita/markdown/filters/qiita_marker.rb +55 -0
- data/lib/qiita/markdown/filters/user_input_sanitizer.rb +14 -9
- data/lib/qiita/markdown/processor.rb +2 -1
- data/lib/qiita/markdown/summary_processor.rb +1 -1
- data/lib/qiita/markdown/version.rb +1 -1
- data/lib/qiita/markdown.rb +4 -5
- data/qiita-markdown.gemspec +2 -3
- data/spec/qiita/markdown/filters/checkbox_spec.rb +28 -0
- data/spec/qiita/markdown/filters/heading_anchor_spec.rb +73 -0
- data/spec/qiita/markdown/filters/html_toc_spec.rb +223 -0
- data/spec/qiita/markdown/filters/qiita_marker_spec.rb +60 -0
- data/spec/qiita/markdown/processor_spec.rb +48 -54
- data/spec/qiita/markdown/summary_processor_spec.rb +2 -2
- metadata +23 -39
- data/benchmark/heading_anchor_rendering.rb +0 -248
- data/benchmark/sample.md +0 -317
- data/lib/qiita/markdown/filters/greenmat.rb +0 -38
- data/lib/qiita/markdown/greenmat/heading_rendering.rb +0 -61
- data/lib/qiita/markdown/greenmat/html_renderer.rb +0 -60
- data/lib/qiita/markdown/greenmat/html_toc_renderer.rb +0 -78
- data/spec/qiita/markdown/filters/greenmat_spec.rb +0 -15
- data/spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb +0 -156
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 196cc261921bae3253f06a912b56e96a5912ed4552ec6352415756bcca1d98ed
         | 
| 4 | 
            +
              data.tar.gz: '018a907a21f827e68a814ce0d15ff96f3cdccb4e6e52411b7ff63399c5c55f4b'
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 267fcb94bfc63e83b1f42bb42d01f61744d3979be9a92b1df767fc3c7ff3beed8b6299958677835f113abed3c6990bced41618c916650f34c31d5d125e16750d
         | 
| 7 | 
            +
              data.tar.gz: 4a072057a0d55751e5b9e52357641930b1fd0301fe779720820705d453aaaae4fe5cd20bfec3354bb47eb8981ff3742b8a200b8bc647c3b42c5b99e27930458c
         | 
    
        data/.github/workflows/test.yml
    CHANGED
    
    | @@ -20,7 +20,7 @@ jobs: | |
| 20 20 | 
             
                  - uses: actions/checkout@v3
         | 
| 21 21 | 
             
                  - uses: ruby/setup-ruby@v1
         | 
| 22 22 | 
             
                    with:
         | 
| 23 | 
            -
                      ruby-version: '2. | 
| 23 | 
            +
                      ruby-version: '2.7'
         | 
| 24 24 | 
             
                      bundler-cache: true
         | 
| 25 25 | 
             
                  - name: Test & publish code coverage
         | 
| 26 26 | 
             
                    if: "${{ env.CC_TEST_REPORTER_ID != '' }}"
         | 
| @@ -37,7 +37,7 @@ jobs: | |
| 37 37 | 
             
                  fail-fast: false
         | 
| 38 38 | 
             
                  matrix:
         | 
| 39 39 | 
             
                    os: ['ubuntu-18.04', 'ubuntu-latest', 'macos-latest']
         | 
| 40 | 
            -
                    ruby: ['2. | 
| 40 | 
            +
                    ruby: ['2.7', '3.0', '3.1']
         | 
| 41 41 | 
             
                    experimental: [false]
         | 
| 42 42 | 
             
                    include:
         | 
| 43 43 | 
             
                      - os: 'ubuntu-latest'
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/.rubocop_todo.yml
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # This configuration was generated by
         | 
| 2 2 | 
             
            # `rubocop --auto-gen-config --exclude-limit 99999`
         | 
| 3 | 
            -
            # on 2022-11- | 
| 3 | 
            +
            # on 2022-11-15 12:42:36 UTC using RuboCop version 1.39.0.
         | 
| 4 4 | 
             
            # The point is for the user to remove these configuration records
         | 
| 5 5 | 
             
            # one by one as the offenses are removed from the code base.
         | 
| 6 6 | 
             
            # Note that changes in the inspected code, or installation of new
         | 
| @@ -13,12 +13,12 @@ Gemspec/RequiredRubyVersion: | |
| 13 13 | 
             
              Exclude:
         | 
| 14 14 | 
             
                - 'qiita-markdown.gemspec'
         | 
| 15 15 |  | 
| 16 | 
            -
            # Offense count:  | 
| 16 | 
            +
            # Offense count: 8
         | 
| 17 17 | 
             
            # Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods, CountRepeatedAttributes.
         | 
| 18 18 | 
             
            Metrics/AbcSize:
         | 
| 19 | 
            -
              Max:  | 
| 19 | 
            +
              Max: 26
         | 
| 20 20 |  | 
| 21 | 
            -
            # Offense count:  | 
| 21 | 
            +
            # Offense count: 10
         | 
| 22 22 | 
             
            # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods.
         | 
| 23 23 | 
             
            Metrics/MethodLength:
         | 
| 24 24 | 
             
              Max: 20
         | 
| @@ -36,23 +36,13 @@ Naming/FileName: | |
| 36 36 | 
             
              Exclude:
         | 
| 37 37 | 
             
                - 'lib/qiita-markdown.rb'
         | 
| 38 38 |  | 
| 39 | 
            -
            # Offense count:  | 
| 39 | 
            +
            # Offense count: 21
         | 
| 40 40 | 
             
            # Configuration parameters: ForbiddenDelimiters.
         | 
| 41 41 | 
             
            # ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
         | 
| 42 42 | 
             
            Naming/HeredocDelimiterNaming:
         | 
| 43 43 | 
             
              Exclude:
         | 
| 44 | 
            -
                - 'spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb'
         | 
| 45 44 | 
             
                - 'spec/qiita/markdown/summary_processor_spec.rb'
         | 
| 46 45 |  | 
| 47 | 
            -
            # Offense count: 3
         | 
| 48 | 
            -
            # Configuration parameters: EnforcedStyleForLeadingUnderscores.
         | 
| 49 | 
            -
            # SupportedStylesForLeadingUnderscores: disallowed, required, optional
         | 
| 50 | 
            -
            Naming/MemoizedInstanceVariableName:
         | 
| 51 | 
            -
              Exclude:
         | 
| 52 | 
            -
                - 'benchmark/heading_anchor_rendering.rb'
         | 
| 53 | 
            -
                - 'lib/qiita/markdown/filters/greenmat.rb'
         | 
| 54 | 
            -
                - 'lib/qiita/markdown/greenmat/heading_rendering.rb'
         | 
| 55 | 
            -
             | 
| 56 46 | 
             
            # Offense count: 1
         | 
| 57 47 | 
             
            # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
         | 
| 58 48 | 
             
            # AllowedNames: as, at, by, db, id, if, in, io, ip, of, on, os, pp, to
         | 
| @@ -60,7 +50,7 @@ Naming/MethodParameterName: | |
| 60 50 | 
             
              Exclude:
         | 
| 61 51 | 
             
                - 'lib/qiita/markdown/filters/footnote.rb'
         | 
| 62 52 |  | 
| 63 | 
            -
            # Offense count:  | 
| 53 | 
            +
            # Offense count: 37
         | 
| 64 54 | 
             
            # This cop supports unsafe autocorrection (--autocorrect-all).
         | 
| 65 55 | 
             
            # Configuration parameters: EnforcedStyle.
         | 
| 66 56 | 
             
            # SupportedStyles: always, always_true, never
         | 
| @@ -68,7 +58,6 @@ Style/FrozenStringLiteralComment: | |
| 68 58 | 
             
              Exclude:
         | 
| 69 59 | 
             
                - 'Gemfile'
         | 
| 70 60 | 
             
                - 'Rakefile'
         | 
| 71 | 
            -
                - 'benchmark/heading_anchor_rendering.rb'
         | 
| 72 61 | 
             
                - 'lib/qiita-markdown.rb'
         | 
| 73 62 | 
             
                - 'lib/qiita/markdown.rb'
         | 
| 74 63 | 
             
                - 'lib/qiita/markdown/base_processor.rb'
         | 
| @@ -81,12 +70,9 @@ Style/FrozenStringLiteralComment: | |
| 81 70 | 
             
                - 'lib/qiita/markdown/embed/youtube.rb'
         | 
| 82 71 | 
             
                - 'lib/qiita/markdown/filters/checkbox.rb'
         | 
| 83 72 | 
             
                - 'lib/qiita/markdown/filters/code_block.rb'
         | 
| 84 | 
            -
                - 'lib/qiita/markdown/filters/custom_block.rb'
         | 
| 85 73 | 
             
                - 'lib/qiita/markdown/filters/emoji.rb'
         | 
| 86 74 | 
             
                - 'lib/qiita/markdown/filters/external_link.rb'
         | 
| 87 | 
            -
                - 'lib/qiita/markdown/filters/final_sanitizer.rb'
         | 
| 88 75 | 
             
                - 'lib/qiita/markdown/filters/footnote.rb'
         | 
| 89 | 
            -
                - 'lib/qiita/markdown/filters/greenmat.rb'
         | 
| 90 76 | 
             
                - 'lib/qiita/markdown/filters/group_mention.rb'
         | 
| 91 77 | 
             
                - 'lib/qiita/markdown/filters/image_link.rb'
         | 
| 92 78 | 
             
                - 'lib/qiita/markdown/filters/inline_code_color.rb'
         | 
| @@ -95,10 +81,6 @@ Style/FrozenStringLiteralComment: | |
| 95 81 | 
             
                - 'lib/qiita/markdown/filters/syntax_highlight.rb'
         | 
| 96 82 | 
             
                - 'lib/qiita/markdown/filters/toc.rb'
         | 
| 97 83 | 
             
                - 'lib/qiita/markdown/filters/truncate.rb'
         | 
| 98 | 
            -
                - 'lib/qiita/markdown/filters/user_input_sanitizer.rb'
         | 
| 99 | 
            -
                - 'lib/qiita/markdown/greenmat/heading_rendering.rb'
         | 
| 100 | 
            -
                - 'lib/qiita/markdown/greenmat/html_renderer.rb'
         | 
| 101 | 
            -
                - 'lib/qiita/markdown/greenmat/html_toc_renderer.rb'
         | 
| 102 84 | 
             
                - 'lib/qiita/markdown/processor.rb'
         | 
| 103 85 | 
             
                - 'lib/qiita/markdown/summary_processor.rb'
         | 
| 104 86 | 
             
                - 'lib/qiita/markdown/transformers/filter_attributes.rb'
         | 
| @@ -107,9 +89,7 @@ Style/FrozenStringLiteralComment: | |
| 107 89 | 
             
                - 'lib/qiita/markdown/transformers/strip_invalid_node.rb'
         | 
| 108 90 | 
             
                - 'lib/qiita/markdown/version.rb'
         | 
| 109 91 | 
             
                - 'qiita-markdown.gemspec'
         | 
| 110 | 
            -
                - 'spec/qiita/markdown/filters/greenmat_spec.rb'
         | 
| 111 92 | 
             
                - 'spec/qiita/markdown/filters/inline_code_color_spec.rb'
         | 
| 112 | 
            -
                - 'spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb'
         | 
| 113 93 | 
             
                - 'spec/qiita/markdown/processor_spec.rb'
         | 
| 114 94 | 
             
                - 'spec/qiita/markdown/summary_processor_spec.rb'
         | 
| 115 95 | 
             
                - 'spec/spec_helper.rb'
         | 
| @@ -131,24 +111,6 @@ Style/MutableConstant: | |
| 131 111 | 
             
                - 'lib/qiita/markdown/filters/syntax_highlight.rb'
         | 
| 132 112 | 
             
                - 'lib/qiita/markdown/version.rb'
         | 
| 133 113 |  | 
| 134 | 
            -
            # Offense count: 5
         | 
| 135 | 
            -
            # This cop supports unsafe autocorrection (--autocorrect-all).
         | 
| 136 | 
            -
            # Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns, IgnoredMethods.
         | 
| 137 | 
            -
            # SupportedStyles: predicate, comparison
         | 
| 138 | 
            -
            Style/NumericPredicate:
         | 
| 139 | 
            -
              Exclude:
         | 
| 140 | 
            -
                - 'spec/**/*'
         | 
| 141 | 
            -
                - 'benchmark/heading_anchor_rendering.rb'
         | 
| 142 | 
            -
                - 'lib/qiita/markdown/greenmat/heading_rendering.rb'
         | 
| 143 | 
            -
                - 'lib/qiita/markdown/greenmat/html_toc_renderer.rb'
         | 
| 144 | 
            -
             | 
| 145 | 
            -
            # Offense count: 1
         | 
| 146 | 
            -
            # Configuration parameters: AllowedMethods.
         | 
| 147 | 
            -
            # AllowedMethods: respond_to_missing?
         | 
| 148 | 
            -
            Style/OptionalBooleanParameter:
         | 
| 149 | 
            -
              Exclude:
         | 
| 150 | 
            -
                - 'lib/qiita/markdown/greenmat/heading_rendering.rb'
         | 
| 151 | 
            -
             | 
| 152 114 | 
             
            # Offense count: 1
         | 
| 153 115 | 
             
            # This cop supports unsafe autocorrection (--autocorrect-all).
         | 
| 154 116 | 
             
            # Configuration parameters: Methods.
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,15 @@ | |
| 1 1 | 
             
            ## Unreleased
         | 
| 2 2 |  | 
| 3 | 
            +
            ## 1.0.0
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            - Drop Ruby 2.6 support
         | 
| 6 | 
            +
            - Change markdown parser from Greenmat to Qiita Marker
         | 
| 7 | 
            +
            - Fix bug on rendering loose tasklist
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ### Braking change on HTML output
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Some notations will be changed between Greenmat and Qiita Marker and rendering results may change. More details, see [#130](https://github.com/increments/qiita-markdown/issues/130).
         | 
| 12 | 
            +
             | 
| 3 13 | 
             
            ## 0.44.1
         | 
| 4 14 |  | 
| 5 15 | 
             
            - Rename package name from `Qiita::Markdown` to `Qiita Markdown` in README
         | 
    
        data/README.md
    CHANGED
    
    | @@ -16,6 +16,7 @@ Qiita-specified markdown processor. | |
| 16 16 | 
             
            - Syntax highlighting
         | 
| 17 17 | 
             
            - Mention
         | 
| 18 18 | 
             
            - Footnotes
         | 
| 19 | 
            +
            - Note notation's custom block
         | 
| 19 20 |  | 
| 20 21 | 
             
            ## Basic Usage
         | 
| 21 22 |  | 
| @@ -68,7 +69,8 @@ processor.call(text) | |
| 68 69 | 
             
            :inline_code_color_class_name - Class name for inline code color. (String)
         | 
| 69 70 | 
             
            :language_aliases             - Alias table for some language names. (Hash)
         | 
| 70 71 | 
             
            :markdown                     - A hash for enabling / disabling optional Markdown syntax. (Hash)
         | 
| 71 | 
            -
                                            Currently  | 
| 72 | 
            +
                                            Currently :footnotes (default: true) and :sourcepos (defalut: false) are supported.
         | 
| 73 | 
            +
                                            For more information on these options, please see [increments/qiita_marker](https://github.com/increments/qiita_marker).
         | 
| 72 74 | 
             
            :rule                         - Sanitization rule table. (Hash)
         | 
| 73 75 | 
             
            :script                       - A flag to allow to embed script element. (Boolean)
         | 
| 74 76 | 
             
            ```
         | 
| @@ -55,7 +55,11 @@ module Qiita | |
| 55 55 | 
             
                      end
         | 
| 56 56 |  | 
| 57 57 | 
             
                      def first_text_node
         | 
| 58 | 
            -
                         | 
| 58 | 
            +
                        is_loose_list_node = @node.children.first&.text == "\n" && @node.children[1]&.name == "p"
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                        if is_loose_list_node
         | 
| 61 | 
            +
                          @node.children[1].children.first
         | 
| 62 | 
            +
                        elsif @node.children.first && @node.children.first.name == "p"
         | 
| 59 63 | 
             
                          @node.children.first.children.first
         | 
| 60 64 | 
             
                        else
         | 
| 61 65 | 
             
                          @node.children.first
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Qiita
         | 
| 2 4 | 
             
              module Markdown
         | 
| 3 5 | 
             
                module Filters
         | 
| @@ -31,7 +33,7 @@ module Qiita | |
| 31 33 | 
             
                      attr_reader :node, :type
         | 
| 32 34 |  | 
| 33 35 | 
             
                      ALLOWED_TYPES = %w[info warn alert].freeze
         | 
| 34 | 
            -
                      DEFAULT_TYPE = "info" | 
| 36 | 
            +
                      DEFAULT_TYPE = "info"
         | 
| 35 37 |  | 
| 36 38 | 
             
                      # @param node [Nokogiri::XML::Node]
         | 
| 37 39 | 
             
                      # @param type [String, nil]
         | 
| @@ -41,17 +43,16 @@ module Qiita | |
| 41 43 | 
             
                      end
         | 
| 42 44 |  | 
| 43 45 | 
             
                      def convert
         | 
| 44 | 
            -
                         | 
| 46 | 
            +
                        children = node.children
         | 
| 47 | 
            +
                        children.each(&:unlink)
         | 
| 48 | 
            +
                        node.add_child("<div></div>")
         | 
| 49 | 
            +
                        node.children.first.children = children
         | 
| 45 50 | 
             
                        node["class"] = "note #{type}"
         | 
| 46 51 | 
             
                        node.children.first.add_previous_sibling(icon) if icon
         | 
| 47 52 | 
             
                      end
         | 
| 48 53 |  | 
| 49 54 | 
             
                      private
         | 
| 50 55 |  | 
| 51 | 
            -
                      def message
         | 
| 52 | 
            -
                        "<p>#{node.text}</p>"
         | 
| 53 | 
            -
                      end
         | 
| 54 | 
            -
             | 
| 55 56 | 
             
                      def icon
         | 
| 56 57 | 
             
                        {
         | 
| 57 58 | 
             
                          info: %(<span class="fa fa-fw fa-check-circle"></span>),
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Qiita
         | 
| 2 4 | 
             
              module Markdown
         | 
| 3 5 | 
             
                module Filters
         | 
| @@ -9,7 +11,7 @@ module Qiita | |
| 9 11 | 
             
                  # generated by other filters.
         | 
| 10 12 | 
             
                  #
         | 
| 11 13 | 
             
                  # @see Qiita::Markdown::Filters::UserInputSanitizerr
         | 
| 12 | 
            -
                  class FinalSanitizer < HTML::Pipeline::Filter
         | 
| 14 | 
            +
                  class FinalSanitizer < ::HTML::Pipeline::Filter
         | 
| 13 15 | 
             
                    RULE = {
         | 
| 14 16 | 
             
                      attributes: {
         | 
| 15 17 | 
             
                        "a" => %w[
         | 
| @@ -23,6 +25,7 @@ module Qiita | |
| 23 25 | 
             
                          allowfullscreen
         | 
| 24 26 | 
             
                          frameborder
         | 
| 25 27 | 
             
                          height
         | 
| 28 | 
            +
                          loading
         | 
| 26 29 | 
             
                          marginheight
         | 
| 27 30 | 
             
                          marginwidth
         | 
| 28 31 | 
             
                          scrolling
         | 
| @@ -81,6 +84,7 @@ module Qiita | |
| 81 84 | 
             
                          cols
         | 
| 82 85 | 
             
                          colspan
         | 
| 83 86 | 
             
                          data-lang
         | 
| 87 | 
            +
                          data-sourcepos
         | 
| 84 88 | 
             
                          datetime
         | 
| 85 89 | 
             
                          height
         | 
| 86 90 | 
             
                          hreflang
         | 
| @@ -107,6 +111,7 @@ module Qiita | |
| 107 111 | 
             
                        b
         | 
| 108 112 | 
             
                        blockquote
         | 
| 109 113 | 
             
                        br
         | 
| 114 | 
            +
                        caption
         | 
| 110 115 | 
             
                        code
         | 
| 111 116 | 
             
                        dd
         | 
| 112 117 | 
             
                        del
         | 
| @@ -142,6 +147,7 @@ module Qiita | |
| 142 147 | 
             
                        samp
         | 
| 143 148 | 
             
                        script
         | 
| 144 149 | 
             
                        iframe
         | 
| 150 | 
            +
                        section
         | 
| 145 151 | 
             
                        span
         | 
| 146 152 | 
             
                        strike
         | 
| 147 153 | 
             
                        strong
         | 
| @@ -200,7 +206,7 @@ module Qiita | |
| 200 206 | 
             
                      rule[:attributes][:all] = rule[:attributes][:all] + [:data]
         | 
| 201 207 | 
             
                      rule[:elements] = RULE[:elements] + ["video"]
         | 
| 202 208 | 
             
                      rule[:transformers] = rule[:transformers] - [Transformers::FilterScript, Transformers::FilterIframe]
         | 
| 203 | 
            -
                    end
         | 
| 209 | 
            +
                    end.freeze
         | 
| 204 210 |  | 
| 205 211 | 
             
                    def call
         | 
| 206 212 | 
             
                      ::Sanitize.clean_node!(doc, rule)
         | 
| @@ -0,0 +1,44 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Qiita
         | 
| 4 | 
            +
              module Markdown
         | 
| 5 | 
            +
                module Filters
         | 
| 6 | 
            +
                  class HeadingAnchor < ::HTML::Pipeline::Filter
         | 
| 7 | 
            +
                    def call
         | 
| 8 | 
            +
                      doc.search("h1, h2, h3, h4, h5, h6").each do |heading|
         | 
| 9 | 
            +
                        heading["id"] = suffixed_id(heading)
         | 
| 10 | 
            +
                      end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      doc
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    def counter
         | 
| 18 | 
            +
                      @counter ||= ::Hash.new(0)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    def get_count(id)
         | 
| 22 | 
            +
                      counter[id]
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def increment_count(id)
         | 
| 26 | 
            +
                      counter[id] += 1
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    def heading_id(node)
         | 
| 30 | 
            +
                      node.text.downcase.gsub(/[^\p{Word}\- ]/u, "").tr(" ", "-")
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    def suffixed_id(node)
         | 
| 34 | 
            +
                      id = heading_id(node)
         | 
| 35 | 
            +
                      count = get_count(id)
         | 
| 36 | 
            +
                      suffix = count.positive? ? "-#{count}" : ""
         | 
| 37 | 
            +
                      increment_count(id)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      "#{id}#{suffix}"
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| @@ -0,0 +1,67 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Qiita
         | 
| 4 | 
            +
              module Markdown
         | 
| 5 | 
            +
                module Filters
         | 
| 6 | 
            +
                  class HtmlToc < ::HTML::Pipeline::Filter
         | 
| 7 | 
            +
                    # @return [Nokogiri::HTML::DocumentFragment]
         | 
| 8 | 
            +
                    def call
         | 
| 9 | 
            +
                      headings = doc.search("h1, h2, h3, h4, h5, h6")
         | 
| 10 | 
            +
                      return "" if headings.empty?
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      toc = %W[<ul>\n]
         | 
| 13 | 
            +
                      top_level = nil
         | 
| 14 | 
            +
                      last_level = nil
         | 
| 15 | 
            +
                      depth = 1
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      headings.each do |node|
         | 
| 18 | 
            +
                        heading_rank = node.name.match(/h(\d)/)[1].to_i
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                        # The first heading is displayed as the top level.
         | 
| 21 | 
            +
                        # The following headings, of higher rank than the first, are placed as top level.
         | 
| 22 | 
            +
                        top_level ||= heading_rank
         | 
| 23 | 
            +
                        current_level = [heading_rank, top_level].max
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                        link = toc_with_link(node.text, node.attributes["id"]&.value)
         | 
| 26 | 
            +
                        toc << (nest_string(last_level, current_level) + link)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                        depth += current_level - last_level if last_level
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                        last_level = current_level
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      toc << ("</li>\n</ul>\n" * depth)
         | 
| 34 | 
            +
                      toc.join
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    private
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    # @param text [String]
         | 
| 40 | 
            +
                    # @param id [String]
         | 
| 41 | 
            +
                    # @return [String]
         | 
| 42 | 
            +
                    def toc_with_link(text, id)
         | 
| 43 | 
            +
                      %(<a href="##{id}">#{CGI.escapeHTML(text)}</a>\n)
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    # @param last_level [Integer, nil]
         | 
| 47 | 
            +
                    # @param current_level [Integer]
         | 
| 48 | 
            +
                    # @return [String]
         | 
| 49 | 
            +
                    def nest_string(last_level, current_level)
         | 
| 50 | 
            +
                      if last_level.nil?
         | 
| 51 | 
            +
                        return "<li>\n"
         | 
| 52 | 
            +
                      elsif current_level == last_level
         | 
| 53 | 
            +
                        return "</li>\n<li>\n"
         | 
| 54 | 
            +
                      elsif current_level > last_level
         | 
| 55 | 
            +
                        level_difference = current_level - last_level
         | 
| 56 | 
            +
                        return "<ul>\n<li>\n" * level_difference
         | 
| 57 | 
            +
                      elsif current_level < last_level
         | 
| 58 | 
            +
                        level_difference = last_level - current_level
         | 
| 59 | 
            +
                        return %(#{"</li>\n</ul>\n" * level_difference}</li>\n<li>\n)
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                      ""
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Qiita
         | 
| 4 | 
            +
              module Markdown
         | 
| 5 | 
            +
                module Filters
         | 
| 6 | 
            +
                  class QiitaMarker < ::HTML::Pipeline::TextFilter
         | 
| 7 | 
            +
                    DEFAULT_OPTIONS = {
         | 
| 8 | 
            +
                      footnotes: true,
         | 
| 9 | 
            +
                      sourcepos: false,
         | 
| 10 | 
            +
                    }.freeze
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    # @return [Nokogiri::HTML::DocumentFragment]
         | 
| 13 | 
            +
                    def call
         | 
| 14 | 
            +
                      ::Nokogiri::HTML.fragment(render(@text))
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    private
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    # @param text [String]
         | 
| 20 | 
            +
                    # @return [String]
         | 
| 21 | 
            +
                    def render(text)
         | 
| 22 | 
            +
                      ::QiitaMarker.render_html(text, qiita_marker_options, qiita_marker_extensions)
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    def qiita_marker_options
         | 
| 26 | 
            +
                      options_to_append = (options[:footnotes] ? [:FOOTNOTES] : [])
         | 
| 27 | 
            +
                                          .concat(options[:sourcepos] ? [:SOURCEPOS] : [])
         | 
| 28 | 
            +
                      @qiita_marker_options ||= %i[
         | 
| 29 | 
            +
                        HARDBREAKS
         | 
| 30 | 
            +
                        UNSAFE
         | 
| 31 | 
            +
                        LIBERAL_HTML_TAG
         | 
| 32 | 
            +
                        STRIKETHROUGH_DOUBLE_TILDE
         | 
| 33 | 
            +
                        TABLE_PREFER_STYLE_ATTRIBUTES
         | 
| 34 | 
            +
                        CODE_DATA_METADATA
         | 
| 35 | 
            +
                        MENTION_NO_EMPHASIS
         | 
| 36 | 
            +
                        AUTOLINK_CLASS_NAME
         | 
| 37 | 
            +
                      ].concat(options_to_append)
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def qiita_marker_extensions
         | 
| 41 | 
            +
                      @qiita_marker_extensions ||= %i[
         | 
| 42 | 
            +
                        table
         | 
| 43 | 
            +
                        strikethrough
         | 
| 44 | 
            +
                        autolink
         | 
| 45 | 
            +
                        custom_block
         | 
| 46 | 
            +
                      ]
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    def options
         | 
| 50 | 
            +
                      @options ||= DEFAULT_OPTIONS.merge(context[:markdown] || {})
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
| @@ -1,16 +1,18 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Qiita
         | 
| 2 4 | 
             
              module Markdown
         | 
| 3 5 | 
             
                module Filters
         | 
| 4 6 | 
             
                  # Sanitizes user input if :strict context is given.
         | 
| 5 | 
            -
                  class UserInputSanitizer < HTML::Pipeline::Filter
         | 
| 7 | 
            +
                  class UserInputSanitizer < ::HTML::Pipeline::Filter
         | 
| 6 8 | 
             
                    RULE = {
         | 
| 7 9 | 
             
                      elements: %w[
         | 
| 8 | 
            -
                        a b blockquote br code dd del details div dl dt em font h1 h2 h3 h4 h5 h6
         | 
| 9 | 
            -
                        hr i img ins kbd li ol p pre q rp rt ruby s samp script iframe strike strong sub
         | 
| 10 | 
            +
                        a b blockquote br caption code dd del details div dl dt em font h1 h2 h3 h4 h5 h6
         | 
| 11 | 
            +
                        hr i img ins kbd li ol p pre q rp rt ruby s samp script iframe section strike strong sub
         | 
| 10 12 | 
             
                        summary sup table tbody td tfoot th thead tr ul var
         | 
| 11 13 | 
             
                      ],
         | 
| 12 14 | 
             
                      attributes: {
         | 
| 13 | 
            -
                        "a" => %w[class href rel title],
         | 
| 15 | 
            +
                        "a" => %w[class href rel title id],
         | 
| 14 16 | 
             
                        "blockquote" => %w[cite] + Embed::Tweet::ATTRIBUTES,
         | 
| 15 17 | 
             
                        "code" => %w[data-metadata],
         | 
| 16 18 | 
             
                        "div" => %w[class data-type data-metadata],
         | 
| @@ -26,11 +28,16 @@ module Qiita | |
| 26 28 | 
             
                        "li" => %w[id],
         | 
| 27 29 | 
             
                        "p" => Embed::CodePen::ATTRIBUTES,
         | 
| 28 30 | 
             
                        "q" => %w[cite],
         | 
| 29 | 
            -
                        " | 
| 31 | 
            +
                        "section" => %w[class],
         | 
| 32 | 
            +
                        "script" => %w[async src id].concat(
         | 
| 33 | 
            +
                          Embed::SpeekerDeck::ATTRIBUTES,
         | 
| 34 | 
            +
                          Embed::Docswell::ATTRIBUTES,
         | 
| 35 | 
            +
                        ),
         | 
| 30 36 | 
             
                        "iframe" => %w[
         | 
| 31 37 | 
             
                          allowfullscreen
         | 
| 32 38 | 
             
                          frameborder
         | 
| 33 39 | 
             
                          height
         | 
| 40 | 
            +
                          loading
         | 
| 34 41 | 
             
                          marginheight
         | 
| 35 42 | 
             
                          marginwidth
         | 
| 36 43 | 
             
                          scrolling
         | 
| @@ -41,6 +48,7 @@ module Qiita | |
| 41 48 | 
             
                        "sup" => %w[id],
         | 
| 42 49 | 
             
                        "td" => %w[colspan rowspan style],
         | 
| 43 50 | 
             
                        "th" => %w[colspan rowspan style],
         | 
| 51 | 
            +
                        all: %w[data-sourcepos],
         | 
| 44 52 | 
             
                      },
         | 
| 45 53 | 
             
                      protocols: {
         | 
| 46 54 | 
             
                        "a" => { "href" => ["http", "https", "mailto", :relative] },
         | 
| @@ -48,10 +56,7 @@ module Qiita | |
| 48 56 | 
             
                        "q" => { "cite" => ["http", "https", :relative] },
         | 
| 49 57 | 
             
                      },
         | 
| 50 58 | 
             
                      css: {
         | 
| 51 | 
            -
                        properties: %w[
         | 
| 52 | 
            -
                          text-align
         | 
| 53 | 
            -
                          border
         | 
| 54 | 
            -
                        ],
         | 
| 59 | 
            +
                        properties: %w[text-align border],
         | 
| 55 60 | 
             
                      },
         | 
| 56 61 | 
             
                      transformers: [
         | 
| 57 62 | 
             
                        Transformers::FilterAttributes,
         | 
    
        data/lib/qiita/markdown.rb
    CHANGED
    
    | @@ -1,9 +1,9 @@ | |
| 1 1 | 
             
            require "cgi"
         | 
| 2 | 
            -
            require "greenmat"
         | 
| 3 2 | 
             
            require "html/pipeline"
         | 
| 4 3 | 
             
            require "linguist"
         | 
| 5 4 | 
             
            require "mem"
         | 
| 6 5 | 
             
            require "nokogiri"
         | 
| 6 | 
            +
            require "qiita_marker"
         | 
| 7 7 | 
             
            require "rouge"
         | 
| 8 8 | 
             
            require "sanitize"
         | 
| 9 9 |  | 
| @@ -27,19 +27,18 @@ require "qiita/markdown/filters/emoji" | |
| 27 27 | 
             
            require "qiita/markdown/filters/external_link"
         | 
| 28 28 | 
             
            require "qiita/markdown/filters/final_sanitizer"
         | 
| 29 29 | 
             
            require "qiita/markdown/filters/footnote"
         | 
| 30 | 
            -
            require "qiita/markdown/filters/greenmat"
         | 
| 31 30 | 
             
            require "qiita/markdown/filters/group_mention"
         | 
| 31 | 
            +
            require "qiita/markdown/filters/heading_anchor"
         | 
| 32 | 
            +
            require "qiita/markdown/filters/html_toc"
         | 
| 32 33 | 
             
            require "qiita/markdown/filters/image_link"
         | 
| 33 34 | 
             
            require "qiita/markdown/filters/inline_code_color"
         | 
| 34 35 | 
             
            require "qiita/markdown/filters/mention"
         | 
| 36 | 
            +
            require "qiita/markdown/filters/qiita_marker"
         | 
| 35 37 | 
             
            require "qiita/markdown/filters/simplify"
         | 
| 36 38 | 
             
            require "qiita/markdown/filters/syntax_highlight"
         | 
| 37 39 | 
             
            require "qiita/markdown/filters/toc"
         | 
| 38 40 | 
             
            require "qiita/markdown/filters/truncate"
         | 
| 39 41 | 
             
            require "qiita/markdown/filters/user_input_sanitizer"
         | 
| 40 | 
            -
            require "qiita/markdown/greenmat/heading_rendering"
         | 
| 41 | 
            -
            require "qiita/markdown/greenmat/html_renderer"
         | 
| 42 | 
            -
            require "qiita/markdown/greenmat/html_toc_renderer"
         | 
| 43 42 | 
             
            require "qiita/markdown/base_processor"
         | 
| 44 43 | 
             
            require "qiita/markdown/processor"
         | 
| 45 44 | 
             
            require "qiita/markdown/summary_processor"
         | 
    
        data/qiita-markdown.gemspec
    CHANGED
    
    | @@ -15,21 +15,20 @@ Gem::Specification.new do |spec| | |
| 15 15 | 
             
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         | 
| 16 16 | 
             
              spec.require_paths = ["lib"]
         | 
| 17 17 |  | 
| 18 | 
            -
              spec.required_ruby_version = ">= 2. | 
| 18 | 
            +
              spec.required_ruby_version = ">= 2.7.0"
         | 
| 19 19 |  | 
| 20 20 | 
             
              spec.add_dependency "addressable"
         | 
| 21 21 | 
             
              spec.add_dependency "gemoji"
         | 
| 22 22 | 
             
              spec.add_dependency "github-linguist", "~> 4.0"
         | 
| 23 | 
            -
              spec.add_dependency "greenmat", "3.5.1.4"
         | 
| 24 23 | 
             
              spec.add_dependency "html-pipeline", "~> 2.0"
         | 
| 25 24 | 
             
              spec.add_dependency "mem"
         | 
| 26 25 | 
             
              spec.add_dependency "rouge", "3.26.0"
         | 
| 27 26 | 
             
              spec.add_dependency "sanitize"
         | 
| 28 27 | 
             
              spec.add_development_dependency "activesupport", "~> 5.2.7"
         | 
| 29 | 
            -
              spec.add_development_dependency "benchmark-ips", "~> 1.2"
         | 
| 30 28 | 
             
              spec.add_development_dependency "bundler"
         | 
| 31 29 | 
             
              spec.add_development_dependency "codeclimate-test-reporter", "0.4.4"
         | 
| 32 30 | 
             
              spec.add_development_dependency "pry"
         | 
| 31 | 
            +
              spec.add_development_dependency "qiita_marker", "~> 0.23.6"
         | 
| 33 32 | 
             
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 34 33 | 
             
              spec.add_development_dependency "rspec", "~> 3.1"
         | 
| 35 34 | 
             
              spec.add_development_dependency "rubocop", "~> 1.39.0"
         | 
| @@ -26,6 +26,34 @@ describe Qiita::Markdown::Filters::Checkbox do | |
| 26 26 | 
             
                  expect(filter.call.to_s).to eq(output_html)
         | 
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 | 
            +
                context "when list is loose" do
         | 
| 30 | 
            +
                  let(:input_html) do
         | 
| 31 | 
            +
                    <<~HTML
         | 
| 32 | 
            +
                      <li>
         | 
| 33 | 
            +
                      <p>[ ] a</p>
         | 
| 34 | 
            +
                      </li>
         | 
| 35 | 
            +
                      <li>
         | 
| 36 | 
            +
                      <p>[x] b</p>
         | 
| 37 | 
            +
                      </li>
         | 
| 38 | 
            +
                    HTML
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  let(:output_html) do
         | 
| 42 | 
            +
                    <<~HTML
         | 
| 43 | 
            +
                      <li class="task-list-item">
         | 
| 44 | 
            +
                      <p><input type="checkbox" class="task-list-item-checkbox" disabled>a</p>
         | 
| 45 | 
            +
                      </li>
         | 
| 46 | 
            +
                      <li class="task-list-item">
         | 
| 47 | 
            +
                      <p><input type="checkbox" class="task-list-item-checkbox" checked disabled>b</p>
         | 
| 48 | 
            +
                      </li>
         | 
| 49 | 
            +
                    HTML
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  it "replaces checkboxes" do
         | 
| 53 | 
            +
                    expect(filter.call.to_s).to eq(output_html)
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 29 57 | 
             
                context "when input html has many spaces after checkbox mark" do
         | 
| 30 58 | 
             
                  let(:input_html) do
         | 
| 31 59 | 
             
                    <<~HTML
         |