metanorma 2.0.0 → 2.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/.gitignore +3 -0
  4. data/.rubocop.yml +23 -2
  5. data/Gemfile +17 -0
  6. data/Gemfile.devel +10 -0
  7. data/README.adoc +1 -1
  8. data/lib/metanorma/collection/artifact_store.rb +142 -0
  9. data/lib/metanorma/collection/collection.rb +160 -122
  10. data/lib/metanorma/collection/config/bibdata.rb +3 -3
  11. data/lib/metanorma/collection/config/compile_options.rb +4 -5
  12. data/lib/metanorma/collection/config/config.rb +81 -83
  13. data/lib/metanorma/collection/config/converters.rb +92 -8
  14. data/lib/metanorma/collection/config/directive.rb +9 -3
  15. data/lib/metanorma/collection/config/doc_container.rb +28 -0
  16. data/lib/metanorma/collection/config/manifest.rb +59 -29
  17. data/lib/metanorma/collection/config/namespaces.rb +12 -0
  18. data/lib/metanorma/collection/document/document.rb +56 -15
  19. data/lib/metanorma/collection/filelookup/filelookup.rb +185 -77
  20. data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +99 -27
  21. data/lib/metanorma/collection/filelookup/utils.rb +52 -0
  22. data/lib/metanorma/collection/helpers.rb +82 -0
  23. data/lib/metanorma/collection/log.rb +24 -0
  24. data/lib/metanorma/collection/manifest/manifest.rb +45 -14
  25. data/lib/metanorma/collection/multilingual/multilingual.rb +660 -0
  26. data/lib/metanorma/collection/renderer/filelocation.rb +166 -0
  27. data/lib/metanorma/collection/renderer/fileparse.rb +135 -115
  28. data/lib/metanorma/collection/renderer/fileprocess.rb +185 -37
  29. data/lib/metanorma/collection/renderer/navigation.rb +21 -7
  30. data/lib/metanorma/collection/renderer/render_word.rb +15 -10
  31. data/lib/metanorma/collection/renderer/renderer.rb +236 -32
  32. data/lib/metanorma/collection/renderer/svg.rb +107 -0
  33. data/lib/metanorma/collection/renderer/utils.rb +110 -39
  34. data/lib/metanorma/collection/sectionsplit/collection.rb +110 -0
  35. data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +198 -115
  36. data/lib/metanorma/collection/util/disambig_files.rb +4 -5
  37. data/lib/metanorma/collection/util/util.rb +155 -18
  38. data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +47 -33
  39. data/lib/metanorma/compile/assets/icc-boilerplate.adoc +41 -0
  40. data/lib/metanorma/compile/compile.rb +181 -156
  41. data/lib/metanorma/compile/compile_options.rb +186 -79
  42. data/lib/metanorma/compile/extract.rb +75 -58
  43. data/lib/metanorma/compile/flavor.rb +28 -0
  44. data/lib/metanorma/compile/output_filename.rb +75 -0
  45. data/lib/metanorma/compile/output_filename_config.rb +27 -0
  46. data/lib/metanorma/compile/relaton_drop.rb +56 -0
  47. data/lib/metanorma/compile/render.rb +226 -0
  48. data/lib/metanorma/compile/validator.rb +26 -0
  49. data/lib/metanorma/compile/writeable.rb +12 -0
  50. data/lib/metanorma/util/fontist_helper.rb +35 -19
  51. data/lib/metanorma/version.rb +1 -1
  52. data/lib/metanorma.rb +1 -7
  53. data/metanorma.gemspec +15 -21
  54. data/plans/collection-rendering-architecture-review.md +516 -0
  55. metadata +65 -113
  56. data/.hound.yml +0 -5
  57. data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +0 -22
  58. data/lib/metanorma/asciidoctor_extensions.rb +0 -1
  59. data/lib/metanorma/compile/compile_validate.rb +0 -68
  60. data/lib/metanorma/config/config.rb +0 -23
  61. data/lib/metanorma/input/asciidoc.rb +0 -107
  62. data/lib/metanorma/input/base.rb +0 -9
  63. data/lib/metanorma/input.rb +0 -7
  64. data/lib/metanorma/processor/processor.rb +0 -54
  65. data/lib/metanorma/processor.rb +0 -6
  66. data/lib/metanorma/registry/registry.rb +0 -63
  67. data/lib/metanorma/shale_monkeypatch.rb +0 -15
  68. data/lib/metanorma/util/util.rb +0 -45
@@ -5,14 +5,15 @@ module Metanorma
5
5
  # xml.root["type"] = key # to force recognition of internal refs
6
6
  # bookmarks etc as new id elements introduced in Presentation XML:
7
7
  # add doc suffix
8
+ # Run on Semantic XML
8
9
  def xref_preprocess(xml, isodoc)
9
10
  @isodoc = isodoc
10
11
  key = (0...8).map { rand(65..90).chr }.join # random string
11
12
  xml.root["type"] = key
12
- Metanorma::Utils::anchor_attributes
13
- .each do |(tag_name, attribute_name)|
14
- ::Metanorma::Collection::Util::add_suffix_to_attributes(
15
- xml, xml.root["document_suffix"], tag_name, attribute_name, isodoc
13
+ Util::anchor_id_attributes.each do |(tag_name, attr_name)|
14
+ #tag_name == "xref" and tag_name = "fmt-xref"
15
+ ::Metanorma::Collection::Util::add_suffix_to_attrs(
16
+ xml, xml.root["document_suffix"], tag_name, attr_name, isodoc
16
17
  )
17
18
  end
18
19
  key
@@ -22,38 +23,39 @@ module Metanorma
22
23
  @isodoc.ns(xpath)
23
24
  end
24
25
 
25
- def xref_process(section, xml, key, ident, isodoc)
26
+ def xref_process(section, xml, key, ident, isodoc, presxml)
26
27
  @isodoc ||= isodoc
27
- svg_preprocess(section, Metanorma::Utils::to_ncname(ident))
28
- refs = eref_to_internal_eref(section, xml, key)
29
- refs += xref_to_internal_eref(section, xml, key)
28
+ svg_preprocess(section, Metanorma::Utils::to_ncname(ident), presxml)
29
+ refs = eref_to_internal_eref(section, xml, key, presxml)
30
+ refs += xref_to_internal_eref(section, xml, key, presxml)
30
31
  ins = new_hidden_ref(section)
31
32
  copied_refs = copy_repo_items_biblio(ins, section, xml)
32
33
  insert_indirect_biblio(ins, refs - copied_refs, key, xml)
33
34
  end
34
35
 
35
- def svg_preprocess(xml, doc_suffix)
36
+ def svg_preprocess(xml, doc_suffix, presxml)
36
37
  suffix = doc_suffix.nil? || doc_suffix.blank? ? "" : "_#{doc_suffix}"
37
38
  xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
38
- m = svgmap_wrap(s)
39
- svg_xrefs(s, m, suffix)
39
+ m = svgmap_wrap(s) or next
40
+ svg_xrefs(s, m, suffix, presxml)
40
41
  end
41
42
  xml
42
43
  end
43
44
 
44
45
  def svgmap_wrap(svg)
45
46
  ret = svg.at("./ancestor::xmlns:svgmap") and return ret
46
- ret = svg.at("./ancestor::xmlns:figure")
47
+ ret = svg.at("./ancestor::xmlns:figure") or return
47
48
  ret.wrap("<svgmap/>")
48
49
  svg.at("./ancestor::xmlns:svgmap")
49
50
  end
50
51
 
51
- def svg_xrefs(svg, svgmap, suffix)
52
+ def svg_xrefs(svg, svgmap, suffix, presxml)
53
+ tag = presxml ? "fmt-xref" : "xref"
52
54
  svg.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
53
55
  /^#/.match? a["href"] or next
54
56
  a["href"] = a["href"].sub(/^#/, "")
55
57
  svgmap << "<target href='#{a['href']}'>" \
56
- "<xref target='#{a['href']}#{suffix}'/></target>"
58
+ "<#{tag} target='#{a['href']}#{suffix}'/></target>"
57
59
  end
58
60
  end
59
61
 
@@ -65,15 +67,16 @@ module Metanorma
65
67
  "#{anchor}</referenceFrom></locality></localityStack>"
66
68
  end
67
69
 
68
- def xref_to_internal_eref(section, xml, key)
70
+ def xref_to_internal_eref(section, xml, key, presxml)
69
71
  key or return [] # no sectionsplit, no playing with xrefs
70
72
  bibitems, indirect = xref_to_internal_eref_prep(section, xml)
71
- section.xpath(ns("//xref")).each_with_object({}) do |x, m|
73
+ tag = presxml ? "fmt-xref" : "xref"
74
+ section.xpath(ns("//#{tag}")).each_with_object({}) do |x, m|
72
75
  xref_prefix_key(x, key, indirect)
73
76
  x["bibitemid"] = x["target"]
74
77
  m[x["bibitemid"]] = true
75
- xref_to_internal_eref_anchor(x, key, bibitems,
76
- xml.root["document_suffix"])
78
+ xref_to_internal_eref_anchor(x, bibitems,
79
+ xml.root["document_suffix"], presxml)
77
80
  end.keys
78
81
  end
79
82
 
@@ -84,8 +87,9 @@ module Metanorma
84
87
  [bibitems, indirect_bibitems]
85
88
  end
86
89
 
87
- def xref_to_internal_eref_anchor(xref, key, bibitems, document_suffix)
90
+ def xref_to_internal_eref_anchor(xref, bibitems, document_suffix, presxml)
88
91
  t = xref["target"]
92
+ key = xref["type"]
89
93
  if d = bibitems[t]&.at(ns("./docidentifier[@type = 'repository']"))
90
94
  m = %r{^([^/]+)}.match(d.text) and
91
95
  t.sub!(%r(#{m[0]}_), "")
@@ -93,7 +97,7 @@ module Metanorma
93
97
  key and t.sub!(%r{^#{key}_}, "")
94
98
  make_anchor(xref, t.sub(%r(_#{document_suffix}$), ""))
95
99
  xref.delete("target")
96
- xref.name = "eref"
100
+ xref.name = presxml ? "fmt-eref" : "eref"
97
101
  end
98
102
 
99
103
  def xref_prefix_key(xref, key, indirect)
@@ -106,30 +110,40 @@ module Metanorma
106
110
  end
107
111
  end
108
112
 
109
- def eref_to_internal_eref(section, xml, key)
110
- bibitems, indirect, bibids = eref_to_internal_eref_prep(section, xml)
111
- eref_to_internal_eref_select(section, xml, bibitems)
113
+ def select_citation_uri(bib, lang)
114
+ bib or return
115
+ url = bib.at(ns("./uri[@type = 'citation']" \
116
+ "[@language = '#{lang}']")) ||
117
+ bib.at(ns("./uri[@type = 'citation']"))
118
+ url&.text
119
+ end
120
+
121
+ def eref_to_internal_eref(section, xml, key, presxml)
122
+ bibitems, indirect, bibids, lang =
123
+ eref_to_internal_eref_prep(section, xml, presxml)
124
+ eref_to_internal_eref_select(section, xml, bibitems, presxml)
112
125
  .each_with_object([]) do |x, m|
113
- url = bibitems[x]&.at(ns("./uri[@type = 'citation']"))&.text
126
+ url = select_citation_uri(bibitems[x], lang)
114
127
  bibids[x]&.each do |e|
115
128
  e.at(ns("./localityStack | ./locality")) and next
116
- id = eref_to_internal_eref1(e, key, url, indirect) and m << id
129
+ id = eref_to_internal_eref1(e, key, url, indirect, presxml) and m << id
117
130
  end
118
131
  end
119
132
  end
120
133
 
121
- def eref_to_internal_eref_prep(section, xml)
134
+ def eref_to_internal_eref_prep(section, xml, presxml)
122
135
  bibitems = ::Metanorma::Collection::Util::gather_bibitems(xml)
123
136
  .delete_if { |_, v| internal_bib?(v) }
124
137
  indirect = ::Metanorma::Collection::Util::gather_bibitems(xml)
125
138
  .select { |_, v| indirect_bib?(v) }
126
- bibitemids = ::Metanorma::Collection::Util::gather_bibitemids(section)
127
- [bibitems, indirect, bibitemids]
139
+ bibitemids = ::Metanorma::Collection::Util::gather_bibitemids(section, presxml)
140
+ lang = xml.at(ns("//bibdata/language"))&.text || "en"
141
+ [bibitems, indirect, bibitemids, lang]
128
142
  end
129
143
 
130
- def eref_to_internal_eref1(elem, key, url, indirect)
144
+ def eref_to_internal_eref1(elem, key, url, indirect, presxml)
131
145
  if url
132
- elem.name = "link"
146
+ elem.name = presxml ? "fmt-link" : "link"
133
147
  elem["target"] = url
134
148
  nil
135
149
  elsif !indirect[elem["bibitemid"]]
@@ -152,8 +166,8 @@ module Metanorma
152
166
  elem["bibitemid"]
153
167
  end
154
168
 
155
- def eref_to_internal_eref_select(section, _xml, bibitems)
156
- refs = ::Metanorma::Collection::Util::gather_bibitemids(section).keys
169
+ def eref_to_internal_eref_select(section, _xml, bibitems, presxml)
170
+ refs = ::Metanorma::Collection::Util::gather_bibitemids(section, presxml).keys
157
171
  refs.uniq.reject do |x|
158
172
  b = bibitems[x] and (indirect_bib?(b) || internal_bib?(b))
159
173
  end
@@ -211,7 +225,7 @@ module Metanorma
211
225
 
212
226
  def new_indirect_bibitem(ident, prefix)
213
227
  <<~BIBENTRY
214
- <bibitem id="#{ident}" type="internal">
228
+ <bibitem id="#{ident}" anchor="#{ident}" type="internal">
215
229
  <docidentifier type="repository">#{ident.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
216
230
  </bibitem>
217
231
  BIBENTRY
@@ -0,0 +1,41 @@
1
+ == copyright-statement
2
+ === Copyright notice
3
+
4
+ Copyright © 1994-{{docyear}} International Color Consortium®
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+ the Specification and associated documentation files (the “Specification”) to
8
+ deal in the Specification without restriction, including without limitation the
9
+ rights to use, copy, modify, merge, publish, distribute, and/or sublicense
10
+ copies of the Specification, and to permit persons to whom the Specification is
11
+ furnished to do so, subject to the following conditions.
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Specification.
15
+
16
+ The Specification is provided "as is", without warranty of any kind, express,
17
+ implied, or otherwise, including but not limited to the warranties of
18
+ merchantability, fitness for a particular purpose and noninfringement. In no
19
+ event shall the International Color Consortium be liable for any claim, damages
20
+ or other liability, whether in an action of contract, tort or otherwise, arising
21
+ from, out of, or in connection with the Specification or the use or other
22
+ dealings in the Specification.
23
+
24
+ Except as contained in this notice, the name of the International Color
25
+ Consortium shall not be used in advertising or otherwise to promote the use or
26
+ other dealings in this Specification without prior written authorization from
27
+ the International Color Consortium.
28
+
29
+ == license-statement
30
+ === Licenses and trademarks
31
+
32
+ International Color Consortium and the ICC logo are registered trademarks of the
33
+ International Color Consortium. Rather than put a trademark symbol in every
34
+ occurrence of other trademarked names, we state that we are using the names only
35
+ in an editorial fashion, and to the benefit of the trademark owner, with no
36
+ intention of infringement of the trademark.
37
+
38
+ == feedback-statement
39
+ === For additional information on the ICC
40
+
41
+ Visit the ICC Web site: http://www.color.org
@@ -1,21 +1,38 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "fileutils"
2
4
  require "nokogiri"
3
5
  require "htmlentities"
4
6
  require "yaml"
5
7
  require "fontist"
6
- require "fontist/manifest/install"
7
- require_relative "compile_validate"
8
+ require "fontist/manifest"
9
+ require "metanorma-taste"
10
+ require_relative "writeable"
11
+ require_relative "validator"
8
12
  require_relative "compile_options"
9
13
  require_relative "../util/fontist_helper"
10
- require_relative "../util/util"
14
+ require "metanorma-core"
11
15
  require_relative "extract"
12
16
  require_relative "../collection/sectionsplit/sectionsplit"
13
17
  require_relative "../util/worker_pool"
18
+ require_relative "output_filename"
19
+ require_relative "output_filename_config"
20
+ require_relative "flavor"
21
+ require_relative "relaton_drop"
22
+ require_relative "render"
14
23
 
15
24
  module Metanorma
16
25
  class Compile
26
+ include Validator
27
+ include CompileOptions
28
+ include Flavor
29
+ include Writeable
30
+
31
+ DEFAULT_NUM_WORKERS = 3
32
+
17
33
  # @return [Array<String>]
18
- attr_reader :errors, :processor
34
+ attr_reader :errors
35
+ attr_reader :processor
19
36
 
20
37
  def initialize
21
38
  @registry = Metanorma::Registry.instance
@@ -25,21 +42,43 @@ module Metanorma
25
42
  @log = Metanorma::Utils::Log.new
26
43
  end
27
44
 
45
+ # Main compile method that orchestrates the document conversion process
46
+ # @param filename [String] path to the input file
47
+ # @param options [Hash] compilation options
28
48
  def compile(filename, options = {})
29
- options_process(filename, options)
49
+ process_options!(filename, options)
30
50
  @processor = @registry.find_processor(options[:type].to_sym)
31
- extensions = get_extensions(options) or return nil
32
- (file, isodoc = process_input(filename, options)) or return nil
33
- relaton_export(isodoc, options)
34
- extract(isodoc, options[:extract], options[:extract_type])
35
- process_exts(filename, extensions, file, isodoc, options)
51
+
52
+ # Step 1: Generate Semantic XML
53
+ semantic_result = generate_semantic_xml(filename, options) or return nil
54
+ source_file, semantic_xml = semantic_result
55
+
56
+ # Step 2: Prepare output paths
57
+ xml = Nokogiri::XML(semantic_xml, &:huge)
58
+ bibdata = extract_relaton_metadata(xml)
59
+ output_paths = prepare_output_paths(filename, bibdata, options)
60
+
61
+ # Step 3: Determine which output formats to generate
62
+ extensions = get_extensions(options)
63
+ @extensions = extensions # Capture extensions for later access
64
+ extensions or return nil
65
+
66
+ # Step 4: Extract information from Semantic XML if requested
67
+ extract_information(semantic_xml, bibdata, options)
68
+
69
+ # Step 5: Generate output formats from Semantic XML
70
+ generate_outputs(
71
+ source_file, semantic_xml, bibdata, extensions, output_paths,
72
+ options
73
+ )
74
+ ensure
36
75
  clean_exit(options)
37
76
  end
38
77
 
39
- def options_process(filename, options)
78
+ def process_options!(filename, options)
40
79
  require_libraries(options)
41
- options = options_extract(filename, options)
42
- validate_options(options)
80
+ options = extract_options(filename, options)
81
+ validate_options!(options)
43
82
  @log.save_to(filename, options[:output_dir])
44
83
  options[:log] = @log
45
84
  end
@@ -49,7 +88,11 @@ module Metanorma
49
88
  @log.write
50
89
  end
51
90
 
52
- def process_input(filename, options)
91
+ # Step 1: Generate Semantic XML from input file
92
+ # @param filename [String] input file path
93
+ # @param options [Hash] compilation options
94
+ # @return [Array, nil] tuple of [source_file, semantic_xml] or nil on failure
95
+ def generate_semantic_xml(filename, options)
53
96
  case extname = File.extname(filename)
54
97
  when ".adoc" then process_input_adoc(filename, options)
55
98
  when ".xml" then process_input_xml(filename, options)
@@ -60,175 +103,157 @@ module Metanorma
60
103
  end
61
104
  end
62
105
 
63
- def process_input_adoc(filename, options)
64
- Util.log("[metanorma] Processing: AsciiDoc input.", :info)
65
- file = read_file(filename)
66
- options[:asciimath] and
67
- file.sub!(/^(=[^\n]+\n)/, "\\1:mn-keep-asciimath:\n")
68
- dir = File.dirname(filename)
69
- dir != "." and
70
- file = file.gsub(/^include::/, "include::#{dir}/")
71
- .gsub(/^embed::/, "embed::#{dir}/")
72
- [file, @processor.input_to_isodoc(file, filename, options)]
106
+ # Step 2: Prepare output paths for generated files
107
+ # Use default filename template if empty string is provided.
108
+ #
109
+ # @param filename [String] input file path
110
+ # @param bibdata [Nokogiri::XML::Element] the bibliographic data element
111
+ # @param options [Hash] compilation options
112
+ # @return [Hash] paths for different output formats
113
+ def prepare_output_paths(filename, bibdata, options)
114
+ basename = if options[:filename_template].nil?
115
+ filename.sub(/\.[^.]+$/, "")
116
+ else
117
+ drop = RelatonDrop.new(bibdata)
118
+ config = OutputFilenameConfig.new(options[:filename_template])
119
+ config.generate_filename(drop)
120
+ end
121
+ @output_filename = OutputFilename.new(
122
+ basename, options[:output_dir], @processor
123
+ )
124
+ {
125
+ xml: @output_filename.semantic_xml,
126
+ orig_filename: filename,
127
+ presentationxml: @output_filename.presentation_xml,
128
+ }
73
129
  end
74
130
 
75
- def process_input_xml(filename, _options)
76
- Util.log("[metanorma] Processing: Metanorma XML input.", :info)
77
- # TODO NN: this is a hack -- we should provide/bridge the
78
- # document attributes in Metanorma XML
79
- ["", read_file(filename)]
131
+ # Step 4: Extract information from Semantic XML
132
+ # @param semantic_xml [String] semantic XML content
133
+ # @param options [Hash] compilation options
134
+ def extract_information(semantic_xml, bibdata, options)
135
+ # Extract Relaton bibliographic data
136
+ export_relaton_from_bibdata(bibdata, options) if options[:relaton]
137
+ # Extract other components (sourcecode, images, requirements)
138
+ if options[:extract]
139
+ Extract.extract(
140
+ semantic_xml, options[:extract], options[:extract_type]
141
+ )
142
+ end
80
143
  end
81
144
 
82
- def read_file(filename)
83
- File.read(filename, encoding: "utf-8").gsub("\r\n", "\n")
145
+ # Step 5: Generate output formats from Semantic XML
146
+ # @param source_file [String] source file content
147
+ # @param semantic_xml [String] semantic XML content
148
+ # @param bibdata [Nokogiri::XML::Element] the bibliographic data element
149
+ # @param extensions [Array<Symbol>] output formats to generate
150
+ # @param output_paths [Hash] paths for output files
151
+ # @param options [Hash] compilation options
152
+ def generate_outputs(
153
+ source_file, semantic_xml, bibdata, extensions, output_paths, options
154
+ )
155
+ if extensions == %i(presentation)
156
+ # Just generate presentation XML
157
+ generate_presentation_xml(
158
+ source_file, semantic_xml, bibdata, output_paths, options
159
+ )
160
+ else
161
+ # Generate multiple output formats with parallel processing
162
+ generate_outputs_parallel(
163
+ source_file, semantic_xml, bibdata, extensions, output_paths, options
164
+ )
165
+ end
84
166
  end
85
167
 
86
- def relaton_export(isodoc, options)
87
- return unless options[:relaton]
88
-
89
- xml = Nokogiri::XML(isodoc, &:huge)
90
- bibdata = xml.at("//bibdata") || xml.at("//xmlns:bibdata")
91
- # docid = bibdata&.at("./xmlns:docidentifier")&.text || options[:filename]
92
- # outname = docid.sub(/^\s+/, "").sub(/\s+$/, "").gsub(/\s+/, "-") + ".xml"
93
- File.open(options[:relaton], "w:UTF-8") { |f| f.write bibdata.to_xml }
168
+ def process_input_adoc_hdr(file, options)
169
+ hdr, rest = Metanorma::Input::Asciidoc.new.header(file)
170
+ attrs = hdr.split("\n")
171
+ options[:asciimath] and attrs << ":mn-keep-asciimath:"
172
+ process_input_adoc_overrides(attrs, options)
173
+ "#{attrs.join("\n")}\n\n#{rest}"
94
174
  end
95
175
 
96
- def export_output(fname, content, **options)
97
- mode = options[:binary] ? "wb" : "w:UTF-8"
98
- File.open(fname, mode) { |f| f.write content }
176
+ def process_input_adoc_overrides(attrs, options)
177
+ Metanorma::TasteRegister.instance.available_tastes
178
+ .include?(options[:supplied_type]) or return
179
+ c = Metanorma::TasteRegister.get(options[:supplied_type])
180
+ c.process_input_adoc_overrides(attrs, options)
99
181
  end
100
182
 
101
- def wrap_html(options, file_extension, outfilename)
102
- if options[:wrapper] && /html$/.match(file_extension)
103
- outfilename = outfilename.sub(/\.html$/, "")
104
- FileUtils.mkdir_p outfilename
105
- FileUtils.mv "#{outfilename}.html", outfilename
106
- FileUtils.mv "#{outfilename}_images", outfilename, force: true
107
- end
183
+ def process_input_adoc_includes(file, filename)
184
+ dir = File.dirname(filename)
185
+ dir != "." and
186
+ file = file.gsub(/^include::/, "include::#{dir}/")
187
+ .gsub(/^embed::/, "embed::#{dir}/")
188
+ file
108
189
  end
109
190
 
110
- # isodoc is Raw Metanorma XML
111
- def process_exts(filename, extensions, file, isodoc, options)
112
- f = File.expand_path(change_output_dir(options))
113
- fnames = { xml: f.sub(/\.[^.]+$/, ".xml"), f: f,
114
- orig_filename: File.expand_path(filename),
115
- presentationxml: f.sub(/\.[^.]+$/, ".presentation.xml") }
116
- @queue = ::Metanorma::Util::WorkersPool
117
- .new(ENV["METANORMA_PARALLEL"]&.to_i || 3)
118
- gather_and_install_fonts(file, options.dup, extensions)
119
- process_exts_run(fnames, file, isodoc, extensions, options)
120
- @queue.shutdown
191
+ def process_input_adoc(filename, options)
192
+ Util.log("[metanorma] Processing: AsciiDoc input.", :info)
193
+ file = read_file(filename)
194
+ file = process_input_adoc_hdr(file, options)
195
+ file = process_input_adoc_includes(file, filename)
196
+ update_options_after_preprocessing(file, options)
197
+ [file, @processor.input_to_isodoc(file, filename, options)]
121
198
  end
122
199
 
123
- def process_exts_run(fnames, file, isodoc, extensions, options)
124
- Util.sort_extensions_execution(extensions).each do |ext|
125
- process_ext(ext, file, isodoc, fnames, options) or break
200
+ # need to update options, for any content added;
201
+ # e.g. new attributes from Metanorma taste
202
+ def update_options_after_preprocessing(file, options)
203
+ new_options = { extension_keys: options[:extension_keys] }
204
+ Tempfile.open(["tmp", ".adoc"], encoding: "UTF-8") do |f|
205
+ f.write(file)
206
+ f.close
207
+ new_options = extract_options(f, new_options)
126
208
  end
209
+ new_options.compact!
210
+ new_options.delete(:filename)
211
+ options.merge!(new_options)
127
212
  end
128
213
 
129
- def gather_and_install_fonts(file, options, extensions)
130
- Util.sort_extensions_execution(extensions).each do |ext|
131
- isodoc_options = get_isodoc_options(file, options, ext)
132
- font_install(isodoc_options.merge(options))
133
- end
214
+ def process_input_xml(filename, _options)
215
+ Util.log("[metanorma] Processing: Metanorma XML input.", :info)
216
+ # TODO NN: this is a hack -- we should provide/bridge the
217
+ # document attributes in Metanorma XML
218
+ ["", read_file(filename)]
134
219
  end
135
220
 
136
- def process_ext(ext, file, isodoc, fnames, options)
137
- fnames[:ext] = @processor.output_formats[ext]
138
- fnames[:out] = fnames[:f].sub(/\.[^.]+$/, ".#{fnames[:ext]}")
139
- isodoc_options = get_isodoc_options(file, options, ext)
140
- thread = true
141
- unless process_ext_simple(ext, isodoc, fnames, options,
142
- isodoc_options)
143
- thread = process_exts1(ext, fnames, isodoc, options, isodoc_options)
144
- end
145
- thread
146
- end
147
-
148
- def process_ext_simple(ext, isodoc, fnames, options, isodoc_options)
149
- if ext == :rxl
150
- relaton_export(isodoc, options.merge(relaton: fnames[:out]))
151
- elsif options[:passthrough_presentation_xml] && ext == :presentation
152
- f = File.exist?(fnames[:f]) ? fnames[:f] : fnames[:orig_filename]
153
- FileUtils.cp f, fnames[:presentationxml]
154
- elsif ext == :html && options[:sectionsplit]
155
- sectionsplit_convert(fnames[:xml], isodoc, fnames[:out],
156
- isodoc_options)
157
- else return false
158
- end
159
- true
221
+ def read_file(filename)
222
+ File.read(filename, encoding: "utf-8").gsub("\r\n", "\n")
160
223
  end
161
224
 
162
- def process_exts1(ext, fnames, isodoc, options, isodoc_options)
163
- if @processor.use_presentation_xml(ext)
164
- @queue.schedule(ext, fnames.dup, options.dup,
165
- isodoc_options.dup) do |a, b, c, d|
166
- process_output_threaded(a, b, c, d)
225
+ # Returns a mapping of format types to file suffixes based on the
226
+ # extensions that were determined during compilation.
227
+ # This method is only available after compile() has been called and
228
+ # reached Step 3 where extensions are finalized.
229
+ #
230
+ # @return [Hash] mapping of format symbols to file extensions
231
+ # e.g., { html: "html", doc: "doc", pdf: "pdf" }
232
+ # @return [Hash] empty hash if extensions haven't been captured yet
233
+ def output_format_mapping
234
+ @extensions && @processor or return {}
235
+ @extensions.each_with_object({}) do |ext, mapping|
236
+ if @processor.output_formats[ext]
237
+ mapping[ext] = @processor.output_formats[ext]
167
238
  end
168
- else
169
- process_output_unthreaded(ext, fnames, isodoc, isodoc_options)
170
239
  end
171
240
  end
172
241
 
173
- def process_output_threaded(ext, fnames1, options1, isodoc_options1)
174
- @processor.output(nil, fnames1[:presentationxml], fnames1[:out], ext,
175
- isodoc_options1)
176
- wrap_html(options1, fnames1[:ext], fnames1[:out])
177
- rescue StandardError => e
178
- strict = ext == :presentation || isodoc_options1[:strict] == true
179
- isodoc_error_process(e, strict, false)
180
- end
181
-
182
- def process_output_unthreaded(ext, fnames, isodoc, isodoc_options)
183
- @processor.output(isodoc, fnames[:xml], fnames[:out], ext,
184
- isodoc_options)
185
- true # return as Thread
186
- rescue StandardError => e
187
- strict = ext == :presentation || isodoc_options[:strict] == "true"
188
- isodoc_error_process(e, strict, true)
189
- ext != :presentation
190
- end
191
-
192
- # assume we pass in Presentation XML, but we want to recover Semantic XML
193
- def sectionsplit_convert(input_filename, file, output_filename = nil,
194
- opts = {})
195
- @isodoc ||= IsoDoc::PresentationXMLConvert.new({})
196
- input_filename += ".xml" unless input_filename.match?(/\.xml$/)
197
- File.exist?(input_filename) or
198
- File.open(input_filename, "w:UTF-8") { |f| f.write(file) }
199
- presxml = File.read(input_filename, encoding: "utf-8")
200
- _xml, filename, dir = @isodoc.convert_init(presxml, input_filename, false)
201
-
202
- ::Metanorma::Collection::Sectionsplit.new(
203
- input: input_filename,
204
- isodoc: @isodoc,
205
- xml: presxml,
206
- base: File.basename(output_filename || filename),
207
- output: output_filename || filename,
208
- dir: dir,
209
- compile_opts: opts,
210
- ).build_collection
211
- end
212
-
213
- private
214
-
215
- def isodoc_error_process(err, strict, must_abort)
216
- if strict || err.message.include?("Fatal:")
217
- @errors << err.message
218
- else
219
- puts err.message
220
- end
221
- puts err.backtrace.join("\n")
222
- must_abort and 1
242
+ def process_compile_dummy(flavor)
243
+ file = Tempfile.new(%w(tmp .adoc))
244
+ file.write <<~OUTPUT
245
+ Document Title
246
+ :flavor: #{flavor}
247
+ :mn-output-extensions: xml, presentation
248
+
249
+ OUTPUT
250
+ file.close
251
+ compile(file.path, agree_to_terms: true)
223
252
  end
224
253
 
225
- # @param options [Hash]
226
- # @return [String]
227
- def change_output_dir(options)
228
- if options[:output_dir]
229
- File.join options[:output_dir], File.basename(options[:filename])
230
- else options[:filename]
231
- end
254
+ def extract_log_messages(flavor)
255
+ process_compile_dummy(flavor)
256
+ @log.display_messages
232
257
  end
233
258
  end
234
259
  end