asciidoctor 1.5.8 → 2.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.adoc +628 -45
  4. data/LICENSE +2 -1
  5. data/README-de.adoc +28 -38
  6. data/README-fr.adoc +30 -43
  7. data/README-jp.adoc +255 -201
  8. data/README-zh_CN.adoc +40 -44
  9. data/README.adoc +170 -143
  10. data/asciidoctor.gemspec +22 -34
  11. data/bin/asciidoctor +5 -4
  12. data/data/locale/attributes-ar.adoc +4 -3
  13. data/data/locale/attributes-be.adoc +23 -0
  14. data/data/locale/attributes-bg.adoc +4 -3
  15. data/data/locale/attributes-ca.adoc +6 -5
  16. data/data/locale/attributes-cs.adoc +4 -3
  17. data/data/locale/attributes-da.adoc +6 -5
  18. data/data/locale/attributes-de.adoc +6 -5
  19. data/data/locale/attributes-en.adoc +4 -4
  20. data/data/locale/attributes-es.adoc +6 -5
  21. data/data/locale/attributes-fa.adoc +4 -3
  22. data/data/locale/attributes-fi.adoc +4 -3
  23. data/data/locale/attributes-fr.adoc +8 -7
  24. data/data/locale/attributes-hu.adoc +4 -3
  25. data/data/locale/attributes-id.adoc +4 -3
  26. data/data/locale/attributes-it.adoc +6 -5
  27. data/data/locale/attributes-ja.adoc +4 -3
  28. data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
  29. data/data/locale/attributes-nb.adoc +4 -3
  30. data/data/locale/attributes-nl.adoc +6 -5
  31. data/data/locale/attributes-nn.adoc +4 -3
  32. data/data/locale/attributes-pl.adoc +8 -7
  33. data/data/locale/attributes-pt.adoc +6 -5
  34. data/data/locale/attributes-pt_BR.adoc +6 -5
  35. data/data/locale/attributes-ro.adoc +4 -3
  36. data/data/locale/attributes-ru.adoc +6 -5
  37. data/data/locale/attributes-sr.adoc +4 -4
  38. data/data/locale/attributes-sr_Latn.adoc +4 -4
  39. data/data/locale/attributes-sv.adoc +4 -4
  40. data/data/locale/attributes-th.adoc +23 -0
  41. data/data/locale/attributes-tr.adoc +4 -3
  42. data/data/locale/attributes-uk.adoc +6 -5
  43. data/data/locale/attributes-vi.adoc +23 -0
  44. data/data/locale/attributes-zh_CN.adoc +4 -3
  45. data/data/locale/attributes-zh_TW.adoc +4 -3
  46. data/data/reference/syntax.adoc +296 -0
  47. data/data/stylesheets/asciidoctor-default.css +120 -114
  48. data/data/stylesheets/coderay-asciidoctor.css +15 -17
  49. data/lib/asciidoctor/abstract_block.rb +146 -140
  50. data/lib/asciidoctor/abstract_node.rb +152 -170
  51. data/lib/asciidoctor/attribute_list.rb +77 -89
  52. data/lib/asciidoctor/block.rb +29 -28
  53. data/lib/asciidoctor/callouts.rb +4 -2
  54. data/lib/asciidoctor/cli/invoker.rb +20 -24
  55. data/lib/asciidoctor/cli/options.rb +107 -96
  56. data/lib/asciidoctor/cli.rb +3 -2
  57. data/lib/asciidoctor/convert.rb +199 -0
  58. data/lib/asciidoctor/converter/composite.rb +40 -48
  59. data/lib/asciidoctor/converter/docbook5.rb +627 -644
  60. data/lib/asciidoctor/converter/html5.rb +1053 -951
  61. data/lib/asciidoctor/converter/manpage.rb +581 -532
  62. data/lib/asciidoctor/converter/template.rb +232 -271
  63. data/lib/asciidoctor/converter.rb +370 -185
  64. data/lib/asciidoctor/core_ext/float/truncate.rb +20 -0
  65. data/lib/asciidoctor/core_ext/hash/merge.rb +8 -0
  66. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  67. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  68. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  69. data/lib/asciidoctor/core_ext.rb +8 -17
  70. data/lib/asciidoctor/document.rb +503 -461
  71. data/lib/asciidoctor/extensions.rb +127 -174
  72. data/lib/asciidoctor/helpers.rb +184 -107
  73. data/lib/asciidoctor/inline.rb +9 -12
  74. data/lib/asciidoctor/list.rb +11 -29
  75. data/lib/asciidoctor/load.rb +119 -0
  76. data/lib/asciidoctor/logging.rb +22 -17
  77. data/lib/asciidoctor/parser.rb +673 -719
  78. data/lib/asciidoctor/path_resolver.rb +48 -33
  79. data/lib/asciidoctor/reader.rb +383 -338
  80. data/lib/asciidoctor/rouge_ext.rb +39 -0
  81. data/lib/asciidoctor/rx.rb +723 -0
  82. data/lib/asciidoctor/section.rb +17 -16
  83. data/lib/asciidoctor/stylesheets.rb +19 -37
  84. data/lib/asciidoctor/substitutors.rb +926 -1022
  85. data/lib/asciidoctor/syntax_highlighter/coderay.rb +88 -0
  86. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +34 -0
  87. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  88. data/lib/asciidoctor/syntax_highlighter/prettify.rb +30 -0
  89. data/lib/asciidoctor/syntax_highlighter/pygments.rb +157 -0
  90. data/lib/asciidoctor/syntax_highlighter/rouge.rb +143 -0
  91. data/lib/asciidoctor/syntax_highlighter.rb +253 -0
  92. data/lib/asciidoctor/table.rb +152 -114
  93. data/lib/asciidoctor/timings.rb +7 -5
  94. data/lib/asciidoctor/version.rb +2 -1
  95. data/lib/asciidoctor/writer.rb +30 -0
  96. data/lib/asciidoctor.rb +266 -1340
  97. data/man/asciidoctor.1 +49 -47
  98. data/man/asciidoctor.adoc +54 -45
  99. metadata +50 -245
  100. data/CONTRIBUTING.adoc +0 -185
  101. data/Gemfile +0 -60
  102. data/Rakefile +0 -129
  103. data/bin/asciidoctor-safe +0 -15
  104. data/features/open_block.feature +0 -92
  105. data/features/pass_block.feature +0 -66
  106. data/features/step_definitions.rb +0 -49
  107. data/features/text_formatting.feature +0 -57
  108. data/features/xref.feature +0 -1039
  109. data/lib/asciidoctor/converter/base.rb +0 -59
  110. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  111. data/lib/asciidoctor/converter/factory.rb +0 -226
  112. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  113. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  114. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  115. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  116. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  117. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  118. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  119. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  120. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  121. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  122. data/test/api_test.rb +0 -1240
  123. data/test/attribute_list_test.rb +0 -242
  124. data/test/attributes_test.rb +0 -1623
  125. data/test/blocks_test.rb +0 -3870
  126. data/test/converter_test.rb +0 -470
  127. data/test/document_test.rb +0 -1853
  128. data/test/extensions_test.rb +0 -1560
  129. data/test/fixtures/asciidoc_index.txt +0 -521
  130. data/test/fixtures/basic-docinfo-footer.html +0 -6
  131. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  132. data/test/fixtures/basic-docinfo.html +0 -1
  133. data/test/fixtures/basic-docinfo.xml +0 -4
  134. data/test/fixtures/basic.asciidoc +0 -5
  135. data/test/fixtures/chapter-a.adoc +0 -3
  136. data/test/fixtures/child-include.adoc +0 -5
  137. data/test/fixtures/circle.svg +0 -9
  138. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  139. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  140. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  141. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  142. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  143. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  144. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  145. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  146. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  147. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  148. data/test/fixtures/docinfo-footer.html +0 -1
  149. data/test/fixtures/docinfo-footer.xml +0 -9
  150. data/test/fixtures/docinfo.html +0 -1
  151. data/test/fixtures/docinfo.xml +0 -3
  152. data/test/fixtures/doctime-localtime.adoc +0 -2
  153. data/test/fixtures/dot.gif +0 -0
  154. data/test/fixtures/encoding.asciidoc +0 -13
  155. data/test/fixtures/file-with-missing-include.adoc +0 -1
  156. data/test/fixtures/grandchild-include.adoc +0 -3
  157. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  158. data/test/fixtures/include-file.asciidoc +0 -24
  159. data/test/fixtures/include-file.jsx +0 -8
  160. data/test/fixtures/include-file.ml +0 -3
  161. data/test/fixtures/include-file.xml +0 -5
  162. data/test/fixtures/lists.adoc +0 -96
  163. data/test/fixtures/master.adoc +0 -5
  164. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  165. data/test/fixtures/other-chapters.adoc +0 -11
  166. data/test/fixtures/outer-include.adoc +0 -5
  167. data/test/fixtures/parent-include-restricted.adoc +0 -5
  168. data/test/fixtures/parent-include.adoc +0 -5
  169. data/test/fixtures/sample.asciidoc +0 -30
  170. data/test/fixtures/section-a.adoc +0 -4
  171. data/test/fixtures/stylesheets/custom.css +0 -3
  172. data/test/fixtures/subdir/index.adoc +0 -3
  173. data/test/fixtures/subdir/inner-include.adoc +0 -3
  174. data/test/fixtures/subdir/middle-include.adoc +0 -5
  175. data/test/fixtures/subs-docinfo.html +0 -2
  176. data/test/fixtures/subs.adoc +0 -6
  177. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  178. data/test/fixtures/tagged-class.rb +0 -23
  179. data/test/fixtures/tip.gif +0 -0
  180. data/test/fixtures/unclosed-tag.adoc +0 -3
  181. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  182. data/test/invoker_test.rb +0 -745
  183. data/test/links_test.rb +0 -855
  184. data/test/lists_test.rb +0 -5151
  185. data/test/logger_test.rb +0 -211
  186. data/test/manpage_test.rb +0 -660
  187. data/test/options_test.rb +0 -262
  188. data/test/paragraphs_test.rb +0 -562
  189. data/test/parser_test.rb +0 -742
  190. data/test/paths_test.rb +0 -395
  191. data/test/preamble_test.rb +0 -173
  192. data/test/reader_test.rb +0 -2161
  193. data/test/sections_test.rb +0 -3575
  194. data/test/substitutions_test.rb +0 -2066
  195. data/test/tables_test.rb +0 -2036
  196. data/test/test_helper.rb +0 -447
  197. data/test/text_test.rb +0 -309
data/lib/asciidoctor.rb CHANGED
@@ -1,10 +1,4 @@
1
- # encoding: UTF-8
2
- RUBY_ENGINE = 'unknown' unless defined? RUBY_ENGINE
3
- RUBY_ENGINE_OPAL = (RUBY_ENGINE == 'opal')
4
- RUBY_ENGINE_JRUBY = (RUBY_ENGINE == 'jruby')
5
- RUBY_MIN_VERSION_1_9 = (RUBY_VERSION >= '1.9')
6
- RUBY_MIN_VERSION_2 = (RUBY_VERSION >= '2')
7
-
1
+ # frozen_string_literal: true
8
2
  require 'set'
9
3
 
10
4
  # NOTE RUBY_ENGINE == 'opal' conditional blocks like this are filtered by the Opal preprocessor
@@ -13,81 +7,78 @@ if RUBY_ENGINE == 'opal'
13
7
  require 'asciidoctor/js'
14
8
  else
15
9
  autoload :Base64, 'base64'
16
- autoload :URI, 'uri'
10
+ require 'cgi/util'
17
11
  autoload :OpenURI, 'open-uri'
18
12
  autoload :Pathname, 'pathname'
19
13
  autoload :StringScanner, 'strscan'
14
+ autoload :URI, 'uri'
20
15
  end
21
16
 
22
- # ideally we should use require_relative instead of modifying the LOAD_PATH
23
- $:.unshift File.dirname __FILE__
24
-
25
- require 'asciidoctor/logging'
26
-
27
- # Public: Methods for parsing AsciiDoc input files and converting documents
28
- # using eRuby templates.
29
- #
30
- # AsciiDoc documents comprise a header followed by zero or more sections.
31
- # Sections are composed of blocks of content. For example:
17
+ # Public: The main application interface (API) for Asciidoctor. This API provides methods to parse AsciiDoc content and
18
+ # convert it to various output formats using built-in or third-party converters or Tilt-supported templates.
32
19
  #
33
- # = Doc Title
20
+ # An AsciiDoc document can be as simple as a single line of content, though it more commonly starts with a document
21
+ # header that declares the document title and document attribute definitions. The document header is then followed by
22
+ # zero or more section titles, optionally nested, to organize the paragraphs, blocks, lists, etc. of the document.
34
23
  #
35
- # == Section 1
24
+ # By default, the processor converts the AsciiDoc document to HTML 5 using a built-in converter. However, this behavior
25
+ # can be changed by specifying a different backend (e.g., +docbook+). A backend is a keyword for an output format (e.g.,
26
+ # DocBook). That keyword, in turn, is used to select a converter, which carries out the request to convert the document
27
+ # to that format.
36
28
  #
37
- # This is a paragraph block in the first section.
29
+ # In addition to this API, Asciidoctor also provides a command-line interface (CLI) named +asciidoctor+ for converting
30
+ # AsciiDoc content. See the provided man(ual) page for usage and options.
38
31
  #
39
- # == Section 2
32
+ # Examples
40
33
  #
41
- # This section has a paragraph block and an olist block.
34
+ # # Convert an AsciiDoc file
35
+ # Asciidoctor.convert_file 'document.adoc', safe: :safe
42
36
  #
43
- # . Item 1
44
- # . Item 2
37
+ # # Convert an AsciiDoc string
38
+ # puts Asciidoctor.convert "I'm using *Asciidoctor* version {asciidoctor-version}.", safe: :safe
45
39
  #
46
- # Examples:
40
+ # # Convert an AsciiDoc file using Tilt-supported templates
41
+ # Asciidoctor.convert_file 'document.adoc', safe: :safe, template_dir: '/path/to/templates'
47
42
  #
48
- # Use built-in converter:
43
+ # # Parse an AsciiDoc file into a document object
44
+ # doc = Asciidoctor.load_file 'document.adoc', safe: :safe
49
45
  #
50
- # Asciidoctor.convert_file 'sample.adoc'
51
- #
52
- # Use custom (Tilt-supported) templates:
53
- #
54
- # Asciidoctor.convert_file 'sample.adoc', :template_dir => 'path/to/templates'
46
+ # # Parse an AsciiDoc string into a document object
47
+ # doc = Asciidoctor.load "= Document Title\n\nfirst paragraph\n\nsecond paragraph", safe: :safe
55
48
  #
56
49
  module Asciidoctor
57
-
58
- # alias the RUBY_ENGINE constant inside the Asciidoctor namespace
59
- RUBY_ENGINE = ::RUBY_ENGINE
50
+ # alias the RUBY_ENGINE constant inside the Asciidoctor namespace and define a precomputed alias for runtime
51
+ RUBY_ENGINE_OPAL = (RUBY_ENGINE = ::RUBY_ENGINE) == 'opal'
60
52
 
61
53
  module SafeMode
62
-
63
54
  # A safe mode level that disables any of the security features enforced
64
55
  # by Asciidoctor (Ruby is still subject to its own restrictions).
65
- UNSAFE = 0;
56
+ UNSAFE = 0
66
57
 
67
58
  # A safe mode level that closely parallels safe mode in AsciiDoc. This value
68
59
  # prevents access to files which reside outside of the parent directory of
69
60
  # the source file and disables any macro other than the include::[] directive.
70
- SAFE = 1;
61
+ SAFE = 1
71
62
 
72
63
  # A safe mode level that disallows the document from setting attributes
73
64
  # that would affect the conversion of the document, in addition to all the
74
- # security features of SafeMode::SAFE. For instance, this level disallows
75
- # changing the backend or the source-highlighter using an attribute defined
76
- # in the source document. This is the most fundamental level of security
77
- # for server-side deployments (hence the name).
78
- SERVER = 10;
65
+ # security features of SafeMode::SAFE. For instance, this level forbids
66
+ # changing the backend or source-highlighter using an attribute defined
67
+ # in the source document header. This is the most fundamental level of
68
+ # security for server deployments (hence the name).
69
+ SERVER = 10
79
70
 
80
71
  # A safe mode level that disallows the document from attempting to read
81
72
  # files from the file system and including the contents of them into the
82
73
  # document, in additional to all the security features of SafeMode::SERVER.
83
74
  # For instance, this level disallows use of the include::[] directive and the
84
75
  # embedding of binary content (data uri), stylesheets and JavaScripts
85
- # referenced by the document.(Asciidoctor and trusted extensions may still
76
+ # referenced by the document. (Asciidoctor and trusted extensions may still
86
77
  # be allowed to embed trusted content into the document).
87
78
  #
88
79
  # Since Asciidoctor is aiming for wide adoption, this level is the default
89
- # and is recommended for server-side deployments.
90
- SECURE = 20;
80
+ # and is recommended for server deployments.
81
+ SECURE = 20
91
82
 
92
83
  # A planned safe mode level that disallows the use of passthrough macros and
93
84
  # prevents the document from setting any known attributes, in addition to all
@@ -95,14 +86,12 @@ module Asciidoctor
95
86
  #
96
87
  # Please note that this level is not currently implemented (and therefore not
97
88
  # enforced)!
98
- #PARANOID = 100;
89
+ #PARANOID = 100
99
90
 
100
- rec = {}
101
- constants.each {|sym| rec[const_get sym] = sym.to_s.downcase }
102
- @names_by_value = rec
91
+ @names_by_value = (constants false).map {|sym| [(const_get sym), sym.to_s.downcase] }.sort {|(a), (b)| a <=> b }.to_h
103
92
 
104
93
  def self.value_for_name name
105
- const_get name.upcase
94
+ const_get name.upcase, false
106
95
  end
107
96
 
108
97
  def self.name_for_value value
@@ -119,14 +108,14 @@ module Asciidoctor
119
108
  @keys = ::Set.new
120
109
  class << self
121
110
  attr_reader :keys
122
- end
123
111
 
124
- # Defines a new compliance key and assigns an initial value.
125
- def self.define key, value
126
- instance_variable_set %(@#{key}), value
127
- class << self; self; end.send :attr_accessor, key
128
- @keys << key
129
- nil
112
+ # Defines a new compliance key and assigns an initial value.
113
+ def define key, value
114
+ instance_variable_set %(@#{key}), value
115
+ singleton_class.send :attr_accessor, key
116
+ @keys << key
117
+ nil
118
+ end
130
119
  end
131
120
 
132
121
  # AsciiDoc terminates paragraphs adjacent to
@@ -147,17 +136,19 @@ module Asciidoctor
147
136
  # Compliance value: true
148
137
  define :underline_style_section_titles, true
149
138
 
150
- # Asciidoctor will unwrap the content in a preamble
151
- # if the document has a title and no sections.
139
+ # Asciidoctor will unwrap the content in a preamble if the document has a
140
+ # title and no sections, then discard the empty preamble.
152
141
  # Compliance value: false
153
142
  define :unwrap_standalone_preamble, true
154
143
 
155
144
  # AsciiDoc drops lines that contain references to missing attributes.
156
- # This behavior is not intuitive to most writers
145
+ # This behavior is not intuitive to most writers.
146
+ # Asciidoctor allows this behavior to be configured.
147
+ # Possible options are 'skip', 'drop', 'drop-line', and 'warn'.
157
148
  # Compliance value: 'drop-line'
158
149
  define :attribute_missing, 'skip'
159
150
 
160
- # AsciiDoc drops lines that contain an attribute unassignemnt.
151
+ # AsciiDoc drops lines that contain an attribute unassignment.
161
152
  # This behavior may need to be tuned depending on the circumstances.
162
153
  # Compliance value: 'drop-line'
163
154
  define :attribute_undefined, 'drop-line'
@@ -184,51 +175,47 @@ module Asciidoctor
184
175
  define :markdown_syntax, true
185
176
  end
186
177
 
187
- # The absolute root path of the Asciidoctor RubyGem
188
- ROOT_PATH = ::File.dirname ::File.dirname ::File.expand_path __FILE__
178
+ # The absolute root directory of the Asciidoctor RubyGem
179
+ ROOT_DIR = ::File.dirname ::File.absolute_path __dir__ unless defined? ROOT_DIR
189
180
 
190
- # The absolute lib path of the Asciidoctor RubyGem
191
- #LIB_PATH = ::File.join ROOT_PATH, 'lib'
181
+ # The absolute lib directory of the Asciidoctor RubyGem
182
+ LIB_DIR = ::File.join ROOT_DIR, 'lib'
192
183
 
193
- # The absolute data path of the Asciidoctor RubyGem
194
- DATA_PATH = ::File.join ROOT_PATH, 'data'
184
+ # The absolute data directory of the Asciidoctor RubyGem
185
+ DATA_DIR = ::File.join ROOT_DIR, 'data'
195
186
 
196
187
  # The user's home directory, as best we can determine it
197
- # NOTE not using infix rescue for performance reasons, see: https://github.com/jruby/jruby/issues/1816
198
- begin
199
- USER_HOME = ::Dir.home
200
- rescue
201
- USER_HOME = ::ENV['HOME'] || ::Dir.pwd
202
- end
188
+ # IMPORTANT this rescue is required for running Asciidoctor on GitHub.com
189
+ USER_HOME = ::Dir.home rescue (::ENV['HOME'] || ::Dir.pwd)
190
+
191
+ # The newline character used for output; stored in constant table as an optimization
192
+ LF = ?\n
193
+
194
+ # The null character to use for splitting attribute values
195
+ NULL = ?\0
196
+
197
+ # String for matching tab character
198
+ TAB = ?\t
203
199
 
204
- # Flag to indicate whether encoding can be coerced to UTF-8
205
- # _All_ input data must be force encoded to UTF-8 if Encoding.default_external is *not* UTF-8
206
- # Addresses failures performing string operations that are reported as "invalid byte sequence in US-ASCII"
207
- # Ruby 1.8 doesn't seem to experience this problem (perhaps because it isn't validating the encodings)
208
- COERCE_ENCODING = !::RUBY_ENGINE_OPAL && ::RUBY_MIN_VERSION_1_9
200
+ # Maximum integer value for "boundless" operations; equal to MAX_SAFE_INTEGER in JavaScript
201
+ MAX_INT = 9007199254740991
209
202
 
210
- # Flag to indicate whether encoding of external strings needs to be forced to UTF-8
211
- FORCE_ENCODING = COERCE_ENCODING && ::Encoding.default_external != ::Encoding::UTF_8
203
+ # Alias UTF_8 encoding for convenience / speed
204
+ UTF_8 = ::Encoding::UTF_8
212
205
 
213
206
  # Byte arrays for UTF-* Byte Order Marks
214
207
  BOM_BYTES_UTF_8 = [0xef, 0xbb, 0xbf]
215
208
  BOM_BYTES_UTF_16LE = [0xff, 0xfe]
216
209
  BOM_BYTES_UTF_16BE = [0xfe, 0xff]
217
210
 
218
- # Flag to indicate that line length should be calculated using a unicode mode hint
219
- FORCE_UNICODE_LINE_LENGTH = !::RUBY_MIN_VERSION_1_9
220
-
221
- # The endline character used for output; stored in constant table as an optimization
222
- LF = EOL = "\n"
211
+ # The mode to use when opening a file for reading
212
+ FILE_READ_MODE = RUBY_ENGINE_OPAL ? 'r' : 'rb:utf-8:utf-8'
223
213
 
224
- # The null character to use for splitting attribute values
225
- NULL = "\0"
226
-
227
- # String for matching tab character
228
- TAB = "\t"
214
+ # The mode to use when opening a URI for reading
215
+ URI_READ_MODE = FILE_READ_MODE
229
216
 
230
- # Maximum integer value for "boundless" operations; equal to MAX_SAFE_INTEGER in JavaScript
231
- MAX_INT = 9007199254740991
217
+ # The mode to use when opening a file for writing
218
+ FILE_WRITE_MODE = RUBY_ENGINE_OPAL ? 'w' : 'w:utf-8'
232
219
 
233
220
  # The default document type
234
221
  # Can influence markup generated by the converters
@@ -243,7 +230,7 @@ module Asciidoctor
243
230
 
244
231
  # Pointers to the preferred version for a given backend.
245
232
  BACKEND_ALIASES = {
246
- 'html' => 'html5',
233
+ 'html' => 'html5',
247
234
  'docbook' => 'docbook5'
248
235
  }
249
236
 
@@ -262,7 +249,8 @@ module Asciidoctor
262
249
  'asciidoc' => '.adoc'
263
250
  }
264
251
 
265
- # Set of file extensions recognized as AsciiDoc documents (stored as a truth hash)
252
+ # A map of file extensions that are recognized as AsciiDoc documents
253
+ # TODO .txt should be deprecated
266
254
  ASCIIDOC_EXTENSIONS = {
267
255
  '.adoc' => true,
268
256
  '.asciidoc' => true,
@@ -282,40 +270,43 @@ module Asciidoctor
282
270
 
283
271
  ADMONITION_STYLES = ['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION'].to_set
284
272
 
285
- ADMONITION_STYLE_HEADS = ['N', 'T', 'I', 'W', 'C'].to_set
273
+ ADMONITION_STYLE_HEADS = ::Set.new.tap {|accum| ADMONITION_STYLES.each {|s| accum << s.chr } }
286
274
 
287
275
  PARAGRAPH_STYLES = ['comment', 'example', 'literal', 'listing', 'normal', 'open', 'pass', 'quote', 'sidebar', 'source', 'verse', 'abstract', 'partintro'].to_set
288
276
 
289
277
  VERBATIM_STYLES = ['literal', 'listing', 'source', 'verse'].to_set
290
278
 
291
279
  DELIMITED_BLOCKS = {
292
- '--' => [:open, ['comment', 'example', 'literal', 'listing', 'pass', 'quote', 'sidebar', 'source', 'verse', 'admonition', 'abstract', 'partintro'].to_set],
280
+ '--' => [:open, ['comment', 'example', 'literal', 'listing', 'pass', 'quote', 'sidebar', 'source', 'verse', 'admonition', 'abstract', 'partintro'].to_set],
293
281
  '----' => [:listing, ['literal', 'source'].to_set],
294
282
  '....' => [:literal, ['listing', 'source'].to_set],
295
283
  '====' => [:example, ['admonition'].to_set],
296
284
  '****' => [:sidebar, ::Set.new],
297
285
  '____' => [:quote, ['verse'].to_set],
298
- '""' => [:quote, ['verse'].to_set],
299
286
  '++++' => [:pass, ['stem', 'latexmath', 'asciimath'].to_set],
300
287
  '|===' => [:table, ::Set.new],
301
288
  ',===' => [:table, ::Set.new],
302
289
  ':===' => [:table, ::Set.new],
303
290
  '!===' => [:table, ::Set.new],
304
291
  '////' => [:comment, ::Set.new],
305
- '```' => [:fenced_code, ::Set.new]
292
+ '```' => [:fenced_code, ::Set.new]
306
293
  }
307
294
 
308
- DELIMITED_BLOCK_HEADS = DELIMITED_BLOCKS.keys.map {|key| key.slice 0, 2 }.to_set
295
+ DELIMITED_BLOCK_HEADS = {}.tap {|accum| DELIMITED_BLOCKS.each_key {|k| accum[k.slice 0, 2] = true } }
296
+ DELIMITED_BLOCK_TAILS = {}.tap {|accum| DELIMITED_BLOCKS.each_key {|k| accum[k] = k[k.length - 1] if k.length == 4 } }
297
+
298
+ # NOTE the 'figure' key as a string is historical and used by image blocks
299
+ CAPTION_ATTRIBUTE_NAMES = { example: 'example-caption', 'figure' => 'figure-caption', listing: 'listing-caption', table: 'table-caption' }
309
300
 
310
301
  LAYOUT_BREAK_CHARS = {
311
302
  '\'' => :thematic_break,
312
- '<' => :page_break
303
+ '<' => :page_break
313
304
  }
314
305
 
315
306
  MARKDOWN_THEMATIC_BREAK_CHARS = {
316
- '-' => :thematic_break,
317
- '*' => :thematic_break,
318
- '_' => :thematic_break
307
+ '-' => :thematic_break,
308
+ '*' => :thematic_break,
309
+ '_' => :thematic_break
319
310
  }
320
311
 
321
312
  HYBRID_LAYOUT_BREAK_CHARS = LAYOUT_BREAK_CHARS.merge MARKDOWN_THEMATIC_BREAK_CHARS
@@ -328,8 +319,8 @@ module Asciidoctor
328
319
  ORDERED_LIST_STYLES = [:arabic, :loweralpha, :lowerroman, :upperalpha, :upperroman] #, :lowergreek]
329
320
 
330
321
  ORDERED_LIST_KEYWORDS = {
331
- #'arabic' => '1',
332
- #'decimal' => '1',
322
+ #'arabic' => '1',
323
+ #'decimal' => '1',
333
324
  'loweralpha' => 'a',
334
325
  'lowerroman' => 'i',
335
326
  #'lowergreek' => 'a',
@@ -341,23 +332,21 @@ module Asciidoctor
341
332
 
342
333
  LIST_CONTINUATION = '+'
343
334
 
344
- # NOTE AsciiDoc Python allows + to be preceded by TAB; Asciidoctor does not
335
+ # NOTE AsciiDoc.py allows + to be preceded by TAB; Asciidoctor does not
345
336
  HARD_LINE_BREAK = ' +'
346
337
 
347
338
  LINE_CONTINUATION = ' \\'
348
339
 
349
340
  LINE_CONTINUATION_LEGACY = ' +'
350
341
 
351
- MATHJAX_VERSION = '2.7.4'
352
-
353
342
  BLOCK_MATH_DELIMITERS = {
354
- :asciimath => ['\$', '\$'],
355
- :latexmath => ['\[', '\]'],
343
+ asciimath: ['\$', '\$'],
344
+ latexmath: ['\[', '\]'],
356
345
  }
357
346
 
358
347
  INLINE_MATH_DELIMITERS = {
359
- :asciimath => ['\$', '\$'],
360
- :latexmath => ['\(', '\)'],
348
+ asciimath: ['\$', '\$'],
349
+ latexmath: ['\(', '\)'],
361
350
  }
362
351
 
363
352
  (STEM_TYPE_ALIASES = {
@@ -368,878 +357,136 @@ module Asciidoctor
368
357
 
369
358
  FONT_AWESOME_VERSION = '4.7.0'
370
359
 
371
- # attributes which be changed within the content of the document (but not
372
- # header) because it has semantic meaning; ex. sectnums
373
- FLEXIBLE_ATTRIBUTES = ['sectnums']
374
-
375
- # A collection of regular expressions used by the parser.
376
- #
377
- # NOTE The following pattern, which appears frequently, captures the
378
- # contents between square brackets, ignoring escaped closing brackets
379
- # (closing brackets prefixed with a backslash '\' character)
380
- #
381
- # Pattern: \[(|#{CC_ALL}*?[^\\])\]
382
- # Matches: [enclosed text] and [enclosed [text\]], not [enclosed text \\] or [\\] (as these require a trailing space)
383
- #
384
- # NOTE \w only matches ASCII word characters, whereas [[:word:]] or \p{Word} matches any character in the Unicode word category.
385
- #(pseudo)module Rx
386
-
387
- ## Regular expression character classes (to ensure regexp compatibility between Ruby and JavaScript)
388
- ## CC stands for "character class", CG stands for "character class group"
389
-
390
- if RUBY_ENGINE == 'opal'
391
- CC_ANY = '[^\n]' unless defined? CC_ANY
392
- else
393
- # CC_ALL is any character, including newlines (must be accompanied by multiline regexp flag)
394
- CC_ALL = '.'
395
- # CC_ANY is any character except newlines
396
- CC_ANY = '.'
397
- CC_EOL = '$'
398
- # character classes for the Regexp engine in Ruby >= 2 (Ruby 1.9 supports \p{} but has problems w/ encoding)
399
- if ::RUBY_MIN_VERSION_2
400
- CC_ALPHA = CG_ALPHA = '\p{Alpha}'
401
- CC_ALNUM = CG_ALNUM = '\p{Alnum}'
402
- CG_BLANK = '\p{Blank}'
403
- CC_WORD = CG_WORD = '\p{Word}'
404
- # character classes for the Regexp engine in Ruby < 2
405
- else
406
- CC_ALPHA = '[:alpha:]'
407
- CG_ALPHA = '[[:alpha:]]'
408
- CC_ALNUM = '[:alnum:]'
409
- CG_ALNUM = '[[:alnum:]]'
410
- if ::RUBY_MIN_VERSION_1_9
411
- CG_BLANK = '[[:blank:]]'
412
- CC_WORD = '[:word:]'
413
- CG_WORD = '[[:word:]]'
414
- else
415
- # NOTE Ruby 1.8 cannot match word characters beyond the ASCII range; if you need this feature, upgrade!
416
- CG_BLANK = '[ \t]'
417
- CC_WORD = '[:alnum:]_'
418
- CG_WORD = '[[:alnum:]_]'
419
- end
420
- end
421
- end
422
-
423
- ## Document header
424
-
425
- # Matches the author info line immediately following the document title.
426
- #
427
- # Examples
428
- #
429
- # Doc Writer <doc@example.com>
430
- # Mary_Sue Brontë
431
- #
432
- AuthorInfoLineRx = /^(#{CG_WORD}[#{CC_WORD}\-'.]*)(?: +(#{CG_WORD}[#{CC_WORD}\-'.]*))?(?: +(#{CG_WORD}[#{CC_WORD}\-'.]*))?(?: +<([^>]+)>)?$/
433
-
434
- # Matches the revision info line, which appears immediately following
435
- # the author info line beneath the document title.
436
- #
437
- # Examples
438
- #
439
- # v1.0
440
- # 2013-01-01
441
- # v1.0, 2013-01-01: Ring in the new year release
442
- # 1.0, Jan 01, 2013
443
- #
444
- RevisionInfoLineRx = /^(?:[^\d{]*(#{CC_ANY}*?),)? *(?!:)(#{CC_ANY}*?)(?: *(?!^),?: *(#{CC_ANY}*))?$/
445
-
446
- # Matches the title and volnum in the manpage doctype.
447
- #
448
- # Examples
449
- #
450
- # = asciidoctor(1)
451
- # = asciidoctor ( 1 )
452
- #
453
- ManpageTitleVolnumRx = /^(#{CC_ANY}+?) *\( *(#{CC_ANY}+?) *\)$/
454
-
455
- # Matches the name and purpose in the manpage doctype.
456
- #
457
- # Examples
458
- #
459
- # asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
460
- #
461
- ManpageNamePurposeRx = /^(#{CC_ANY}+?) +- +(#{CC_ANY}+)$/
462
-
463
- ## Preprocessor directives
464
-
465
- # Matches a conditional preprocessor directive (e.g., ifdef, ifndef, ifeval and endif).
466
- #
467
- # Examples
468
- #
469
- # ifdef::basebackend-html[]
470
- # ifndef::theme[]
471
- # ifeval::["{asciidoctor-version}" >= "0.1.0"]
472
- # ifdef::asciidoctor[Asciidoctor!]
473
- # endif::theme[]
474
- # endif::basebackend-html[]
475
- # endif::[]
476
- #
477
- ConditionalDirectiveRx = /^(\\)?(ifdef|ifndef|ifeval|endif)::(\S*?(?:([,+])\S*?)?)\[(#{CC_ANY}+)?\]$/
478
-
479
- # Matches a restricted (read as safe) eval expression.
480
- #
481
- # Examples
482
- #
483
- # "{asciidoctor-version}" >= "0.1.0"
484
- #
485
- EvalExpressionRx = /^(#{CC_ANY}+?) *([=!><]=|[><]) *(#{CC_ANY}+)$/
486
-
487
- # Matches an include preprocessor directive.
488
- #
489
- # Examples
490
- #
491
- # include::chapter1.ad[]
492
- # include::example.txt[lines=1;2;5..10]
493
- #
494
- IncludeDirectiveRx = /^(\\)?include::([^\[][^\[]*)\[(#{CC_ANY}+)?\]$/
495
-
496
- # Matches a trailing tag directive in an include file.
497
- #
498
- # Examples
499
- #
500
- # // tag::try-catch[]
501
- # try {
502
- # someMethod();
503
- # catch (Exception e) {
504
- # log(e);
505
- # }
506
- # // end::try-catch[]
507
- # NOTE m flag is required for Asciidoctor.js
508
- TagDirectiveRx = /\b(?:tag|(e)nd)::(\S+?)\[\](?=$|[ \r])/m
509
-
510
- ## Attribute entries and references
511
-
512
- # Matches a document attribute entry.
513
- #
514
- # Examples
515
- #
516
- # :foo: bar
517
- # :First Name: Dan
518
- # :sectnums!:
519
- # :!toc:
520
- # :long-entry: Attribute value lines ending in ' \' \
521
- # are joined together as a single value, \
522
- # collapsing the line breaks and indentation to \
523
- # a single space.
524
- #
525
- AttributeEntryRx = /^:(!?#{CG_WORD}[^:]*):(?:[ \t]+(#{CC_ANY}*))?$/
526
-
527
- # Matches invalid characters in an attribute name.
528
- InvalidAttributeNameCharsRx = /[^-#{CC_WORD}]/
529
-
530
- # Matches a pass inline macro that surrounds the value of an attribute
531
- # entry once it has been parsed.
532
- #
533
- # Examples
534
- #
535
- # pass:[text]
536
- # pass:a[{a} {b} {c}]
537
- #
538
- if RUBY_ENGINE == 'opal'
539
- # NOTE In JavaScript, ^ and $ match the boundaries of the string when the m flag is not set
540
- AttributeEntryPassMacroRx = /^pass:([a-z]+(?:,[a-z]+)*)?\[([\S\s]*)\]$/
541
- else
542
- AttributeEntryPassMacroRx = /\Apass:([a-z]+(?:,[a-z]+)*)?\[(.*)\]\Z/m
543
- end
544
-
545
- # Matches an inline attribute reference.
546
- #
547
- # Examples
548
- #
549
- # {foobar} or {app_name} or {product-version}
550
- # {counter:sequence-name:1}
551
- # {set:foo:bar}
552
- # {set:name!}
553
- #
554
- AttributeReferenceRx = /(\\)?\{(#{CG_WORD}[-#{CC_WORD}]*|(set|counter2?):#{CC_ANY}+?)(\\)?\}/
555
-
556
- ## Paragraphs and delimited blocks
557
-
558
- # Matches an anchor (i.e., id + optional reference text) on a line above a block.
559
- #
560
- # Examples
561
- #
562
- # [[idname]]
563
- # [[idname,Reference Text]]
564
- #
565
- BlockAnchorRx = /^\[\[(?:|([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)(?:, *(#{CC_ANY}+))?)\]\]$/
566
-
567
- # Matches an attribute list above a block element.
568
- #
569
- # Examples
570
- #
571
- # # strictly positional
572
- # [quote, Adam Smith, Wealth of Nations]
573
- #
574
- # # name/value pairs
575
- # [NOTE, caption="Good to know"]
576
- #
577
- # # as attribute reference
578
- # [{lead}]
579
- #
580
- BlockAttributeListRx = /^\[(|[#{CC_WORD}.#%{,"']#{CC_ANY}*)\]$/
581
-
582
- # A combined pattern that matches either a block anchor or a block attribute list.
583
- #
584
- # TODO this one gets hit a lot, should be optimized as much as possible
585
- BlockAttributeLineRx = /^\[(?:|[#{CC_WORD}.#%{,"']#{CC_ANY}*|\[(?:|[#{CC_ALPHA}_:][#{CC_WORD}:.-]*(?:, *#{CC_ANY}+)?)\])\]$/
586
-
587
- # Matches a title above a block.
588
- #
589
- # Examples
590
- #
591
- # .Title goes here
592
- #
593
- BlockTitleRx = /^\.(\.?[^ \t.]#{CC_ANY}*)$/
594
-
595
- # Matches an admonition label at the start of a paragraph.
596
- #
597
- # Examples
598
- #
599
- # NOTE: Just a little note.
600
- # TIP: Don't forget!
601
- #
602
- AdmonitionParagraphRx = /^(#{ADMONITION_STYLES.to_a.join '|'}):[ \t]+/
603
-
604
- # Matches a literal paragraph, which is a line of text preceded by at least one space.
605
- #
606
- # Examples
607
- #
608
- # <SPACE>Foo
609
- # <TAB>Foo
610
- LiteralParagraphRx = /^([ \t]+#{CC_ANY}*)$/
611
-
612
- # Matches a comment block.
613
- #
614
- # Examples
615
- #
616
- # ////
617
- # This is a block comment.
618
- # It can span one or more lines.
619
- # ////
620
- #CommentBlockRx = %r(^/{4,}$)
621
-
622
- # Matches a comment line.
623
- #
624
- # Examples
625
- #
626
- # // note to author
627
- #
628
- #CommentLineRx = %r(^//(?=[^/]|$))
629
-
630
- ## Section titles
631
-
632
- # Matches an Atx (single-line) section title.
633
- #
634
- # Examples
635
- #
636
- # == Foo
637
- # // ^ a level 1 (h2) section title
638
- #
639
- # == Foo ==
640
- # // ^ also a level 1 (h2) section title
641
- #
642
- AtxSectionTitleRx = /^(=={0,5})[ \t]+(#{CC_ANY}+?)(?:[ \t]+\1)?$/
643
-
644
- # Matches an extended Atx section title that includes support for the Markdown variant.
645
- ExtAtxSectionTitleRx = /^(=={0,5}|#\#{0,5})[ \t]+(#{CC_ANY}+?)(?:[ \t]+\1)?$/
646
-
647
- # Matches the title only (first line) of an Setext (two-line) section title.
648
- # The title cannot begin with a dot and must have at least one alphanumeric character.
649
- SetextSectionTitleRx = /^((?!\.)#{CC_ANY}*?#{CG_WORD}#{CC_ANY}*)$/
650
-
651
- # Matches an anchor (i.e., id + optional reference text) inside a section title.
652
- #
653
- # Examples
654
- #
655
- # Section Title [[idname]]
656
- # Section Title [[idname,Reference Text]]
657
- #
658
- InlineSectionAnchorRx = / (\\)?\[\[([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)(?:, *(#{CC_ANY}+))?\]\]$/
659
-
660
- # Matches invalid ID characters in a section title.
661
- #
662
- # NOTE uppercase chars not included since expression is only run on a lowercase string
663
- InvalidSectionIdCharsRx = /<[^>]+>|&(?:[a-z][a-z]+\d{0,2}|#\d\d\d{0,4}|#x[\da-f][\da-f][\da-f]{0,3});|[^ #{CC_WORD}\-.]+?/
664
-
665
- ## Lists
666
-
667
- # Detects the start of any list item.
668
- #
669
- # NOTE we only have to check as far as the blank character because we know it means non-whitespace follows.
670
- # IMPORTANT if this regexp does not agree with the regexp for each list type, the parser will hang.
671
- AnyListRx = %r(^(?:[ \t]*(?:-|\*\**|\.\.*|\u2022|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!//[^/])#{CC_ANY}*?(?::::{0,2}|;;)(?:$|[ \t])|<?\d+>[ \t]))
672
-
673
- # Matches an unordered list item (one level for hyphens, up to 5 levels for asterisks).
674
- #
675
- # Examples
676
- #
677
- # * Foo
678
- # - Foo
679
- #
680
- # NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
681
- UnorderedListRx = /^[ \t]*(-|\*\**|\u2022)[ \t]+(#{CC_ANY}*)$/
682
-
683
- # Matches an ordered list item (explicit numbering or up to 5 consecutive dots).
684
- #
685
- # Examples
686
- #
687
- # . Foo
688
- # .. Foo
689
- # 1. Foo (arabic, default)
690
- # a. Foo (loweralpha)
691
- # A. Foo (upperalpha)
692
- # i. Foo (lowerroman)
693
- # I. Foo (upperroman)
694
- #
695
- # NOTE leading space match is not always necessary, but is used for list reader
696
- # NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
697
- OrderedListRx = /^[ \t]*(\.\.*|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]+(#{CC_ANY}*)$/
698
-
699
- # Matches the ordinals for each type of ordered list.
700
- OrderedListMarkerRxMap = {
701
- :arabic => /\d+\./,
702
- :loweralpha => /[a-z]\./,
703
- :lowerroman => /[ivx]+\)/,
704
- :upperalpha => /[A-Z]\./,
705
- :upperroman => /[IVX]+\)/
706
- #:lowergreek => /[a-z]\]/
707
- }
708
-
709
- # Matches a description list entry.
710
- #
711
- # Examples
712
- #
713
- # foo::
714
- # bar:::
715
- # baz::::
716
- # blah;;
717
- #
718
- # # the term may be followed by a description on the same line...
719
- #
720
- # foo:: The metasyntactic variable that commonly accompanies 'bar' (see also, <<bar>>).
721
- #
722
- # # ...or on a separate line, which may optionally be indented
723
- #
724
- # foo::
725
- # The metasyntactic variable that commonly accompanies 'bar' (see also, <<bar>>).
726
- #
727
- # # attribute references may be used in both the term and the description
728
- #
729
- # {foo-term}:: {foo-desc}
730
- #
731
- # NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
732
- # NOTE must skip line comment when looking for next list item inside list
733
- DescriptionListRx = %r(^(?!//[^/])[ \t]*(#{CC_ANY}*?)(:::{0,2}|;;)(?:$|[ \t]+(#{CC_ANY}*)$))
734
-
735
- # Matches a sibling description list item (which does not include the type in the key).
736
- # NOTE must skip line comment when looking for sibling list item
737
- DescriptionListSiblingRx = {
738
- '::' => %r(^(?!//[^/])[ \t]*(#{CC_ANY}*[^:]|)(::)(?:$|[ \t]+(#{CC_ANY}*)$)),
739
- ':::' => %r(^(?!//[^/])[ \t]*(#{CC_ANY}*[^:]|)(:::)(?:$|[ \t]+(#{CC_ANY}*)$)),
740
- '::::' => %r(^(?!//[^/])[ \t]*(#{CC_ANY}*[^:]|)(::::)(?:$|[ \t]+(#{CC_ANY}*)$)),
741
- ';;' => %r(^(?!//[^/])[ \t]*(#{CC_ANY}*?)(;;)(?:$|[ \t]+(#{CC_ANY}*)$))
742
- }
743
-
744
- # Matches a callout list item.
745
- #
746
- # Examples
747
- #
748
- # <1> Explanation
749
- #
750
- # or
751
- #
752
- # <.> Explanation with automatic number
753
- #
754
- # NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
755
- CalloutListRx = /^<(\d+|\.)>[ \t]+(#{CC_ANY}*)$/
756
-
757
- # Matches a callout reference inside literal text.
758
- #
759
- # Examples
760
- # <1> (optionally prefixed by //, #, -- or ;; line comment chars)
761
- # <1> <2> (multiple callouts on one line)
762
- # <!--1--> (for XML-based languages)
763
- # <.> (auto-numbered)
764
- #
765
- # NOTE extract regexps are applied line-by-line, so we can use $ as end-of-line char
766
- CalloutExtractRx = %r(((?://|#|--|;;) ?)?(\\)?<!?(|--)(\d+|\.)\3>(?=(?: ?\\?<!?\3(?:\d+|\.)\3>)*$))
767
- CalloutExtractRxt = '(\\\\)?<()(\\d+|\\.)>(?=(?: ?\\\\?<(?:\\d+|\\.)>)*$)'
768
- CalloutExtractRxMap = ::Hash.new {|h, k| h[k] = /(#{::Regexp.escape k} ?)?#{CalloutExtractRxt}/ }
769
- # NOTE special characters have not been replaced when scanning
770
- CalloutScanRx = /\\?<!?(|--)(\d+|\.)\1>(?=(?: ?\\?<!?\1(?:\d+|\.)\1>)*#{CC_EOL})/
771
- # NOTE special characters have already been replaced when converting to an SGML format
772
- CalloutSourceRx = %r(((?://|#|--|;;) ?)?(\\)?&lt;!?(|--)(\d+|\.)\3&gt;(?=(?: ?\\?&lt;!?\3(?:\d+|\.)\3&gt;)*#{CC_EOL}))
773
- CalloutSourceRxt = "(\\\\)?&lt;()(\\d+|\\.)&gt;(?=(?: ?\\\\?&lt;(?:\\d+|\\.)&gt;)*#{CC_EOL})"
774
- CalloutSourceRxMap = ::Hash.new {|h, k| h[k] = /(#{::Regexp.escape k} ?)?#{CalloutSourceRxt}/ }
775
-
776
- # A Hash of regexps for lists used for dynamic access.
777
- ListRxMap = {
778
- :ulist => UnorderedListRx,
779
- :olist => OrderedListRx,
780
- :dlist => DescriptionListRx,
781
- :colist => CalloutListRx
782
- }
783
-
784
- ## Tables
785
-
786
- # Parses the column spec (i.e., colspec) for a table.
787
- #
788
- # Examples
789
- #
790
- # 1*h,2*,^3e
791
- #
792
- ColumnSpecRx = /^(?:(\d+)\*)?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?(\d+%?|~)?([a-z])?$/
793
-
794
- # Parses the start and end of a cell spec (i.e., cellspec) for a table.
795
- #
796
- # Examples
797
- #
798
- # 2.3+<.>m
799
- #
800
- # FIXME use step-wise scan (or treetop) rather than this mega-regexp
801
- CellSpecStartRx = /^[ \t]*(?:(\d+(?:\.\d*)?|(?:\d*\.)?\d+)([*+]))?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?([a-z])?$/
802
- CellSpecEndRx = /[ \t]+(?:(\d+(?:\.\d*)?|(?:\d*\.)?\d+)([*+]))?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?([a-z])?$/
803
-
804
- # Block macros
805
-
806
- # Matches the custom block macro pattern.
807
- #
808
- # Examples
809
- #
810
- # gist::123456[]
811
- #
812
- #--
813
- # NOTE we've relaxed the match for target to accomodate the short format (e.g., name::[attrlist])
814
- CustomBlockMacroRx = /^(#{CG_WORD}[-#{CC_WORD}]*)::(|\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
815
-
816
- # Matches an image, video or audio block macro.
817
- #
818
- # Examples
819
- #
820
- # image::filename.png[Caption]
821
- # video::http://youtube.com/12345[Cats vs Dogs]
822
- #
823
- BlockMediaMacroRx = /^(image|video|audio)::(\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
824
-
825
- # Matches the TOC block macro.
826
- #
827
- # Examples
828
- #
829
- # toc::[]
830
- # toc::[levels=2]
831
- #
832
- BlockTocMacroRx = /^toc::\[(#{CC_ANY}+)?\]$/
833
-
834
- ## Inline macros
835
-
836
- # Matches an anchor (i.e., id + optional reference text) in the flow of text.
837
- #
838
- # Examples
839
- #
840
- # [[idname]]
841
- # [[idname,Reference Text]]
842
- # anchor:idname[]
843
- # anchor:idname[Reference Text]
844
- #
845
- InlineAnchorRx = /(\\)?(?:\[\[([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)(?:, *(#{CC_ANY}+?))?\]\]|anchor:([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)\[(?:\]|(#{CC_ANY}*?[^\\])\]))/
846
-
847
- # Scans for a non-escaped anchor (i.e., id + optional reference text) in the flow of text.
848
- InlineAnchorScanRx = /(?:^|[^\\\[])\[\[([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)(?:, *(#{CC_ANY}+?))?\]\]|(?:^|[^\\])anchor:([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)\[(?:\]|(#{CC_ANY}*?[^\\])\])/
849
-
850
- # Scans for a leading, non-escaped anchor (i.e., id + optional reference text).
851
- LeadingInlineAnchorRx = /^\[\[([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)(?:, *(#{CC_ANY}+?))?\]\]/
852
-
853
- # Matches a bibliography anchor at the start of the list item text (in a bibliography list).
854
- #
855
- # Examples
856
- #
857
- # [[[Fowler_1997]]] Fowler M. ...
858
- #
859
- InlineBiblioAnchorRx = /^\[\[\[([#{CC_ALPHA}_:][#{CC_WORD}:.-]*)(?:, *(#{CC_ANY}+?))?\]\]\]/
860
-
861
- # Matches an inline e-mail address.
862
- #
863
- # doc.writer@example.com
864
- #
865
- InlineEmailRx = %r(([\\>:/])?#{CG_WORD}[#{CC_WORD}.%+-]*@#{CG_ALNUM}[#{CC_ALNUM}.-]*\.#{CG_ALPHA}{2,4}\b)
866
-
867
- # Matches an inline footnote macro, which is allowed to span multiple lines.
868
- #
869
- # Examples
870
- # footnote:[text] (not referenceable)
871
- # footnote:id[text] (referenceable)
872
- # footnote:id[] (reference)
873
- # footnoteref:[id,text] (legacy)
874
- # footnoteref:[id] (legacy)
875
- #
876
- InlineFootnoteMacroRx = /\\?footnote(?:(ref):|:([\w-]+)?)\[(?:|(#{CC_ALL}*?[^\\]))\]/m
877
-
878
- # Matches an image or icon inline macro.
879
- #
880
- # Examples
881
- #
882
- # image:filename.png[Alt Text]
883
- # image:http://example.com/images/filename.png[Alt Text]
884
- # image:filename.png[More [Alt\] Text] (alt text becomes "More [Alt] Text")
885
- # icon:github[large]
886
- #
887
- # NOTE be as non-greedy as possible by not allowing endline or left square bracket in target
888
- InlineImageMacroRx = /\\?i(?:mage|con):([^:\s\[](?:[^\n\[]*[^\s\[])?)\[(|#{CC_ALL}*?[^\\])\]/m
889
-
890
- # Matches an indexterm inline macro, which may span multiple lines.
891
- #
892
- # Examples
893
- #
894
- # indexterm:[Tigers,Big cats]
895
- # (((Tigers,Big cats)))
896
- # indexterm2:[Tigers]
897
- # ((Tigers))
898
- #
899
- InlineIndextermMacroRx = /\\?(?:(indexterm2?):\[(#{CC_ALL}*?[^\\])\]|\(\((#{CC_ALL}+?)\)\)(?!\)))/m
900
-
901
- # Matches either the kbd or btn inline macro.
902
- #
903
- # Examples
904
- #
905
- # kbd:[F3]
906
- # kbd:[Ctrl+Shift+T]
907
- # kbd:[Ctrl+\]]
908
- # kbd:[Ctrl,T]
909
- # btn:[Save]
910
- #
911
- InlineKbdBtnMacroRx = /(\\)?(kbd|btn):\[(#{CC_ALL}*?[^\\])\]/m
912
-
913
- # Matches an implicit link and some of the link inline macro.
914
- #
915
- # Examples
916
- #
917
- # https://github.com
918
- # https://github.com[GitHub]
919
- # <https://github.com>
920
- # link:https://github.com[]
921
- #
922
- # FIXME revisit! the main issue is we need different rules for implicit vs explicit
923
- InlineLinkRx = %r((^|link:|#{CG_BLANK}|&lt;|[>\(\)\[\];])(\\?(?:https?|file|ftp|irc)://[^\s\[\]<]*[^\s.,\[\]<])(?:\[(|#{CC_ALL}*?[^\\])\])?)m
924
-
925
- # Match a link or e-mail inline macro.
926
- #
927
- # Examples
928
- #
929
- # link:path[label]
930
- # mailto:doc.writer@example.com[]
931
- #
932
- # NOTE be as non-greedy as possible by not allowing space or left square bracket in target
933
- InlineLinkMacroRx = /\\?(?:link|(mailto)):(|[^:\s\[][^\s\[]*)\[(|#{CC_ALL}*?[^\\])\]/m
934
-
935
- # Matches the name of a macro.
936
- #
937
- MacroNameRx = /^#{CG_WORD}[-#{CC_WORD}]*$/
938
-
939
- # Matches a stem (and alternatives, asciimath and latexmath) inline macro, which may span multiple lines.
940
- #
941
- # Examples
942
- #
943
- # stem:[x != 0]
944
- # asciimath:[x != 0]
945
- # latexmath:[\sqrt{4} = 2]
946
- #
947
- InlineStemMacroRx = /\\?(stem|(?:latex|ascii)math):([a-z]+(?:,[a-z]+)*)?\[(#{CC_ALL}*?[^\\])\]/m
948
-
949
- # Matches a menu inline macro.
950
- #
951
- # Examples
952
- #
953
- # menu:File[Save As...]
954
- # menu:View[Page Style > No Style]
955
- # menu:View[Page Style, No Style]
956
- #
957
- InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(#{CC_ALL}*?[^\\])?\]/m
958
-
959
- # Matches an implicit menu inline macro.
960
- #
961
- # Examples
962
- #
963
- # "File > New..."
964
- #
965
- InlineMenuRx = /\\?"([#{CC_WORD}&][^"]*?[ \n]+&gt;[ \n]+[^"]*)"/
966
-
967
- # Matches an inline passthrough, which may span multiple lines.
968
- #
969
- # Examples
970
- #
971
- # +text+
972
- # `text` (compat)
973
- #
974
- # NOTE we always capture the attributes so we know when to use compatible (i.e., legacy) behavior
975
- InlinePassRx = {
976
- false => ['+', '`', /(^|[^#{CC_WORD};:])(?:\[([^\]]+)\])?(\\?(\+|`)(\S|\S#{CC_ALL}*?\S)\4)(?!#{CG_WORD})/m],
977
- true => ['`', nil, /(^|[^`#{CC_WORD}])(?:\[([^\]]+)\])?(\\?(`)([^`\s]|[^`\s]#{CC_ALL}*?\S)\4)(?![`#{CC_WORD}])/m]
978
- }
979
-
980
- # Matches an inline plus passthrough spanning multiple lines, but only when it occurs directly
981
- # inside constrained monospaced formatting in non-compat mode.
982
- #
983
- # Examples
984
- #
985
- # +text+
986
- #
987
- SinglePlusInlinePassRx = /^(\\)?\+(\S|\S#{CC_ALL}*?\S)\+$/m
988
-
989
- # Matches several variants of the passthrough inline macro, which may span multiple lines.
990
- #
991
- # Examples
992
- #
993
- # +++text+++
994
- # $$text$$
995
- # pass:quotes[text]
996
- #
997
- # NOTE we have to support an empty pass:[] for compatibility with AsciiDoc Python
998
- InlinePassMacroRx = /(?:(?:(\\?)\[([^\]]+)\])?(\\{0,2})(\+\+\+?|\$\$)(#{CC_ALL}*?)\4|(\\?)pass:([a-z]+(?:,[a-z]+)*)?\[(|#{CC_ALL}*?[^\\])\])/m
999
-
1000
- # Matches an xref (i.e., cross-reference) inline macro, which may span multiple lines.
1001
- #
1002
- # Examples
1003
- #
1004
- # <<id,reftext>>
1005
- # xref:id[reftext]
1006
- #
1007
- # NOTE special characters have already been escaped, hence the entity references
1008
- # NOTE { is included in start characters to support target that begins with attribute reference in title content
1009
- InlineXrefMacroRx = %r(\\?(?:&lt;&lt;([#{CC_WORD}#/.:{]#{CC_ALL}*?)&gt;&gt;|xref:([#{CC_WORD}#/.:{]#{CC_ALL}*?)\[(?:\]|(#{CC_ALL}*?[^\\])\])))m
1010
-
1011
- ## Layout
1012
-
1013
- # Matches a trailing + preceded by at least one space character,
1014
- # which forces a hard line break (<br> tag in HTML output).
1015
- #
1016
- # NOTE AsciiDoc Python allows + to be preceded by TAB; Asciidoctor does not
1017
- #
1018
- # Examples
1019
- #
1020
- # Humpty Dumpty sat on a wall, +
1021
- # Humpty Dumpty had a great fall.
1022
- #
1023
- if RUBY_ENGINE == 'opal'
1024
- # NOTE In JavaScript, ^ and $ only match the start and end of line if the multiline flag is present
1025
- HardLineBreakRx = /^(#{CC_ANY}*) \+$/m
1026
- else
1027
- # NOTE In Ruby, ^ and $ always match start and end of line
1028
- HardLineBreakRx = /^(.*) \+$/
1029
- end
1030
-
1031
- # Matches a Markdown horizontal rule.
1032
- #
1033
- # Examples
1034
- #
1035
- # --- or - - -
1036
- # *** or * * *
1037
- # ___ or _ _ _
1038
- #
1039
- MarkdownThematicBreakRx = /^ {0,3}([-*_])( *)\1\2\1$/
1040
-
1041
- # Matches an AsciiDoc or Markdown horizontal rule or AsciiDoc page break.
1042
- #
1043
- # Examples
1044
- #
1045
- # ''' (horizontal rule)
1046
- # <<< (page break)
1047
- # --- or - - - (horizontal rule, Markdown)
1048
- # *** or * * * (horizontal rule, Markdown)
1049
- # ___ or _ _ _ (horizontal rule, Markdown)
1050
- #
1051
- ExtLayoutBreakRx = /^(?:'{3,}|<{3,}|([-*_])( *)\1\2\1)$/
1052
-
1053
- ## General
1054
-
1055
- # Matches consecutive blank lines.
1056
- #
1057
- # Examples
1058
- #
1059
- # one
1060
- #
1061
- # two
1062
- #
1063
- BlankLineRx = /\n{2,}/
1064
-
1065
- # Matches a comma or semi-colon delimiter.
1066
- #
1067
- # Examples
1068
- #
1069
- # one,two
1070
- # three;four
1071
- #
1072
- #DataDelimiterRx = /[,;]/
1073
-
1074
- # Matches whitespace (space, tab, newline) escaped by a backslash.
1075
- #
1076
- # Examples
1077
- #
1078
- # three\ blind\ mice
1079
- #
1080
- EscapedSpaceRx = /\\([ \t\n])/
1081
-
1082
- # Detects if text is a possible candidate for the replacements substitution.
1083
- #
1084
- ReplaceableTextRx = /[&']|--|\.\.\.|\([CRT]M?\)/
1085
-
1086
- # Matches a whitespace delimiter, a sequence of spaces, tabs, and/or newlines.
1087
- # Matches the parsing rules of %w strings in Ruby.
1088
- #
1089
- # Examples
1090
- #
1091
- # one two three four
1092
- # five six
1093
- #
1094
- # TODO change to /(?<!\\)[ \t\n]+/ after dropping support for Ruby 1.8.7
1095
- SpaceDelimiterRx = /([^\\])[ \t\n]+/
1096
-
1097
- # Matches a + or - modifier in a subs list
1098
- #
1099
- SubModifierSniffRx = /[+-]/
1100
-
1101
- # Matches one or more consecutive digits at the end of a line.
1102
- #
1103
- # Examples
1104
- #
1105
- # docbook45
1106
- # html5
1107
- #
1108
- TrailingDigitsRx = /\d+$/
1109
-
1110
- # Matches any character with multibyte support explicitly enabled (length of multibyte char = 1)
1111
- #
1112
- unless RUBY_ENGINE == 'opal'
1113
- UnicodeCharScanRx = /./u if FORCE_UNICODE_LINE_LENGTH
1114
- end
1115
-
1116
- # Detects strings that resemble URIs.
1117
- #
1118
- # Examples
1119
- # http://domain
1120
- # https://domain
1121
- # file:///path
1122
- # data:info
1123
- #
1124
- # not c:/sample.adoc or c:\sample.adoc
1125
- #
1126
- UriSniffRx = %r(^#{CG_ALPHA}[#{CC_ALNUM}.+-]+:/{0,2})
1127
-
1128
- # Detects the end of an implicit URI in the text
1129
- #
1130
- # Examples
1131
- #
1132
- # (http://google.com)
1133
- # &gt;http://google.com&lt;
1134
- # (See http://google.com):
1135
- #
1136
- UriTerminatorRx = /[);:]$/
360
+ HIGHLIGHT_JS_VERSION = '9.18.3'
361
+
362
+ MATHJAX_VERSION = '2.7.9'
363
+
364
+ DEFAULT_ATTRIBUTES = {
365
+ 'appendix-caption' => 'Appendix',
366
+ 'appendix-refsig' => 'Appendix',
367
+ 'caution-caption' => 'Caution',
368
+ 'chapter-refsig' => 'Chapter',
369
+ #'encoding' => 'UTF-8',
370
+ 'example-caption' => 'Example',
371
+ 'figure-caption' => 'Figure',
372
+ 'important-caption' => 'Important',
373
+ 'last-update-label' => 'Last updated',
374
+ #'listing-caption' => 'Listing',
375
+ 'note-caption' => 'Note',
376
+ 'part-refsig' => 'Part',
377
+ #'preface-title' => 'Preface',
378
+ 'prewrap' => '',
379
+ 'sectids' => '',
380
+ 'section-refsig' => 'Section',
381
+ 'table-caption' => 'Table',
382
+ 'tip-caption' => 'Tip',
383
+ 'toc-placement' => 'auto',
384
+ 'toc-title' => 'Table of Contents',
385
+ 'untitled-label' => 'Untitled',
386
+ 'version-label' => 'Version',
387
+ 'warning-caption' => 'Warning',
388
+ }
1137
389
 
1138
- # Detects XML tags
1139
- XmlSanitizeRx = /<[^>]+>/
1140
- #end
390
+ # attributes which be changed throughout the flow of the document (e.g., sectnums)
391
+ FLEXIBLE_ATTRIBUTES = ['sectnums']
1141
392
 
1142
393
  INTRINSIC_ATTRIBUTES = {
1143
- 'startsb' => '[',
1144
- 'endsb' => ']',
1145
- 'vbar' => '|',
1146
- 'caret' => '^',
1147
- 'asterisk' => '*',
1148
- 'tilde' => '~',
1149
- 'plus' => '&#43;',
1150
- 'backslash' => '\\',
1151
- 'backtick' => '`',
1152
- 'blank' => '',
1153
- 'empty' => '',
1154
- 'sp' => ' ',
394
+ 'startsb' => '[',
395
+ 'endsb' => ']',
396
+ 'vbar' => '|',
397
+ 'caret' => '^',
398
+ 'asterisk' => '*',
399
+ 'tilde' => '~',
400
+ 'plus' => '&#43;',
401
+ 'backslash' => '\\',
402
+ 'backtick' => '`',
403
+ 'blank' => '',
404
+ 'empty' => '',
405
+ 'sp' => ' ',
1155
406
  'two-colons' => '::',
1156
407
  'two-semicolons' => ';;',
1157
- 'nbsp' => '&#160;',
1158
- 'deg' => '&#176;',
1159
- 'zwsp' => '&#8203;',
1160
- 'quot' => '&#34;',
1161
- 'apos' => '&#39;',
1162
- 'lsquo' => '&#8216;',
1163
- 'rsquo' => '&#8217;',
1164
- 'ldquo' => '&#8220;',
1165
- 'rdquo' => '&#8221;',
1166
- 'wj' => '&#8288;',
1167
- 'brvbar' => '&#166;',
1168
- 'pp' => '&#43;&#43;',
1169
- 'cpp' => 'C&#43;&#43;',
1170
- 'amp' => '&',
1171
- 'lt' => '<',
1172
- 'gt' => '>'
408
+ 'nbsp' => '&#160;',
409
+ 'deg' => '&#176;',
410
+ 'zwsp' => '&#8203;',
411
+ 'quot' => '&#34;',
412
+ 'apos' => '&#39;',
413
+ 'lsquo' => '&#8216;',
414
+ 'rsquo' => '&#8217;',
415
+ 'ldquo' => '&#8220;',
416
+ 'rdquo' => '&#8221;',
417
+ 'wj' => '&#8288;',
418
+ 'brvbar' => '&#166;',
419
+ 'pp' => '&#43;&#43;',
420
+ 'cpp' => 'C&#43;&#43;',
421
+ 'amp' => '&',
422
+ 'lt' => '<',
423
+ 'gt' => '>'
1173
424
  }
1174
425
 
1175
- # unconstrained quotes:: can appear anywhere
1176
- # constrained quotes:: must be bordered by non-word characters
1177
- # NOTE these substitutions are processed in the order they appear here and
1178
- # the order in which they are replaced is important
1179
- quote_subs = [
1180
- # **strong**
1181
- [:strong, :unconstrained, /\\?(?:\[([^\]]+)\])?\*\*(#{CC_ALL}+?)\*\*/m],
1182
-
1183
- # *strong*
1184
- [:strong, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?\*(\S|\S#{CC_ALL}*?\S)\*(?!#{CG_WORD})/m],
1185
-
1186
- # "`double-quoted`"
1187
- [:double, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?"`(\S|\S#{CC_ALL}*?\S)`"(?!#{CG_WORD})/m],
1188
-
1189
- # '`single-quoted`'
1190
- [:single, :constrained, /(^|[^#{CC_WORD};:`}])(?:\[([^\]]+)\])?'`(\S|\S#{CC_ALL}*?\S)`'(?!#{CG_WORD})/m],
1191
-
1192
- # ``monospaced``
1193
- [:monospaced, :unconstrained, /\\?(?:\[([^\]]+)\])?``(#{CC_ALL}+?)``/m],
1194
-
1195
- # `monospaced`
1196
- [:monospaced, :constrained, /(^|[^#{CC_WORD};:"'`}])(?:\[([^\]]+)\])?`(\S|\S#{CC_ALL}*?\S)`(?![#{CC_WORD}"'`])/m],
1197
-
1198
- # __emphasis__
1199
- [:emphasis, :unconstrained, /\\?(?:\[([^\]]+)\])?__(#{CC_ALL}+?)__/m],
1200
-
1201
- # _emphasis_
1202
- [:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?_(\S|\S#{CC_ALL}*?\S)_(?!#{CG_WORD})/m],
1203
-
1204
- # ##mark## (referred to in AsciiDoc Python as unquoted)
1205
- [:mark, :unconstrained, /\\?(?:\[([^\]]+)\])?##(#{CC_ALL}+?)##/m],
1206
-
1207
- # #mark# (referred to in AsciiDoc Python as unquoted)
1208
- [:mark, :constrained, /(^|[^#{CC_WORD}&;:}])(?:\[([^\]]+)\])?#(\S|\S#{CC_ALL}*?\S)#(?!#{CG_WORD})/m],
1209
-
1210
- # ^superscript^
1211
- [:superscript, :unconstrained, /\\?(?:\[([^\]]+)\])?\^(\S+?)\^/],
1212
-
1213
- # ~subscript~
1214
- [:subscript, :unconstrained, /\\?(?:\[([^\]]+)\])?~(\S+?)~/]
1215
- ]
426
+ # Regular expression character classes (to ensure regexp compatibility between Ruby and JavaScript)
427
+ # CC stands for "character class", CG stands for "character class group"
428
+ unless RUBY_ENGINE == 'opal'
429
+ # CC_ALL is any character, including newlines (must be accompanied by multiline regexp flag)
430
+ CC_ALL = '.'
431
+ # CC_ANY is any character except newlines
432
+ CC_ANY = '.'
433
+ CC_EOL = '$'
434
+ CC_ALPHA = CG_ALPHA = '\p{Alpha}'
435
+ CC_ALNUM = CG_ALNUM = '\p{Alnum}'
436
+ CG_BLANK = '\p{Blank}'
437
+ CC_WORD = CG_WORD = '\p{Word}'
438
+ end
1216
439
 
1217
- compat_quote_subs = quote_subs.drop 0
1218
- # ``quoted''
1219
- compat_quote_subs[2] = [:double, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?``(\S|\S#{CC_ALL}*?\S)''(?!#{CG_WORD})/m]
1220
- # `quoted'
1221
- compat_quote_subs[3] = [:single, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?`(\S|\S#{CC_ALL}*?\S)'(?!#{CG_WORD})/m]
1222
- # ++monospaced++
1223
- compat_quote_subs[4] = [:monospaced, :unconstrained, /\\?(?:\[([^\]]+)\])?\+\+(#{CC_ALL}+?)\+\+/m]
1224
- # +monospaced+
1225
- compat_quote_subs[5] = [:monospaced, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?\+(\S|\S#{CC_ALL}*?\S)\+(?!#{CG_WORD})/m]
1226
- # #unquoted#
1227
- #compat_quote_subs[8] = [:unquoted, *compat_quote_subs[8][1..-1]]
1228
- # ##unquoted##
1229
- #compat_quote_subs[9] = [:unquoted, *compat_quote_subs[9][1..-1]]
1230
- # 'emphasis'
1231
- compat_quote_subs.insert 3, [:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?'(\S|\S#{CC_ALL}*?\S)'(?!#{CG_WORD})/m]
1232
-
1233
- QUOTE_SUBS = {
1234
- false => quote_subs,
1235
- true => compat_quote_subs
1236
- }
1237
- quote_subs = nil
1238
- compat_quote_subs = nil
440
+ QUOTE_SUBS = {}.tap do |accum|
441
+ # unconstrained quotes:: can appear anywhere
442
+ # constrained quotes:: must be bordered by non-word characters
443
+ # NOTE these substitutions are processed in the order they appear here and
444
+ # the order in which they are replaced is important
445
+ accum[false] = normal = [
446
+ # **strong**
447
+ [:strong, :unconstrained, /\\?(?:\[([^\]]+)\])?\*\*(#{CC_ALL}+?)\*\*/m],
448
+ # *strong*
449
+ [:strong, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?\*(\S|\S#{CC_ALL}*?\S)\*(?!#{CG_WORD})/m],
450
+ # "`double-quoted`"
451
+ [:double, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?"`(\S|\S#{CC_ALL}*?\S)`"(?!#{CG_WORD})/m],
452
+ # '`single-quoted`'
453
+ [:single, :constrained, /(^|[^#{CC_WORD};:`}])(?:\[([^\]]+)\])?'`(\S|\S#{CC_ALL}*?\S)`'(?!#{CG_WORD})/m],
454
+ # ``monospaced``
455
+ [:monospaced, :unconstrained, /\\?(?:\[([^\]]+)\])?``(#{CC_ALL}+?)``/m],
456
+ # `monospaced`
457
+ [:monospaced, :constrained, /(^|[^#{CC_WORD};:"'`}])(?:\[([^\]]+)\])?`(\S|\S#{CC_ALL}*?\S)`(?![#{CC_WORD}"'`])/m],
458
+ # __emphasis__
459
+ [:emphasis, :unconstrained, /\\?(?:\[([^\]]+)\])?__(#{CC_ALL}+?)__/m],
460
+ # _emphasis_
461
+ [:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?_(\S|\S#{CC_ALL}*?\S)_(?!#{CG_WORD})/m],
462
+ # ##mark## (referred to in AsciiDoc.py as unquoted)
463
+ [:mark, :unconstrained, /\\?(?:\[([^\]]+)\])?##(#{CC_ALL}+?)##/m],
464
+ # #mark# (referred to in AsciiDoc.py as unquoted)
465
+ [:mark, :constrained, /(^|[^#{CC_WORD}&;:}])(?:\[([^\]]+)\])?#(\S|\S#{CC_ALL}*?\S)#(?!#{CG_WORD})/m],
466
+ # ^superscript^
467
+ [:superscript, :unconstrained, /\\?(?:\[([^\]]+)\])?\^(\S+?)\^/],
468
+ # ~subscript~
469
+ [:subscript, :unconstrained, /\\?(?:\[([^\]]+)\])?~(\S+?)~/]
470
+ ]
471
+
472
+ accum[true] = compat = normal.drop 0
473
+ # ``quoted''
474
+ compat[2] = [:double, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?``(\S|\S#{CC_ALL}*?\S)''(?!#{CG_WORD})/m]
475
+ # `quoted'
476
+ compat[3] = [:single, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?`(\S|\S#{CC_ALL}*?\S)'(?!#{CG_WORD})/m]
477
+ # ++monospaced++
478
+ compat[4] = [:monospaced, :unconstrained, /\\?(?:\[([^\]]+)\])?\+\+(#{CC_ALL}+?)\+\+/m]
479
+ # +monospaced+
480
+ compat[5] = [:monospaced, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?\+(\S|\S#{CC_ALL}*?\S)\+(?!#{CG_WORD})/m]
481
+ # #unquoted#
482
+ #compat[8] = [:unquoted, *compat[8][1..-1]]
483
+ # ##unquoted##
484
+ #compat[9] = [:unquoted, *compat[9][1..-1]]
485
+ # 'emphasis'
486
+ compat.insert 3, [:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?'(\S|\S#{CC_ALL}*?\S)'(?!#{CG_WORD})/m]
487
+ end
1239
488
 
1240
- # NOTE in Ruby 1.8.7, [^\\] does not match start of line,
1241
- # so we need to match it explicitly
1242
- # order is significant
489
+ # NOTE order of replacements is significant
1243
490
  REPLACEMENTS = [
1244
491
  # (C)
1245
492
  [/\\?\(C\)/, '&#169;', :none],
@@ -1247,13 +494,13 @@ module Asciidoctor
1247
494
  [/\\?\(R\)/, '&#174;', :none],
1248
495
  # (TM)
1249
496
  [/\\?\(TM\)/, '&#8482;', :none],
1250
- # foo -- bar
1251
- # FIXME this drops the endline if it appears at end of line
1252
- [/(^|\n| |\\)--( |\n|$)/, '&#8201;&#8212;&#8201;', :none],
497
+ # foo -- bar (where either space character can be a newline)
498
+ # NOTE this necessarily drops the newline if replacement appears at end of line
499
+ [/(?: |\n|^|\\)--(?: |\n|$)/, '&#8201;&#8212;&#8201;', :none],
1253
500
  # foo--bar
1254
501
  [/(#{CG_WORD})\\?--(?=#{CG_WORD})/, '&#8212;&#8203;', :leading],
1255
502
  # ellipsis
1256
- [/\\?\.\.\./, '&#8230;&#8203;', :leading],
503
+ [/\\?\.\.\./, '&#8230;&#8203;', :none],
1257
504
  # right single quote
1258
505
  [/\\?`'/, '&#8217;', :none],
1259
506
  # apostrophe (inside a word)
@@ -1270,334 +517,6 @@ module Asciidoctor
1270
517
  [/\\?(&)amp;((?:[a-zA-Z][a-zA-Z]+\d{0,2}|#\d\d\d{0,4}|#x[\da-fA-F][\da-fA-F][\da-fA-F]{0,3});)/, '', :bounding]
1271
518
  ]
1272
519
 
1273
- class << self
1274
-
1275
- # Public: Parse the AsciiDoc source input into a {Document}
1276
- #
1277
- # Accepts input as an IO (or StringIO), String or String Array object. If the
1278
- # input is a File, the object is expected to be opened for reading and is not
1279
- # closed afterwards by this method. Information about the file (filename,
1280
- # directory name, etc) gets assigned to attributes on the Document object.
1281
- #
1282
- # input - the AsciiDoc source as a IO, String or Array.
1283
- # options - a String, Array or Hash of options to control processing (default: {})
1284
- # String and Array values are converted into a Hash.
1285
- # See {Document#initialize} for details about these options.
1286
- #
1287
- # Returns the Document
1288
- def load input, options = {}
1289
- options = options.dup
1290
-
1291
- if (timings = options[:timings])
1292
- timings.start :read
1293
- end
1294
-
1295
- if (logger = options[:logger]) && logger != LoggerManager.logger
1296
- LoggerManager.logger = logger
1297
- end
1298
-
1299
- if !(attrs = options[:attributes])
1300
- attrs = {}
1301
- elsif ::Hash === attrs || (::RUBY_ENGINE_JRUBY && ::Java::JavaUtil::Map === attrs)
1302
- attrs = attrs.dup
1303
- elsif ::Array === attrs
1304
- attrs, attrs_arr = {}, attrs
1305
- attrs_arr.each do |entry|
1306
- k, v = entry.split '=', 2
1307
- attrs[k] = v || ''
1308
- end
1309
- elsif ::String === attrs
1310
- # condense and convert non-escaped spaces to null, unescape escaped spaces, then split on null
1311
- attrs, attrs_arr = {}, attrs.gsub(SpaceDelimiterRx, %(\\1#{NULL})).gsub(EscapedSpaceRx, '\1').split(NULL)
1312
- attrs_arr.each do |entry|
1313
- k, v = entry.split '=', 2
1314
- attrs[k] = v || ''
1315
- end
1316
- elsif (attrs.respond_to? :keys) && (attrs.respond_to? :[])
1317
- # convert it to a Hash as we know it
1318
- attrs = ::Hash[attrs.keys.map {|k| [k, attrs[k]] }]
1319
- else
1320
- raise ::ArgumentError, %(illegal type for attributes option: #{attrs.class.ancestors.join ' < '})
1321
- end
1322
-
1323
- lines = nil
1324
- if ::File === input
1325
- # TODO cli checks if input path can be read and is file, but might want to add check to API
1326
- input_path = ::File.expand_path input.path
1327
- # See https://reproducible-builds.org/specs/source-date-epoch/
1328
- # NOTE Opal can't call key? on ENV
1329
- input_mtime = ::ENV['SOURCE_DATE_EPOCH'] ? ::Time.at(Integer ::ENV['SOURCE_DATE_EPOCH']).utc : input.mtime
1330
- lines = input.readlines
1331
- # hold off on setting infile and indir until we get a better sense of their purpose
1332
- attrs['docfile'] = input_path
1333
- attrs['docdir'] = ::File.dirname input_path
1334
- attrs['docname'] = Helpers.basename input_path, (attrs['docfilesuffix'] = ::File.extname input_path)
1335
- if (docdate = attrs['docdate'])
1336
- attrs['docyear'] ||= ((docdate.index '-') == 4 ? (docdate.slice 0, 4) : nil)
1337
- else
1338
- docdate = attrs['docdate'] = (input_mtime.strftime '%F')
1339
- attrs['docyear'] ||= input_mtime.year.to_s
1340
- end
1341
- # %Z is OS dependent and may contain characters that aren't UTF-8 encoded (see asciidoctor#2770 and asciidoctor.js#23)
1342
- # Ruby 1.8 doesn't support %:z
1343
- doctime = (attrs['doctime'] ||= input_mtime.strftime %(%T #{input_mtime.utc_offset == 0 ? 'UTC' : '%z'}))
1344
- attrs['docdatetime'] = %(#{docdate} #{doctime})
1345
- elsif input.respond_to? :readlines
1346
- # NOTE tty, pipes & sockets can't be rewound, but can't be sniffed easily either
1347
- # just fail the rewind operation silently to handle all cases
1348
- begin
1349
- input.rewind
1350
- rescue
1351
- end
1352
- lines = input.readlines
1353
- elsif ::String === input
1354
- lines = ::RUBY_MIN_VERSION_2 ? input.lines : input.each_line.to_a
1355
- elsif ::Array === input
1356
- lines = input.drop 0
1357
- else
1358
- raise ::ArgumentError, %(unsupported input type: #{input.class})
1359
- end
1360
-
1361
- if timings
1362
- timings.record :read
1363
- timings.start :parse
1364
- end
1365
-
1366
- options[:attributes] = attrs
1367
- doc = options[:parse] == false ? (Document.new lines, options) : (Document.new lines, options).parse
1368
-
1369
- timings.record :parse if timings
1370
- doc
1371
- rescue => ex
1372
- begin
1373
- context = %(asciidoctor: FAILED: #{attrs['docfile'] || '<stdin>'}: Failed to load AsciiDoc document)
1374
- if ex.respond_to? :exception
1375
- # The original message must be explicitely preserved when wrapping a Ruby exception
1376
- wrapped_ex = ex.exception %(#{context} - #{ex.message})
1377
- # JRuby automatically sets backtrace, but not MRI
1378
- wrapped_ex.set_backtrace ex.backtrace
1379
- else
1380
- # Likely a Java exception class
1381
- wrapped_ex = ex.class.new context, ex
1382
- wrapped_ex.stack_trace = ex.stack_trace
1383
- end
1384
- rescue
1385
- wrapped_ex = ex
1386
- end
1387
- raise wrapped_ex
1388
- end
1389
-
1390
- # Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
1391
- #
1392
- # input - the String AsciiDoc source filename
1393
- # options - a String, Array or Hash of options to control processing (default: {})
1394
- # String and Array values are converted into a Hash.
1395
- # See Asciidoctor::Document#initialize for details about options.
1396
- #
1397
- # Returns the Asciidoctor::Document
1398
- def load_file filename, options = {}
1399
- ::File.open(filename, 'rb') {|file| self.load file, options }
1400
- end
1401
-
1402
- # Public: Parse the AsciiDoc source input into an Asciidoctor::Document and
1403
- # convert it to the specified backend format.
1404
- #
1405
- # Accepts input as an IO (or StringIO), String or String Array object. If the
1406
- # input is a File, the object is expected to be opened for reading and is not
1407
- # closed afterwards by this method. Information about the file (filename,
1408
- # directory name, etc) gets assigned to attributes on the Document object.
1409
- #
1410
- # If the :to_file option is true, and the input is a File, the output is
1411
- # written to a file adjacent to the input file, having an extension that
1412
- # corresponds to the backend format. Otherwise, if the :to_file option is
1413
- # specified, the file is written to that file. If :to_file is not an absolute
1414
- # path, it is resolved relative to :to_dir, if given, otherwise the
1415
- # Document#base_dir. If the target directory does not exist, it will not be
1416
- # created unless the :mkdirs option is set to true. If the file cannot be
1417
- # written because the target directory does not exist, or because it falls
1418
- # outside of the Document#base_dir in safe mode, an IOError is raised.
1419
- #
1420
- # If the output is going to be written to a file, the header and footer are
1421
- # included unless specified otherwise (writing to a file implies creating a
1422
- # standalone document). Otherwise, the header and footer are not included by
1423
- # default and the converted result is returned.
1424
- #
1425
- # input - the String AsciiDoc source filename
1426
- # options - a String, Array or Hash of options to control processing (default: {})
1427
- # String and Array values are converted into a Hash.
1428
- # See Asciidoctor::Document#initialize for details about options.
1429
- #
1430
- # Returns the Document object if the converted String is written to a
1431
- # file, otherwise the converted String
1432
- def convert input, options = {}
1433
- options = options.dup
1434
- options.delete(:parse)
1435
- to_file = options.delete(:to_file)
1436
- to_dir = options.delete(:to_dir)
1437
- mkdirs = options.delete(:mkdirs) || false
1438
-
1439
- case to_file
1440
- when true, nil
1441
- write_to_same_dir = !to_dir && ::File === input
1442
- stream_output = false
1443
- write_to_target = to_dir
1444
- to_file = nil
1445
- when false
1446
- write_to_same_dir = false
1447
- stream_output = false
1448
- write_to_target = false
1449
- to_file = nil
1450
- when '/dev/null'
1451
- return self.load input, options
1452
- else
1453
- write_to_same_dir = false
1454
- write_to_target = (stream_output = to_file.respond_to? :write) ? false : (options[:to_file] = to_file)
1455
- end
1456
-
1457
- unless options.key? :header_footer
1458
- options[:header_footer] = true if write_to_same_dir || write_to_target
1459
- end
1460
-
1461
- # NOTE outfile may be controlled by document attributes, so resolve outfile after loading
1462
- if write_to_same_dir
1463
- input_path = ::File.expand_path input.path
1464
- options[:to_dir] = (outdir = ::File.dirname input_path)
1465
- elsif write_to_target
1466
- if to_dir
1467
- if to_file
1468
- options[:to_dir] = ::File.dirname ::File.expand_path ::File.join to_dir, to_file
1469
- else
1470
- options[:to_dir] = ::File.expand_path to_dir
1471
- end
1472
- elsif to_file
1473
- options[:to_dir] = ::File.dirname ::File.expand_path to_file
1474
- end
1475
- end
1476
-
1477
- # NOTE :to_dir is always set when outputting to a file
1478
- # NOTE :to_file option only passed if assigned an explicit path
1479
- doc = self.load input, options
1480
-
1481
- if write_to_same_dir # write to file in same directory
1482
- outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
1483
- if outfile == input_path
1484
- raise ::IOError, %(input file and output file cannot be the same: #{outfile})
1485
- end
1486
- elsif write_to_target # write to explicit file or directory
1487
- working_dir = (options.key? :base_dir) ? (::File.expand_path options[:base_dir]) : ::Dir.pwd
1488
- # QUESTION should the jail be the working_dir or doc.base_dir???
1489
- jail = doc.safe >= SafeMode::SAFE ? working_dir : nil
1490
- if to_dir
1491
- outdir = doc.normalize_system_path(to_dir, working_dir, jail, :target_name => 'to_dir', :recover => false)
1492
- if to_file
1493
- outfile = doc.normalize_system_path(to_file, outdir, nil, :target_name => 'to_dir', :recover => false)
1494
- # reestablish outdir as the final target directory (in the case to_file had directory segments)
1495
- outdir = ::File.dirname outfile
1496
- else
1497
- outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
1498
- end
1499
- elsif to_file
1500
- outfile = doc.normalize_system_path(to_file, working_dir, jail, :target_name => 'to_dir', :recover => false)
1501
- # establish outdir as the final target directory (in the case to_file had directory segments)
1502
- outdir = ::File.dirname outfile
1503
- end
1504
-
1505
- if ::File === input && outfile == (::File.expand_path input.path)
1506
- raise ::IOError, %(input file and output file cannot be the same: #{outfile})
1507
- end
1508
-
1509
- if mkdirs
1510
- Helpers.mkdir_p outdir
1511
- else
1512
- # NOTE we intentionally refer to the directory as it was passed to the API
1513
- raise ::IOError, %(target directory does not exist: #{to_dir} (hint: set mkdirs option)) unless ::File.directory? outdir
1514
- end
1515
- else # write to stream
1516
- outfile = to_file
1517
- outdir = nil
1518
- end
1519
-
1520
- opts = outfile && !stream_output ? { 'outfile' => outfile, 'outdir' => outdir } : {}
1521
- output = doc.convert opts
1522
-
1523
- if outfile
1524
- doc.write output, outfile
1525
-
1526
- # NOTE document cannot control this behavior if safe >= SafeMode::SERVER
1527
- # NOTE skip if stylesdir is a URI
1528
- if !stream_output && doc.safe < SafeMode::SECURE && (doc.attr? 'linkcss') &&
1529
- (doc.attr? 'copycss') && (doc.attr? 'basebackend-html') &&
1530
- !((stylesdir = (doc.attr 'stylesdir')) && (Helpers.uriish? stylesdir))
1531
- copy_asciidoctor_stylesheet = false
1532
- copy_user_stylesheet = false
1533
- if (stylesheet = (doc.attr 'stylesheet'))
1534
- if DEFAULT_STYLESHEET_KEYS.include? stylesheet
1535
- copy_asciidoctor_stylesheet = true
1536
- elsif !(Helpers.uriish? stylesheet)
1537
- copy_user_stylesheet = true
1538
- end
1539
- end
1540
- copy_coderay_stylesheet = (doc.attr? 'source-highlighter', 'coderay') && (doc.attr 'coderay-css', 'class') == 'class'
1541
- copy_pygments_stylesheet = (doc.attr? 'source-highlighter', 'pygments') && (doc.attr 'pygments-css', 'class') == 'class'
1542
- if copy_asciidoctor_stylesheet || copy_user_stylesheet || copy_coderay_stylesheet || copy_pygments_stylesheet
1543
- stylesoutdir = doc.normalize_system_path(stylesdir, outdir, doc.safe >= SafeMode::SAFE ? outdir : nil)
1544
- if mkdirs
1545
- Helpers.mkdir_p stylesoutdir
1546
- else
1547
- raise ::IOError, %(target stylesheet directory does not exist: #{stylesoutdir} (hint: set mkdirs option)) unless ::File.directory? stylesoutdir
1548
- end
1549
-
1550
- if copy_asciidoctor_stylesheet
1551
- Stylesheets.instance.write_primary_stylesheet stylesoutdir
1552
- # FIXME should Stylesheets also handle the user stylesheet?
1553
- elsif copy_user_stylesheet
1554
- if (stylesheet_src = (doc.attr 'copycss')).empty?
1555
- stylesheet_src = doc.normalize_system_path stylesheet
1556
- else
1557
- # NOTE in this case, copycss is a source location (but cannot be a URI)
1558
- stylesheet_src = doc.normalize_system_path stylesheet_src
1559
- end
1560
- stylesheet_dest = doc.normalize_system_path stylesheet, stylesoutdir, (doc.safe >= SafeMode::SAFE ? outdir : nil)
1561
- # NOTE don't warn if src can't be read and dest already exists (see #2323)
1562
- if stylesheet_src != stylesheet_dest && (stylesheet_data = doc.read_asset stylesheet_src,
1563
- :warn_on_failure => !(::File.file? stylesheet_dest), :label => 'stylesheet')
1564
- ::IO.write stylesheet_dest, stylesheet_data
1565
- end
1566
- end
1567
-
1568
- if copy_coderay_stylesheet
1569
- Stylesheets.instance.write_coderay_stylesheet stylesoutdir
1570
- elsif copy_pygments_stylesheet
1571
- Stylesheets.instance.write_pygments_stylesheet stylesoutdir, (doc.attr 'pygments-style')
1572
- end
1573
- end
1574
- end
1575
- doc
1576
- else
1577
- output
1578
- end
1579
- end
1580
-
1581
- # Alias render to convert to maintain backwards compatibility
1582
- alias render convert
1583
-
1584
- # Public: Parse the contents of the AsciiDoc source file into an
1585
- # Asciidoctor::Document and convert it to the specified backend format.
1586
- #
1587
- # input - the String AsciiDoc source filename
1588
- # options - a String, Array or Hash of options to control processing (default: {})
1589
- # String and Array values are converted into a Hash.
1590
- # See Asciidoctor::Document#initialize for details about options.
1591
- #
1592
- # Returns the Document object if the converted String is written to a
1593
- # file, otherwise the converted String
1594
- def convert_file filename, options = {}
1595
- ::File.open(filename, 'rb') {|file| self.convert file, options }
1596
- end
1597
-
1598
- # Alias render_file to convert_file to maintain backwards compatibility
1599
- alias render_file convert_file
1600
-
1601
520
  # Internal: Automatically load the Asciidoctor::Extensions module.
1602
521
  #
1603
522
  # Requires the Asciidoctor::Extensions module if the name is :Extensions.
@@ -1608,51 +527,58 @@ module Asciidoctor
1608
527
  # defined prior to it being loaded.
1609
528
  #
1610
529
  # Returns the resolved constant, if resolved, otherwise nothing.
1611
- def const_missing name
530
+ def self.const_missing name
1612
531
  if name == :Extensions
1613
- require 'asciidoctor/extensions'
532
+ require_relative 'asciidoctor/extensions'
1614
533
  Extensions
1615
534
  else
1616
535
  super
1617
536
  end
1618
537
  end unless RUBY_ENGINE == 'opal'
1619
538
 
1620
- end
1621
-
1622
- if RUBY_ENGINE == 'opal'
1623
- require 'asciidoctor/timings'
1624
- require 'asciidoctor/version'
1625
- else
1626
- autoload :Timings, 'asciidoctor/timings'
1627
- autoload :VERSION, 'asciidoctor/version'
539
+ unless RUBY_ENGINE == 'opal'
540
+ autoload :SyntaxHighlighter, %(#{__dir__}/asciidoctor/syntax_highlighter)
541
+ autoload :Timings, %(#{__dir__}/asciidoctor/timings)
1628
542
  end
1629
543
  end
1630
544
 
1631
545
  # core extensions
1632
- require 'asciidoctor/core_ext'
546
+ require_relative 'asciidoctor/core_ext'
1633
547
 
1634
- # modules
1635
- require 'asciidoctor/helpers'
1636
- require 'asciidoctor/substitutors'
548
+ # modules and helpers
549
+ require_relative 'asciidoctor/helpers'
550
+ require_relative 'asciidoctor/logging'
551
+ require_relative 'asciidoctor/rx'
552
+ require_relative 'asciidoctor/substitutors'
553
+ require_relative 'asciidoctor/version'
1637
554
 
1638
555
  # abstract classes
1639
- require 'asciidoctor/abstract_node'
1640
- require 'asciidoctor/abstract_block'
556
+ require_relative 'asciidoctor/abstract_node'
557
+ require_relative 'asciidoctor/abstract_block'
1641
558
 
1642
559
  # concrete classes
1643
- require 'asciidoctor/attribute_list'
1644
- require 'asciidoctor/block'
1645
- require 'asciidoctor/callouts'
1646
- require 'asciidoctor/converter'
1647
- require 'asciidoctor/document'
1648
- require 'asciidoctor/inline'
1649
- require 'asciidoctor/list'
1650
- require 'asciidoctor/parser'
1651
- require 'asciidoctor/path_resolver'
1652
- require 'asciidoctor/reader'
1653
- require 'asciidoctor/section'
1654
- require 'asciidoctor/stylesheets'
1655
- require 'asciidoctor/table'
1656
-
1657
- # this require is satisfied by the Asciidoctor.js build; it supplies compile and runtime overrides for Asciidoctor.js
1658
- require 'asciidoctor/js/postscript' if RUBY_ENGINE == 'opal'
560
+ require_relative 'asciidoctor/attribute_list'
561
+ require_relative 'asciidoctor/block'
562
+ require_relative 'asciidoctor/callouts'
563
+ require_relative 'asciidoctor/converter'
564
+ require_relative 'asciidoctor/document'
565
+ require_relative 'asciidoctor/inline'
566
+ require_relative 'asciidoctor/list'
567
+ require_relative 'asciidoctor/parser'
568
+ require_relative 'asciidoctor/path_resolver'
569
+ require_relative 'asciidoctor/reader'
570
+ require_relative 'asciidoctor/section'
571
+ require_relative 'asciidoctor/stylesheets'
572
+ require_relative 'asciidoctor/table'
573
+ require_relative 'asciidoctor/writer'
574
+
575
+ # main API entry points
576
+ require_relative 'asciidoctor/load'
577
+ require_relative 'asciidoctor/convert'
578
+
579
+ if RUBY_ENGINE == 'opal'
580
+ require_relative 'asciidoctor/syntax_highlighter'
581
+ require_relative 'asciidoctor/timings'
582
+ # this require is satisfied by the Asciidoctor.js build; it supplies compile and runtime overrides for Asciidoctor.js
583
+ require 'asciidoctor/js/postscript'
584
+ end