metanorma-nist 0.0.1

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.hound.yml +3 -0
  3. data/.rubocop.yml +10 -0
  4. data/.travis.yml +16 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +25 -0
  8. data/README.adoc +358 -0
  9. data/bin/console +14 -0
  10. data/bin/rspec +18 -0
  11. data/bin/setup +8 -0
  12. data/lib/asciidoctor/nist.rb +7 -0
  13. data/lib/asciidoctor/nist/biblio.rng +921 -0
  14. data/lib/asciidoctor/nist/converter.rb +271 -0
  15. data/lib/asciidoctor/nist/front.rb +150 -0
  16. data/lib/asciidoctor/nist/isodoc.rng +1063 -0
  17. data/lib/asciidoctor/nist/isostandard.rng +1071 -0
  18. data/lib/asciidoctor/nist/nist.rng +196 -0
  19. data/lib/isodoc/nist/html/commerce-logo-color.png +0 -0
  20. data/lib/isodoc/nist/html/deptofcommerce.png +0 -0
  21. data/lib/isodoc/nist/html/header.html +163 -0
  22. data/lib/isodoc/nist/html/html_nist_intro.html +46 -0
  23. data/lib/isodoc/nist/html/html_nist_titlepage.html +140 -0
  24. data/lib/isodoc/nist/html/htmlstyle.scss +1160 -0
  25. data/lib/isodoc/nist/html/logo.png +0 -0
  26. data/lib/isodoc/nist/html/nist.scss +749 -0
  27. data/lib/isodoc/nist/html/scripts.html +82 -0
  28. data/lib/isodoc/nist/html/scripts.pdf.html +70 -0
  29. data/lib/isodoc/nist/html/word_nist_intro.html +142 -0
  30. data/lib/isodoc/nist/html/word_nist_titlepage.html +247 -0
  31. data/lib/isodoc/nist/html/wordstyle.scss +1134 -0
  32. data/lib/isodoc/nist/html_convert.rb +454 -0
  33. data/lib/isodoc/nist/i18n-en.yaml +3 -0
  34. data/lib/isodoc/nist/metadata.rb +116 -0
  35. data/lib/isodoc/nist/pdf_convert.rb +456 -0
  36. data/lib/isodoc/nist/word_convert.rb +472 -0
  37. data/lib/metanorma-nist.rb +11 -0
  38. data/lib/metanorma/nist.rb +7 -0
  39. data/lib/metanorma/nist/processor.rb +43 -0
  40. data/lib/metanorma/nist/version.rb +5 -0
  41. data/metanorma-nist.gemspec +44 -0
  42. metadata +310 -0
@@ -0,0 +1,454 @@
1
+ require "isodoc"
2
+ require_relative "metadata"
3
+ require "fileutils"
4
+
5
+ module IsoDoc
6
+ module NIST
7
+ # A {Converter} implementation that generates HTML output, and a document
8
+ # schema encapsulation of the document for validation
9
+ class HtmlConvert < IsoDoc::HtmlConvert
10
+ def initialize(options)
11
+ @libdir = File.dirname(__FILE__)
12
+ super
13
+ end
14
+
15
+ def convert1(docxml, filename, dir)
16
+ FileUtils.cp html_doc_path('logo.png'), "#{@localdir}/logo.png"
17
+ FileUtils.cp html_doc_path('commerce-logo-color.png'), "#{@localdir}/commerce-logo-color.png"
18
+ @files_to_delete << "#{@localdir}/logo.png"
19
+ @files_to_delete << "#{@localdir}/commerce-logo-color.png"
20
+ super
21
+ end
22
+
23
+ def default_fonts(options)
24
+ {
25
+ bodyfont: (options[:script] == "Hans" ? '"SimSun",serif' : '"Libre Baskerville",serif'),
26
+ headerfont: (options[:script] == "Hans" ? '"SimHei",sans-serif' : '"Libre Baskerville",serif'),
27
+ monospacefont: '"Space Mono",monospace'
28
+ }
29
+ end
30
+
31
+ def default_file_locations(_options)
32
+ {
33
+ htmlstylesheet: html_doc_path("htmlstyle.scss"),
34
+ htmlcoverpage: html_doc_path("html_nist_titlepage.html"),
35
+ htmlintropage: html_doc_path("html_nist_intro.html"),
36
+ scripts: html_doc_path("scripts.html"),
37
+ }
38
+ end
39
+
40
+ def metadata_init(lang, script, labels)
41
+ @meta = Metadata.new(lang, script, labels)
42
+ end
43
+
44
+ def html_head
45
+ <<~HEAD.freeze
46
+ <title>{{ doctitle }}</title>
47
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
48
+
49
+ <!--TOC script import-->
50
+ <script type="text/javascript" src="https://cdn.rawgit.com/jgallen23/toc/0.3.2/dist/toc.min.js"></script>
51
+
52
+ <!--Google fonts-->
53
+ <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,600,600i" rel="stylesheet">
54
+ <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i|Space+Mono:400,700" rel="stylesheet" />
55
+ <link href="https://fonts.googleapis.com/css?family=Libre+Baskerville:400,400i,700,700i" rel="stylesheet">
56
+
57
+ <!--Font awesome import for the link icon-->
58
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/solid.css" integrity="sha384-v2Tw72dyUXeU3y4aM2Y0tBJQkGfplr39mxZqlTBDUZAb9BGoC40+rdFCG0m10lXk" crossorigin="anonymous">
59
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/fontawesome.css" integrity="sha384-q3jl8XQu1OpdLgGFvNRnPdj5VIlCvgsDQTQB6owSOHWlAurxul7f+JpUOVdAiJ5P" crossorigin="anonymous">
60
+ <style class="anchorjs"></style>
61
+ HEAD
62
+ end
63
+
64
+ def make_body(xml, docxml)
65
+ body_attr = { lang: "EN-US", link: "blue", vlink: "#954F72", "xml:lang": "EN-US", class: "container" }
66
+ xml.body **body_attr do |body|
67
+ make_body1(body, docxml)
68
+ make_body2(body, docxml)
69
+ make_body3(body, docxml)
70
+ end
71
+ end
72
+
73
+ def html_toc(docxml)
74
+ docxml
75
+ end
76
+
77
+ def cleanup(docxml)
78
+ super
79
+ term_cleanup(docxml)
80
+ requirement_cleanup(docxml)
81
+ end
82
+
83
+ def make_body3(body, docxml)
84
+ body.div **{ class: "main-section" } do |div3|
85
+ abstract docxml, div3
86
+ keywords docxml, div3
87
+ preface docxml, div3
88
+ middle docxml, div3
89
+ footnotes div3
90
+ comments div3
91
+ end
92
+ end
93
+
94
+ def abstract(isoxml, out)
95
+ f = isoxml.at(ns("//preface/abstract")) || return
96
+ page_break(out)
97
+ out.div **attr_code(id: f["id"]) do |s|
98
+ clause_name(nil, @abstract_lbl, s, class: "AbstractTitle")
99
+ f.elements.each { |e| parse(e, s) unless e.name == "title" }
100
+ end
101
+ end
102
+
103
+ def keywords(_docxml, out)
104
+ kw = @meta.get[:keywords]
105
+ kw.empty? and return
106
+ out.div **{ class: "Section3" } do |div|
107
+ clause_name(nil, "Keywords", div, class: "IntroTitle")
108
+ div.p kw.sort.join("; ")
109
+ end
110
+ end
111
+
112
+ FRONT_CLAUSE = "//*[parent::preface][not(local-name() = 'abstract')]".freeze
113
+
114
+ def preface(isoxml, out)
115
+ isoxml.xpath(ns(FRONT_CLAUSE)).each do |c|
116
+ foreword(isoxml, out) and next if c.name == "foreword"
117
+ next if skip_render(c, isoxml)
118
+ out.div **attr_code(id: c["id"]) do |s|
119
+ clause_name(get_anchors[c['id']][:label],
120
+ c&.at(ns("./title"))&.content, s, nil)
121
+ c.elements.reject { |c1| c1.name == "title" }.each do |c1|
122
+ parse(c1, s)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def skip_render(c, isoxml)
129
+ return false unless c.name == "reviewernote"
130
+ status = isoxml&.at(ns("//bibdata/status"))&.text
131
+ return true if status.nil?
132
+ return ["published", "withdrawn"].include? status
133
+ end
134
+
135
+ def term_defs_boilerplate(div, source, term, preface)
136
+ if source.empty? && term.nil?
137
+ div << @no_terms_boilerplate
138
+ else
139
+ div << term_defs_boilerplate_cont(source, term)
140
+ end
141
+ end
142
+
143
+ def i18n_init(lang, script)
144
+ super
145
+ end
146
+
147
+ def fileloc(loc)
148
+ File.join(File.dirname(__FILE__), loc)
149
+ end
150
+
151
+ def term_cleanup(docxml)
152
+ docxml.xpath("//p[@class = 'Terms']").each do |d|
153
+ h2 = d.at("./preceding-sibling::*[@class = 'TermNum'][1]")
154
+ h2.add_child("&nbsp;")
155
+ h2.add_child(d.remove)
156
+ end
157
+ docxml
158
+ end
159
+
160
+ def requirement_cleanup(docxml)
161
+ docxml.xpath("//div[@class = 'recommend'][title]").each do |d|
162
+ title = d.at("./title")
163
+ title.name = "b"
164
+ n = title.next_element
165
+ n&.children&.first&.add_previous_sibling(" ")
166
+ n&.children&.first&.add_previous_sibling(title.remove)
167
+ end
168
+ docxml
169
+ end
170
+
171
+ def figure_parse(node, out)
172
+ return pseudocode_parse(node, out) if node["type"] == "pseudocode"
173
+ super
174
+ end
175
+
176
+ def pseudocode_parse(node, out)
177
+ @in_figure = true
178
+ name = node.at(ns("./name"))
179
+ out.div **attr_code(id: node["id"], class: "pseudocode") do |div|
180
+ node.children.each do |n|
181
+ parse(n, div) unless n.name == "name"
182
+ end
183
+ figure_name_parse(node, div, name) if name
184
+ end
185
+ @in_figure = false
186
+ end
187
+
188
+ def dl_parse(node, out)
189
+ return glossary_parse(node, out) if node["type"] == "glossary"
190
+ super
191
+ end
192
+
193
+ def glossary_parse(node, out)
194
+ out.dl **attr_code(id: node["id"], class: "glossary") do |v|
195
+ node.elements.select { |n| dt_dd? n }.each_slice(2) do |dt, dd|
196
+ v.dt **attr_code(id: dt["id"]) do |term|
197
+ dt_parse(dt, term)
198
+ end
199
+ v.dd **attr_code(id: dd["id"]) do |listitem|
200
+ dd.children.each { |n| parse(n, listitem) }
201
+ end
202
+ end
203
+ end
204
+ node.elements.reject { |n| dt_dd? n }.each { |n| parse(n, out) }
205
+ end
206
+
207
+ def error_parse(node, out)
208
+ case node.name
209
+ when "nistvariable" then nistvariable_parse(node, out)
210
+ when "recommendation" then recommendation_parse(node, out)
211
+ when "requirement" then requirement_parse(node, out)
212
+ when "permission" then permission_parse(node, out)
213
+ when "errata" then errata_parse(node, out)
214
+ else
215
+ super
216
+ end
217
+ end
218
+
219
+ def nistvariable_parse(node, out)
220
+ out.span **{class: "nistvariable"} do |s|
221
+ node.children.each { |n| parse(n, s) }
222
+ end
223
+ end
224
+
225
+ def recommendation_parse(node, out)
226
+ name = node["type"]
227
+ out.div **{ class: "recommend" } do |t|
228
+ t.title { |b| b << "Recommendation #{get_anchors[node['id']][:label]}:" }
229
+ node.children.each do |n|
230
+ parse(n, t)
231
+ end
232
+ end
233
+ end
234
+
235
+ def requirement_parse(node, out)
236
+ name = node["type"]
237
+ out.div **{ class: "recommend" } do |t|
238
+ t.title { |b| b << "Requirement #{get_anchors[node['id']][:label]}:" }
239
+ node.children.each do |n|
240
+ parse(n, t)
241
+ end
242
+ end
243
+ end
244
+
245
+ def permission_parse(node, out)
246
+ name = node["type"]
247
+ out.div **{ class: "recommend" } do |t|
248
+ t.title { |b| b << "Permission #{get_anchors[node['id']][:label]}:" }
249
+ node.children.each do |n|
250
+ parse(n, t)
251
+ end
252
+ end
253
+ end
254
+
255
+ def errata_parse(node, out)
256
+ out.table **make_table_attr(node) do |t|
257
+ t.thead do |h|
258
+ h.tr do |tr|
259
+ %w(Date Type Change Pages).each do |hdr|
260
+ tr.th hdr
261
+ end
262
+ end
263
+ end
264
+ t.tbody do |b|
265
+ node.xpath(ns("./row")).each do |row|
266
+ b.tr do |tr|
267
+ tr.td do |td|
268
+ row&.at(ns("./date"))&.children.each do |n|
269
+ parse(n, td)
270
+ end
271
+ end
272
+ tr.td do |td|
273
+ row&.at(ns("./type"))&.children.each do |n|
274
+ parse(n, td)
275
+ end
276
+ end
277
+ tr.td do |td|
278
+ row&.at(ns("./change"))&.children.each do |n|
279
+ parse(n, td)
280
+ end
281
+ end
282
+ tr.td do |td|
283
+ row&.at(ns("./pages"))&.children.each do |n|
284
+ parse(n, td)
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end
292
+
293
+ MIDDLE_CLAUSE = "//clause[parent::sections]|//terms[parent::sections]".freeze
294
+
295
+ def middle(isoxml, out)
296
+ middle_title(out)
297
+ clause isoxml, out
298
+ annex isoxml, out
299
+ bibliography isoxml, out
300
+ end
301
+
302
+ def bibliography(isoxml, out)
303
+ f = isoxml.at(ns("//bibliography/clause | //bibliography/references")) || return
304
+ page_break(out)
305
+ isoxml.xpath(ns("//bibliography/clause | //bibliography/references")).each do |f|
306
+ out.div do |div|
307
+ div.h1 **{ class: "Section3" } do |h1|
308
+ f&.at(ns("./title"))&.children.each { |n| parse(n, h1) }
309
+ end
310
+ f.elements.reject do |e|
311
+ ["reference", "title", "bibitem"].include? e.name
312
+ end.each { |e| parse(e, div) }
313
+ biblio_list(f, div, false)
314
+ end
315
+ end
316
+ end
317
+
318
+ def info(isoxml, out)
319
+ @meta.keywords isoxml, out
320
+ super
321
+ end
322
+
323
+ SECTIONS_XPATH =
324
+ "//foreword | //introduction | //reviewnote | //execsummary | //annex | "\
325
+ "//sections/clause | //bibliography/references | "\
326
+ "//bibliography/clause".freeze
327
+
328
+ def initial_anchor_names(d)
329
+ d.xpath("//xmlns:preface/child::*").each do |c|
330
+ preface_names(c)
331
+ end
332
+ sequential_asset_names(d.xpath("//xmlns:preface/child::*"))
333
+ clause_names(d, 0)
334
+ middle_section_asset_names(d)
335
+ termnote_anchor_names(d)
336
+ termexample_anchor_names(d)
337
+ end
338
+
339
+ def back_anchor_names(docxml)
340
+ docxml.xpath(ns("//annex")).each_with_index do |c, i|
341
+ annex_names(c, (65 + i).chr.to_s)
342
+ end
343
+ docxml.xpath(ns("//bibliography/clause | "\
344
+ "//bibliography/references")).each do |b|
345
+ preface_names(b)
346
+ end
347
+ docxml.xpath(ns("//bibitem[not(ancestor::bibitem)]")).each do |ref|
348
+ reference_names(ref)
349
+ end
350
+ end
351
+
352
+
353
+ def prefaceprefix(nodes)
354
+ i = 0
355
+ nodes.each do |n|
356
+ case n.name
357
+ when "executivesummary" then @anchors[n["id"]][:prefix] = "ES"
358
+ when "abstract" then @anchors[n["id"]][:prefix] = "ABS"
359
+ when "reviewernote" then @anchors[n["id"]][:prefix] = "NTR"
360
+ else
361
+ @anchors[n["id"]][:prefix] = "PR" + i.to_s
362
+ i += 1
363
+ end
364
+ end
365
+ end
366
+
367
+ def middle_section_asset_names(d)
368
+ prefaceprefix(d.xpath("//xmlns:preface/child::*"))
369
+ d.xpath("//xmlns:preface/child::*").each do |s|
370
+ hierarchical_asset_names(s, @anchors[s["id"]][:prefix])
371
+ end
372
+ d.xpath("//xmlns:sections/child::*").each do |s|
373
+ hierarchical_asset_names(s, @anchors[s["id"]][:label])
374
+ end
375
+ end
376
+
377
+ def hierarchical_asset_names(clause, num)
378
+ super
379
+ hierarchical_permission_names(clause, num)
380
+ hierarchical_requirement_names(clause, num)
381
+ hierarchical_recommendation_names(clause, num)
382
+ end
383
+
384
+ def hierarchical_permission_names(clause, num)
385
+ clause.xpath(ns(".//permission")).each_with_index do |t, i|
386
+ next if t["id"].nil? || t["id"].empty?
387
+ @anchors[t["id"]] = anchor_struct("#{num}.#{i + 1}",
388
+ t, "Permission", "permission")
389
+ end
390
+ end
391
+
392
+ def hierarchical_requirement_names(clause, num)
393
+ clause.xpath(ns(".//requirement")).each_with_index do |t, i|
394
+ next if t["id"].nil? || t["id"].empty?
395
+ @anchors[t["id"]] = anchor_struct("#{num}.#{i + 1}",
396
+ t, "Requirement", "requirement")
397
+ end
398
+ end
399
+
400
+ def hierarchical_recommendation_names(clause, num)
401
+ clause.xpath(ns(".//recommendation")).each_with_index do |t, i|
402
+ next if t["id"].nil? || t["id"].empty?
403
+ @anchors[t["id"]] = anchor_struct("#{num}.#{i + 1}",
404
+ t, "Recommendation", "recommendation")
405
+ end
406
+ end
407
+
408
+ def clause_names(docxml, sect_num)
409
+ q = "//xmlns:sections/child::*"
410
+ docxml.xpath(q).each_with_index do |c, i|
411
+ section_names(c, (i + sect_num), 1)
412
+ end
413
+ end
414
+
415
+ def get_linkend(node)
416
+ link = anchor_linkend(node, docid_l10n(node["target"] || "[#{node['citeas']}]"))
417
+ link += eref_localities(node.xpath(ns("./locality")), link)
418
+ contents = node.children.select { |c| c.name != "locality" }
419
+ return link if contents.nil? || contents.empty?
420
+ Nokogiri::XML::NodeSet.new(node.document, contents).to_xml
421
+ # so not <origin bibitemid="ISO7301" citeas="ISO 7301">
422
+ # <locality type="section"><reference>3.1</reference></locality></origin>
423
+ end
424
+
425
+ def load_yaml(lang, script)
426
+ y = if @i18nyaml then YAML.load_file(@i18nyaml)
427
+ elsif lang == "en"
428
+ YAML.load_file(File.join(File.dirname(__FILE__), "i18n-en.yaml"))
429
+ else
430
+ YAML.load_file(File.join(File.dirname(__FILE__), "i18n-en.yaml"))
431
+ end
432
+ super.merge(y)
433
+ end
434
+
435
+ def annex_name_lbl(clause, num)
436
+ l10n("<b>#{@annex_lbl} #{num}</b>")
437
+ end
438
+
439
+ def annex_name(annex, name, div)
440
+ div.h1 **{ class: "Annex" } do |t|
441
+ t << "#{get_anchors[annex['id']][:label]} &mdash; "
442
+ t.b do |b|
443
+ name&.children&.each { |c2| parse(c2, b) }
444
+ end
445
+ end
446
+ end
447
+
448
+ def hiersep
449
+ "-"
450
+ end
451
+
452
+ end
453
+ end
454
+ end