metanorma-bsi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.hound.yml +3 -0
  4. data/.rubocop.yml +14 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +25 -0
  8. data/README.adoc +199 -0
  9. data/Rakefile +8 -0
  10. data/bin/rspec +18 -0
  11. data/lib/asciidoctor/bsi/basicdoc.rng +1131 -0
  12. data/lib/asciidoctor/bsi/biblio.rng +1235 -0
  13. data/lib/asciidoctor/bsi/bsi.rng +120 -0
  14. data/lib/asciidoctor/bsi/bsi_intro_en.xml +105 -0
  15. data/lib/asciidoctor/bsi/cleanup.rb +78 -0
  16. data/lib/asciidoctor/bsi/cleanup_ref.rb +183 -0
  17. data/lib/asciidoctor/bsi/converter.rb +83 -0
  18. data/lib/asciidoctor/bsi/front.rb +67 -0
  19. data/lib/asciidoctor/bsi/isodoc.rng +1870 -0
  20. data/lib/asciidoctor/bsi/isostandard.rng +477 -0
  21. data/lib/asciidoctor/bsi/reqt.rng +194 -0
  22. data/lib/asciidoctor/bsi/validate.rb +224 -0
  23. data/lib/asciidoctor/bsi/validate_list.rb +72 -0
  24. data/lib/asciidoctor/bsi/validate_requirement.rb +163 -0
  25. data/lib/isodoc/bsi/base_convert.rb +91 -0
  26. data/lib/isodoc/bsi/bsi.international-standard.xsl +6540 -0
  27. data/lib/isodoc/bsi/html/html_bsi_intro.html +8 -0
  28. data/lib/isodoc/bsi/html/html_bsi_titlepage.html +50 -0
  29. data/lib/isodoc/bsi/html/htmlstyle.css +968 -0
  30. data/lib/isodoc/bsi/html/htmlstyle.scss +699 -0
  31. data/lib/isodoc/bsi/html_convert.rb +56 -0
  32. data/lib/isodoc/bsi/i18n-en.yaml +56 -0
  33. data/lib/isodoc/bsi/i18n.rb +15 -0
  34. data/lib/isodoc/bsi/init.rb +24 -0
  35. data/lib/isodoc/bsi/metadata.rb +33 -0
  36. data/lib/isodoc/bsi/pdf_convert.rb +17 -0
  37. data/lib/isodoc/bsi/presentation_xml_convert.rb +72 -0
  38. data/lib/isodoc/bsi/sts_convert.rb +30 -0
  39. data/lib/isodoc/bsi/xref.rb +134 -0
  40. data/lib/metanorma-bsi.rb +15 -0
  41. data/lib/metanorma/bsi.rb +6 -0
  42. data/lib/metanorma/bsi/processor.rb +51 -0
  43. data/lib/metanorma/bsi/version.rb +6 -0
  44. data/metanorma-bsi.gemspec +47 -0
  45. data/spec/asciidoctor/base_spec.rb +778 -0
  46. data/spec/asciidoctor/blocks_spec.rb +553 -0
  47. data/spec/asciidoctor/cleanup_spec.rb +547 -0
  48. data/spec/asciidoctor/inline_spec.rb +176 -0
  49. data/spec/asciidoctor/lists_spec.rb +194 -0
  50. data/spec/asciidoctor/refs_spec.rb +318 -0
  51. data/spec/asciidoctor/section_spec.rb +382 -0
  52. data/spec/asciidoctor/validate_spec.rb +858 -0
  53. data/spec/assets/header.html +7 -0
  54. data/spec/assets/html.css +2 -0
  55. data/spec/assets/iso.xml +71 -0
  56. data/spec/assets/rice_image1.png +0 -0
  57. data/spec/assets/word.css +2 -0
  58. data/spec/assets/wordintro.html +4 -0
  59. data/spec/assets/xref_error.adoc +7 -0
  60. data/spec/isodoc/blocks_spec.rb +259 -0
  61. data/spec/isodoc/i18n_spec.rb +442 -0
  62. data/spec/isodoc/inline_spec.rb +287 -0
  63. data/spec/isodoc/iso_spec.rb +116 -0
  64. data/spec/isodoc/metadata_spec.rb +262 -0
  65. data/spec/isodoc/postproc_spec.rb +137 -0
  66. data/spec/isodoc/ref_spec.rb +376 -0
  67. data/spec/isodoc/section_spec.rb +467 -0
  68. data/spec/isodoc/terms_spec.rb +246 -0
  69. data/spec/isodoc/xref_spec.rb +1730 -0
  70. data/spec/metanorma/processor_spec.rb +76 -0
  71. data/spec/spec_helper.rb +291 -0
  72. data/spec/vcr_cassettes/iso-639.yml +182 -0
  73. data/spec/vcr_cassettes/isobib_get_639_1967.yml +136 -0
  74. data/spec/vcr_cassettes/multistandard.yml +352 -0
  75. metadata +343 -0
@@ -0,0 +1,194 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
3
+ <!--
4
+ Presupposes isodoc.rnc, is included in it
5
+ include "isodoc.rnc" { }
6
+ -->
7
+ <define name="requirement">
8
+ <element name="requirement">
9
+ <ref name="RequirementType"/>
10
+ </element>
11
+ </define>
12
+ <define name="recommendation">
13
+ <element name="recommendation">
14
+ <ref name="RequirementType"/>
15
+ </element>
16
+ </define>
17
+ <define name="permission">
18
+ <element name="permission">
19
+ <ref name="RequirementType"/>
20
+ </element>
21
+ </define>
22
+ <define name="RequirementType">
23
+ <optional>
24
+ <attribute name="obligation">
25
+ <ref name="ObligationType"/>
26
+ </attribute>
27
+ </optional>
28
+ <optional>
29
+ <attribute name="unnumbered">
30
+ <data type="boolean"/>
31
+ </attribute>
32
+ </optional>
33
+ <optional>
34
+ <attribute name="number"/>
35
+ </optional>
36
+ <optional>
37
+ <attribute name="subsequence"/>
38
+ </optional>
39
+ <optional>
40
+ <attribute name="keep-with-next">
41
+ <data type="boolean"/>
42
+ </attribute>
43
+ </optional>
44
+ <optional>
45
+ <attribute name="keep-lines-together">
46
+ <data type="boolean"/>
47
+ </attribute>
48
+ </optional>
49
+ <attribute name="id">
50
+ <data type="ID"/>
51
+ </attribute>
52
+ <optional>
53
+ <attribute name="filename"/>
54
+ </optional>
55
+ <optional>
56
+ <attribute name="model"/>
57
+ </optional>
58
+ <optional>
59
+ <attribute name="type"/>
60
+ </optional>
61
+ <optional>
62
+ <ref name="reqtitle"/>
63
+ </optional>
64
+ <optional>
65
+ <ref name="label"/>
66
+ </optional>
67
+ <optional>
68
+ <ref name="subject"/>
69
+ </optional>
70
+ <zeroOrMore>
71
+ <ref name="reqinherit"/>
72
+ </zeroOrMore>
73
+ <zeroOrMore>
74
+ <ref name="classification"/>
75
+ </zeroOrMore>
76
+ <zeroOrMore>
77
+ <choice>
78
+ <ref name="measurementtarget"/>
79
+ <ref name="specification"/>
80
+ <ref name="verification"/>
81
+ <ref name="import"/>
82
+ <ref name="description"/>
83
+ </choice>
84
+ </zeroOrMore>
85
+ <optional>
86
+ <ref name="reqt_references"/>
87
+ </optional>
88
+ <zeroOrMore>
89
+ <choice>
90
+ <ref name="requirement"/>
91
+ <ref name="recommendation"/>
92
+ <ref name="permission"/>
93
+ </choice>
94
+ </zeroOrMore>
95
+ </define>
96
+ <define name="reqtitle">
97
+ <element name="title">
98
+ <ref name="FormattedString"/>
99
+ </element>
100
+ </define>
101
+ <define name="label">
102
+ <element name="label">
103
+ <text/>
104
+ </element>
105
+ </define>
106
+ <define name="subject">
107
+ <element name="subject">
108
+ <text/>
109
+ </element>
110
+ </define>
111
+ <define name="reqinherit">
112
+ <element name="inherit">
113
+ <text/>
114
+ </element>
115
+ </define>
116
+ <define name="measurementtarget">
117
+ <element name="measurement-target">
118
+ <ref name="RequirementSubpart"/>
119
+ </element>
120
+ </define>
121
+ <define name="specification">
122
+ <element name="specification">
123
+ <ref name="RequirementSubpart"/>
124
+ </element>
125
+ </define>
126
+ <define name="verification">
127
+ <element name="verification">
128
+ <ref name="RequirementSubpart"/>
129
+ </element>
130
+ </define>
131
+ <define name="import">
132
+ <element name="import">
133
+ <ref name="RequirementSubpart"/>
134
+ </element>
135
+ </define>
136
+ <define name="description">
137
+ <element name="description">
138
+ <ref name="RequirementSubpart"/>
139
+ </element>
140
+ </define>
141
+ <define name="reqt_references">
142
+ <element name="references">
143
+ <oneOrMore>
144
+ <ref name="bibitem"/>
145
+ </oneOrMore>
146
+ </element>
147
+ </define>
148
+ <define name="RequirementSubpart">
149
+ <optional>
150
+ <attribute name="type"/>
151
+ </optional>
152
+ <optional>
153
+ <attribute name="exclude">
154
+ <data type="boolean"/>
155
+ </attribute>
156
+ </optional>
157
+ <optional>
158
+ <attribute name="keep-with-next">
159
+ <data type="boolean"/>
160
+ </attribute>
161
+ </optional>
162
+ <optional>
163
+ <attribute name="keep-lines-together">
164
+ <data type="boolean"/>
165
+ </attribute>
166
+ </optional>
167
+ <oneOrMore>
168
+ <ref name="BasicBlock"/>
169
+ </oneOrMore>
170
+ </define>
171
+ <define name="ObligationType">
172
+ <choice>
173
+ <value>requirement</value>
174
+ <value>recommendation</value>
175
+ <value>permission</value>
176
+ </choice>
177
+ </define>
178
+ <define name="classification">
179
+ <element name="classification">
180
+ <ref name="classification_tag"/>
181
+ <ref name="classification_value"/>
182
+ </element>
183
+ </define>
184
+ <define name="classification_tag">
185
+ <element name="tag">
186
+ <text/>
187
+ </element>
188
+ </define>
189
+ <define name="classification_value">
190
+ <element name="value">
191
+ <text/>
192
+ </element>
193
+ </define>
194
+ </grammar>
@@ -0,0 +1,224 @@
1
+ require_relative "./validate_requirement"
2
+ require_relative "./validate_list"
3
+
4
+ module Asciidoctor
5
+ module BSI
6
+ class Converter < ISO::Converter
7
+ # BSI 0:2016 9.4.1
8
+ def doctype_validate(xmldoc)
9
+ doctype = xmldoc&.at("//bibdata/ext/doctype")&.text
10
+ %w(specification management-systems-standard code-of-practice
11
+ guide method-of-test method-of-specifying vocabulary
12
+ classification).include? doctype or
13
+ @log.add("Document Attributes", nil,
14
+ "#{doctype} is not a recognised document type")
15
+ end
16
+
17
+ def validate(doc)
18
+ content_validate(doc)
19
+ schema_validate(formattedstr_strip(doc.dup),
20
+ File.join(File.dirname(__FILE__), "bsi.rng"))
21
+ end
22
+
23
+ def image_name_validate(xmldoc); end
24
+
25
+ def norm_ref_validate(doc); end
26
+
27
+ def style(node, text)
28
+ super
29
+ style_plusminus(node, text)
30
+ style_subscript(node)
31
+ end
32
+
33
+ # Rules for Structure 27.5
34
+ def style_plusminus(node, text)
35
+ style_regex(/\s*(?<num>\S+\u00b1\s*\S+)/,
36
+ "no space before plus-minus sign", node, text)
37
+ style_regex(/\s*(?<num>\S+\s*\u00b1\s+\S+)/,
38
+ "space after plus-minus sign", node, text)
39
+ end
40
+
41
+ # Rules for Structure 27.6
42
+ def style_subscript(node)
43
+ node.xpath(".//sub[.//sub]").each do |r|
44
+ style_warning(node, "Nested subscript", r)
45
+ end
46
+ node.xpath(".//m:msub[.//m:msub]", "m" => MATHML_NS).each do |r|
47
+ style_warning(node, "Nested subscript", r)
48
+ end
49
+ node.xpath(".//sup[.//sup]").each do |r|
50
+ style_warning(node, "Nested superscript", r)
51
+ end
52
+ node.xpath(".//m:msup[.//m:msup]", "m" => MATHML_NS).each do |r|
53
+ style_warning(node, "Nested superscript", r)
54
+ end
55
+ end
56
+
57
+ # protest decimal comma not decimal point
58
+ # TODO we will not yet override decimal comma warning if this is a National Annex to Eurocode (Rules for Structure Annex B)
59
+ def style_number(node, text)
60
+ style_two_regex_not_prev(
61
+ node, text, /^(?<num>-?[0-9]{4,}[,0-9]*)$/,
62
+ %r{\b(ISO|IEC|IEEE/|(in|January|February|March|April|May|June|August|September|October|November|December)\b)$},
63
+ "number not broken up in threes"
64
+ )
65
+ style_regex(/\b(?<num>[0-9]+,[0-9]+)/i,
66
+ "possible decimal comma", node, text)
67
+ style_regex(/\b(?<num>billions?)\b/i,
68
+ "ambiguous number", node, text)
69
+ ordinal_check(node)
70
+ end
71
+
72
+ # Rules for Structure 9.1
73
+ def ordinal_check(node)
74
+ node.xpath(".//sup").each do |s|
75
+ next unless %w(st nd rd th).include? s.text
76
+
77
+ style_warning(s, "text contains ordinal superscript", s.text)
78
+ end
79
+ end
80
+
81
+ def section_style(root)
82
+ super
83
+ @doctype = root.at("//bibdata/ext/doctype")&.text
84
+ @type = @doctype.gsub(/-/, " ").split.map(&:capitalize).join(" ")
85
+ informative_text_style(root)
86
+ normative_text_style(root)
87
+ avoid_must(root)
88
+ annex_validate(root)
89
+ end
90
+
91
+ def annex_validate(root)
92
+ annex_normative_validate(root)
93
+ annex_ordering_validate(root)
94
+ end
95
+
96
+ # Rules for Structure 20.2
97
+ def annex_normative_validate(root)
98
+ @doctype == "guide" and root.xpath("//annex[@obligation = 'normative']")
99
+ .each do |s|
100
+ style_warning(s, "Guide contains normative annex",
101
+ s&.at("./title")&.text)
102
+ end
103
+ end
104
+
105
+ # Rules for Structure 20.4
106
+ def annex_ordering_validate(root)
107
+ ids = citation_order(root.xpath("//annex"))
108
+ cite_order = ids.keys.sort { |a, b| ids[a] <=> ids[b] }
109
+ annex_order = root.xpath("//annex").map { |x| x["id"] }
110
+ cite_order.each_with_index do |a, i|
111
+ next if annex_order[i] == a
112
+
113
+ annex = root.at("//annex[@id = '#{a}']")
114
+ title = annex&.at("./title")&.text || "Annex #{a}"
115
+ style_warning(annex, "#{title} should be annex ##{i + 1}", nil)
116
+ end
117
+ end
118
+
119
+ BSI_PUBLISHER_XPATH =
120
+ "./contributor[role/@type = 'publisher']/"\
121
+ "organization[abbreviation = 'ISO' or abbreviation = 'IEC' or "\
122
+ "abbreviation = 'BSI' or abbreviation = 'CEN' or "\
123
+ "abbreviation = 'CENELEC']".freeze
124
+
125
+ NORM_BSI_WARN = "reference other than BSI, CEN, CENELEC, ISO, IEC "\
126
+ "not expected as normative".freeze
127
+
128
+ # Rules for Structure 10.2
129
+ def norm_bibitem_style(root)
130
+ root.xpath(NORM_BIBITEMS).each do |b|
131
+ b.at(BSI_PUBLISHER_XPATH).nil? and
132
+ @log.add("Style", b, "#{NORM_BSI_WARN}: #{b.text}")
133
+ status = b&.at("./status/stage")&.text
134
+ /^9.$/.match?(status) and
135
+ @log.add("Style", b,
136
+ "Do not cite withdrawn standards as normative: #{b.text}")
137
+ /^[0-5].$/.match?(status) and @log.add(
138
+ "Style", b,
139
+ "Do not cite unpublished standards as normative: #{b.text}"
140
+ )
141
+ end
142
+ end
143
+
144
+ # Rules for Structure 11.5.2
145
+ def title_names_type_validate(root)
146
+ super
147
+ doctypes = /British\sStandard/xi
148
+ title_main_en = title_lang_part(root, "main", "en")
149
+ !title_main_en.nil? && doctypes.match(title_main_en.text) and
150
+ @log.add("Style", title_main_en, "Main Title may name document type")
151
+ title_intro_en = title_lang_part(root, "intro", "en")
152
+ !title_intro_en.nil? && doctypes.match(title_intro_en.text) and
153
+ @log.add("Style", title_intro_en,
154
+ "Title Intro may name document type")
155
+ end
156
+
157
+ # Rules for Structure 16.5.5
158
+ def termdef_style(xmldoc)
159
+ super
160
+ xmldoc.xpath("//term").each do |t|
161
+ para = t.at("./definition") || return
162
+ term = t.at("./preferred").text.strip
163
+ termdef_warn(para.text, /^[A-Z]/, t, term,
164
+ "term definition starts with upper case character")
165
+ termdef_warn(para.text, /\b#{term.downcase}\b/i, t, term,
166
+ "term definition may be circular")
167
+ end
168
+ end
169
+
170
+ def content_validate(doc)
171
+ super
172
+ symbol_style(doc)
173
+ table_validate(doc)
174
+ listcount_validate(doc)
175
+ list_punctuation(doc)
176
+ end
177
+
178
+ # Rules for Structure 17.5
179
+ def symbol_style(xmldoc)
180
+ return if @novalid
181
+
182
+ xmldoc.xpath("//definitions//dd").each do |para|
183
+ term = para&.at("./preceding::dt[1]")&.text&.strip || "[symbol]"
184
+ termdef_warn(para.text, /^(the|a)\b/i, para, term,
185
+ "symbol definition starts with article")
186
+ termdef_warn(para.text, /\.$/i, para, term,
187
+ "symbol definition ends with period")
188
+ termdef_warn(para.text, /^[A-Z]/, para, term,
189
+ "symbol definition starts with upper case character")
190
+ termdef_warn(para.text, /\b#{term.downcase}\b/i, para, term,
191
+ "symbol definition may be circular")
192
+ end
193
+ end
194
+
195
+ # Rules for Structure 22.3.2
196
+ def subclause_validate(root)
197
+ return if @novalid
198
+
199
+ root.xpath("//clause/clause/clause/clause/clause/clause")
200
+ .each do |c|
201
+ style_warning(c, "Exceeds the maximum clause depth of 5", nil)
202
+ end
203
+ end
204
+
205
+ # Rules for Structure 29.6
206
+ def table_validate(xmldoc)
207
+ xmldoc.xpath("//td[not(./*) and normalize-space(.)=''] | "\
208
+ "//th[not(./*) and normalize-space(.)='']").each do |td|
209
+ style_warning(td, "Empty table cell", nil)
210
+ end
211
+ end
212
+
213
+ # TODO: we will not block foreword from National Annex to Eurocode (Rules for Structure G.6.1)
214
+ #
215
+ # TODO: we will not test location of commentaries (Rules for Structure 24.7)
216
+ #
217
+ # TODO: we will not check for space either side of mathematical sign (Rules for Structure 27.5)
218
+ #
219
+ # TODO: we will not check for conflict of ln and log_e or log lg log_10 (Rules for Structure 27.8)
220
+ #
221
+ # TODO: we will not check order of brackets in stem as {[( (Rules for Structure 27.9)
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,72 @@
1
+ module Asciidoctor
2
+ module BSI
3
+ class Converter < ISO::Converter
4
+ # Rules for Structure 23.3
5
+ def listcount_validate(doc)
6
+ return if @novalid
7
+
8
+ doc.xpath("//clause[not(.//clause)] | //annex").each do |c|
9
+ next if c.xpath(".//ol").empty?
10
+
11
+ ols = c.xpath(".//ol") - c.xpath(".//ul//ol | .//ol//ol")
12
+ ols.size > 3 and
13
+ style_warning(c, "More than 3 ordered lists in a numbered clause",
14
+ nil)
15
+ end
16
+ end
17
+
18
+ # Rules for Structure 23.5
19
+ def list_punctuation(doc)
20
+ return if @novalid
21
+
22
+ ((doc.xpath("//ol") - doc.xpath("//ul//ol | //ol//ol")) +
23
+ (doc.xpath("//ul") - doc.xpath("//ul//ul | //ol//ul"))).each do |list|
24
+ prec = list.previous_element
25
+ prec&.name == "p" or
26
+ style_warning(list, "All lists must be preceded by "\
27
+ "introductory phrase", nil)
28
+ list_punctuation1(list, prec.text)
29
+ end
30
+ end
31
+
32
+ def list_punctuation1(list, prectext)
33
+ entries = list.xpath(".//li")
34
+ case prectext.sub(/^.*?(\S)\s*$/, "\\1")
35
+ when ":"
36
+ list.xpath(".//li").each_with_index do |li, i|
37
+ list_semicolon_phrase(li, i == entries.size - 1)
38
+ end
39
+ when "." then entries.each { |li| list_full_sentence(li) }
40
+ else style_warning(list, "All lists must be preceded by "\
41
+ "colon or full stop", prectext)
42
+ end
43
+ end
44
+
45
+ def list_semicolon_phrase(elem, last)
46
+ text = elem.text.strip
47
+ text.match?(/^[^A-Za-z]*[a-z]/) or
48
+ style_warning(elem, "List entry after colon must start with "\
49
+ "lowercase letter", text)
50
+ punct = text.sub(/^.*?(\S)\s*$/, "\\1")
51
+ if last
52
+ punct == "." or style_warning(elem, "Final list entry after colon "\
53
+ "must end with full stop", text)
54
+ else
55
+ punct == ";" or style_warning(elem, "List entry after colon must "\
56
+ "end with semicolon", text)
57
+ end
58
+ end
59
+
60
+ def list_full_sentence(elem)
61
+ text = elem.text.strip
62
+ text.match?(/^[^A-Za-z]*[A-Z]/) or
63
+ style_warning(elem, "List entry after full stop must start with "\
64
+ "uppercase letter", text)
65
+ punct = text.sub(/^.*?(\S)\s*$/, "\\1")
66
+ punct == "." or
67
+ style_warning(elem, "List entry after full stop must "\
68
+ "end with full stop", text)
69
+ end
70
+ end
71
+ end
72
+ end