"Fossies" - the Fresh Open Source Software Archive

Member "asciidoctor-2.0.10/lib/asciidoctor.rb" (1 Jun 2019, 20374 Bytes) of package /linux/www/asciidoctor-2.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "asciidoctor.rb": 2.0.9_vs_2.0.10.

    1 # frozen_string_literal: true
    2 require 'set'
    3 
    4 # NOTE RUBY_ENGINE == 'opal' conditional blocks like this are filtered by the Opal preprocessor
    5 if RUBY_ENGINE == 'opal'
    6   # this require is satisfied by the Asciidoctor.js build; it augments the Ruby environment for Asciidoctor.js
    7   require 'asciidoctor/js'
    8 else
    9   autoload :Base64, 'base64'
   10   require 'cgi/util'
   11   autoload :OpenURI, 'open-uri'
   12   autoload :Pathname, 'pathname'
   13   autoload :StringScanner, 'strscan'
   14   autoload :URI, 'uri'
   15 end
   16 
   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.
   19 #
   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.
   23 #
   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.
   28 #
   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.
   31 #
   32 # Examples
   33 #
   34 #   # Convert an AsciiDoc file
   35 #   Asciidoctor.convert_file 'document.adoc', safe: :safe
   36 #
   37 #   # Convert an AsciiDoc string
   38 #   puts Asciidoctor.convert "I'm using *Asciidoctor* version {asciidoctor-version}.", safe: :safe
   39 #
   40 #   # Convert an AsciiDoc file using Tilt-supported templates
   41 #   Asciidoctor.convert_file 'document.adoc', safe: :safe, template_dir: '/path/to/templates'
   42 #
   43 #   # Parse an AsciiDoc file into a document object
   44 #   doc = Asciidoctor.load_file 'document.adoc', safe: :safe
   45 #
   46 #   # Parse an AsciiDoc string into a document object
   47 #   doc = Asciidoctor.load "= Document Title\n\nfirst paragraph\n\nsecond paragraph", safe: :safe
   48 #
   49 module Asciidoctor
   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'
   52 
   53   module SafeMode
   54     # A safe mode level that disables any of the security features enforced
   55     # by Asciidoctor (Ruby is still subject to its own restrictions).
   56     UNSAFE = 0;
   57 
   58     # A safe mode level that closely parallels safe mode in AsciiDoc. This value
   59     # prevents access to files which reside outside of the parent directory of
   60     # the source file and disables any macro other than the include::[] directive.
   61     SAFE = 1;
   62 
   63     # A safe mode level that disallows the document from setting attributes
   64     # that would affect the conversion of the document, in addition to all the
   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;
   70 
   71     # A safe mode level that disallows the document from attempting to read
   72     # files from the file system and including the contents of them into the
   73     # document, in additional to all the security features of SafeMode::SERVER.
   74     # For instance, this level disallows use of the include::[] directive and the
   75     # embedding of binary content (data uri), stylesheets and JavaScripts
   76     # referenced by the document.(Asciidoctor and trusted extensions may still
   77     # be allowed to embed trusted content into the document).
   78     #
   79     # Since Asciidoctor is aiming for wide adoption, this level is the default
   80     # and is recommended for server deployments.
   81     SECURE = 20;
   82 
   83     # A planned safe mode level that disallows the use of passthrough macros and
   84     # prevents the document from setting any known attributes, in addition to all
   85     # the security features of SafeMode::SECURE.
   86     #
   87     # Please note that this level is not currently implemented (and therefore not
   88     # enforced)!
   89     #PARANOID = 100;
   90 
   91     @names_by_value = {}.tap {|accum| (constants false).each {|sym| accum[const_get sym, false] = sym.to_s.downcase } }
   92 
   93     def self.value_for_name name
   94       const_get name.upcase, false
   95     end
   96 
   97     def self.name_for_value value
   98       @names_by_value[value]
   99     end
  100 
  101     def self.names
  102       @names_by_value.values
  103     end
  104   end
  105 
  106   # Flags to control compliance with the behavior of AsciiDoc
  107   module Compliance
  108     @keys = ::Set.new
  109     class << self
  110       attr_reader :keys
  111 
  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
  119     end
  120 
  121     # AsciiDoc terminates paragraphs adjacent to
  122     # block content (delimiter or block attribute list)
  123     # This option allows this behavior to be modified
  124     # TODO what about literal paragraph?
  125     # Compliance value: true
  126     define :block_terminates_paragraph, true
  127 
  128     # AsciiDoc does not parse paragraphs with a verbatim style
  129     # (i.e., literal, listing, source, verse) as verbatim content.
  130     # This options allows this behavior to be modified
  131     # Compliance value: false
  132     define :strict_verbatim_paragraphs, true
  133 
  134     # AsciiDoc supports both atx (single-line) and setext (underlined) section titles.
  135     # This option can be used to disable the setext variant.
  136     # Compliance value: true
  137     define :underline_style_section_titles, true
  138 
  139     # Asciidoctor will unwrap the content in a preamble
  140     # if the document has a title and no sections.
  141     # Compliance value: false
  142     define :unwrap_standalone_preamble, true
  143 
  144     # AsciiDoc drops lines that contain references to missing attributes.
  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'.
  148     # Compliance value: 'drop-line'
  149     define :attribute_missing, 'skip'
  150 
  151     # AsciiDoc drops lines that contain an attribute unassignemnt.
  152     # This behavior may need to be tuned depending on the circumstances.
  153     # Compliance value: 'drop-line'
  154     define :attribute_undefined, 'drop-line'
  155 
  156     # Asciidoctor will allow the id, role and options to be set
  157     # on blocks using a shorthand syntax (e.g., #idname.rolename%optionname)
  158     # Compliance value: false
  159     define :shorthand_property_syntax, true
  160 
  161     # Asciidoctor will attempt to resolve the target of a cross reference by
  162     # matching its reference text (reftext or title) (e.g., <<Section Title>>)
  163     # Compliance value: false
  164     define :natural_xrefs, true
  165 
  166     # Asciidoctor will start counting at the following number
  167     # when creating a unique id when there is a conflict
  168     # Compliance value: 2
  169     define :unique_id_start_index, 2
  170 
  171     # Asciidoctor will recognize commonly-used Markdown syntax
  172     # to the degree it does not interfere with existing
  173     # AsciiDoc syntax and behavior.
  174     # Compliance value: false
  175     define :markdown_syntax, true
  176   end
  177 
  178   # The absolute root directory of the Asciidoctor RubyGem
  179   ROOT_DIR = ::File.dirname ::File.absolute_path __dir__ unless defined? ROOT_DIR
  180 
  181   # The absolute lib directory of the Asciidoctor RubyGem
  182   LIB_DIR = ::File.join ROOT_DIR, 'lib'
  183 
  184   # The absolute data directory of the Asciidoctor RubyGem
  185   DATA_DIR = ::File.join ROOT_DIR, 'data'
  186 
  187   # The user's home directory, as best we can determine it
  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
  199 
  200   # Maximum integer value for "boundless" operations; equal to MAX_SAFE_INTEGER in JavaScript
  201   MAX_INT = 9007199254740991
  202 
  203   # Alias UTF_8 encoding for convenience / speed
  204   UTF_8 = ::Encoding::UTF_8
  205 
  206   # Byte arrays for UTF-* Byte Order Marks
  207   BOM_BYTES_UTF_8 = [0xef, 0xbb, 0xbf]
  208   BOM_BYTES_UTF_16LE = [0xff, 0xfe]
  209   BOM_BYTES_UTF_16BE = [0xfe, 0xff]
  210 
  211   # The mode to use when opening a file for reading
  212   FILE_READ_MODE = RUBY_ENGINE_OPAL ? 'r' : 'rb:utf-8:utf-8'
  213 
  214   # The mode to use when opening a URI for reading
  215   URI_READ_MODE = FILE_READ_MODE
  216 
  217   # The mode to use when opening a file for writing
  218   FILE_WRITE_MODE = RUBY_ENGINE_OPAL ? 'w' : 'w:utf-8'
  219 
  220   # The default document type
  221   # Can influence markup generated by the converters
  222   DEFAULT_DOCTYPE = 'article'
  223 
  224   # The backend determines the format of the converted output, default to html5
  225   DEFAULT_BACKEND = 'html5'
  226 
  227   DEFAULT_STYLESHEET_KEYS = ['', 'DEFAULT'].to_set
  228 
  229   DEFAULT_STYLESHEET_NAME = 'asciidoctor.css'
  230 
  231   # Pointers to the preferred version for a given backend.
  232   BACKEND_ALIASES = {
  233     'html' => 'html5',
  234     'docbook' => 'docbook5'
  235   }
  236 
  237   # Default page widths for calculating absolute widths
  238   DEFAULT_PAGE_WIDTHS = {
  239     'docbook' => 425
  240   }
  241 
  242   # Default extensions for the respective base backends
  243   DEFAULT_EXTENSIONS = {
  244     'html' => '.html',
  245     'docbook' => '.xml',
  246     'pdf' => '.pdf',
  247     'epub' => '.epub',
  248     'manpage' => '.man',
  249     'asciidoc' => '.adoc'
  250   }
  251 
  252   # A map of file extensions that are recognized as AsciiDoc documents
  253   # TODO .txt should be deprecated
  254   ASCIIDOC_EXTENSIONS = {
  255     '.adoc' => true,
  256     '.asciidoc' => true,
  257     '.asc' => true,
  258     '.ad' => true,
  259     # TODO .txt should be deprecated
  260     '.txt' => true
  261   }
  262 
  263   SETEXT_SECTION_LEVELS = {
  264     '=' => 0,
  265     '-' => 1,
  266     '~' => 2,
  267     '^' => 3,
  268     '+' => 4
  269   }
  270 
  271   ADMONITION_STYLES = ['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION'].to_set
  272 
  273   ADMONITION_STYLE_HEADS = ::Set.new.tap {|accum| ADMONITION_STYLES.each {|s| accum << s.chr } }
  274 
  275   PARAGRAPH_STYLES = ['comment', 'example', 'literal', 'listing', 'normal', 'open', 'pass', 'quote', 'sidebar', 'source', 'verse', 'abstract', 'partintro'].to_set
  276 
  277   VERBATIM_STYLES = ['literal', 'listing', 'source', 'verse'].to_set
  278 
  279   DELIMITED_BLOCKS = {
  280     '--' => [:open, ['comment', 'example', 'literal', 'listing', 'pass', 'quote', 'sidebar', 'source', 'verse', 'admonition', 'abstract', 'partintro'].to_set],
  281     '----' => [:listing, ['literal', 'source'].to_set],
  282     '....' => [:literal, ['listing', 'source'].to_set],
  283     '====' => [:example, ['admonition'].to_set],
  284     '****' => [:sidebar, ::Set.new],
  285     '____' => [:quote, ['verse'].to_set],
  286     '++++' => [:pass, ['stem', 'latexmath', 'asciimath'].to_set],
  287     '|===' => [:table, ::Set.new],
  288     ',===' => [:table, ::Set.new],
  289     ':===' => [:table, ::Set.new],
  290     '!===' => [:table, ::Set.new],
  291     '////' => [:comment, ::Set.new],
  292     '```' => [:fenced_code, ::Set.new]
  293   }
  294 
  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_ATTR_NAMES = { example: 'example-caption', 'figure' => 'figure-caption', listing: 'listing-caption', table: 'table-caption' }
  300 
  301   LAYOUT_BREAK_CHARS = {
  302     '\'' => :thematic_break,
  303     '<' => :page_break
  304   }
  305 
  306   MARKDOWN_THEMATIC_BREAK_CHARS = {
  307     '-' => :thematic_break,
  308     '*' => :thematic_break,
  309     '_' => :thematic_break
  310   }
  311 
  312   HYBRID_LAYOUT_BREAK_CHARS = LAYOUT_BREAK_CHARS.merge MARKDOWN_THEMATIC_BREAK_CHARS
  313 
  314   #LIST_CONTEXTS = [:ulist, :olist, :dlist, :colist]
  315 
  316   NESTABLE_LIST_CONTEXTS = [:ulist, :olist, :dlist]
  317 
  318   # TODO validate use of explicit style name above ordered list (this list is for selecting an implicit style)
  319   ORDERED_LIST_STYLES = [:arabic, :loweralpha, :lowerroman, :upperalpha, :upperroman] #, :lowergreek]
  320 
  321   ORDERED_LIST_KEYWORDS = {
  322     #'arabic' => '1',
  323     #'decimal' => '1',
  324     'loweralpha' => 'a',
  325     'lowerroman' => 'i',
  326     #'lowergreek' => 'a',
  327     'upperalpha' => 'A',
  328     'upperroman' => 'I'
  329   }
  330 
  331   ATTR_REF_HEAD = '{'
  332 
  333   LIST_CONTINUATION = '+'
  334 
  335   # NOTE AsciiDoc Python allows + to be preceded by TAB; Asciidoctor does not
  336   HARD_LINE_BREAK = ' +'
  337 
  338   LINE_CONTINUATION = ' \\'
  339 
  340   LINE_CONTINUATION_LEGACY = ' +'
  341 
  342   BLOCK_MATH_DELIMITERS = {
  343     asciimath: ['\$', '\$'],
  344     latexmath: ['\[', '\]'],
  345   }
  346 
  347   INLINE_MATH_DELIMITERS = {
  348     asciimath: ['\$', '\$'],
  349     latexmath: ['\(', '\)'],
  350   }
  351 
  352   (STEM_TYPE_ALIASES = {
  353     'latexmath' => 'latexmath',
  354     'latex' => 'latexmath',
  355     'tex' => 'latexmath'
  356   }).default = 'asciimath'
  357 
  358   FONT_AWESOME_VERSION = '4.7.0'
  359 
  360   HIGHLIGHT_JS_VERSION = '9.15.6'
  361 
  362   MATHJAX_VERSION = '2.7.5'
  363 
  364   # attributes which be changed throughout the flow of the document (e.g., sectnums)
  365   FLEXIBLE_ATTRIBUTES = ['sectnums']
  366 
  367   INTRINSIC_ATTRIBUTES = {
  368     'startsb' => '[',
  369     'endsb' => ']',
  370     'vbar' => '|',
  371     'caret' => '^',
  372     'asterisk' => '*',
  373     'tilde' => '~',
  374     'plus' => '&#43;',
  375     'backslash' => '\\',
  376     'backtick' => '`',
  377     'blank' => '',
  378     'empty' => '',
  379     'sp' => ' ',
  380     'two-colons' => '::',
  381     'two-semicolons' => ';;',
  382     'nbsp' => '&#160;',
  383     'deg' => '&#176;',
  384     'zwsp' => '&#8203;',
  385     'quot' => '&#34;',
  386     'apos' => '&#39;',
  387     'lsquo' => '&#8216;',
  388     'rsquo' => '&#8217;',
  389     'ldquo' => '&#8220;',
  390     'rdquo' => '&#8221;',
  391     'wj' => '&#8288;',
  392     'brvbar' => '&#166;',
  393     'pp' => '&#43;&#43;',
  394     'cpp' => 'C&#43;&#43;',
  395     'amp' => '&',
  396     'lt' => '<',
  397     'gt' => '>'
  398   }
  399 
  400   # Regular expression character classes (to ensure regexp compatibility between Ruby and JavaScript)
  401   # CC stands for "character class", CG stands for "character class group"
  402   unless RUBY_ENGINE == 'opal'
  403     # CC_ALL is any character, including newlines (must be accompanied by multiline regexp flag)
  404     CC_ALL = '.'
  405     # CC_ANY is any character except newlines
  406     CC_ANY = '.'
  407     CC_EOL = '$'
  408     CC_ALPHA = CG_ALPHA = '\p{Alpha}'
  409     CC_ALNUM = CG_ALNUM = '\p{Alnum}'
  410     CG_BLANK = '\p{Blank}'
  411     CC_WORD = CG_WORD = '\p{Word}'
  412   end
  413 
  414   QUOTE_SUBS = {}.tap do |accum|
  415     # unconstrained quotes:: can appear anywhere
  416     # constrained quotes:: must be bordered by non-word characters
  417     # NOTE these substitutions are processed in the order they appear here and
  418     # the order in which they are replaced is important
  419     accum[false] = normal = [
  420       # **strong**
  421       [:strong, :unconstrained, /\\?(?:\[([^\]]+)\])?\*\*(#{CC_ALL}+?)\*\*/m],
  422       # *strong*
  423       [:strong, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?\*(\S|\S#{CC_ALL}*?\S)\*(?!#{CG_WORD})/m],
  424       # "`double-quoted`"
  425       [:double, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?"`(\S|\S#{CC_ALL}*?\S)`"(?!#{CG_WORD})/m],
  426       # '`single-quoted`'
  427       [:single, :constrained, /(^|[^#{CC_WORD};:`}])(?:\[([^\]]+)\])?'`(\S|\S#{CC_ALL}*?\S)`'(?!#{CG_WORD})/m],
  428       # ``monospaced``
  429       [:monospaced, :unconstrained, /\\?(?:\[([^\]]+)\])?``(#{CC_ALL}+?)``/m],
  430       # `monospaced`
  431       [:monospaced, :constrained, /(^|[^#{CC_WORD};:"'`}])(?:\[([^\]]+)\])?`(\S|\S#{CC_ALL}*?\S)`(?![#{CC_WORD}"'`])/m],
  432       # __emphasis__
  433       [:emphasis, :unconstrained, /\\?(?:\[([^\]]+)\])?__(#{CC_ALL}+?)__/m],
  434       # _emphasis_
  435       [:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?_(\S|\S#{CC_ALL}*?\S)_(?!#{CG_WORD})/m],
  436       # ##mark## (referred to in AsciiDoc Python as unquoted)
  437       [:mark, :unconstrained, /\\?(?:\[([^\]]+)\])?##(#{CC_ALL}+?)##/m],
  438       # #mark# (referred to in AsciiDoc Python as unquoted)
  439       [:mark, :constrained, /(^|[^#{CC_WORD}&;:}])(?:\[([^\]]+)\])?#(\S|\S#{CC_ALL}*?\S)#(?!#{CG_WORD})/m],
  440       # ^superscript^
  441       [:superscript, :unconstrained, /\\?(?:\[([^\]]+)\])?\^(\S+?)\^/],
  442       # ~subscript~
  443       [:subscript, :unconstrained, /\\?(?:\[([^\]]+)\])?~(\S+?)~/]
  444     ]
  445 
  446     accum[true] = compat = normal.drop 0
  447     # ``quoted''
  448     compat[2] = [:double, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?``(\S|\S#{CC_ALL}*?\S)''(?!#{CG_WORD})/m]
  449     # `quoted'
  450     compat[3] = [:single, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?`(\S|\S#{CC_ALL}*?\S)'(?!#{CG_WORD})/m]
  451     # ++monospaced++
  452     compat[4] = [:monospaced, :unconstrained, /\\?(?:\[([^\]]+)\])?\+\+(#{CC_ALL}+?)\+\+/m]
  453     # +monospaced+
  454     compat[5] = [:monospaced, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?\+(\S|\S#{CC_ALL}*?\S)\+(?!#{CG_WORD})/m]
  455     # #unquoted#
  456     #compat[8] = [:unquoted, *compat[8][1..-1]]
  457     # ##unquoted##
  458     #compat[9] = [:unquoted, *compat[9][1..-1]]
  459     # 'emphasis'
  460     compat.insert 3, [:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?'(\S|\S#{CC_ALL}*?\S)'(?!#{CG_WORD})/m]
  461   end
  462 
  463   # NOTE order of replacements is significant
  464   REPLACEMENTS = [
  465     # (C)
  466     [/\\?\(C\)/, '&#169;', :none],
  467     # (R)
  468     [/\\?\(R\)/, '&#174;', :none],
  469     # (TM)
  470     [/\\?\(TM\)/, '&#8482;', :none],
  471     # foo -- bar (where either space character can be a newline)
  472     # NOTE this necessarily drops the newline if replacement appears at end of line
  473     [/(?: |\n|^|\\)--(?: |\n|$)/, '&#8201;&#8212;&#8201;', :none],
  474     # foo--bar
  475     [/(#{CG_WORD})\\?--(?=#{CG_WORD})/, '&#8212;&#8203;', :leading],
  476     # ellipsis
  477     [/\\?\.\.\./, '&#8230;&#8203;', :none],
  478     # right single quote
  479     [/\\?`'/, '&#8217;', :none],
  480     # apostrophe (inside a word)
  481     [/(#{CG_ALNUM})\\?'(?=#{CG_ALPHA})/, '&#8217;', :leading],
  482     # right arrow ->
  483     [/\\?-&gt;/, '&#8594;', :none],
  484     # right double arrow =>
  485     [/\\?=&gt;/, '&#8658;', :none],
  486     # left arrow <-
  487     [/\\?&lt;-/, '&#8592;', :none],
  488     # left double arrow <=
  489     [/\\?&lt;=/, '&#8656;', :none],
  490     # restore entities
  491     [/\\?(&)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]
  492   ]
  493 
  494   # Internal: Automatically load the Asciidoctor::Extensions module.
  495   #
  496   # Requires the Asciidoctor::Extensions module if the name is :Extensions.
  497   # Otherwise, delegates to the super method.
  498   #
  499   # This method provides the same functionality as using autoload on
  500   # Asciidoctor::Extensions, except that the constant isn't recognized as
  501   # defined prior to it being loaded.
  502   #
  503   # Returns the resolved constant, if resolved, otherwise nothing.
  504   def self.const_missing name
  505     if name == :Extensions
  506       require_relative 'asciidoctor/extensions'
  507       Extensions
  508     else
  509       super
  510     end
  511   end unless RUBY_ENGINE == 'opal'
  512 
  513   unless RUBY_ENGINE == 'opal'
  514     autoload :SyntaxHighlighter, %(#{LIB_DIR}/asciidoctor/syntax_highlighter)
  515     autoload :Timings, %(#{LIB_DIR}/asciidoctor/timings)
  516   end
  517 end
  518 
  519 # core extensions
  520 require_relative 'asciidoctor/core_ext'
  521 
  522 # modules and helpers
  523 require_relative 'asciidoctor/helpers'
  524 require_relative 'asciidoctor/logging'
  525 require_relative 'asciidoctor/rx'
  526 require_relative 'asciidoctor/substitutors'
  527 require_relative 'asciidoctor/version'
  528 
  529 # abstract classes
  530 require_relative 'asciidoctor/abstract_node'
  531 require_relative 'asciidoctor/abstract_block'
  532 
  533 # concrete classes
  534 require_relative 'asciidoctor/attribute_list'
  535 require_relative 'asciidoctor/block'
  536 require_relative 'asciidoctor/callouts'
  537 require_relative 'asciidoctor/converter'
  538 require_relative 'asciidoctor/document'
  539 require_relative 'asciidoctor/inline'
  540 require_relative 'asciidoctor/list'
  541 require_relative 'asciidoctor/parser'
  542 require_relative 'asciidoctor/path_resolver'
  543 require_relative 'asciidoctor/reader'
  544 require_relative 'asciidoctor/section'
  545 require_relative 'asciidoctor/stylesheets'
  546 require_relative 'asciidoctor/table'
  547 require_relative 'asciidoctor/writer'
  548 
  549 # main API entry points
  550 require_relative 'asciidoctor/load'
  551 require_relative 'asciidoctor/convert'
  552 
  553 if RUBY_ENGINE == 'opal'
  554   require_relative 'asciidoctor/syntax_highlighter'
  555   require_relative 'asciidoctor/timings'
  556   # this require is satisfied by the Asciidoctor.js build; it supplies compile and runtime overrides for Asciidoctor.js
  557   require 'asciidoctor/js/postscript'
  558 end