kramdown-asciidoc 1.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.adoc +10 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.adoc +22 -0
  5. data/README.adoc +147 -0
  6. data/Rakefile +3 -0
  7. data/bin/kramdoc +24 -0
  8. data/kramdown-asciidoc.gemspec +41 -0
  9. data/lib/kramdown-asciidoc.rb +2 -0
  10. data/lib/kramdown-asciidoc/converter.rb +413 -0
  11. data/lib/kramdown-asciidoc/version.rb +3 -0
  12. data/spec/converter_spec.rb +114 -0
  13. data/spec/fixtures/a/bare-url.adoc +1 -0
  14. data/spec/fixtures/a/bare-url.md +1 -0
  15. data/spec/fixtures/a/interdoc-xref.adoc +1 -0
  16. data/spec/fixtures/a/interdoc-xref.md +1 -0
  17. data/spec/fixtures/a/internal.adoc +5 -0
  18. data/spec/fixtures/a/internal.md +5 -0
  19. data/spec/fixtures/a/local.adoc +1 -0
  20. data/spec/fixtures/a/local.md +1 -0
  21. data/spec/fixtures/a/url-matches-text.adoc +1 -0
  22. data/spec/fixtures/a/url-matches-text.md +1 -0
  23. data/spec/fixtures/a/url-with-text.adoc +1 -0
  24. data/spec/fixtures/a/url-with-text.md +1 -0
  25. data/spec/fixtures/blockquote/basic.adoc +3 -0
  26. data/spec/fixtures/blockquote/basic.md +1 -0
  27. data/spec/fixtures/blockquote/list.adoc +5 -0
  28. data/spec/fixtures/blockquote/list.md +3 -0
  29. data/spec/fixtures/blockquote/multiple-lines.adoc +5 -0
  30. data/spec/fixtures/blockquote/multiple-lines.md +3 -0
  31. data/spec/fixtures/blockquote/nested.adoc +7 -0
  32. data/spec/fixtures/blockquote/nested.md +3 -0
  33. data/spec/fixtures/blockquote/with-attribution.adoc +5 -0
  34. data/spec/fixtures/blockquote/with-attribution.md +3 -0
  35. data/spec/fixtures/br/tag-followed-by-newline.adoc +3 -0
  36. data/spec/fixtures/br/tag-followed-by-newline.md +3 -0
  37. data/spec/fixtures/br/tag-preceded-by-space.adoc +3 -0
  38. data/spec/fixtures/br/tag-preceded-by-space.md +1 -0
  39. data/spec/fixtures/br/tag.adoc +3 -0
  40. data/spec/fixtures/br/tag.md +1 -0
  41. data/spec/fixtures/br/trailing-double-space.adoc +3 -0
  42. data/spec/fixtures/br/trailing-double-space.md +3 -0
  43. data/spec/fixtures/codeblock/contiguous-lines.adoc +5 -0
  44. data/spec/fixtures/codeblock/contiguous-lines.md +3 -0
  45. data/spec/fixtures/codeblock/fenced/bash-to-console.adoc +4 -0
  46. data/spec/fixtures/codeblock/fenced/bash-to-console.md +3 -0
  47. data/spec/fixtures/codeblock/fenced/with-command-prompt.adoc +1 -0
  48. data/spec/fixtures/codeblock/fenced/with-command-prompt.md +3 -0
  49. data/spec/fixtures/codeblock/fenced/with-language.adoc +8 -0
  50. data/spec/fixtures/codeblock/fenced/with-language.md +7 -0
  51. data/spec/fixtures/codeblock/fenced/with-non-contiguous-command-prompts.adoc +5 -0
  52. data/spec/fixtures/codeblock/fenced/with-non-contiguous-command-prompts.md +5 -0
  53. data/spec/fixtures/codeblock/fenced/without-language.adoc +5 -0
  54. data/spec/fixtures/codeblock/fenced/without-language.md +5 -0
  55. data/spec/fixtures/codeblock/non-contiguous-lines.adoc +7 -0
  56. data/spec/fixtures/codeblock/non-contiguous-lines.md +5 -0
  57. data/spec/fixtures/codeblock/with-command-prompt.adoc +1 -0
  58. data/spec/fixtures/codeblock/with-command-prompt.md +1 -0
  59. data/spec/fixtures/codeblock/with-non-contiguous-command-prompts.adoc +5 -0
  60. data/spec/fixtures/codeblock/with-non-contiguous-command-prompts.md +3 -0
  61. data/spec/fixtures/codespan/constrained.adoc +1 -0
  62. data/spec/fixtures/codespan/constrained.md +1 -0
  63. data/spec/fixtures/codespan/literal.adoc +3 -0
  64. data/spec/fixtures/codespan/literal.md +3 -0
  65. data/spec/fixtures/em/asterisks.adoc +1 -0
  66. data/spec/fixtures/em/asterisks.md +1 -0
  67. data/spec/fixtures/em/constrained.adoc +1 -0
  68. data/spec/fixtures/em/constrained.md +1 -0
  69. data/spec/fixtures/entity/numeric.adoc +1 -0
  70. data/spec/fixtures/entity/numeric.md +1 -0
  71. data/spec/fixtures/entity/reverse.adoc +1 -0
  72. data/spec/fixtures/entity/reverse.md +1 -0
  73. data/spec/fixtures/heading/out-of-sequence.adoc +23 -0
  74. data/spec/fixtures/heading/out-of-sequence.md +21 -0
  75. data/spec/fixtures/heading/outline.adoc +13 -0
  76. data/spec/fixtures/heading/outline.md +13 -0
  77. data/spec/fixtures/heading/with-anchor.adoc +2 -0
  78. data/spec/fixtures/heading/with-anchor.md +1 -0
  79. data/spec/fixtures/heading/with-formatting.adoc +1 -0
  80. data/spec/fixtures/heading/with-formatting.md +1 -0
  81. data/spec/fixtures/hr/between-blocks.adoc +5 -0
  82. data/spec/fixtures/hr/between-blocks.md +5 -0
  83. data/spec/fixtures/hr/dashes.adoc +1 -0
  84. data/spec/fixtures/hr/dashes.md +1 -0
  85. data/spec/fixtures/html_element/abbr.adoc +1 -0
  86. data/spec/fixtures/html_element/abbr.md +1 -0
  87. data/spec/fixtures/html_element/heading-with-class.adoc +7 -0
  88. data/spec/fixtures/html_element/heading-with-class.md +5 -0
  89. data/spec/fixtures/html_element/heading-with-id.adoc +2 -0
  90. data/spec/fixtures/html_element/heading-with-id.md +1 -0
  91. data/spec/fixtures/html_element/native.adoc +1 -0
  92. data/spec/fixtures/html_element/native.md +1 -0
  93. data/spec/fixtures/html_element/sub.adoc +1 -0
  94. data/spec/fixtures/html_element/sub.md +1 -0
  95. data/spec/fixtures/html_element/sup.adoc +1 -0
  96. data/spec/fixtures/html_element/sup.md +1 -0
  97. data/spec/fixtures/img/block-with-alt.adoc +1 -0
  98. data/spec/fixtures/img/block-with-alt.md +1 -0
  99. data/spec/fixtures/img/block-with-link-and-alt.adoc +1 -0
  100. data/spec/fixtures/img/block-with-link-and-alt.md +1 -0
  101. data/spec/fixtures/img/block-with-link.adoc +1 -0
  102. data/spec/fixtures/img/block-with-link.md +1 -0
  103. data/spec/fixtures/img/block.adoc +1 -0
  104. data/spec/fixtures/img/block.md +1 -0
  105. data/spec/fixtures/img/imagesdir.adoc +4 -0
  106. data/spec/fixtures/img/imagesdir.md +3 -0
  107. data/spec/fixtures/img/imagesdir.opts +2 -0
  108. data/spec/fixtures/img/implicit-imagesdir.adoc +3 -0
  109. data/spec/fixtures/img/implicit-imagesdir.md +3 -0
  110. data/spec/fixtures/img/implicit-imagesdir.opts +2 -0
  111. data/spec/fixtures/img/inline-with-alt.adoc +1 -0
  112. data/spec/fixtures/img/inline-with-alt.md +1 -0
  113. data/spec/fixtures/img/inline-with-link-and-alt.adoc +1 -0
  114. data/spec/fixtures/img/inline-with-link-and-alt.md +1 -0
  115. data/spec/fixtures/img/inline-with-link.adoc +1 -0
  116. data/spec/fixtures/img/inline-with-link.md +1 -0
  117. data/spec/fixtures/img/inline.adoc +1 -0
  118. data/spec/fixtures/img/inline.md +1 -0
  119. data/spec/fixtures/ol/compound-separated.adoc +25 -0
  120. data/spec/fixtures/ol/compound-separated.md +23 -0
  121. data/spec/fixtures/ol/compound.adoc +25 -0
  122. data/spec/fixtures/ol/compound.md +18 -0
  123. data/spec/fixtures/ol/mixed-separated.adoc +6 -0
  124. data/spec/fixtures/ol/mixed-separated.md +11 -0
  125. data/spec/fixtures/ol/mixed.adoc +6 -0
  126. data/spec/fixtures/ol/mixed.md +6 -0
  127. data/spec/fixtures/ol/nested-separated.adoc +7 -0
  128. data/spec/fixtures/ol/nested-separated.md +13 -0
  129. data/spec/fixtures/ol/nested.adoc +7 -0
  130. data/spec/fixtures/ol/nested.md +7 -0
  131. data/spec/fixtures/ol/simple-separated.adoc +4 -0
  132. data/spec/fixtures/ol/simple-separated.md +7 -0
  133. data/spec/fixtures/ol/simple.adoc +4 -0
  134. data/spec/fixtures/ol/simple.md +4 -0
  135. data/spec/fixtures/p/admonition/emphasis.adoc +11 -0
  136. data/spec/fixtures/p/admonition/emphasis.md +11 -0
  137. data/spec/fixtures/p/admonition/in-list-item.adoc +6 -0
  138. data/spec/fixtures/p/admonition/in-list-item.md +6 -0
  139. data/spec/fixtures/p/admonition/plain.adoc +11 -0
  140. data/spec/fixtures/p/admonition/plain.md +11 -0
  141. data/spec/fixtures/p/admonition/strong-emphasis.adoc +11 -0
  142. data/spec/fixtures/p/admonition/strong-emphasis.md +11 -0
  143. data/spec/fixtures/p/multiple-lines.adoc +2 -0
  144. data/spec/fixtures/p/multiple-lines.md +2 -0
  145. data/spec/fixtures/p/multiple.adoc +3 -0
  146. data/spec/fixtures/p/multiple.md +3 -0
  147. data/spec/fixtures/p/single-line.adoc +1 -0
  148. data/spec/fixtures/p/single-line.md +1 -0
  149. data/spec/fixtures/root/body-only.adoc +1 -0
  150. data/spec/fixtures/root/body-only.md +1 -0
  151. data/spec/fixtures/root/book-doctype.adoc +10 -0
  152. data/spec/fixtures/root/book-doctype.md +9 -0
  153. data/spec/fixtures/root/header-and-body.adoc +3 -0
  154. data/spec/fixtures/root/header-and-body.md +3 -0
  155. data/spec/fixtures/root/header-only.adoc +1 -0
  156. data/spec/fixtures/root/header-only.md +1 -0
  157. data/spec/fixtures/smart_quote/apostrophe.adoc +1 -0
  158. data/spec/fixtures/smart_quote/apostrophe.md +1 -0
  159. data/spec/fixtures/smart_quote/double-quotes.adoc +1 -0
  160. data/spec/fixtures/smart_quote/double-quotes.md +1 -0
  161. data/spec/fixtures/smart_quote/single-quotes.adoc +1 -0
  162. data/spec/fixtures/smart_quote/single-quotes.md +1 -0
  163. data/spec/fixtures/strong/constrained.adoc +1 -0
  164. data/spec/fixtures/strong/constrained.md +1 -0
  165. data/spec/fixtures/strong/nested-emphasis.adoc +1 -0
  166. data/spec/fixtures/strong/nested-emphasis.md +1 -0
  167. data/spec/fixtures/table/with-header.adoc +9 -0
  168. data/spec/fixtures/table/with-header.md +4 -0
  169. data/spec/fixtures/table/without-header.adoc +8 -0
  170. data/spec/fixtures/table/without-header.md +2 -0
  171. data/spec/fixtures/text/lte.adoc +1 -0
  172. data/spec/fixtures/text/lte.md +1 -0
  173. data/spec/fixtures/text/plus-plus.adoc +6 -0
  174. data/spec/fixtures/text/plus-plus.md +5 -0
  175. data/spec/fixtures/text/typographic_sym/apostrophe.adoc +1 -0
  176. data/spec/fixtures/text/typographic_sym/apostrophe.md +1 -0
  177. data/spec/fixtures/text/typographic_sym/double-quotes.adoc +1 -0
  178. data/spec/fixtures/text/typographic_sym/double-quotes.md +1 -0
  179. data/spec/fixtures/text/typographic_sym/ellipsis.adoc +1 -0
  180. data/spec/fixtures/text/typographic_sym/ellipsis.md +1 -0
  181. data/spec/fixtures/text/typographic_sym/mdash.adoc +1 -0
  182. data/spec/fixtures/text/typographic_sym/mdash.md +1 -0
  183. data/spec/fixtures/text/typographic_sym/ndash.adoc +1 -0
  184. data/spec/fixtures/text/typographic_sym/ndash.md +1 -0
  185. data/spec/fixtures/text/typographic_sym/single-quotes.adoc +1 -0
  186. data/spec/fixtures/text/typographic_sym/single-quotes.md +1 -0
  187. data/spec/fixtures/typographic_sym/ellipsis.adoc +1 -0
  188. data/spec/fixtures/typographic_sym/ellipsis.md +1 -0
  189. data/spec/fixtures/typographic_sym/mdash.adoc +1 -0
  190. data/spec/fixtures/typographic_sym/mdash.md +1 -0
  191. data/spec/fixtures/typographic_sym/ndash.adoc +1 -0
  192. data/spec/fixtures/typographic_sym/ndash.md +1 -0
  193. data/spec/fixtures/ul/compound-separated.adoc +25 -0
  194. data/spec/fixtures/ul/compound-separated.md +23 -0
  195. data/spec/fixtures/ul/compound.adoc +25 -0
  196. data/spec/fixtures/ul/compound.md +18 -0
  197. data/spec/fixtures/ul/nested-separated.adoc +11 -0
  198. data/spec/fixtures/ul/nested-separated.md +21 -0
  199. data/spec/fixtures/ul/nested.adoc +11 -0
  200. data/spec/fixtures/ul/nested.md +11 -0
  201. data/spec/fixtures/ul/simple-separated.adoc +3 -0
  202. data/spec/fixtures/ul/simple-separated.md +5 -0
  203. data/spec/fixtures/ul/simple.adoc +3 -0
  204. data/spec/fixtures/ul/simple.md +3 -0
  205. data/spec/fixtures/xml_comment/block.adoc +7 -0
  206. data/spec/fixtures/xml_comment/block.md +6 -0
  207. data/spec/fixtures/xml_comment/line-offset-by-space.adoc +1 -0
  208. data/spec/fixtures/xml_comment/line-offset-by-space.md +1 -0
  209. data/spec/fixtures/xml_comment/line.adoc +1 -0
  210. data/spec/fixtures/xml_comment/line.md +1 -0
  211. data/spec/fixtures/xml_comment/list-separator.adoc +7 -0
  212. data/spec/fixtures/xml_comment/list-separator.md +7 -0
  213. data/spec/fixtures/xml_comment/mixed.adoc +7 -0
  214. data/spec/fixtures/xml_comment/mixed.md +6 -0
  215. data/spec/fixtures/xml_comment/multiline-span.adoc +4 -0
  216. data/spec/fixtures/xml_comment/multiline-span.md +3 -0
  217. data/spec/fixtures/xml_comment/styled.adoc +6 -0
  218. data/spec/fixtures/xml_comment/styled.md +6 -0
  219. data/spec/integration_spec.rb +27 -0
  220. data/spec/spec_helper.rb +9 -0
  221. metadata +533 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 70b7c1c3b371ac7e88456a531413b89ccb7186f706f44ad33abedd96ce6ef52d
4
+ data.tar.gz: b8ee1cb2365ff90ad26abb4528dad929cb75034297bd2e590c48453c2a3f61bc
5
+ SHA512:
6
+ metadata.gz: b2cf8e0cf5ef344ee31621f1b05e86e9504c5392adbc79b443db9594764bf51d39371cb2db57a36d7bb59ed4b0079a0eec0519c95d78cfb615c4cf00d8680830
7
+ data.tar.gz: 1bc00c04fd46be08e697a562eeea7f583a0e6afc3949a9c1bc937f1509d0605c07b367dec9fc2c578a8ff31f4d438349c5832b72799612f18b53eb9306549ce6
@@ -0,0 +1,10 @@
1
+ = {project-name} Changelog
2
+ :project-name: Kramdown AsciiDoc
3
+ :uri-repo: https://github.com/asciidoctor/kramdown-asciidoc
4
+
5
+ This document provides a high-level view of the changes to {project-name} by release.
6
+ For a detailed view of what has changed, refer to the {uri-repo}/commits/master[commit history] on GitHub.
7
+
8
+ == 1.0.0.alpha.1 (2018-05-22) - @mojavelinux
9
+
10
+ Initial release.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ .The MIT License
2
+ ....
3
+ Copyright (C) 2016 OpenDevise Inc. (on behalf of the Asciidoctor Project)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
22
+ ....
@@ -0,0 +1,147 @@
1
+ = {project-name} (Markdown to AsciiDoc)
2
+ Dan Allen <https://github.com/mojavelinux>
3
+ v1.0.0.alpha.1, 2018-05-22
4
+ // Aliases:
5
+ :project-name: Kramdown AsciiDoc
6
+ :project-handle: kramdown-asciidoc
7
+ // Settings:
8
+ :idprefix:
9
+ :idseparator: -
10
+ ifndef::env-github[:icons: font]
11
+ ifdef::env-github,env-browser[]
12
+ :toc: preamble
13
+ :toclevels: 1
14
+ endif::[]
15
+ ifdef::env-github[]
16
+ :status:
17
+ :!toc-title:
18
+ :note-caption: :paperclip:
19
+ :tip-caption: :bulb:
20
+ endif::[]
21
+ // URIs:
22
+ :uri-repo: https://github.com/asciidoctor/kramdown-asciidoc
23
+ :uri-asciidoc: https://asciidoctor.org/docs/what-is-asciidoc/#what-is-asciidoc
24
+ :uri-asciidoctor: https://asciidoctor.org
25
+ :uri-rvm: https://rvm.io
26
+ :uri-install-rvm: https://rvm.io/rvm/install
27
+ //:img-gem: https://img.shields.io/gem/v/kramdown-asciidoc.svg?label=gem
28
+ :uri-ci-travis: https://travis-ci.org/asciidoctor/kramdown-asciidoc
29
+ :img-ci-travis: https://img.shields.io/travis/asciidoctor/kramdown-asciidoc/master.svg
30
+
31
+ ifdef::status[]
32
+ //image:{img-gem}[Gem Version,link={uri-gem}]
33
+ image:{img-ci-travis}[Build Status (Travis CI),link={uri-ci-travis}]
34
+ endif::[]
35
+
36
+ {uri-repo}[{project-name}] (gem: *{project-handle}*) is a Kramdown extension for converting Markdown documents to {uri-asciidoc}[AsciiDoc].
37
+ Notably, the converter generates modern AsciiDoc syntax suitable for use with {uri-asciidoctor}[Asciidoctor].
38
+
39
+ == Prerequisites
40
+
41
+ To install and run {project-name}, you need Ruby 2.4 or better installed and a few RubyGems (aka gems).
42
+ We'll explain how to install the gems in the next section.
43
+
44
+ To check whether you have Ruby installed, and which version you have, run the following command:
45
+
46
+ $ ruby -v
47
+
48
+ If Ruby is not installed, you can install it using {uri-rvm}[RVM] (or, if you prefer, the package manager for your system).
49
+ We generally recommend using RVM because it allows you to install gems without requiring elevated privileges or messing with system libraries.
50
+
51
+ == Installation
52
+
53
+ {project-name} is published as a pre-release gem named {project-handle} to RubyGems.org.
54
+
55
+ You can install the pre-release version using the following command:
56
+
57
+ $ gem install kramdown-asciidoc --pre
58
+
59
+ Installing this gem makes the `kramdoc` command available on your $PATH.
60
+
61
+ TIP: To test a feature that's not yet released, you can <<Development,run the application from source>>.
62
+
63
+ == Usage
64
+
65
+ To convert a Markdown file to AsciiDoc using {project-name}, run the `kramdoc` command as follows:
66
+
67
+ $ kramdoc sample.md
68
+
69
+ The `kramdoc` command automatically creates the output file [.path]_sample.adoc_ in the same folder as the input file.
70
+ This path is calculated by removing the Markdown file extension, `.md`, and adding the AsciiDoc file extension, `.adoc`.
71
+
72
+ NOTE: The converter assumes the input uses the GitHub-flavor Markdown (GFM) syntax.
73
+
74
+ The `kramdoc` command does not currently support any options other than the input file.
75
+ Support for additional options is planned.
76
+
77
+ == Development
78
+
79
+ To help develop {project-name}, or to simply test-drive the development version, you need to retrieve the source from GitHub.
80
+ Follow the instructions below to learn how to clone the source and run the application from source (i.e., your clone).
81
+
82
+ === Retrieve the source code
83
+
84
+ Simply copy the {uri-repo}[GitHub repository URL] and pass it to the `git clone` command:
85
+
86
+ [subs=attributes+]
87
+ $ git clone {uri-repo}
88
+
89
+ Next, switch to the project directory:
90
+
91
+ [subs=attributes+]
92
+ $ cd {project-handle}
93
+
94
+ === Prepare RVM (optional)
95
+
96
+ We recommend using {uri-rvm}[RVM] when developing applications with Ruby.
97
+ We like RVM because it keeps the dependencies required by the project isolated from the rest of your system.
98
+ Follow the {uri-install-rvm}[installation instructions] on the RVM site to setup RVM and install Ruby.
99
+
100
+ Once you have RVM setup, switch to the RVM-managed version of Ruby recommended by the project using this command:
101
+
102
+ $ rvm use
103
+
104
+ The recommended version of Ruby is defined in the [.path]_.ruby-version_ file at the root of the project.
105
+
106
+ === Install the dependencies
107
+
108
+ The dependencies needed to use {project-name} are defined in the [.path]_Gemfile_ at the root of the project.
109
+ You'll use Bundler to install these dependencies.
110
+
111
+ To check if you have Bundler available, use the `bundle` command to query the version installed:
112
+
113
+ $ bundle --version
114
+
115
+ If Bundler is not installed, use the `gem` command to install it.
116
+
117
+ $ gem install bundler
118
+
119
+ Then, use the `bundle` command to install the project dependencies under the project directory:
120
+
121
+ $ bundle --path=.bundle/gems
122
+
123
+ NOTE: You must invoke `bundle` from the project's root directory so it can locate the [.path]_Gemfile_.
124
+
125
+ === Usage
126
+
127
+ When running the `kramdoc` command from source, you must prefix the command with `bundle exec`:
128
+
129
+ $ bundle exec kramdoc sample.md
130
+
131
+ To avoid having to do this, or make the `kramdoc` command available from anywhere, you need to build the development gem and install it.
132
+
133
+ == Alternatives
134
+
135
+ * https://github.com/bodiam/markdown-to-asciidoc[markdown-to-asciidoc] (Java library)
136
+ * http://pandoc.org[pandoc] (Haskell-based CLI tool)
137
+
138
+ == Authors
139
+
140
+ *{project-name}* was written by {email}[{author}].
141
+
142
+ == Copyright
143
+
144
+ Copyright (C) 2016-2018 OpenDevise Inc. (on behalf of the Asciidoctor Project).
145
+ Free use of this software is granted under the terms of the MIT License.
146
+
147
+ See the link:LICENSE.adoc[LICENSE] file for details.
@@ -0,0 +1,3 @@
1
+ Dir.glob('tasks/*.rake').each {|file| load file }
2
+
3
+ task default: %w(spec)
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if File.exist? (kramdown_asciidoc = File.absolute_path '../lib/kramdown-asciidoc', __dir__)
4
+ require kramdown_asciidoc
5
+ else
6
+ require 'kramdown-asciidoc'
7
+ end
8
+
9
+ infile = ARGV.first
10
+ unless infile
11
+ warn 'Please specify a Markdown file to convert.'
12
+ exit 1
13
+ end
14
+ outfile = %(#{infile.slice 0, infile.length - (File.extname infile).length}.adoc)
15
+ input = (IO.read infile, open_args: ['rb:UTF-8']).rstrip
16
+ input = input.slice 1, input.length while input.start_with? ?\n
17
+ attributes = {}
18
+ input = Kramdown::AsciiDoc.extract_front_matter input, attributes
19
+ input = Kramdown::AsciiDoc.replace_toc input, attributes
20
+ # FIXME allow input type to be specified (Kramdown, GFM, etc)
21
+ doc = Kramdown::Document.new input, (Kramdown::AsciiDoc::DEFAULT_PARSER_OPTS.merge attributes: attributes)
22
+ # FIXME provide option to write to different file or stdout
23
+ IO.write outfile, doc.to_asciidoc
24
+ exit 0
@@ -0,0 +1,41 @@
1
+ require File.absolute_path 'lib/kramdown-asciidoc/version', __dir__
2
+ require 'open3' unless defined? Open3
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'kramdown-asciidoc'
6
+ s.version = Kramdown::AsciiDoc::VERSION
7
+ s.summary = 'A Markdown to AsciiDoc converter based on Kramdown'
8
+ s.description = 'A Kramdown extension for converting Markdown documents to AsciiDoc.'
9
+
10
+ s.authors = ['Dan Allen']
11
+ s.email = ['dan.j.allen@gmail.com']
12
+ s.homepage = 'https://github.com/asciidoctor/kramdown-asciidoc'
13
+ s.license = 'MIT'
14
+ s.metadata = {
15
+ 'bug_tracker_uri' => 'https://github.com/asciidoctor/kramdown-asciidoc/issues',
16
+ 'changelog_uri' => 'https://github.com/asciidoctor/kramdown-asciidoc/blob/master/CHANGELOG.adoc',
17
+ 'mailing_list_uri' => 'http://discuss.asciidoctor.org',
18
+ 'source_code_uri' => 'https://github.com/asciidoctor/kramdown-asciidoc'
19
+ }
20
+ #s.required_ruby_version = '>= 2.4.0'
21
+
22
+ files = begin
23
+ (result = Open3.popen3('git ls-files -z') {|_, out| out.read }.split ?\0).empty? ? Dir['**/*'] : result
24
+ rescue
25
+ Dir['**/*']
26
+ end
27
+ s.files = files.grep %r/^(?:lib\/.+|Gemfile|Rakefile|(?:CHANGELOG|CONTRIBUTING|LICENSE|README)\.adoc|#{s.name}\.gemspec)$/
28
+ s.test_files = files.grep %r/^(?:spec\/.+)$/
29
+ s.executables = ['kramdoc']
30
+
31
+ s.require_paths = ['lib']
32
+
33
+ #s.has_rdoc = true
34
+ #s.rdoc_options = ['--charset=UTF-8']
35
+ #s.extra_rdoc_files = ['CHANGELOG.adoc', 'LICENSE.adoc']
36
+
37
+ s.add_runtime_dependency 'kramdown', '~> 1.16.2'
38
+ s.add_development_dependency 'rake', '~> 12.3.1'
39
+ s.add_development_dependency 'rspec', '~> 3.7.0'
40
+ s.add_development_dependency 'simplecov', '~> 0.16.1'
41
+ end
@@ -0,0 +1,2 @@
1
+ require 'kramdown'
2
+ require_relative 'kramdown-asciidoc/converter'
@@ -0,0 +1,413 @@
1
+ # encoding: UTF-8
2
+ module Kramdown; module AsciiDoc
3
+ DEFAULT_PARSER_OPTS = {
4
+ auto_ids: false,
5
+ hard_wrap: false,
6
+ html_to_native: true,
7
+ input: 'GFM',
8
+ }
9
+
10
+ TocDirectiveTip = '<!-- TOC '
11
+ TocDirectiveRx = /^<!-- TOC .*<!-- \/TOC -->/m
12
+
13
+ def self.replace_toc source, attributes
14
+ if source.include? TocDirectiveTip
15
+ attributes['toc'] = 'macro'
16
+ source.gsub TocDirectiveRx, 'toc::[]'
17
+ else
18
+ source
19
+ end
20
+ end
21
+
22
+ def self.extract_front_matter source, attributes
23
+ if (line_i = (lines = source.each_line).next) && line_i.chomp == '---'
24
+ require 'yaml' unless defined? ::YAML
25
+ lines = lines.drop 1
26
+ front_matter = []
27
+ while (line = lines.shift) && line.chomp != '---'
28
+ front_matter << line
29
+ end
30
+ lines.shift while (line = lines[0]) && line.chomp.empty?
31
+ (::YAML.load front_matter.join).each do |key, val|
32
+ case key
33
+ when 'title'
34
+ # skip
35
+ when 'layout'
36
+ attributes['page-layout'] = val unless val == 'default'
37
+ else
38
+ attributes[key] = val.to_s
39
+ end
40
+ end
41
+ lines.join
42
+ else
43
+ source
44
+ end
45
+ end
46
+
47
+ class Converter < ::Kramdown::Converter::Base
48
+ RESOLVE_ENTITY_TABLE = %w(lt gt).map {|name| Utils::Entities.entity name }.map {|obj| [obj, obj.char] }.to_h
49
+ ADMON_LABELS = %w(Note Tip Caution Warning Important Attention).map {|l| [l, l] }.to_h
50
+ ADMON_MARKERS = ADMON_LABELS.map {|l, _| %(#{l}: ) }
51
+ ADMON_FORMATTED_MARKERS = ADMON_LABELS.map {|l, _| [%(#{l}:), l] }.to_h
52
+ ADMON_TYPE_MAP = ADMON_LABELS.map {|l, _| [l, l.upcase] }.to_h.merge 'Attention' => 'IMPORTANT'
53
+ # FIXME here we reverse the smart quotes; add option to allow them (needs to be handled carefully)
54
+ SMART_QUOTE_ENTITY_TO_MARKUP = { ldquo: ?", rdquo: ?", lsquo: ?', rsquo: ?' }
55
+ TYPOGRAPHIC_SYMBOL_TO_MARKUP = {
56
+ '“' => '"`',
57
+ '”' => '`"',
58
+ '‘' => '\'`',
59
+ '’' => '`\'',
60
+ # FIXME in the future, mdash will be three dashes in AsciiDoc; for now, down-convert
61
+ '—' => '--',
62
+ '–' => '&#8211;',
63
+ '…' => '...',
64
+ }
65
+ TYPOGRAPHIC_ENTITY_TO_MARKUP = {
66
+ # FIXME in the future, mdash will be three dashes in AsciiDoc; for now, down-convert
67
+ mdash: '--',
68
+ ndash: '--',
69
+ hellip: '...',
70
+ laquo: '<<',
71
+ raquo: '>>',
72
+ laquo_scape: '<< ',
73
+ raquo_space: ' >>',
74
+ }
75
+
76
+ ApostropheRx = /\b’\b/
77
+ CommentPrefixRx = /^ *! ?/m
78
+ ReplaceableTextRx = /[-=]>|<[-=]|\.\.\./
79
+ StartOfLinesRx = /^/m
80
+ TypographicSymbolRx = /[“”‘’—–…]/
81
+ XmlCommentRx = /\A<!--(.*)-->\Z/m
82
+
83
+ VoidElement = Element.new nil
84
+
85
+ LF = ?\n
86
+ LFx2 = LF * 2
87
+
88
+ def initialize root, opts
89
+ super
90
+ @header = []
91
+ @attributes = opts[:attributes] || {}
92
+ @imagesdir = (@attributes.delete 'implicit-imagesdir') || @attributes['imagesdir']
93
+ @last_heading_level = nil
94
+ end
95
+
96
+ def convert el, opts = {}
97
+ send %(convert_#{el.type}), el, opts
98
+ end
99
+
100
+ def convert_root el, opts
101
+ body = %(#{inner el, (opts.merge rstrip: true)}#{LF})
102
+ @attributes.each {|k, v| @header << %(:#{k}: #{v}) } unless @attributes.empty?
103
+ @header.empty? ? body : %(#{@header.join LF}#{body == LF ? '' : LFx2}#{body})
104
+ end
105
+
106
+ def convert_blank el, opts
107
+ nil
108
+ end
109
+
110
+ def convert_heading el, opts
111
+ result = []
112
+ style = []
113
+ level = el.options[:level]
114
+ style << 'discrete' if (discrete = @last_heading_level && level > @last_heading_level + 1)
115
+ if (id = el.attr['id'])
116
+ style << %(##{id})
117
+ elsif (child_i = el.children[0] || VoidElement).type == :html_element && child_i.value == 'a' && (id = child_i.attr['id'])
118
+ el.children.shift
119
+ el.children.unshift(*child_i.children) unless child_i.children.empty?
120
+ style << %(##{id})
121
+ elsif (role = el.attr['class'])
122
+ style << %(.#{role.tr ' ', '.'})
123
+ end
124
+ result << %([#{style.join}]) unless style.empty?
125
+ result << %(#{'=' * level} #{inner el, opts})
126
+ @last_heading_level = level unless discrete
127
+ if level == 1 && opts[:result].empty?
128
+ @header = result
129
+ nil
130
+ else
131
+ @attributes['doctype'] = 'book' if level == 1
132
+ %(#{result.join LF}#{LFx2})
133
+ end
134
+ end
135
+
136
+ # Kramdown incorrectly uses the term header for headings
137
+ alias convert_header convert_heading
138
+
139
+ def convert_p el, opts
140
+ if (parent = opts[:parent]) && parent.type == :li
141
+ # NOTE :prev option not set indicates primary text; convert_li appends LF
142
+ return inner el, opts unless opts[:prev]
143
+ parent.options[:compound] = true
144
+ opts[:result].pop unless opts[:result][-1]
145
+ prefix, suffix = %(#{LF}+#{LF}), ''
146
+ else
147
+ prefix, suffix = '', LFx2
148
+ end
149
+ # NOTE detect plain admonition marker (e.g, Note: ...)
150
+ if (child_i = el.children[0] || VoidElement).type == :text && (child_i_text = child_i.value).start_with?(*ADMON_MARKERS)
151
+ marker, child_i_text = child_i_text.split ': ', 2
152
+ child_i.value = %(#{ADMON_TYPE_MAP[marker]}: #{child_i_text})
153
+ contents = inner el, opts
154
+ # NOTE detect formatted admonition marker (e.g., *Note:* ...)
155
+ elsif (child_i.type == :strong || child_i.type == :em) &&
156
+ (marker_el = child_i.children[0]) && ((marker = ADMON_FORMATTED_MARKERS[marker_el.value]) ||
157
+ ((marker = ADMON_LABELS[marker_el.value]) && (child_ii = el.children[1] || VoidElement).type == :text &&
158
+ ((child_ii_text = child_ii.value).start_with? ': ')))
159
+ el.children.shift
160
+ child_ii.value = child_ii_text.slice 1, child_ii_text.length if child_ii
161
+ contents = %(#{ADMON_TYPE_MAP[marker]}:#{inner el, opts})
162
+ else
163
+ contents = inner el, opts
164
+ end
165
+ %(#{prefix}#{contents}#{suffix})
166
+ end
167
+
168
+ # TODO detect admonition masquerading as blockquote
169
+ def convert_blockquote el, opts
170
+ result = []
171
+ # TODO support more than one level of nesting
172
+ boundary = (parent = opts[:parent]) && parent.type == :blockquote ? '______' : '____'
173
+ contents = inner el, (opts.merge rstrip: true)
174
+ if (contents.include? LF) && ((attribution_line = (lines = contents.split LF).pop).start_with? '-- ')
175
+ attribution = attribution_line.slice 3, attribution_line.length
176
+ result << %([,#{attribution}])
177
+ lines.pop while lines.size > 0 && lines[-1].empty?
178
+ contents = lines.join LF
179
+ end
180
+ result << boundary
181
+ result << contents
182
+ result << boundary
183
+ %(#{result.join LF}#{LFx2})
184
+ end
185
+
186
+ def convert_codeblock el, opts
187
+ result = []
188
+ if (parent = opts[:parent]) && parent.type == :li
189
+ parent.options[:compound] = true
190
+ if (current_line = opts[:result].pop)
191
+ opts[:result] << current_line.chomp
192
+ end unless opts[:result].empty?
193
+ list_continuation = %(#{LF}+)
194
+ suffix = ''
195
+ else
196
+ suffix = LFx2
197
+ end
198
+ contents = el.value.rstrip
199
+ if (lang = el.attr['class'])
200
+ lang = lang.slice 9, lang.length if lang.start_with? 'language-'
201
+ #lang = 'console' if lang == 'bash' && (contents.start_with? '$ ')
202
+ lang = 'console' if lang == 'bash'
203
+ result << %([source,#{lang}])
204
+ end
205
+ if !lang && (contents.start_with? '$ ')
206
+ if contents.include? LFx2
207
+ result << '....'
208
+ result << contents
209
+ result << '....'
210
+ else
211
+ list_continuation = LF if list_continuation
212
+ result << (contents.gsub StartOfLinesRx, ' ')
213
+ end
214
+ else
215
+ result << '----'
216
+ result << contents
217
+ result << '----'
218
+ end
219
+ result.unshift list_continuation if list_continuation
220
+ %(#{result.join LF}#{suffix})
221
+ end
222
+
223
+ def convert_ul el, opts
224
+ # TODO create do_in_level block
225
+ level = opts[:level] ? (opts[:level] += 1) : (opts[:level] = 1)
226
+ # REVIEW this is whack
227
+ prefix = (parent = opts[:parent]) && parent.type == :li && !opts[:result][-1] ? LF : ''
228
+ contents = inner el, (opts.merge rstrip: true)
229
+ if level == 1
230
+ suffix = LFx2
231
+ opts.delete :level
232
+ else
233
+ suffix = LF
234
+ opts[:level] -= 1
235
+ end
236
+ %(#{prefix}#{contents}#{suffix})
237
+ end
238
+
239
+ alias convert_ol convert_ul
240
+
241
+ def convert_li el, opts
242
+ prefix = (prev = opts[:prev]) && prev.options[:compound] ? LF : ''
243
+ marker = opts[:parent].type == :ol ? '.' : '*'
244
+ indent = (level = opts[:level]) - 1
245
+ %(#{prefix}#{indent > 0 ? (' ' * indent) : ''}#{marker * level} #{(inner el, (opts.merge rstrip: true))}#{LF})
246
+ end
247
+
248
+ def convert_table el, opts
249
+ head = cols = nil
250
+ table_buf = ['|===']
251
+ el.children.each do |container|
252
+ container.children.each do |row|
253
+ row_buf = []
254
+ row.children.each do |cell|
255
+ row_buf << %(| #{inner cell, opts})
256
+ end
257
+ cols = row_buf.size unless cols
258
+ if container.type == :thead
259
+ head = true
260
+ row_buf = [row_buf * ' ']
261
+ end
262
+ row_buf << ''
263
+ table_buf.concat row_buf
264
+ end
265
+ end
266
+ table_buf.unshift %([cols=#{cols}*]) unless head
267
+ table_buf.pop if table_buf[-1] == ''
268
+ table_buf << '|==='
269
+ %(#{table_buf * LF}#{LFx2})
270
+ end
271
+
272
+ def convert_hr el, opts
273
+ %('''#{LFx2})
274
+ end
275
+
276
+ def convert_text el, opts
277
+ if (result = el.value).include? '++'
278
+ @attributes['pp'] = '{plus}{plus}'
279
+ result = result.gsub '++', '{pp}'
280
+ end
281
+ result = result.gsub '<=', '\\<=' if result.include? '<='
282
+ if result.ascii_only?
283
+ result
284
+ else
285
+ (result.gsub ApostropheRx, ?').gsub TypographicSymbolRx, TYPOGRAPHIC_SYMBOL_TO_MARKUP
286
+ end
287
+ end
288
+
289
+ def convert_codespan el, opts
290
+ (val = el.value) =~ ReplaceableTextRx ? %(`+#{val}+`) : %(`#{val}`)
291
+ end
292
+
293
+ def convert_em el, opts
294
+ %(_#{inner el, opts}_)
295
+ end
296
+
297
+ def convert_strong el, opts
298
+ %(*#{inner el, opts}*)
299
+ end
300
+
301
+ # NOTE this logic assumes the :hard_wrap option is disabled in the parser
302
+ def convert_br el, opts
303
+ prefix = ((opts[:result][-1] || '').end_with? ' ') ? '' : ' '
304
+ # if @attr is set, this is a <br> HTML tag
305
+ if el.instance_variable_get :@attr
306
+ siblings = opts[:parent].children
307
+ suffix = (next_el = siblings[(siblings.index el) + 1] || VoidElement).type == :text && (next_el.value.start_with? LF) ? '' : LF
308
+ else
309
+ suffix = ''
310
+ end
311
+ %(#{prefix}+#{suffix})
312
+ end
313
+
314
+ def convert_smart_quote el, opts
315
+ SMART_QUOTE_ENTITY_TO_MARKUP[el.value]
316
+ end
317
+
318
+ def convert_entity el, opts
319
+ RESOLVE_ENTITY_TABLE[el.value] || el.options[:original]
320
+ end
321
+
322
+ def convert_a el, opts
323
+ if (url = el.attr['href']).start_with? '#'
324
+ %(<<#{url.slice 1, url.length},#{inner el, opts}>>)
325
+ elsif url.start_with? 'https://', 'http://'
326
+ if (child_i = el.children[0] || VoidElement).type == :img
327
+ convert_img child_i, parent: opts[:parent], index: 0, url: url
328
+ else
329
+ ((contents = inner el, opts).chomp '/') == (url.chomp '/') ? url : %(#{url}[#{contents}])
330
+ end
331
+ elsif url.end_with? '.md'
332
+ %(xref:#{url.slice 0, url.length - 3}.adoc[#{inner el, opts}])
333
+ else
334
+ %(link:#{url}[#{inner el, opts}])
335
+ end
336
+ end
337
+
338
+ def convert_img el, opts
339
+ prefix = !(parent = opts[:parent]) || parent.type == :p && parent.children.size == 1 ? 'image::' : 'image:'
340
+ alt_text = el.attr['alt']
341
+ link_attr = (url = opts[:url]) ? %(#{alt_text.empty? ? '' : ','}link=#{url}) : ''
342
+ src = el.attr['src']
343
+ if (imagesdir = @imagesdir) && (src.start_with? %(#{imagesdir}/))
344
+ src = src.slice imagesdir.length + 1, src.length
345
+ end
346
+ %(#{prefix}#{src}[#{alt_text}#{link_attr}])
347
+ end
348
+
349
+ # NOTE leave enabled so we can down-convert mdash to --
350
+ def convert_typographic_sym el, opts
351
+ TYPOGRAPHIC_ENTITY_TO_MARKUP[el.value]
352
+ end
353
+
354
+ def convert_html_element el, opts
355
+ contents = inner el, (opts.merge rstrip: el.options[:category] == :block)
356
+ attrs = (attrs = el.attr).empty? ? '' : attrs.map {|k, v| %( #{k}="#{v}") }.join
357
+ case (tagname = el.value)
358
+ when 'sup'
359
+ %(^#{contents}^)
360
+ when 'sub'
361
+ %(~#{contents}~)
362
+ else
363
+ %(+++<#{tagname}#{attrs}>+++#{contents}+++</#{tagname}>+++)
364
+ end
365
+ end
366
+
367
+ def convert_xml_comment el, opts
368
+ XmlCommentRx =~ el.value
369
+ comment_text = ($1.include? ' !') ? ($1.gsub CommentPrefixRx, '').strip : $1.strip
370
+ #siblings = (parent = opts[:parent]) ? parent.children : []
371
+ if (el.options[:category] == :block)# || (!opts[:result][-1] && siblings[-1] == el)
372
+ if comment_text.empty?
373
+ %(//-#{LFx2})
374
+ elsif comment_text.include? LF
375
+ %(////#{LF}#{comment_text}#{LF}////#{LFx2})
376
+ else
377
+ %(// #{comment_text}#{LFx2})
378
+ end
379
+ else
380
+ if (current_line = opts[:result][-1])
381
+ if current_line.end_with? LF
382
+ prefix = ''
383
+ else
384
+ prefix = LF
385
+ opts[:result][-1] = (current_line = current_line.rstrip) if current_line.end_with? ' '
386
+ end
387
+ else
388
+ prefix = ''
389
+ end
390
+ siblings = (parent = opts[:parent]) && parent.children
391
+ suffix = siblings && siblings[(siblings.index el) + 1] ? LF : ''
392
+ if comment_text.include? LF
393
+ %(#{prefix}#{comment_text.gsub StartOfLinesRx, '// '}#{suffix})
394
+ else
395
+ %(#{prefix}// #{comment_text}#{suffix})
396
+ end
397
+ end
398
+ end
399
+
400
+ def inner el, opts
401
+ rstrip = opts.delete :rstrip
402
+ result = []
403
+ prev = nil
404
+ el.children.each_with_index do |child, idx|
405
+ result << (send %(convert_#{child.type}), child, (opts.merge parent: el, index: idx, result: result, prev: prev))
406
+ prev = child
407
+ end
408
+ rstrip ? result.join.rstrip : result.join
409
+ end
410
+ end
411
+ end; end
412
+
413
+ Kramdown::Converter::Asciidoc = Kramdown::AsciiDoc::Converter