metanorma-nist 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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