metanorma 1.7.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -1
  3. data/lib/metanorma/array_monkeypatch.rb +9 -0
  4. data/lib/metanorma/asciidoctor_extensions/glob_include_processor.rb +13 -11
  5. data/lib/metanorma/collection/collection.rb +225 -0
  6. data/lib/metanorma/collection/config/bibdata.rb +12 -0
  7. data/lib/metanorma/collection/config/compile_options.rb +13 -0
  8. data/lib/metanorma/collection/config/config.rb +163 -0
  9. data/lib/metanorma/collection/config/converters.rb +30 -0
  10. data/lib/metanorma/collection/config/directive.rb +10 -0
  11. data/lib/metanorma/collection/config/manifest.rb +88 -0
  12. data/lib/metanorma/collection/document/document.rb +133 -0
  13. data/lib/metanorma/collection/filelookup/filelookup.rb +250 -0
  14. data/lib/metanorma/collection/filelookup/filelookup_sectionsplit.rb +87 -0
  15. data/lib/metanorma/collection/manifest/manifest.rb +237 -0
  16. data/lib/metanorma/collection/renderer/fileparse.rb +247 -0
  17. data/lib/metanorma/collection/renderer/fileprocess.rb +173 -0
  18. data/lib/metanorma/collection/renderer/navigation.rb +133 -0
  19. data/lib/metanorma/collection/renderer/render_word.rb +133 -0
  20. data/lib/metanorma/collection/renderer/renderer.rb +157 -0
  21. data/lib/metanorma/collection/renderer/utils.rb +183 -0
  22. data/lib/metanorma/collection/sectionsplit/sectionsplit.rb +218 -0
  23. data/lib/metanorma/collection/util/disambig_files.rb +37 -0
  24. data/lib/metanorma/collection/util/util.rb +72 -0
  25. data/lib/metanorma/collection/xrefprocess/xrefprocess.rb +222 -0
  26. data/lib/metanorma/{compile.rb → compile/compile.rb} +17 -11
  27. data/lib/metanorma/{compile_options.rb → compile/compile_options.rb} +9 -5
  28. data/lib/metanorma/{compile_validate.rb → compile/compile_validate.rb} +1 -1
  29. data/lib/metanorma/{extract.rb → compile/extract.rb} +2 -2
  30. data/lib/metanorma/{config.rb → config/config.rb} +1 -1
  31. data/lib/metanorma/input/asciidoc.rb +3 -3
  32. data/lib/metanorma/input/base.rb +1 -5
  33. data/lib/metanorma/processor/processor.rb +54 -0
  34. data/lib/metanorma/processor.rb +1 -49
  35. data/lib/metanorma/{registry.rb → registry/registry.rb} +0 -1
  36. data/lib/metanorma/shale_monkeypatch.rb +15 -0
  37. data/lib/metanorma/util/fontist_helper.rb +130 -0
  38. data/lib/metanorma/util/util.rb +45 -0
  39. data/lib/metanorma/util/worker_pool.rb +39 -0
  40. data/lib/metanorma/version.rb +1 -1
  41. data/lib/metanorma.rb +13 -8
  42. data/metanorma.gemspec +2 -1
  43. metadata +50 -24
  44. data/lib/metanorma/collection.rb +0 -244
  45. data/lib/metanorma/collection_fileparse.rb +0 -257
  46. data/lib/metanorma/collection_fileprocess.rb +0 -168
  47. data/lib/metanorma/collection_manifest.rb +0 -168
  48. data/lib/metanorma/collection_render_utils.rb +0 -169
  49. data/lib/metanorma/collection_render_word.rb +0 -131
  50. data/lib/metanorma/collection_renderer.rb +0 -237
  51. data/lib/metanorma/collection_xref_process.rb +0 -217
  52. data/lib/metanorma/document.rb +0 -133
  53. data/lib/metanorma/files_lookup.rb +0 -224
  54. data/lib/metanorma/files_lookup_sectionsplit.rb +0 -84
  55. data/lib/metanorma/fontist_utils.rb +0 -122
  56. data/lib/metanorma/sectionsplit.rb +0 -216
  57. data/lib/metanorma/util.rb +0 -127
  58. data/lib/metanorma/worker_pool.rb +0 -29
@@ -1,122 +0,0 @@
1
- module Metanorma
2
- class FontistUtils
3
- class << self
4
- private
5
-
6
- def validate_options(options)
7
- agree_to_terms = options[:agree_to_terms] || false
8
- continue_without_fonts = options[:continue_without_fonts] || false
9
- no_progress = options[:no_progress] || false
10
-
11
- [agree_to_terms, continue_without_fonts, no_progress]
12
- end
13
-
14
- def validate_install_fonts(processor, options)
15
- if options[:no_install_fonts]
16
- Util.log("[fontist] Skip font installation because" \
17
- " --no-install-fonts argument passed", :debug)
18
- return false
19
- elsif !has_custom_fonts?(processor, options, options)
20
- Util.log("[fontist] Skip font installation because "\
21
- "fonts_manifest is missing", :debug)
22
- return false
23
- end
24
- true
25
- end
26
-
27
- def install_fonts_safe(manifest, agree, continue, no_progress)
28
- fontist_install(manifest, agree, no_progress)
29
- rescue Fontist::Errors::LicensingError
30
- license_error_log(continue)
31
- rescue Fontist::Errors::FontError => e
32
- log_level = continue ? :warning : :fatal
33
- Util.log("[fontist] '#{e.font}' font is not supported. " \
34
- "Please report this issue at github.com/metanorma/metanorma" \
35
- "/issues to report this issue.", log_level)
36
- rescue Fontist::Errors::FormulaIndexNotFoundError
37
- fintist_update_repo(manifest, agree, continue, no_progress)
38
- end
39
-
40
- def fontist_install(manifest, agree, no_progress)
41
- if agree
42
- no_license_log
43
- else
44
- Fontist.log_level = :info
45
- end
46
-
47
- Fontist::Manifest::Install.from_hash(
48
- manifest,
49
- confirmation: agree ? "yes" : "no",
50
- no_progress: no_progress,
51
- )
52
- end
53
-
54
- def license_error_log(continue)
55
- if continue
56
- Util.log(
57
- "[fontist] Processing will continue without fonts installed",
58
- :debug,
59
- )
60
- else
61
- Util.log("[fontist] Aborting without proper fonts installed," \
62
- " make sure that you have set option --agree-to-terms",
63
- :fatal)
64
- end
65
- end
66
-
67
- def no_license_log
68
- Util.log(
69
- "[fontist] Font licenses are not shown with --agree-to-terms option.",
70
- :info,
71
- )
72
- end
73
-
74
- def fintist_update_repo(manifest, agree, continue, no_progress)
75
- if @@updated_formulas_repo
76
- Util.log(
77
- "[fontist] Bug: formula index not found after 'fontist update'",
78
- :fatal,
79
- )
80
- end
81
- Util.log("[fontist] Missing formula index. Fetching it...", :debug)
82
- Fontist::Formula.update_formulas_repo
83
- @@updated_formulas_repo = true
84
- install_fonts_safe(manifest, agree, continue, no_progress)
85
- end
86
- end
87
-
88
- def self.install_fonts(processor, options)
89
- return unless validate_install_fonts(processor, options)
90
-
91
- @@updated_formulas_repo = false
92
- manifest = processor.fonts_manifest.dup
93
- append_source_fonts(manifest, options)
94
- agree_to_terms, can_without_fonts, no_progress = validate_options(options)
95
-
96
- install_fonts_safe(
97
- manifest,
98
- agree_to_terms,
99
- can_without_fonts,
100
- no_progress,
101
- )
102
- end
103
-
104
- def self.has_custom_fonts?(processor, options, source_attributes)
105
- !options[:no_install_fonts] \
106
- && processor.respond_to?(:fonts_manifest) \
107
- && !processor.fonts_manifest.nil? \
108
- || source_attributes[:fonts]
109
- end
110
-
111
- def self.location_manifest(processor, source_attributes)
112
- Fontist::Manifest::Locations.from_hash(
113
- append_source_fonts(processor.fonts_manifest.dup, source_attributes),
114
- )
115
- end
116
-
117
- def self.append_source_fonts(manifest, source_attributes)
118
- source_attributes[:fonts]&.split(";")&.each { |f| manifest[f] = nil }
119
- manifest
120
- end
121
- end
122
- end
@@ -1,216 +0,0 @@
1
- require "yaml"
2
- require_relative "util"
3
- require_relative "collection_xref_process"
4
-
5
- module Metanorma
6
- class Sectionsplit
7
- attr_accessor :filecache, :key
8
-
9
- def initialize(opts)
10
- @input_filename = opts[:input]
11
- @base = opts[:base]
12
- @output_filename = opts[:output]
13
- @xml = opts[:xml]
14
- @dir = opts[:dir]
15
- @compile_opts = opts[:compile_opts] || {}
16
- @fileslookup = opts[:fileslookup]
17
- @ident = opts[:ident]
18
- @isodoc = opts[:isodoc]
19
- end
20
-
21
- def ns(xpath)
22
- @isodoc.ns(xpath)
23
- end
24
-
25
- def build_collection
26
- collection_setup(@base, @dir)
27
- files = sectionsplit # (@input_filename, @base, @dir, @compile_opts)
28
- input_xml = Nokogiri::XML(File.read(@input_filename,
29
- encoding: "UTF-8"), &:huge)
30
- collection_manifest(@base, files, input_xml, @xml, @dir).render(
31
- { format: %i(html), output_folder: "#{@output_filename}_collection",
32
- coverpage: File.join(@dir, "cover.html") }.merge(@compile_opts),
33
- )
34
- end
35
-
36
- def collection_manifest(filename, files, origxml, _presxml, dir)
37
- File.open(File.join(dir, "#{filename}.html.yaml"), "w:UTF-8") do |f|
38
- f.write(collectionyaml(files, origxml))
39
- end
40
- Metanorma::Collection.parse File.join(dir, "#{filename}.html.yaml")
41
- end
42
-
43
- def collection_setup(filename, dir)
44
- FileUtils.mkdir_p "#{filename}_collection" if filename
45
- FileUtils.mkdir_p dir
46
- File.open(File.join(dir, "cover.html"), "w:UTF-8") do |f|
47
- f.write(coll_cover)
48
- end
49
- end
50
-
51
- def coll_cover
52
- <<~COVER
53
- <html><head><meta charset="UTF-8"/></head><body>
54
- <h1>{{ doctitle }}</h1>
55
- <h2>{{ docnumber }}</h2>
56
- <nav>{{ navigation }}</nav>
57
- </body></html>
58
- COVER
59
- end
60
-
61
- SPLITSECTIONS =
62
- [["//preface/*", "preface"], ["//sections/*", "sections"],
63
- ["//annex", nil],
64
- ["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
65
- ["//indexsect", nil], ["//colophon", nil]].freeze
66
-
67
- # Input XML is Semantic
68
- # def sectionsplit(filename, basename, dir, compile_options, fileslookup = nil, ident = nil)
69
- def sectionsplit
70
- xml = sectionsplit_prep(File.read(@input_filename), @base, @dir)
71
- @key = Metanorma::XrefProcess::xref_preprocess(xml, @isodoc)
72
- SPLITSECTIONS.each_with_object([]) do |n, ret|
73
- conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
74
- ret << sectionfile(xml, emptydoc(xml), "#{@base}.#{ret.size}", s,
75
- n[1])
76
- end
77
- end
78
- end
79
-
80
- def block?(node)
81
- %w(p table formula admonition ol ul dl figure quote sourcecode example
82
- pre note pagebrreak hr bookmark requirement recommendation permission
83
- svgmap inputform toc passthrough review imagemap).include?(node.name)
84
- end
85
-
86
- def conflate_floatingtitles(nodes)
87
- holdover = false
88
- nodes.each_with_object([]) do |x, m|
89
- if holdover then m.last << x
90
- else m << [x]
91
- end
92
- holdover = block?(x)
93
- end
94
- end
95
-
96
- def sectionsplit_prep(file, filename, dir)
97
- @splitdir = dir
98
- xml1filename, type = sectionsplit_preprocess_semxml(file, filename)
99
- Compile.new.compile(
100
- xml1filename,
101
- { format: :asciidoc, extension_keys: [:presentation], type: type }
102
- .merge(@compile_opts),
103
- )
104
- Nokogiri::XML(File.read(xml1filename.sub(/\.xml$/, ".presentation.xml"),
105
- encoding: "utf-8"), &:huge)
106
- end
107
-
108
- def sectionsplit_preprocess_semxml(file, filename)
109
- xml = Nokogiri::XML(file, &:huge)
110
- type = xml.root.name.sub("-standard", "").to_sym
111
- sectionsplit_update_xrefs(xml)
112
- xml1 = sectionsplit_write_semxml(filename, xml)
113
- @filecache ||= []
114
- @filecache << xml1
115
- [xml1.path, type]
116
- end
117
-
118
- def sectionsplit_update_xrefs(xml)
119
- if c = @fileslookup&.parent
120
- n = c.nested
121
- c.nested = true # so unresolved erefs are not deleted
122
- c.update_xrefs(xml, @ident, {})
123
- c.nested = n
124
- end
125
- end
126
-
127
- def sectionsplit_write_semxml(filename, xml)
128
- Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
129
- # f.write(@isodoc.to_xml(svg_preprocess(xml)))
130
- f.write(@isodoc.to_xml(xml))
131
- f
132
- end
133
- end
134
-
135
- def emptydoc(xml)
136
- out = xml.dup
137
- out.xpath(
138
- ns("//preface | //sections | //annex | //bibliography/clause | " \
139
- "//bibliography/references[not(@hidden = 'true')] | //indexsect | " \
140
- "//colophon"),
141
- ).each(&:remove)
142
- out
143
- end
144
-
145
- def sectionfile(fulldoc, xml, file, chunks, parentnode)
146
- fname = create_sectionfile(fulldoc, xml.dup, file, chunks, parentnode)
147
- { order: chunks.last["displayorder"].to_i, url: fname,
148
- title: titlerender(chunks.last) }
149
- end
150
-
151
- def create_sectionfile(xml, out, file, chunks, parentnode)
152
- ins = out.at(ns("//metanorma-extension")) || out.at(ns("//bibdata"))
153
- sectionfile_insert(ins, chunks, parentnode)
154
- Metanorma::XrefProcess::xref_process(out, xml, @key, @ident, @isodoc)
155
- outname = "#{file}.xml"
156
- File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
157
- f.write(out)
158
- end
159
- outname
160
- end
161
-
162
- def sectionfile_insert(ins, chunks, parentnode)
163
- if parentnode
164
- ins.next = "<#{parentnode}/>"
165
- chunks.each { |c| ins.next.add_child(c.dup) }
166
- else chunks.each { |c| ins.next = c.dup }
167
- end
168
- end
169
-
170
- def titlerender(section)
171
- title = section.at(ns("./title")) or return "[Untitled]"
172
- t = title.dup
173
- t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
174
- t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
175
- t.children.to_xml
176
- end
177
-
178
- def collectionyaml(files, xml)
179
- ret = {
180
- directives: ["presentation-xml", "bare-after-first"],
181
- bibdata: {
182
- title: {
183
- type: "title-main", language: @lang,
184
- content: xml.at(ns("//bibdata/title")).text
185
- },
186
- type: "collection",
187
- docid: {
188
- type: xml.at(ns("//bibdata/docidentifier/@type")).text,
189
- id: xml.at(ns("//bibdata/docidentifier")).text,
190
- },
191
- },
192
- manifest: {
193
- level: "collection", title: "Collection",
194
- docref: files.sort_by { |f| f[:order] }.each.map do |f|
195
- { fileref: f[:url], identifier: f[:title] }
196
- end
197
- },
198
- }
199
- Util::recursive_string_keys(ret).to_yaml
200
- end
201
-
202
- def section_split_cover(col, ident, one_doc_coll)
203
- dir = File.dirname(col.file)
204
- collection_setup(nil, dir)
205
- CollectionRenderer.new(col, dir,
206
- output_folder: "#{ident}_collection",
207
- format: %i(html),
208
- coverpage: File.join(dir, "cover.html")).coverpage
209
- #filename = one_doc_coll ? "#{ident}_index.html" : "index.html"
210
- filename = "#{ident}_index.html"
211
- FileUtils.mv "#{ident}_collection/index.html", File.join(dir, filename)
212
- FileUtils.rm_rf "#{ident}_collection"
213
- filename
214
- end
215
- end
216
- end
@@ -1,127 +0,0 @@
1
- module Metanorma
2
- module Util
3
- def self.log(message, type = :info)
4
- log_types = Metanorma.configuration.logs.map(&:to_s) || []
5
-
6
- if log_types.include?(type.to_s)
7
- puts(message)
8
- end
9
-
10
- if type == :fatal
11
- exit(1)
12
- end
13
- end
14
-
15
- # dependency ordering
16
- def self.sort_extensions_execution_ord(ext)
17
- case ext
18
- when :xml then 0
19
- when :rxl then 1
20
- when :presentation then 2
21
- else
22
- 99
23
- end
24
- end
25
-
26
- def self.sort_extensions_execution(ext)
27
- ext.sort do |a, b|
28
- sort_extensions_execution_ord(a) <=> sort_extensions_execution_ord(b)
29
- end
30
- end
31
-
32
- def self.recursive_string_keys(hash)
33
- case hash
34
- when Hash then hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }.to_h
35
- when Enumerable then hash.map { |v| recursive_string_keys(v) }
36
- else
37
- hash
38
- end
39
- end
40
-
41
- def self.gather_bibitems(xml)
42
- xml.xpath("//xmlns:bibitem[@id]").each_with_object({}) do |b, m|
43
- if m[b["id"]]
44
- b.remove
45
- next # we can't update duplicate bibitem, processing updates wrong one
46
- else
47
- m[b["id"]] = b
48
- end
49
- end
50
- end
51
-
52
- def self.gather_bibitemids(xml)
53
- xml.xpath("//*[@bibitemid]").each_with_object({}) do |e, m|
54
- /^semantic__/.match?(e.name) and next
55
- m[e["bibitemid"]] ||= []
56
- m[e["bibitemid"]] << e
57
- end
58
- end
59
-
60
- def self.gather_citeases(xml)
61
- xml.xpath("//*[@citeas]").each_with_object({}) do |e, m|
62
- /^semantic__/.match?(e.name) and next
63
- m[e["citeas"]] ||= []
64
- m[e["citeas"]] << e
65
- end
66
- end
67
-
68
- def self.add_suffix_to_attributes(doc, suffix, tag_name, attr_name, isodoc)
69
- (suffix.nil? || suffix.empty?) and return
70
- doc.xpath(isodoc.ns("//#{tag_name}[@#{attr_name}]")).each do |elem|
71
- a = elem.attributes[attr_name].value
72
- /_#{suffix}$/.match?(a) or
73
- elem.attributes[attr_name].value = "#{a}_#{suffix}"
74
- end
75
- end
76
-
77
- def self.hash_key_detect(directives, key, variable)
78
- c = directives.detect { |x| x.is_a?(Hash) && x.has_key?(key) } or
79
- return variable
80
- c[key]
81
- end
82
-
83
- def self.rel_path_resolve(dir, path)
84
- path.nil? and return path
85
- path.empty? and return path
86
- p = Pathname.new(path)
87
- p.absolute? ? path : File.join(dir, path)
88
- end
89
-
90
- def self.key(ident)
91
- @c ||= HTMLEntities.new
92
- @c.decode(ident).gsub(/(\p{Zs})+/, " ")
93
- end
94
-
95
- class DisambigFiles
96
- def initialize
97
- @seen_filenames = []
98
- end
99
-
100
- def strip_root(name)
101
- name.sub(%r{^(\./)?(\.\./)+}, "")
102
- end
103
-
104
- def source2dest_filename(name, disambig = true)
105
- n = strip_root(name)
106
- dir = File.dirname(n)
107
- base = File.basename(n)
108
- if disambig && @seen_filenames.include?(base)
109
- base = disambiguate_filename(base)
110
- end
111
- @seen_filenames << base
112
- dir == "." ? base : File.join(dir, base)
113
- end
114
-
115
- def disambiguate_filename(base)
116
- m = /^(?<start>.+\.)(?!0)(?<num>\d+)\.(?<suff>[^.]*)$/.match(base) ||
117
- /^(?<start>.+\.)(?<suff>[^.]*)/.match(base) ||
118
- /^(?<start>.+)$/.match(base)
119
- i = m.names.include?("num") ? m["num"].to_i + 1 : 1
120
- while @seen_filenames.include? base = "#{m['start']}#{i}.#{m['suff']}"
121
- i += 1
122
- end
123
- base
124
- end
125
- end
126
- end
127
- end
@@ -1,29 +0,0 @@
1
- module Metanorma
2
- class WorkersPool
3
- def initialize(workers)
4
- @workers = workers
5
- @queue = SizedQueue.new(@workers)
6
- @threads = Array.new(@workers) do
7
- Thread.new do
8
- catch(:exit) do
9
- loop do
10
- job, args = @queue.pop
11
- job.call *args
12
- end
13
- end
14
- end
15
- end
16
- end
17
-
18
- def schedule(*args, &block)
19
- @queue << [block, args]
20
- end
21
-
22
- def shutdown
23
- @workers.times do
24
- schedule { throw :exit }
25
- end
26
- @threads.map(&:join)
27
- end
28
- end
29
- end