├── .gitignore ├── Gemfile ├── lib ├── kramdown-prismic │ └── version.rb ├── kramdown-prismic.rb └── kramdown │ ├── parser │ └── prismic.rb │ └── converter │ └── prismic.rb ├── kramdown1.gemfile ├── kramdown2.gemfile ├── bin ├── html2prismic ├── markdown2prismic └── prismic2markdown ├── Rakefile ├── Gemfile.lock ├── .github └── workflows │ └── ci.yml ├── kramdown-prismic.gemspec ├── LICENSE ├── CHANGELOG.md ├── README.md └── test ├── parser_test.rb └── converter_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.bundle 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /lib/kramdown-prismic/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module KramdownPrismic 4 | VERSION = '0.3.10' 5 | end 6 | -------------------------------------------------------------------------------- /kramdown1.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | gem 'kramdown', '~> 1.0' 7 | -------------------------------------------------------------------------------- /kramdown2.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | gem 'kramdown', '~> 2.0' 7 | -------------------------------------------------------------------------------- /bin/html2prismic: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'kramdown-prismic' 4 | require 'json' 5 | 6 | print Kramdown::Document.new(ARGV[0], input: :html).to_prismic.to_json.to_s 7 | -------------------------------------------------------------------------------- /bin/markdown2prismic: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'kramdown-prismic' 4 | require 'json' 5 | 6 | print Kramdown::Document.new(ARGV[0], input: :markdown).to_prismic.to_json.to_s 7 | -------------------------------------------------------------------------------- /lib/kramdown-prismic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'kramdown' 4 | 5 | require 'kramdown/parser/prismic' 6 | require 'kramdown/converter/prismic' 7 | require 'kramdown-prismic/version' 8 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rake/testtask' 4 | 5 | Rake::TestTask.new do |t| 6 | t.libs << 'test' 7 | t.test_files = FileList['test/*_test.rb'] 8 | t.verbose = true 9 | end 10 | -------------------------------------------------------------------------------- /bin/prismic2markdown: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'kramdown-prismic' 4 | require 'json' 5 | 6 | source = JSON.parse(ARGV[0], symbolize_names: true) 7 | 8 | print Kramdown::Document.new(source, input: :prismic).to_kramdown 9 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | kramdown-prismic (0.3.10) 5 | kramdown (>= 1, < 3) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | kramdown (2.4.0) 11 | rexml 12 | minitest (5.16.3) 13 | rake (13.0.6) 14 | rexml (3.2.5) 15 | 16 | PLATFORMS 17 | ruby 18 | 19 | DEPENDENCIES 20 | kramdown-prismic! 21 | minitest (~> 5.0) 22 | rake (~> 13.0) 23 | 24 | BUNDLED WITH 25 | 2.1.4 26 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | jobs: 5 | test-kramdown2: 6 | strategy: 7 | fail-fast: false 8 | matrix: 9 | ruby: [2.6, 2.7, "3.0", "3.1", "3.2"] 10 | gemfile: [ kramdown2 ] 11 | env: 12 | BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: ruby/setup-ruby@v1 17 | with: 18 | ruby-version: ${{ matrix.ruby }} 19 | bundler-cache: true 20 | - run: bundle exec rake test 21 | 22 | test-kramdown1: 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | ruby: [2.6, 2.7] 27 | gemfile: [ kramdown1 ] 28 | env: 29 | BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}.gemfile 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: ruby/setup-ruby@v1 34 | with: 35 | ruby-version: ${{ matrix.ruby }} 36 | bundler-cache: true 37 | - run: bundle exec rake test 38 | -------------------------------------------------------------------------------- /kramdown-prismic.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require File.expand_path('lib/kramdown-prismic/version', __dir__) 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'kramdown-prismic' 7 | s.version = KramdownPrismic::VERSION 8 | s.summary = 'A Kramdown converter to convert documents into prismic rich text format and the other way around.' 9 | s.description = 'A Kramdown converter to convert documents into prismic rich text format and the other way around.' 10 | s.authors = ['François de Metz'] 11 | s.email = 'francois@2metz.fr' 12 | 13 | s.executables << 'markdown2prismic' 14 | s.executables << 'html2prismic' 15 | s.executables << 'prismic2markdown' 16 | s.files = `git ls-files`.split("\n") 17 | s.test_files = `git ls-files -- test/*`.split("\n") 18 | 19 | s.homepage = 'https://github.com/stormz/kramdown-prismic' 20 | s.license = 'MIT' 21 | 22 | s.add_dependency 'kramdown', '>= 1', '< 3' 23 | s.add_development_dependency 'minitest', '~> 5.0' 24 | s.add_development_dependency 'rake', '~> 13.0' 25 | end 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Stormz 4 | Copyright (c) 2021 François de Metz 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 0.3.10 4 | 5 | - Fix the embed_url conversion 6 | 7 | ## Version 0.3.9 8 | 9 | - Convert the target attribute on links 10 | 11 | ## Version 0.3.8 12 | 13 | - Convert nested html_elements when converting from HTML. 14 | 15 | ## Version 0.3.7 16 | 17 | - Fix converting nested headers 18 | 19 | ## Version 0.3.6 20 | 21 | - Fix converting nested numbered list. 22 | 23 | ## Version 0.3.5 24 | 25 | - Convert `br` element when converting HTML documents. 26 | 27 | ## Version 0.3.4 28 | 29 | - Convert `strong` and `em` elements when converting HTML documents. 30 | 31 | ## Version 0.3.3 32 | 33 | - Renable converting xml comments 34 | 35 | ## Version 0.3.2 36 | 37 | - Parse ordered and unordered lists 38 | - Parse image with link 39 | 40 | ## Version 0.3.1 41 | 42 | - Add binaries `html2primisc`, `markdown2prismic` and `primisc2markdown`. 43 | - Add parsed embed support 44 | 45 | ## Version 0.3.0 46 | 47 | - Relax the kramdown dependency to allows the version 2. 48 | - XML elements support have been removed. 49 | 50 | ## Version 0.2.2 51 | 52 | - Convert links with only an image inside. See #1. 53 | 54 | ## Version 0.2.1 55 | 56 | - Parse embed elements 57 | - Convert inline code 58 | 59 | ## Version 0.2.0 60 | 61 | - Add parser to convert prismic to markdown 62 | 63 | ## Version 0.1.2 64 | 65 | - fix output with empty paragraph 66 | 67 | ## Version 0.1.1 68 | 69 | - Fix json of the image 70 | 71 | ## Version 0.1.0 72 | 73 | - Initial version 74 | -------------------------------------------------------------------------------- /lib/kramdown/parser/prismic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Kramdown 4 | module Parser 5 | class Prismic < Base 6 | def parse 7 | @root.options[:encoding] = 'UTF-8' 8 | @root.children = @source.reduce([]) do |memo, block| 9 | parse_element(block, memo) 10 | end 11 | end 12 | 13 | private 14 | 15 | def parse_element(block, memo) 16 | type = block[:type].gsub('-', '_') 17 | type = 'heading' if type.match(/heading/) 18 | if type == 'list_item' 19 | parse_list(:ul, block, memo) 20 | memo 21 | elsif type == 'o_list_item' 22 | parse_list(:ol, block, memo) 23 | memo 24 | else 25 | element = send("parse_#{type}", block) 26 | parse_spans(element, block) 27 | memo << element 28 | end 29 | end 30 | 31 | def parse_heading(block) 32 | level = block[:type].match(/heading([1-6])/)[1].to_i 33 | Element.new(:header, nil, nil, { level: level, raw_text: '' }) 34 | end 35 | 36 | def parse_paragraph(_block) 37 | Element.new(:p) 38 | end 39 | 40 | def parse_image(block) 41 | p = Element.new(:p) 42 | img = Element.new(:img, nil, { 'src' => block[:data][:origin][:url], 'alt' => block[:data][:alt] }) 43 | if block[:data][:linkTo] 44 | a = Element.new(:a, nil, { 'href' => block[:data][:linkTo][:url] }) 45 | a.children << img 46 | p.children << a 47 | else 48 | p.children << img 49 | end 50 | p 51 | end 52 | 53 | def parse_preformatted(_block) 54 | Element.new(:blockquote) 55 | end 56 | 57 | def parse_list(type, block, memo) 58 | list = memo.last 59 | unless list && list.type == type 60 | list = Element.new(type) 61 | memo << list 62 | end 63 | li = Element.new(:li, nil, nil) 64 | list.children << li 65 | p = Element.new(:p, nil, nil, transparent: true) 66 | li.children << p 67 | parse_spans(p, block) 68 | end 69 | 70 | def parse_embed(block) 71 | Element.new(:html_element, 'iframe', { src: block[:data][:embed_url] }) 72 | end 73 | 74 | def parse_spans(element, block) 75 | stack = [] 76 | 77 | (block[:content][:text].size + 1).times do |index| 78 | starting_spans = find_starting_spans_for(block, index) 79 | ending_spans = find_ending_spans_for(block, index) 80 | 81 | ending_spans.each do |_ending_span| 82 | el = stack.pop 83 | if stack.empty? 84 | element.children << el 85 | else 86 | stack[-1].children << el 87 | end 88 | end 89 | starting_spans.each do |starting_span| 90 | stack << if starting_span[:type] == 'hyperlink' 91 | Element.new(:a, nil, { 'href' => starting_span[:data][:url] }) 92 | else 93 | Element.new(starting_span[:type].to_sym) 94 | end 95 | end 96 | 97 | char = block[:content][:text][index] 98 | next if char.nil? 99 | 100 | current_text = if stack.empty? 101 | element.children.last 102 | else 103 | stack[-1].children.last 104 | end 105 | if current_text.nil? || current_text.type != :text 106 | current_text = Element.new(:text, '') 107 | if stack.empty? 108 | element.children << current_text 109 | else 110 | stack[-1].children << current_text 111 | end 112 | end 113 | current_text.value += char 114 | end 115 | end 116 | 117 | def find_starting_spans_for(block, index) 118 | block[:content][:spans].find_all do |span| 119 | span[:start] == index 120 | end.sort_by do |span| 121 | -span[:end] 122 | end 123 | end 124 | 125 | def find_ending_spans_for(block, index) 126 | block[:content][:spans].find_all do |span| 127 | span[:end] == index 128 | end 129 | end 130 | end 131 | end 132 | end 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kramdown Prismic ![build](https://img.shields.io/github/actions/workflow/status/stormz/kramdown-prismic/ci.yml?branch=master) [![gem](https://img.shields.io/gem/v/kramdown-prismic)](https://rubygems.org/gems/kramdown-prismic) 2 | 3 | A [Kramdown][] parser and converter to convert documents into [prismic][] rich text format and the other way around. 4 | 5 | A useful usage is to convert markdown documents to prismic for [import purpose][prismic-import]. Then you can even convert prismic format back to markdown. 6 | 7 | [Learn more how to import markdown document to Prismic](https://2metz.fr/blog/import-markdown-into-prismic/). 8 | 9 | ## Status 10 | 11 | The converter part (kramdown to prismic) is working and fairly complete. See *Difference between markdown and rich text* below to know more about limitations. 12 | 13 | The parser part is quite new and not feature complete. 14 | 15 | ## Install 16 | 17 | ```ruby 18 | gem 'kramdown-prismic', '~> 0.1' 19 | ``` 20 | 21 | ## Usage 22 | 23 | ### With executables 24 | 25 | *markdown2prismic*: 26 | 27 | markdown2prismic $'# My Title\n\nHello world' 28 | 29 | *html2prismic*: 30 | 31 | html2prismic '

My Title

Hello world

' 32 | 33 | *prismic2markdown*: 34 | 35 | prismic2markdown '[{"type":"heading1","content":{"text":"My Title","spans":[]}},{"type":"paragraph","content":{"text":"Test","spans":[]}}]' 36 | 37 | ### As a library 38 | 39 | **Convert kramdown documents to Prismic** 40 | 41 | ```ruby 42 | require 'kramdown-prismic' 43 | 44 | kramdown = '# Hello world' 45 | Kramdown::Document.new(kramdown).to_prismic 46 | ``` 47 | 48 | **Convert markdown documents to Prismic** 49 | 50 | ```ruby 51 | require 'kramdown-prismic' 52 | 53 | markdown = '# Hello world' 54 | Kramdown::Document.new(markdown, input: :markdown).to_prismic 55 | ``` 56 | 57 | **Convert HTML documents to Prismic** 58 | 59 | ```ruby 60 | require 'kramdown-prismic' 61 | 62 | html = '

Hello world

' 63 | Kramdown::Document.new(html, input: :html).to_prismic 64 | ``` 65 | 66 | **Convert Prismic to markdown** 67 | 68 | ```ruby 69 | require 'kramdown-prismic' 70 | prismic = [ 71 | { 72 | type: "heading1", 73 | content: { 74 | text: "This is the document title", 75 | spans: [] 76 | } 77 | } 78 | ] 79 | Kramdown::Document.new(prismic, input: :prismic).to_kramdown 80 | ``` 81 | 82 | You can also convert to or from others formats supported by Kramdown. See [kramdown documentation](https://kramdown.gettalong.org/documentation.html). 83 | 84 | ### Lookup for warnings 85 | 86 | If there is some elements that cannot be converted (see the status table), a warning will be emitted. 87 | 88 | For instance, html elements in the markdown is not supported: 89 | 90 | ```ruby 91 | require 'kramdown-prismic' 92 | 93 | markdown = '

Hello world

' 94 | result = Kramdown::Document.new(markdown, input: :markdown) 95 | result.to_prismic 96 | p result.warnings 97 | ``` 98 | 99 | ### Difference between markdown and rich text 100 | 101 | Some elements cannot be converted, due to some Prismic limitations. The table below explain the difference and limitations of the current converter: 102 | 103 | | Markdown | Prismic | 104 | |------------------|----------------------------| 105 | | blockquote | converted to preformatted | 106 | | hr | nothing | 107 | | img | moved to the top level | 108 | | nested list | moved to the top level | 109 | | entity | converted to unicode | 110 | | typographic_sym | converted to unicode | 111 | | smart_quote | converted to unicode | 112 | | dl | not supported | 113 | | dt | not supported | 114 | | dd | not supported | 115 | | table | not supported | 116 | | thead | not supported | 117 | | tobdy | not supported | 118 | | tfoot | not supported | 119 | | tr | not supported | 120 | | td | not supported | 121 | | math | not supported | 122 | | footnote | not supported | 123 | | abbreviation | not supported | 124 | | html_element | not supported | 125 | | xml_comment | not supported | 126 | | xml_pi | not supported | 127 | | comment | not supported | 128 | | raw | not supported | 129 | 130 | ## Develop 131 | 132 | Install dependencies: 133 | 134 | bundle install 135 | 136 | Run tests: 137 | 138 | bundle exec rake test 139 | 140 | ## License 141 | 142 | MIT 143 | 144 | [Kramdown]: https://kramdown.gettalong.org/ 145 | [prismic]: https://prismic.io/ 146 | [prismic-import]: https://prismic.io/docs/core-concepts/how-to-import-content 147 | -------------------------------------------------------------------------------- /test/parser_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'minitest/autorun' 4 | require 'kramdown-prismic' 5 | 6 | class KramdownPrismicParserTest < Minitest::Test 7 | 6.times do |heading| 8 | define_method "test_parse_heading_#{heading}" do 9 | prismic = [ 10 | { 11 | type: "heading#{heading + 1}", 12 | content: { 13 | text: 'This is the document title', 14 | spans: [] 15 | } 16 | } 17 | ] 18 | expected = "#{'#' * (heading + 1)} This is the document title\n\n" 19 | doc = Kramdown::Document.new(prismic, input: :prismic) 20 | assert_equal expected, doc.to_kramdown 21 | end 22 | end 23 | 24 | def test_parse_paragraph 25 | prismic = [ 26 | { 27 | type: 'paragraph', 28 | content: { 29 | text: 'This is a paragraph', 30 | spans: [] 31 | } 32 | } 33 | ] 34 | expected = "This is a paragraph\n\n" 35 | doc = Kramdown::Document.new(prismic, input: :prismic) 36 | assert_equal expected, doc.to_kramdown 37 | end 38 | 39 | def test_parse_paragraph_with_spans 40 | prismic = [ 41 | { 42 | type: 'paragraph', 43 | content: { 44 | text: 'This is a paragraph', 45 | spans: [ 46 | { 47 | type: 'em', 48 | start: 0, 49 | end: 4 50 | } 51 | ] 52 | } 53 | } 54 | ] 55 | expected = "*This* is a paragraph\n\n" 56 | doc = Kramdown::Document.new(prismic, input: :prismic) 57 | assert_equal expected, doc.to_kramdown 58 | end 59 | 60 | def test_parse_paragraph_with_multiple_spans 61 | prismic = [ 62 | { 63 | type: 'paragraph', 64 | content: { 65 | text: 'This is a paragraph', 66 | spans: [ 67 | { 68 | type: 'em', 69 | start: 0, 70 | end: 4 71 | }, 72 | { 73 | type: 'strong', 74 | start: 5, 75 | end: 7 76 | } 77 | ] 78 | } 79 | } 80 | ] 81 | expected = "*This* **is** a paragraph\n\n" 82 | doc = Kramdown::Document.new(prismic, input: :prismic) 83 | assert_equal expected, doc.to_kramdown 84 | end 85 | 86 | def test_parse_paragraph_with_link 87 | prismic = [ 88 | { 89 | type: 'paragraph', 90 | content: { 91 | text: 'This is a paragraph', 92 | spans: [ 93 | { 94 | type: 'hyperlink', 95 | start: 0, 96 | end: 19, 97 | data: { 98 | url: 'https://prismic.io' 99 | } 100 | } 101 | ] 102 | } 103 | } 104 | ] 105 | expected = "[This is a paragraph][1]\n\n\n\n[1]: https://prismic.io\n" 106 | doc = Kramdown::Document.new(prismic, input: :prismic) 107 | assert_equal expected, doc.to_kramdown 108 | end 109 | 110 | def test_parse_paragraph_with_nested_spans 111 | prismic = [ 112 | { 113 | type: 'paragraph', 114 | content: { 115 | text: 'This is a paragraph', 116 | spans: [ 117 | { 118 | type: 'em', 119 | start: 0, 120 | end: 4 121 | }, 122 | { 123 | type: 'hyperlink', 124 | start: 0, 125 | end: 19, 126 | data: { 127 | url: 'https://prismic.io' 128 | } 129 | } 130 | ] 131 | } 132 | } 133 | ] 134 | expected = "[*This* is a paragraph][1]\n\n\n\n[1]: https://prismic.io\n" 135 | doc = Kramdown::Document.new(prismic, input: :prismic) 136 | assert_equal expected, doc.to_kramdown 137 | end 138 | 139 | def test_parse_list_item 140 | prismic = [ 141 | { 142 | type: 'list-item', 143 | content: { 144 | text: 'Hello', 145 | spans: [] 146 | } 147 | }, 148 | { 149 | type: 'list-item', 150 | content: { 151 | text: 'World', 152 | spans: [] 153 | } 154 | } 155 | ] 156 | expected = "* Hello\n* World\n\n" 157 | doc = Kramdown::Document.new(prismic, input: :prismic) 158 | assert_equal expected, doc.to_kramdown 159 | end 160 | 161 | def test_parse_list_item_and_spans 162 | prismic = [ 163 | { 164 | type: 'list-item', 165 | content: { 166 | text: 'Hello', 167 | spans: [ 168 | { 169 | type: 'em', 170 | start: 0, 171 | end: 5 172 | } 173 | ] 174 | } 175 | }, 176 | { 177 | type: 'list-item', 178 | content: { 179 | text: 'World', 180 | spans: [] 181 | } 182 | } 183 | ] 184 | expected = "* *Hello*\n* World\n\n" 185 | doc = Kramdown::Document.new(prismic, input: :prismic) 186 | assert_equal expected, doc.to_kramdown 187 | end 188 | 189 | def test_parse_o_list_item 190 | prismic = [ 191 | { 192 | type: 'o-list-item', 193 | content: { 194 | text: 'Hello', 195 | spans: [] 196 | } 197 | }, 198 | { 199 | type: 'o-list-item', 200 | content: { 201 | text: 'World', 202 | spans: [] 203 | } 204 | } 205 | ] 206 | expected = "1. Hello\n2. World\n\n" 207 | doc = Kramdown::Document.new(prismic, input: :prismic) 208 | assert_equal expected, doc.to_kramdown 209 | end 210 | 211 | def test_parse_o_list_item_and_list_item 212 | prismic = [ 213 | { 214 | type: 'o-list-item', 215 | content: { 216 | text: 'Hello', 217 | spans: [] 218 | } 219 | }, 220 | { 221 | type: 'o-list-item', 222 | content: { 223 | text: 'World', 224 | spans: [] 225 | } 226 | }, 227 | { 228 | type: 'list-item', 229 | content: { 230 | text: 'Test', 231 | spans: [] 232 | } 233 | }, 234 | { 235 | type: 'list-item', 236 | content: { 237 | text: 'roger', 238 | spans: [] 239 | } 240 | } 241 | ] 242 | expected = "1. Hello\n2. World\n\n* Test\n* roger\n\n" 243 | doc = Kramdown::Document.new(prismic, input: :prismic) 244 | assert_equal expected, doc.to_kramdown 245 | end 246 | 247 | def test_parse_image 248 | prismic = [ 249 | { 250 | type: 'image', 251 | content: { 252 | text: '', 253 | spans: [] 254 | }, 255 | data: { 256 | origin: { 257 | url: '/img.png' 258 | }, 259 | alt: 'alt text' 260 | } 261 | } 262 | ] 263 | expected = "![alt text](/img.png)\n\n" 264 | doc = Kramdown::Document.new(prismic, input: :prismic) 265 | assert_equal expected, doc.to_kramdown 266 | end 267 | 268 | def test_parse_img_with_link 269 | prismic = [ 270 | { 271 | type: 'image', 272 | content: { 273 | text: '', 274 | spans: [] 275 | }, 276 | data: { 277 | origin: { 278 | url: '/img.png' 279 | }, 280 | alt: 'alt text', 281 | linkTo: { 282 | url: 'https://example.net/' 283 | } 284 | } 285 | } 286 | ] 287 | expected = "[![alt text](/img.png)][1]\n\n\n\n[1]: https://example.net/\n" 288 | doc = Kramdown::Document.new(prismic, input: :prismic) 289 | assert_equal expected, doc.to_kramdown 290 | end 291 | 292 | def test_parse_preformatted 293 | prismic = [ 294 | { 295 | type: 'preformatted', 296 | content: { 297 | text: "This is a pre block\n", 298 | spans: [] 299 | } 300 | } 301 | ] 302 | expected = "> This is a pre block \n\n" 303 | doc = Kramdown::Document.new(prismic, input: :prismic) 304 | assert_equal expected, doc.to_kramdown 305 | end 306 | 307 | def test_parse_embed 308 | prismic = [ 309 | { 310 | type: 'embed', 311 | data: { 312 | type: 'video', 313 | embed_url: 'https://www.youtube.com/watch?v=y6y_4_b6RS8' 314 | }, 315 | content: { 316 | text: '', 317 | spans: [] 318 | } 319 | } 320 | ] 321 | expected = "\n" 322 | doc = Kramdown::Document.new(prismic, input: :prismic) 323 | assert_equal expected, doc.to_kramdown 324 | end 325 | end 326 | -------------------------------------------------------------------------------- /lib/kramdown/converter/prismic.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'kramdown/converter/base' 4 | 5 | module Kramdown 6 | module Converter 7 | class Prismic < Base 8 | def convert(root) 9 | cleanup_ast(root).map do |child| 10 | convert_element(child) 11 | end.compact.flatten 12 | end 13 | 14 | private 15 | 16 | def cleanup_ast(root) 17 | remove_blanks(root) 18 | root.children.map do |child| 19 | elements = [] 20 | extract_non_nestable_elements(child, elements) 21 | [child, elements] 22 | end.flatten.compact 23 | end 24 | 25 | def remove_blanks(root) 26 | root.children = root.children.each_with_object([]) do |child, memo| 27 | unless child.type == :blank 28 | remove_blanks(child) 29 | memo << child 30 | end 31 | end 32 | end 33 | 34 | def extract_non_nestable_elements(child, elements) 35 | child.children = child.children.each_with_object([]) do |element, memo| 36 | if element.type == :a && element.children.size == 1 && element.children.first.type == :img 37 | elements << element 38 | elsif element.type == :img 39 | elements << element 40 | if child.children.size > 1 41 | warning('images inside content will be moved to the top level and may be rendered differently') 42 | end 43 | elsif [:ul, :ol].include?(element.type) 44 | warning('nested list moved to the top level') 45 | elements << element 46 | extract_non_nestable_elements(element, elements) 47 | elsif element.type == :header 48 | warning('header moved to the top level') 49 | elements << element 50 | extract_non_nestable_elements(element, elements) 51 | else 52 | memo << element 53 | extract_non_nestable_elements(element, elements) 54 | end 55 | end 56 | end 57 | 58 | def convert_element(element) 59 | send("convert_#{element.type}", element) 60 | end 61 | 62 | def convert_header(element) 63 | { 64 | type: "heading#{element.options[:level]}", 65 | content: extract_content(element) 66 | } 67 | end 68 | 69 | def convert_p(element) 70 | return nil if element.children.size.zero? 71 | 72 | { 73 | type: 'paragraph', 74 | content: extract_content(element) 75 | } 76 | end 77 | 78 | def convert_ol(element) 79 | convert_list(element, 'o-list-item') 80 | end 81 | 82 | def convert_ul(element) 83 | convert_list(element, 'list-item') 84 | end 85 | 86 | def convert_list(element, type) 87 | element.children.map do |child| 88 | convert_li(type, child) 89 | end 90 | end 91 | 92 | def convert_li(type, element) 93 | { 94 | type: type, 95 | content: extract_content(element) 96 | } 97 | end 98 | 99 | def convert_codeblock(element) 100 | { 101 | type: 'preformatted', 102 | content: { 103 | text: element.value, 104 | spans: [] 105 | } 106 | } 107 | end 108 | 109 | def convert_blockquote(element) 110 | { 111 | type: 'preformatted', 112 | content: extract_content(element) 113 | } 114 | end 115 | 116 | def convert_hr(element); end 117 | def convert_br(element); end 118 | 119 | def convert_img(element) 120 | { 121 | type: 'image', 122 | content: { 123 | text: '', 124 | spans: [] 125 | }, 126 | data: { 127 | origin: { 128 | url: element.attr['src'] 129 | }, 130 | alt: element.attr['alt'] 131 | } 132 | } 133 | end 134 | 135 | # This can only apply when an link with an image inside has been detected 136 | def convert_a(element) 137 | image = element.children.first 138 | { 139 | type: 'image', 140 | content: { 141 | text: '', 142 | spans: [] 143 | }, 144 | data: { 145 | origin: { 146 | url: image.attr['src'] 147 | }, 148 | alt: image.attr['alt'], 149 | linkTo: { 150 | url: element.attr['href'] 151 | } 152 | } 153 | } 154 | end 155 | 156 | def convert_strong(element) 157 | convert_sub_html_element(element, 'strong') 158 | end 159 | 160 | def convert_em(element) 161 | convert_sub_html_element(element, 'em') 162 | end 163 | 164 | def convert_sub_html_element(element, type) 165 | content = extract_content(element) 166 | content[:spans].push({ type: type, start: 0, end: content[:text].size }) 167 | { 168 | type: 'paragraph', 169 | content: content 170 | } 171 | end 172 | 173 | def convert_html_element(element) 174 | if element.value == 'iframe' 175 | { 176 | content: { 177 | spans: [], 178 | text: '' 179 | }, 180 | type: 'embed', 181 | data: { 182 | embed_url: element.attr['src'], 183 | type: 'link' 184 | } 185 | } 186 | else 187 | warning('translating html elements is not supported') 188 | nil 189 | end 190 | end 191 | 192 | def convert_table(_element) 193 | warning('translating table is not supported') 194 | nil 195 | end 196 | 197 | def convert_dl(_element) 198 | warning('translating dl is not supported') 199 | nil 200 | end 201 | 202 | def convert_math(_element) 203 | warning('translating math is not supported') 204 | nil 205 | end 206 | 207 | def convert_comment(_element) 208 | warning('translating comment is not supported') 209 | nil 210 | end 211 | 212 | def convert_xml_comment(_element) 213 | warning('translating xml comment is not supported') 214 | nil 215 | end 216 | 217 | def convert_raw(_element) 218 | warning('translating raw is not supported') 219 | nil 220 | end 221 | 222 | def convert_text(element) 223 | { 224 | type: 'paragraph', 225 | content: { 226 | text: element.value, 227 | spans: [] 228 | } 229 | } 230 | end 231 | 232 | def extract_content(element, memo = { text: '', spans: [] }) 233 | element.children.each_with_object(memo) do |child, memo2| 234 | send("extract_span_#{child.type}", child, memo2) 235 | end 236 | end 237 | 238 | def insert_span(element, memo, span) 239 | span[:start] = memo[:text].size 240 | extract_content(element, memo) 241 | span[:end] = memo[:text].size 242 | memo[:spans] << span 243 | memo 244 | end 245 | 246 | def extract_span_text(element, memo) 247 | memo[:text] += element.value 248 | memo 249 | end 250 | 251 | def extract_span_a(element, memo) 252 | target = element.attr['target'] 253 | insert_span(element, memo, { 254 | type: 'hyperlink', 255 | data: { 256 | url: element.attr['href'], 257 | **(target ? { target: target } : {}), 258 | } 259 | }) 260 | end 261 | 262 | def extract_span_strong(element, memo) 263 | insert_span(element, memo, { 264 | type: 'strong' 265 | }) 266 | end 267 | 268 | def extract_span_em(element, memo) 269 | insert_span(element, memo, { 270 | type: 'em' 271 | }) 272 | end 273 | 274 | def extract_span_p(element, memo) 275 | extract_content(element, memo) 276 | end 277 | 278 | def extract_span_br(_element, memo) 279 | memo[:text] += "\n" 280 | end 281 | 282 | def extract_span_codespan(element, memo) 283 | warning('translating inline code is not supported') 284 | memo[:text] += element.value 285 | end 286 | 287 | def extract_span_html_element(element, memo) 288 | if respond_to?("extract_span_#{element.value}", true) 289 | send("extract_span_#{element.value}", element, memo) 290 | else 291 | warning("translating html element '#{element.value}' is not supported") 292 | end 293 | end 294 | 295 | def extract_span_footnote(_element, _memo) 296 | warning('translating footnote is not supported') 297 | end 298 | 299 | def extract_span_abbreviation(element, memo) 300 | warning('translating abbreviation is not supported') 301 | memo[:text] += element.value 302 | end 303 | 304 | def extract_span_xml_comment(element, memo) 305 | warning('translating xml comment is not supported') 306 | end 307 | 308 | TYPOGRAPHIC_SYMS = { 309 | mdash: [Utils::Entities.entity('mdash')], 310 | ndash: [Utils::Entities.entity('ndash')], 311 | hellip: [Utils::Entities.entity('hellip')], 312 | laquo_space: [Utils::Entities.entity('laquo'), Utils::Entities.entity('nbsp')], 313 | raquo_space: [Utils::Entities.entity('nbsp'), Utils::Entities.entity('raquo')], 314 | laquo: [Utils::Entities.entity('laquo')], 315 | raquo: [Utils::Entities.entity('raquo')] 316 | }.freeze 317 | def extract_span_typographic_sym(element, memo) 318 | value = TYPOGRAPHIC_SYMS[element.value].map(&:char).join('') 319 | memo[:text] += value 320 | end 321 | 322 | def extract_span_entity(element, memo) 323 | memo[:text] += element.value.char 324 | end 325 | 326 | def extract_span_smart_quote(element, memo) 327 | memo[:text] += Utils::Entities.entity(element.value.to_s).char 328 | end 329 | end 330 | end 331 | end 332 | -------------------------------------------------------------------------------- /test/converter_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'minitest/autorun' 4 | require 'kramdown-prismic' 5 | 6 | class KramdownPrismicConverterTest < Minitest::Test 7 | 6.times do |heading| 8 | define_method "test_convert_heading_#{heading}" do 9 | expected = [ 10 | { 11 | type: "heading#{heading + 1}", 12 | content: { 13 | text: 'This is the document title', 14 | spans: [] 15 | } 16 | } 17 | ] 18 | markdown = "#{'#' * (heading + 1)} This is the document title" 19 | assert_equal expected, Kramdown::Document.new(markdown, input: :kramdown).to_prismic 20 | end 21 | end 22 | 23 | def test_convert_heading7 24 | expected = [ 25 | { 26 | type: 'heading6', 27 | content: { 28 | text: '# This is the document title', 29 | spans: [] 30 | } 31 | } 32 | ] 33 | markdown = '####### This is the document title' 34 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 35 | end 36 | 37 | def test_convert_heading_with_spans 38 | expected = [ 39 | { 40 | type: 'heading2', 41 | content: { 42 | text: 'This is a document title', 43 | spans: [ 44 | { 45 | type: 'em', 46 | start: 0, 47 | end: 4 48 | } 49 | ] 50 | } 51 | } 52 | ] 53 | markdown = '## *This* is a document title' 54 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 55 | end 56 | 57 | def test_convert_paragraph 58 | expected = [ 59 | { 60 | type: 'paragraph', 61 | content: { 62 | text: 'This is a paragraph', 63 | spans: [] 64 | } 65 | } 66 | ] 67 | markdown = 'This is a paragraph' 68 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 69 | end 70 | 71 | def test_convert_paragraph_with_spans 72 | expected = [ 73 | { 74 | type: 'paragraph', 75 | content: { 76 | text: 'This is a paragraph', 77 | spans: [ 78 | { 79 | type: 'hyperlink', 80 | start: 0, 81 | end: 19, 82 | data: { 83 | url: 'https://prismic.io' 84 | } 85 | } 86 | ] 87 | } 88 | } 89 | ] 90 | markdown = '[This is a paragraph](https://prismic.io)' 91 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 92 | end 93 | 94 | def test_convert_paragraph_with_strong 95 | expected = [ 96 | { 97 | type: 'paragraph', 98 | content: { 99 | text: 'This is a paragraph', 100 | spans: [ 101 | { 102 | type: 'strong', 103 | start: 0, 104 | end: 19 105 | } 106 | ] 107 | } 108 | } 109 | ] 110 | markdown = '**This is a paragraph**' 111 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 112 | end 113 | 114 | def test_convert_paragraph_with_strong2 115 | expected = [ 116 | { 117 | type: 'paragraph', 118 | content: { 119 | text: 'This is a paragraph', 120 | spans: [ 121 | { 122 | type: 'strong', 123 | start: 0, 124 | end: 4 125 | } 126 | ] 127 | } 128 | } 129 | ] 130 | markdown = '**This** is a paragraph' 131 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 132 | end 133 | 134 | def test_convert_html_strong 135 | expected = [ 136 | { 137 | type: 'paragraph', 138 | content: { 139 | text: 'This is a paragraph', 140 | spans: [ 141 | { 142 | type: 'strong', 143 | start: 0, 144 | end: 19 145 | } 146 | ] 147 | } 148 | } 149 | ] 150 | markdown = 'This is a paragraph' 151 | assert_equal expected, Kramdown::Document.new(markdown, input: :html).to_prismic 152 | end 153 | 154 | def test_convert_paragraph_with_em 155 | expected = [ 156 | { 157 | type: 'paragraph', 158 | content: { 159 | text: 'This is a paragraph', 160 | spans: [ 161 | { 162 | type: 'em', 163 | start: 0, 164 | end: 4 165 | } 166 | ] 167 | } 168 | } 169 | ] 170 | markdown = '*This* is a paragraph' 171 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 172 | end 173 | 174 | def test_convert_html_em 175 | expected = [ 176 | { 177 | type: 'paragraph', 178 | content: { 179 | text: 'This', 180 | spans: [ 181 | { 182 | type: 'em', 183 | start: 0, 184 | end: 4 185 | } 186 | ] 187 | } 188 | } 189 | ] 190 | markdown = 'This' 191 | assert_equal expected, Kramdown::Document.new(markdown, input: :html).to_prismic 192 | end 193 | 194 | def test_convert_list_o 195 | expected = [ 196 | { 197 | type: 'o-list-item', 198 | content: { 199 | text: 'This is a list item', 200 | spans: [ 201 | { 202 | type: 'em', 203 | start: 0, 204 | end: 4 205 | } 206 | ] 207 | } 208 | }, 209 | { 210 | type: 'o-list-item', 211 | content: { 212 | text: 'This is a second list item', 213 | spans: [] 214 | } 215 | } 216 | ] 217 | markdown = "1. *This* is a list item\n2. This is a second list item" 218 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 219 | end 220 | 221 | def test_convert_list_u 222 | expected = [ 223 | { 224 | type: 'list-item', 225 | content: { 226 | text: 'This is a list item', 227 | spans: [ 228 | { 229 | type: 'em', 230 | start: 0, 231 | end: 4 232 | } 233 | ] 234 | } 235 | }, 236 | { 237 | type: 'list-item', 238 | content: { 239 | text: 'This is a second list item', 240 | spans: [] 241 | } 242 | } 243 | ] 244 | markdown = "- *This* is a list item\n- This is a second list item" 245 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 246 | end 247 | 248 | def test_convert_nested_ul 249 | expected = [ 250 | { 251 | type: 'list-item', 252 | content: { 253 | text: "item1\n", 254 | spans: [] 255 | } 256 | }, 257 | { 258 | type: 'list-item', 259 | content: { 260 | text: 'item2', 261 | spans: [] 262 | } 263 | } 264 | ] 265 | markdown = "- item1\n - item2" 266 | doc = Kramdown::Document.new(markdown, input: :markdown) 267 | assert_equal expected, doc.to_prismic 268 | assert_equal 1, doc.warnings.size 269 | end 270 | 271 | def test_convert_nested_ol 272 | expected = [ 273 | { 274 | type: 'list-item', 275 | content: { 276 | text: "item1\n", 277 | spans: [] 278 | } 279 | }, 280 | { 281 | type: 'o-list-item', 282 | content: { 283 | text: 'item2', 284 | spans: [] 285 | } 286 | } 287 | ] 288 | markdown = "- item1\n 1. item2" 289 | doc = Kramdown::Document.new(markdown, input: :markdown) 290 | assert_equal expected, doc.to_prismic 291 | assert_equal 1, doc.warnings.size 292 | end 293 | 294 | def test_convert_nested_nested_ul 295 | expected = [ 296 | { 297 | type: 'list-item', 298 | content: { 299 | text: "item1\n", 300 | spans: [] 301 | } 302 | }, 303 | { 304 | type: 'list-item', 305 | content: { 306 | text: "item2\n", 307 | spans: [] 308 | } 309 | }, 310 | { 311 | type: 'list-item', 312 | content: { 313 | text: 'item3', 314 | spans: [] 315 | } 316 | } 317 | ] 318 | markdown = "- item1\n - item2\n - item3" 319 | doc = Kramdown::Document.new(markdown, input: :markdown) 320 | assert_equal expected, doc.to_prismic 321 | assert_equal 2, doc.warnings.size 322 | end 323 | 324 | def test_convert_heading_in_list 325 | expected = [ 326 | { 327 | type: 'list-item', 328 | content: { 329 | text: "", 330 | spans: [] 331 | } 332 | }, 333 | { 334 | type: 'heading4', 335 | content: { 336 | text: 'Title', 337 | spans: [] 338 | } 339 | } 340 | ] 341 | html = "" 342 | doc = Kramdown::Document.new(html, input: :html) 343 | assert_equal expected, doc.to_prismic 344 | assert_equal 1, doc.warnings.size 345 | end 346 | 347 | def test_convert_preformatted 348 | expected = [ 349 | { 350 | type: 'preformatted', 351 | content: { 352 | text: "This is a pre block\n", 353 | spans: [] 354 | } 355 | } 356 | ] 357 | markdown = " This is a pre block\n" 358 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 359 | end 360 | 361 | def test_convert_blockquote 362 | expected = [ 363 | { 364 | type: 'preformatted', 365 | content: { 366 | text: 'This is a blockquote', 367 | spans: [] 368 | } 369 | } 370 | ] 371 | markdown = "> This is a blockquote\n" 372 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 373 | end 374 | 375 | def test_convert_empty 376 | expected = [] 377 | markdown = '' 378 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 379 | end 380 | 381 | def test_convert_span_blank 382 | expected = [ 383 | { 384 | type: 'o-list-item', 385 | content: { 386 | text: 'Testtest', 387 | spans: [] 388 | } 389 | } 390 | ] 391 | markdown = "\n1. Test\n\n test\n" 392 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 393 | end 394 | 395 | def test_convert_hr 396 | expected = [] 397 | markdown = '---' 398 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 399 | end 400 | 401 | def test_convert_img 402 | expected = [ 403 | { 404 | type: 'image', 405 | content: { 406 | text: '', 407 | spans: [] 408 | }, 409 | data: { 410 | origin: { 411 | url: '/img.png' 412 | }, 413 | alt: 'alt text' 414 | } 415 | } 416 | ] 417 | markdown = '![alt text](/img.png)' 418 | doc = Kramdown::Document.new(markdown) 419 | assert_equal expected, doc.to_prismic 420 | assert_equal 0, doc.warnings.size 421 | end 422 | 423 | def test_convert_double_img 424 | expected = [ 425 | { 426 | type: 'image', 427 | content: { 428 | text: '', 429 | spans: [] 430 | }, 431 | data: { 432 | origin: { 433 | url: '/img.png' 434 | }, 435 | alt: '' 436 | } 437 | }, 438 | { 439 | type: 'image', 440 | content: { 441 | text: '', 442 | spans: [] 443 | }, 444 | data: { 445 | origin: { 446 | url: '/img2.png' 447 | }, 448 | alt: '' 449 | } 450 | } 451 | ] 452 | markdown = '![](/img.png)![](/img2.png)' 453 | doc = Kramdown::Document.new(markdown) 454 | assert_equal expected, doc.to_prismic 455 | assert_equal 2, doc.warnings.size 456 | end 457 | 458 | def test_convert_img_with_link 459 | expected = [ 460 | { 461 | type: 'image', 462 | content: { 463 | text: '', 464 | spans: [] 465 | }, 466 | data: { 467 | origin: { 468 | url: '/img.png' 469 | }, 470 | alt: 'alt text', 471 | linkTo: { 472 | url: 'https://example.net/' 473 | } 474 | } 475 | } 476 | ] 477 | markdown = '[![alt text](/img.png)](https://example.net/)' 478 | doc = Kramdown::Document.new(markdown) 479 | assert_equal expected, doc.to_prismic 480 | assert_equal 0, doc.warnings.size 481 | end 482 | 483 | def test_convert_entity 484 | expected = [ 485 | { 486 | type: 'paragraph', 487 | content: { 488 | text: "\u00a0", 489 | spans: [] 490 | } 491 | } 492 | ] 493 | markdown = ' ' 494 | assert_equal expected, Kramdown::Document.new(markdown, input: :markdown).to_prismic 495 | end 496 | 497 | [['mdash', ' ---', ' —'], 498 | ['ndash', ' --', ' –'], 499 | ['hellip', ' ...', ' …'], 500 | ['laquo', ' <<', ' «'], 501 | ['raquo', '>>', '»'], 502 | ['laquo_space', ' << T', ' « T'], 503 | ['raquo_space', ' >>', ' »']].each do |symbol| 504 | define_method "test_convert_typographic_symbols_#{symbol[0]}" do 505 | expected = [ 506 | { 507 | type: 'paragraph', 508 | content: { 509 | text: "Hello#{symbol[2]}", 510 | spans: [] 511 | } 512 | } 513 | ] 514 | markdown = "Hello#{symbol[1]}" 515 | assert_equal expected, Kramdown::Document.new(markdown, input: :kramdown).to_prismic 516 | end 517 | end 518 | 519 | def test_convert_smart_quote 520 | expected = [ 521 | { 522 | type: 'paragraph', 523 | content: { 524 | text: "Test\u2019", 525 | spans: [] 526 | } 527 | } 528 | ] 529 | markdown = "Test'" 530 | assert_equal expected, Kramdown::Document.new(markdown, input: :kramdown).to_prismic 531 | end 532 | 533 | def test_convert_inline_code 534 | expected = [ 535 | { 536 | type: 'paragraph', 537 | content: { 538 | text: 'Hello code', 539 | spans: [] 540 | } 541 | } 542 | ] 543 | markdown = 'Hello `code`' 544 | doc = Kramdown::Document.new(markdown) 545 | assert_equal expected, doc.to_prismic 546 | assert_equal 1, doc.warnings.size 547 | end 548 | 549 | def test_convert_br 550 | expected = [ 551 | { 552 | type: 'paragraph', 553 | content: { 554 | text: "Test\n", 555 | spans: [] 556 | } 557 | } 558 | ] 559 | html = '

Test

' 560 | assert_equal expected, Kramdown::Document.new(html, input: :html).to_prismic 561 | end 562 | 563 | def test_convert_br_in_root_element 564 | expected = [ 565 | { 566 | type: 'paragraph', 567 | content: { 568 | text: "Test\n", 569 | spans: [] 570 | } 571 | } 572 | ] 573 | html = '

Test

' 574 | assert_equal expected, Kramdown::Document.new(html, input: :html).to_prismic 575 | end 576 | 577 | def test_convert_html_with_no_tags 578 | expected_text = if Gem::Version.new(Kramdown::VERSION) >= Gem::Version.new("2.3.2") 579 | "Test " 580 | else 581 | "Test\n" 582 | end 583 | expected = [ 584 | { 585 | type: 'paragraph', 586 | content: { 587 | text: expected_text, 588 | spans: [] 589 | } 590 | } 591 | ] 592 | html = 'Test' 593 | assert_equal expected, Kramdown::Document.new(html, input: :html).to_prismic 594 | end 595 | 596 | def test_convert_iframe 597 | expected = [ 598 | { 599 | type: 'embed', 600 | content: { 601 | text: '', 602 | spans: [] 603 | }, 604 | data: { 605 | embed_url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', 606 | type: 'link' 607 | } 608 | } 609 | ] 610 | html = '' 611 | doc = Kramdown::Document.new(html, input: :markdown) 612 | assert_equal expected, doc.to_prismic 613 | end 614 | 615 | def test_convert_link 616 | expected = [ 617 | { 618 | type: 'paragraph', 619 | content: { 620 | text: 'Test', 621 | spans: [{type: 'hyperlink', data: {url: 'http://example.net', target: '_blank'}, start: 0, end: 4}] 622 | } 623 | } 624 | ] 625 | html = 'Test' 626 | doc = Kramdown::Document.new(html, input: :markdown) 627 | assert_equal expected, doc.to_prismic 628 | end 629 | 630 | def test_convert_html 631 | expected = [] 632 | html = '
' 633 | doc = Kramdown::Document.new(html, input: :markdown) 634 | assert_equal expected, doc.to_prismic 635 | assert_equal 1, doc.warnings.size 636 | end 637 | 638 | def test_convert_span_html_strong 639 | expected = [ 640 | { 641 | type: 'paragraph', 642 | content: { 643 | text: 'This is a paragraph', 644 | spans: [ 645 | { 646 | type: 'strong', 647 | start: 10, 648 | end: 20 649 | } 650 | ] 651 | } 652 | } 653 | ] 654 | html = '

This is a paragraph

' 655 | doc = Kramdown::Document.new(html, input: :html) 656 | assert_equal expected, doc.to_prismic 657 | assert_equal 0, doc.warnings.size 658 | end 659 | 660 | def test_convert_span_html_br 661 | expected = [ 662 | { 663 | type: 'paragraph', 664 | content: { 665 | text: "\n", 666 | spans: [] 667 | } 668 | } 669 | ] 670 | html = '
' 671 | doc = Kramdown::Document.new(html, input: :markdown) 672 | assert_equal expected, doc.to_prismic 673 | assert_equal 0, doc.warnings.size 674 | end 675 | 676 | def test_convert_span_html_unknown 677 | expected = [ 678 | { 679 | type: 'paragraph', 680 | content: { 681 | text: 'This is a ', 682 | spans: [] 683 | } 684 | } 685 | ] 686 | html = '

This is a

detail

' 687 | doc = Kramdown::Document.new(html, input: :html) 688 | assert_equal expected, doc.to_prismic 689 | assert_equal 1, doc.warnings.size 690 | assert_equal "translating html element 'details' is not supported", doc.warnings.first 691 | end 692 | 693 | def test_convert_table 694 | expected = [] 695 | markdown = '| First cell|Second cell|Third cell|' 696 | doc = Kramdown::Document.new(markdown, input: :kramdown) 697 | assert_equal expected, doc.to_prismic 698 | assert_equal 1, doc.warnings.size 699 | end 700 | 701 | def test_convert_definition 702 | expected = [] 703 | markdown = "kramdown\n: A Markdown-superset converter" 704 | doc = Kramdown::Document.new(markdown, input: :kramdown) 705 | assert_equal expected, doc.to_prismic 706 | assert_equal 1, doc.warnings.size 707 | end 708 | 709 | def test_convert_math 710 | expected = [] 711 | markdown = '$$ 5 + 5 $$' 712 | doc = Kramdown::Document.new(markdown, input: :kramdown) 713 | assert_equal expected, doc.to_prismic 714 | assert_equal 1, doc.warnings.size 715 | end 716 | 717 | def test_convert_footnote 718 | expected = [ 719 | { 720 | type: 'paragraph', 721 | content: { 722 | text: 'test', 723 | spans: [] 724 | } 725 | } 726 | ] 727 | markdown = "test[^1]\n\n[^1]: test" 728 | doc = Kramdown::Document.new(markdown, input: :kramdown) 729 | assert_equal expected, doc.to_prismic 730 | assert_equal 1, doc.warnings.size 731 | end 732 | 733 | def test_convert_abbreviation 734 | expected = [ 735 | { 736 | type: 'paragraph', 737 | content: { 738 | text: 'HTML', 739 | spans: [] 740 | } 741 | } 742 | ] 743 | markdown = "HTML\n\n*[HTML]: test" 744 | doc = Kramdown::Document.new(markdown, input: :kramdown) 745 | assert_equal expected, doc.to_prismic 746 | assert_equal 1, doc.warnings.size 747 | end 748 | 749 | def test_convert_xml_comment 750 | expected = [] 751 | markdown = "" 752 | doc = Kramdown::Document.new(markdown, input: :kramdown) 753 | assert_equal expected, doc.to_prismic 754 | assert_equal 1, doc.warnings.size 755 | end 756 | 757 | def test_convert_span_xml_comment 758 | expected = [ 759 | { 760 | type: 'paragraph', 761 | content: { 762 | text: 'test test', 763 | spans: [] 764 | } 765 | } 766 | ] 767 | markdown = "test test" 768 | doc = Kramdown::Document.new(markdown, input: :kramdown) 769 | assert_equal expected, doc.to_prismic 770 | assert_equal 1, doc.warnings.size 771 | end 772 | 773 | def test_convert_comment 774 | expected = [] 775 | markdown = "{::comment}\nComment\n{:/comment}" 776 | doc = Kramdown::Document.new(markdown, input: :kramdown) 777 | assert_equal expected, doc.to_prismic 778 | assert_equal 1, doc.warnings.size 779 | end 780 | 781 | def test_convert_raw 782 | expected = [] 783 | markdown = "{::nomarkdown}\nComment\n{:/nomarkdown}" 784 | doc = Kramdown::Document.new(markdown, input: :kramdown) 785 | assert_equal expected, doc.to_prismic 786 | assert_equal 1, doc.warnings.size 787 | end 788 | end 789 | --------------------------------------------------------------------------------