asciidoctor 1.5.8 → 2.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +11 -0
- data/CHANGELOG.adoc +628 -45
- data/LICENSE +2 -1
- data/README-de.adoc +28 -38
- data/README-fr.adoc +30 -43
- data/README-jp.adoc +255 -201
- data/README-zh_CN.adoc +40 -44
- data/README.adoc +170 -143
- data/asciidoctor.gemspec +22 -34
- data/bin/asciidoctor +5 -4
- data/data/locale/attributes-ar.adoc +4 -3
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-bg.adoc +4 -3
- data/data/locale/attributes-ca.adoc +6 -5
- data/data/locale/attributes-cs.adoc +4 -3
- data/data/locale/attributes-da.adoc +6 -5
- data/data/locale/attributes-de.adoc +6 -5
- data/data/locale/attributes-en.adoc +4 -4
- data/data/locale/attributes-es.adoc +6 -5
- data/data/locale/attributes-fa.adoc +4 -3
- data/data/locale/attributes-fi.adoc +4 -3
- data/data/locale/attributes-fr.adoc +8 -7
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +6 -5
- data/data/locale/attributes-ja.adoc +4 -3
- data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
- data/data/locale/attributes-nb.adoc +4 -3
- data/data/locale/attributes-nl.adoc +6 -5
- data/data/locale/attributes-nn.adoc +4 -3
- data/data/locale/attributes-pl.adoc +8 -7
- data/data/locale/attributes-pt.adoc +6 -5
- data/data/locale/attributes-pt_BR.adoc +6 -5
- data/data/locale/attributes-ro.adoc +4 -3
- data/data/locale/attributes-ru.adoc +6 -5
- data/data/locale/attributes-sr.adoc +4 -4
- data/data/locale/attributes-sr_Latn.adoc +4 -4
- data/data/locale/attributes-sv.adoc +4 -4
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/reference/syntax.adoc +296 -0
- data/data/stylesheets/asciidoctor-default.css +120 -114
- data/data/stylesheets/coderay-asciidoctor.css +15 -17
- data/lib/asciidoctor/abstract_block.rb +146 -140
- data/lib/asciidoctor/abstract_node.rb +152 -170
- data/lib/asciidoctor/attribute_list.rb +77 -89
- data/lib/asciidoctor/block.rb +29 -28
- data/lib/asciidoctor/callouts.rb +4 -2
- data/lib/asciidoctor/cli/invoker.rb +20 -24
- data/lib/asciidoctor/cli/options.rb +107 -96
- data/lib/asciidoctor/cli.rb +3 -2
- data/lib/asciidoctor/convert.rb +199 -0
- data/lib/asciidoctor/converter/composite.rb +40 -48
- data/lib/asciidoctor/converter/docbook5.rb +627 -644
- data/lib/asciidoctor/converter/html5.rb +1053 -951
- data/lib/asciidoctor/converter/manpage.rb +581 -532
- data/lib/asciidoctor/converter/template.rb +232 -271
- data/lib/asciidoctor/converter.rb +370 -185
- data/lib/asciidoctor/core_ext/float/truncate.rb +20 -0
- data/lib/asciidoctor/core_ext/hash/merge.rb +8 -0
- data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
- data/lib/asciidoctor/core_ext.rb +8 -17
- data/lib/asciidoctor/document.rb +503 -461
- data/lib/asciidoctor/extensions.rb +127 -174
- data/lib/asciidoctor/helpers.rb +184 -107
- data/lib/asciidoctor/inline.rb +9 -12
- data/lib/asciidoctor/list.rb +11 -29
- data/lib/asciidoctor/load.rb +119 -0
- data/lib/asciidoctor/logging.rb +22 -17
- data/lib/asciidoctor/parser.rb +673 -719
- data/lib/asciidoctor/path_resolver.rb +48 -33
- data/lib/asciidoctor/reader.rb +383 -338
- data/lib/asciidoctor/rouge_ext.rb +39 -0
- data/lib/asciidoctor/rx.rb +723 -0
- data/lib/asciidoctor/section.rb +17 -16
- data/lib/asciidoctor/stylesheets.rb +19 -37
- data/lib/asciidoctor/substitutors.rb +926 -1022
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +88 -0
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +34 -0
- data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +30 -0
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +157 -0
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +143 -0
- data/lib/asciidoctor/syntax_highlighter.rb +253 -0
- data/lib/asciidoctor/table.rb +152 -114
- data/lib/asciidoctor/timings.rb +7 -5
- data/lib/asciidoctor/version.rb +2 -1
- data/lib/asciidoctor/writer.rb +30 -0
- data/lib/asciidoctor.rb +266 -1340
- data/man/asciidoctor.1 +49 -47
- data/man/asciidoctor.adoc +54 -45
- metadata +50 -245
- data/CONTRIBUTING.adoc +0 -185
- data/Gemfile +0 -60
- data/Rakefile +0 -129
- data/bin/asciidoctor-safe +0 -15
- data/features/open_block.feature +0 -92
- data/features/pass_block.feature +0 -66
- data/features/step_definitions.rb +0 -49
- data/features/text_formatting.feature +0 -57
- data/features/xref.feature +0 -1039
- data/lib/asciidoctor/converter/base.rb +0 -59
- data/lib/asciidoctor/converter/docbook45.rb +0 -93
- data/lib/asciidoctor/converter/factory.rb +0 -226
- data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
- data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
- data/test/api_test.rb +0 -1240
- data/test/attribute_list_test.rb +0 -242
- data/test/attributes_test.rb +0 -1623
- data/test/blocks_test.rb +0 -3870
- data/test/converter_test.rb +0 -470
- data/test/document_test.rb +0 -1853
- data/test/extensions_test.rb +0 -1560
- data/test/fixtures/asciidoc_index.txt +0 -521
- data/test/fixtures/basic-docinfo-footer.html +0 -6
- data/test/fixtures/basic-docinfo-footer.xml +0 -8
- data/test/fixtures/basic-docinfo.html +0 -1
- data/test/fixtures/basic-docinfo.xml +0 -4
- data/test/fixtures/basic.asciidoc +0 -5
- data/test/fixtures/chapter-a.adoc +0 -3
- data/test/fixtures/child-include.adoc +0 -5
- data/test/fixtures/circle.svg +0 -9
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
- data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
- data/test/fixtures/docinfo-footer.html +0 -1
- data/test/fixtures/docinfo-footer.xml +0 -9
- data/test/fixtures/docinfo.html +0 -1
- data/test/fixtures/docinfo.xml +0 -3
- data/test/fixtures/doctime-localtime.adoc +0 -2
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +0 -13
- data/test/fixtures/file-with-missing-include.adoc +0 -1
- data/test/fixtures/grandchild-include.adoc +0 -3
- data/test/fixtures/hello-asciidoctor.pdf +0 -69
- data/test/fixtures/include-file.asciidoc +0 -24
- data/test/fixtures/include-file.jsx +0 -8
- data/test/fixtures/include-file.ml +0 -3
- data/test/fixtures/include-file.xml +0 -5
- data/test/fixtures/lists.adoc +0 -96
- data/test/fixtures/master.adoc +0 -5
- data/test/fixtures/mismatched-end-tag.adoc +0 -7
- data/test/fixtures/other-chapters.adoc +0 -11
- data/test/fixtures/outer-include.adoc +0 -5
- data/test/fixtures/parent-include-restricted.adoc +0 -5
- data/test/fixtures/parent-include.adoc +0 -5
- data/test/fixtures/sample.asciidoc +0 -30
- data/test/fixtures/section-a.adoc +0 -4
- data/test/fixtures/stylesheets/custom.css +0 -3
- data/test/fixtures/subdir/index.adoc +0 -3
- data/test/fixtures/subdir/inner-include.adoc +0 -3
- data/test/fixtures/subdir/middle-include.adoc +0 -5
- data/test/fixtures/subs-docinfo.html +0 -2
- data/test/fixtures/subs.adoc +0 -6
- data/test/fixtures/tagged-class-enclosed.rb +0 -25
- data/test/fixtures/tagged-class.rb +0 -23
- data/test/fixtures/tip.gif +0 -0
- data/test/fixtures/unclosed-tag.adoc +0 -3
- data/test/fixtures/unexpected-end-tag.adoc +0 -4
- data/test/invoker_test.rb +0 -745
- data/test/links_test.rb +0 -855
- data/test/lists_test.rb +0 -5151
- data/test/logger_test.rb +0 -211
- data/test/manpage_test.rb +0 -660
- data/test/options_test.rb +0 -262
- data/test/paragraphs_test.rb +0 -562
- data/test/parser_test.rb +0 -742
- data/test/paths_test.rb +0 -395
- data/test/preamble_test.rb +0 -173
- data/test/reader_test.rb +0 -2161
- data/test/sections_test.rb +0 -3575
- data/test/substitutions_test.rb +0 -2066
- data/test/tables_test.rb +0 -2036
- data/test/test_helper.rb +0 -447
- data/test/text_test.rb +0 -309
data/lib/asciidoctor.rb
CHANGED
@@ -1,10 +1,4 @@
|
|
1
|
-
#
|
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
|
-
|
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
|
-
#
|
23
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
32
|
+
# Examples
|
40
33
|
#
|
41
|
-
#
|
34
|
+
# # Convert an AsciiDoc file
|
35
|
+
# Asciidoctor.convert_file 'document.adoc', safe: :safe
|
42
36
|
#
|
43
|
-
#
|
44
|
-
# .
|
37
|
+
# # Convert an AsciiDoc string
|
38
|
+
# puts Asciidoctor.convert "I'm using *Asciidoctor* version {asciidoctor-version}.", safe: :safe
|
45
39
|
#
|
46
|
-
#
|
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
|
-
#
|
43
|
+
# # Parse an AsciiDoc file into a document object
|
44
|
+
# doc = Asciidoctor.load_file 'document.adoc', safe: :safe
|
49
45
|
#
|
50
|
-
#
|
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
|
-
|
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
|
75
|
-
# changing the backend or
|
76
|
-
# in the source document. This is the most fundamental level of
|
77
|
-
# for server
|
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
|
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
|
-
|
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
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
#
|
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
|
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
|
188
|
-
|
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
|
191
|
-
|
181
|
+
# The absolute lib directory of the Asciidoctor RubyGem
|
182
|
+
LIB_DIR = ::File.join ROOT_DIR, 'lib'
|
192
183
|
|
193
|
-
# The absolute data
|
194
|
-
|
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
|
-
#
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
#
|
205
|
-
|
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
|
-
#
|
211
|
-
|
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
|
-
#
|
219
|
-
|
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
|
225
|
-
|
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
|
-
#
|
231
|
-
|
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'
|
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
|
-
#
|
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 =
|
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
|
-
'--'
|
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
|
-
'```'
|
292
|
+
'```' => [:fenced_code, ::Set.new]
|
306
293
|
}
|
307
294
|
|
308
|
-
DELIMITED_BLOCK_HEADS = DELIMITED_BLOCKS.
|
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
|
-
'<'
|
303
|
+
'<' => :page_break
|
313
304
|
}
|
314
305
|
|
315
306
|
MARKDOWN_THEMATIC_BREAK_CHARS = {
|
316
|
-
'-'
|
317
|
-
'*'
|
318
|
-
'_'
|
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'
|
332
|
-
#'decimal'
|
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
|
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
|
-
:
|
355
|
-
:
|
343
|
+
asciimath: ['\$', '\$'],
|
344
|
+
latexmath: ['\[', '\]'],
|
356
345
|
}
|
357
346
|
|
358
347
|
INLINE_MATH_DELIMITERS = {
|
359
|
-
:
|
360
|
-
:
|
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
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
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(((?://|#|--|;;) ?)?(\\)?<!?(|--)(\d+|\.)\3>(?=(?: ?\\?<!?\3(?:\d+|\.)\3>)*#{CC_EOL}))
|
773
|
-
CalloutSourceRxt = "(\\\\)?<()(\\d+|\\.)>(?=(?: ?\\\\?<(?:\\d+|\\.)>)*#{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}|<|[>\(\)\[\];])(\\?(?: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]+>[ \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(\\?(?:<<([#{CC_WORD}#/.:{]#{CC_ALL}*?)>>|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
|
-
# >http://google.com<
|
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
|
-
|
1139
|
-
|
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'
|
1150
|
-
'backslash'
|
1151
|
-
'backtick'
|
1152
|
-
'blank'
|
1153
|
-
'empty'
|
1154
|
-
'sp'
|
394
|
+
'startsb' => '[',
|
395
|
+
'endsb' => ']',
|
396
|
+
'vbar' => '|',
|
397
|
+
'caret' => '^',
|
398
|
+
'asterisk' => '*',
|
399
|
+
'tilde' => '~',
|
400
|
+
'plus' => '+',
|
401
|
+
'backslash' => '\\',
|
402
|
+
'backtick' => '`',
|
403
|
+
'blank' => '',
|
404
|
+
'empty' => '',
|
405
|
+
'sp' => ' ',
|
1155
406
|
'two-colons' => '::',
|
1156
407
|
'two-semicolons' => ';;',
|
1157
|
-
'nbsp'
|
1158
|
-
'deg'
|
1159
|
-
'zwsp'
|
1160
|
-
'quot'
|
1161
|
-
'apos'
|
1162
|
-
'lsquo'
|
1163
|
-
'rsquo'
|
1164
|
-
'ldquo'
|
1165
|
-
'rdquo'
|
1166
|
-
'wj'
|
1167
|
-
'brvbar'
|
1168
|
-
'pp'
|
1169
|
-
'cpp'
|
1170
|
-
'amp'
|
1171
|
-
'lt'
|
1172
|
-
'gt'
|
408
|
+
'nbsp' => ' ',
|
409
|
+
'deg' => '°',
|
410
|
+
'zwsp' => '​',
|
411
|
+
'quot' => '"',
|
412
|
+
'apos' => ''',
|
413
|
+
'lsquo' => '‘',
|
414
|
+
'rsquo' => '’',
|
415
|
+
'ldquo' => '“',
|
416
|
+
'rdquo' => '”',
|
417
|
+
'wj' => '⁠',
|
418
|
+
'brvbar' => '¦',
|
419
|
+
'pp' => '++',
|
420
|
+
'cpp' => 'C++',
|
421
|
+
'amp' => '&',
|
422
|
+
'lt' => '<',
|
423
|
+
'gt' => '>'
|
1173
424
|
}
|
1174
425
|
|
1175
|
-
#
|
1176
|
-
#
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
#
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
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
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
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
|
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\)/, '©', :none],
|
@@ -1247,13 +494,13 @@ module Asciidoctor
|
|
1247
494
|
[/\\?\(R\)/, '®', :none],
|
1248
495
|
# (TM)
|
1249
496
|
[/\\?\(TM\)/, '™', :none],
|
1250
|
-
# foo -- bar
|
1251
|
-
#
|
1252
|
-
[/(
|
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|$)/, ' — ', :none],
|
1253
500
|
# foo--bar
|
1254
501
|
[/(#{CG_WORD})\\?--(?=#{CG_WORD})/, '—​', :leading],
|
1255
502
|
# ellipsis
|
1256
|
-
[/\\?\.\.\./, '…​', :
|
503
|
+
[/\\?\.\.\./, '…​', :none],
|
1257
504
|
# right single quote
|
1258
505
|
[/\\?`'/, '’', :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
|
-
|
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
|
-
|
1621
|
-
|
1622
|
-
|
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
|
-
|
546
|
+
require_relative 'asciidoctor/core_ext'
|
1633
547
|
|
1634
|
-
# modules
|
1635
|
-
|
1636
|
-
|
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
|
-
|
1640
|
-
|
556
|
+
require_relative 'asciidoctor/abstract_node'
|
557
|
+
require_relative 'asciidoctor/abstract_block'
|
1641
558
|
|
1642
559
|
# concrete classes
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
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
|