lib/giblish/treeconverter.rb in giblish-2.0.0 vs lib/giblish/treeconverter.rb in giblish-2.0.1
- old
+ new
@@ -154,24 +154,24 @@
"source-highlighter" => "rouge",
"source-linenums-option" => true
}
# see https://docs.asciidoctor.org/asciidoctor/latest/api/options/
- DEFAULT_ADOC_OPTS = {
- backend: "html5",
+ DEFAULT_ADOC_API_OPTS = {
+ # backend: "html5",
# base_dir:
- catalog_assets: false,
+ # catalog_assets: false,
# converter:
- doctype: "article",
+ # doctype: "article",
# eruby:
# ignore extention stuff
- header_only: false,
+ # header_only: false,
# logger:
- mkdirs: false,
- parse: true,
+ # mkdirs: false,
+ # parse: true,
safe: :unsafe,
- sourcemap: false,
+ # sourcemap: false,
# template stuff TBD,
# to_file:
# to_dir:
standalone: true
}
@@ -190,18 +190,73 @@
@conv_cb = opts.fetch(:conversion_cb, {
success: ->(src, dst, dst_rel_path, doc, logstr) { TreeConverter.on_success(src, dst, dst_rel_path, doc, logstr) },
failure: ->(src, dst, dst_rel_path, ex, logstr) { TreeConverter.on_failure(src, dst, dst_rel_path, ex, logstr) }
})
- # merge user's options with the default, giving preference
- # to the user
- @adoc_api_opts = DEFAULT_ADOC_OPTS.dup
- .merge!(opts.fetch(:adoc_api_opts, {}))
- @adoc_api_opts[:attributes] = DEFAULT_ADOC_DOC_ATTRIBS.dup
- .merge!(opts.fetch(:adoc_doc_attribs, {}))
+ # cache external configuration
+ @config_opts = opts.dup
end
+ # Resolve the document attributes according to the precedence.
+ #
+ # According to https://docs.asciidoctor.org/asciidoc/latest/attributes/assignment-precedence/
+ # The attribute precedence is:
+ # 1. An attribute passed to the API or CLI whose value does not end in @
+ # 2. An attribute defined in the document
+ # 3. An attribute passed to the API or CLI whose value or name ends in @
+ # 4. The default value of the attribute, if applicable
+ #
+ # giblish adds the following rules:
+ # 1.5 An attribute defined in an attribute provider for a specific source node
+ # 3.5 The default value set by giblish, if applicable
+ def resolve_doc_attributes(doc_src, node_attr)
+ # rule 3.5
+ doc_attr = DEFAULT_ADOC_DOC_ATTRIBS.dup
+
+ # sort attribs into soft and hard (rule 1 and 3)
+ soft_attr = {}
+ hard_attr = {}
+ @config_opts.fetch(:adoc_doc_attribs, {}).each do |k, v|
+ ks = k.to_s.strip
+ vs = v.to_s.strip
+
+ if ks.end_with?("@")
+ soft_attr[ks[0..]] = vs
+ next
+ end
+ if vs.end_with?("@")
+ soft_attr[ks] = vs[0..]
+ next
+ end
+ hard_attr[ks] = vs
+ end
+
+ # rule 3.
+ doc_attr.merge!(soft_attr)
+
+ # rule 2
+ Giblish.process_header_lines(doc_src.lines) do |line|
+ a = /^:(.+):(.*)$/.match(line)
+ next unless a
+ @logger.debug { "got header attr from doc: #{a[1]} : #{a[2]}" }
+ doc_attr[a[1].strip] = a[2].strip
+ end
+
+ @logger.debug { "idprefix before: #{doc_attr["idprefix"]}" }
+
+ # rule 1.5
+ doc_attr.merge!(node_attr)
+
+ # rule 1.
+ doc_attr.merge!(hard_attr)
+
+ @logger.debug { "idprefix after: #{doc_attr["idprefix"]}" }
+
+ # @logger&.debug { "Header attribs: #{doc_attr}" }
+ doc_attr
+ end
+
# require the following methods to be available from the src node:
# adoc_source
#
# the following methods will be called if supported:
# document_attributes
@@ -214,50 +269,60 @@
# under which all converted files are written.
def convert(src_node, dst_node, dst_top)
@logger&.info { "Converting #{src_node.pathname} and store result under #{dst_node.parent.pathname}" }
# merge the common api opts with node specific
- api_opts = @adoc_api_opts.dup
+ api_opts = DEFAULT_ADOC_API_OPTS.dup
+ api_opts.merge!(@config_opts.fetch(:adoc_api_opts, {}))
api_opts.merge!(src_node.api_options(src_node, dst_node, dst_top)) if src_node.respond_to?(:api_options)
- api_opts[:attributes].merge!(src_node.document_attributes(src_node, dst_node, dst_top)) if src_node.respond_to?(:document_attributes)
# use a new logger instance for each conversion
adoc_logger = Giblish::AsciidoctorLogger.new(@logger, @adoc_log_level)
begin
- # load the source to enable access to doc properties
+ doc_src = src_node.adoc_source(src_node, dst_node, dst_top)
+
+ node_attr = src_node.respond_to?(:document_attributes) ?
+ src_node.document_attributes(src_node, dst_node, dst_top) : {}
+ doc_attr = resolve_doc_attributes(doc_src, node_attr)
+ # piggy-back our own info on the doc attributes hash so that
+ # asciidoctor extensions can use this info later on
+ doc_attr["giblish-info"] = {
+ src_node: src_node,
+ dst_node: dst_node,
+ dst_top: dst_top
+ }
+
+ # load the source to enable access to doc attributes and properties
#
- # NOTE: the 'parse: false' is needed to prevent preprocessor extensions to be run as part
+ # NOTE: 'parse' is set to false to prevent preprocessor extensions to be run as part
# of loading the document. We want them to run during the 'convert' call later when
# doc attribs have been amended.
- doc = Asciidoctor.load(src_node.adoc_source(src_node, dst_node, dst_top), api_opts.merge(
+ #
+ # NOTE2: by trial-and-error, it seems that some document attributes must be set when
+ # calling 'load' and not added after the call and before the 'convert' call to have
+ # the expected effect (e.g. idprefix).
+ doc = Asciidoctor.load(doc_src, api_opts.merge(
{
+ attributes: doc_attr,
parse: false,
logger: adoc_logger
}
))
- # piggy-back our own info on the doc attributes hash so that
- # asciidoctor extensions can use this info later on
- doc.attributes["giblish-info"] = {
- src_node: src_node,
- dst_node: dst_node,
- dst_top: dst_top
- }
-
# update the destination node with the correct file suffix. This is dependent
# on the type of conversion performed
dst_node.name = dst_node.name.sub_ext(doc.attributes["outfilesuffix"])
d = dst_node.pathname
# make sure the dst dir exists
d.dirname.mkpath
- # write the converted doc to the file
- output = doc.convert(api_opts.merge({logger: adoc_logger}))
+ # do the conversion and write the converted doc to file
+ output = doc.convert(api_opts)
doc.write(output, d.to_s)
- # give user the opportunity to eg store the result of the conversion
+ # give the user the opportunity to eg store the result of the conversion
# as data in the destination node
@conv_cb[:success]&.call(src_node, dst_node, dst_top, doc, adoc_logger.in_mem_storage.string)
true
rescue => ex
@logger&.error { "Conversion failed for #{src_node.pathname}" }