metanorma-iso 2.2.4 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/lib/isodoc/iso/base_convert.rb +9 -3
- data/lib/isodoc/iso/html/isodoc-dis.css +4 -4
- data/lib/isodoc/iso/html/isodoc-dis.scss +4 -4
- data/lib/isodoc/iso/html/isodoc.css +4 -4
- data/lib/isodoc/iso/html/isodoc.scss +4 -4
- data/lib/isodoc/iso/html_convert.rb +1 -1
- data/lib/isodoc/iso/index.rb +2 -2
- data/lib/isodoc/iso/init.rb +12 -1
- data/lib/isodoc/iso/iso.amendment.xsl +300 -227
- data/lib/isodoc/iso/iso.international-standard.xsl +300 -227
- data/lib/isodoc/iso/isosts_convert.rb +8 -3
- data/lib/isodoc/iso/presentation_xml_convert.rb +5 -5
- data/lib/isodoc/iso/presentation_xref.rb +23 -21
- data/lib/isodoc/iso/word_cleanup.rb +4 -0
- data/lib/isodoc/iso/word_convert.rb +1 -1
- data/lib/isodoc/iso/word_dis_cleanup.rb +7 -3
- data/lib/isodoc/iso/word_dis_convert.rb +1 -7
- data/lib/isodoc/iso/xref.rb +13 -9
- data/lib/isodoc/iso/xref_section.rb +3 -4
- data/lib/metanorma/iso/basicdoc.rng +3 -0
- data/lib/metanorma/iso/biblio-standoc.rng +1 -1
- data/lib/metanorma/iso/isodoc.rng +11 -0
- data/lib/metanorma/iso/version.rb +1 -1
- data/lib/metanorma/requirements/modspec.rb +3 -54
- data/lib/relaton/render/config.yml +1 -0
- data/metanorma-iso.gemspec +1 -1
- metadata +5 -5
@@ -13,14 +13,19 @@ module IsoDoc
|
|
13
13
|
@suffix = "isosts.xml"
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
file = File.read(input_fname, encoding: "utf-8") if file.nil?
|
18
|
-
_, fname, dir = convert_init(file, input_fname, debug)
|
16
|
+
def get_input_fname(input_fname)
|
19
17
|
/\.xml$/.match(input_fname) or
|
20
18
|
input_fname = Tempfile.open([fname, ".xml"], encoding: "utf-8") do |f|
|
21
19
|
f.write file
|
22
20
|
f.path
|
23
21
|
end
|
22
|
+
input_fname
|
23
|
+
end
|
24
|
+
|
25
|
+
def convert(input_fname, file = nil, debug = false, output_fname = nil)
|
26
|
+
file = File.read(input_fname, encoding: "utf-8") if file.nil?
|
27
|
+
_, fname, dir = convert_init(file, input_fname, debug)
|
28
|
+
input_fname = get_input_fname(input_fname)
|
24
29
|
FileUtils.rm_rf dir
|
25
30
|
MnConvert.convert(input_fname,
|
26
31
|
{
|
@@ -101,7 +101,7 @@ module IsoDoc
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def concept_term1(node, seen)
|
104
|
-
term = node
|
104
|
+
term = to_xml(node.at(ns("./refterm")))
|
105
105
|
if term && seen[term]
|
106
106
|
concept_render(node, ital: "false", ref: "false",
|
107
107
|
linkref: "true", linkmention: "false")
|
@@ -114,8 +114,8 @@ module IsoDoc
|
|
114
114
|
|
115
115
|
def concept1_ref_content(ref)
|
116
116
|
repl = if ref.name == "termref"
|
117
|
-
@i18n.term_defined_in.sub(/%/, ref
|
118
|
-
else "(#{ref
|
117
|
+
@i18n.term_defined_in.sub(/%/, to_xml(ref))
|
118
|
+
else "(#{to_xml(ref)})"
|
119
119
|
end
|
120
120
|
ref.replace(repl)
|
121
121
|
end
|
@@ -152,7 +152,7 @@ module IsoDoc
|
|
152
152
|
(v = elem.at(ns("./definition/verbal-definition"))) &&
|
153
153
|
v.elements.first.name == "p") or return
|
154
154
|
v.elements.first.children.first.previous =
|
155
|
-
"<#{d.remove.children
|
155
|
+
"<#{to_xml(d.remove.children)}> "
|
156
156
|
end
|
157
157
|
|
158
158
|
def insertall_after_here(node, insert, name)
|
@@ -186,7 +186,7 @@ module IsoDoc
|
|
186
186
|
p = n.next_element
|
187
187
|
return unless p.name == "p"
|
188
188
|
|
189
|
-
p.children.first.previous = admonition_name(n.remove.children
|
189
|
+
p.children.first.previous = admonition_name(to_xml(n.remove.children))
|
190
190
|
end
|
191
191
|
|
192
192
|
def admonition_name(xml)
|
@@ -33,9 +33,10 @@ module IsoDoc
|
|
33
33
|
ret = resolve_eref_connectives(eref_locality_stacks(refs, target,
|
34
34
|
node))
|
35
35
|
node["droploc"] = droploc
|
36
|
-
eref_localities1(target,
|
37
|
-
|
38
|
-
|
36
|
+
eref_localities1({ target: target, number: "pl",
|
37
|
+
type: prefix_clause(target, refs.first.at(ns("./locality"))),
|
38
|
+
from: l10n(ret[1..-1].join),
|
39
|
+
node: node, lang: @lang })
|
39
40
|
end
|
40
41
|
|
41
42
|
def prefix_clause(target, loc)
|
@@ -79,29 +80,30 @@ module IsoDoc
|
|
79
80
|
ret.join
|
80
81
|
end
|
81
82
|
|
82
|
-
def eref_localities1_zh(
|
83
|
-
ret = " 第#{from}" if from
|
84
|
-
ret += "–#{upto}" if upto
|
85
|
-
node["droploc"] != "true" &&
|
86
|
-
|
87
|
-
|
88
|
-
|
83
|
+
def eref_localities1_zh(opt)
|
84
|
+
ret = " 第#{opt[:from]}" if opt[:from]
|
85
|
+
ret += "–#{opt[:upto]}" if opt[:upto]
|
86
|
+
opt[:node]["droploc"] != "true" &&
|
87
|
+
!subclause?(opt[:target], opt[:type], opt[:from]) and
|
88
|
+
ret += eref_locality_populate(opt[:type], opt[:node], "sg")
|
89
|
+
ret += ")" if opt[:type] == "list"
|
90
|
+
locality_span_wrap(ret, opt[:type])
|
89
91
|
end
|
90
92
|
|
91
|
-
def eref_localities1(
|
92
|
-
return nil if type == "anchor"
|
93
|
+
def eref_localities1(opt)
|
94
|
+
return nil if opt[:type] == "anchor"
|
93
95
|
|
94
|
-
type = type.downcase
|
95
|
-
lang == "zh" and
|
96
|
-
return l10n(eref_localities1_zh(target, type, from, upto, node))
|
96
|
+
opt[:type] = opt[:type].downcase
|
97
|
+
opt[:lang] == "zh" and return l10n(eref_localities1_zh(opt))
|
97
98
|
ret = ""
|
98
|
-
node["droploc"] != "true" &&
|
99
|
-
|
100
|
-
|
101
|
-
ret += "
|
102
|
-
ret += "
|
99
|
+
opt[:node]["droploc"] != "true" &&
|
100
|
+
!subclause?(opt[:target], opt[:type], opt[:from]) and
|
101
|
+
ret = eref_locality_populate(opt[:type], opt[:node], opt[:number])
|
102
|
+
ret += " #{opt[:from]}" if opt[:from]
|
103
|
+
ret += "–#{opt[:upto]}" if opt[:upto]
|
104
|
+
ret += ")" if opt[:type] == "list"
|
103
105
|
ret = l10n(ret)
|
104
|
-
locality_span_wrap(ret, type)
|
106
|
+
locality_span_wrap(ret, opt[:type])
|
105
107
|
end
|
106
108
|
|
107
109
|
def prefix_container(container, linkend, node, target)
|
@@ -101,7 +101,7 @@ module IsoDoc
|
|
101
101
|
|
102
102
|
def footnote_reference_format(link)
|
103
103
|
link.children =
|
104
|
-
"<span class='MsoFootnoteReference'>#{link.children
|
104
|
+
"<span class='MsoFootnoteReference'>#{to_xml(link.children)}</span>)"
|
105
105
|
end
|
106
106
|
|
107
107
|
def bibliography_attrs
|
@@ -35,6 +35,10 @@ module IsoDoc
|
|
35
35
|
docxml.xpath("//p[not(@class)]").each { |p| p["class"] = "MsoBodyText" }
|
36
36
|
end
|
37
37
|
|
38
|
+
def sourcecode_style
|
39
|
+
"Code"
|
40
|
+
end
|
41
|
+
|
38
42
|
def dis_styles1(docxml)
|
39
43
|
amd_style(docxml)
|
40
44
|
code_style(docxml)
|
@@ -205,7 +209,7 @@ module IsoDoc
|
|
205
209
|
docxml.xpath("//p[@id = 'boilerplate-address']")&.each do |p|
|
206
210
|
p["class"] = "zzCopyright"
|
207
211
|
p["style"] = "text-indent:20.15pt;"
|
208
|
-
p.replace(p.
|
212
|
+
p.replace(to_xml(p).gsub(%r{<br/>}, "</p>\n<p class='zzCopyright' " \
|
209
213
|
"style='text-indent:20.15pt;'>"))
|
210
214
|
end
|
211
215
|
docxml.xpath("//p[@class = 'zzCopyrightHdr']")&.each do |p|
|
@@ -217,7 +221,7 @@ module IsoDoc
|
|
217
221
|
def copyright_dis(docxml)
|
218
222
|
docxml.xpath("//p[@id = 'boilerplate-address']")&.each do |p|
|
219
223
|
p["class"] = "zzCopyright"
|
220
|
-
p.replace(p.
|
224
|
+
p.replace(to_xml(p).gsub(%r{<br/>}, "</p>\n<p class='zzCopyright'>"))
|
221
225
|
end
|
222
226
|
docxml.xpath("//p[@class = 'zzCopyrightHdr']")&.each do |p|
|
223
227
|
p.remove
|
@@ -235,7 +239,7 @@ module IsoDoc
|
|
235
239
|
if t.at("./p |./div")
|
236
240
|
t.xpath("./p | ./div").each { |p| p["class"] = s }
|
237
241
|
else
|
238
|
-
t.children = "<div class='#{s}'>#{t.children
|
242
|
+
t.children = "<div class='#{s}'>#{to_xml(t.children)}</div>"
|
239
243
|
end
|
240
244
|
end
|
241
245
|
end
|
@@ -63,13 +63,7 @@ module IsoDoc
|
|
63
63
|
TOC
|
64
64
|
end
|
65
65
|
|
66
|
-
def
|
67
|
-
ret = super
|
68
|
-
ret[:sdo] = std_docid_semantic(ret[:sdo])
|
69
|
-
ret
|
70
|
-
end
|
71
|
-
|
72
|
-
def make_tr_attr(cell, row, totalrows, header)
|
66
|
+
def make_tr_attr(cell, row, totalrows, header, bordered)
|
73
67
|
super.merge(header: header)
|
74
68
|
end
|
75
69
|
|
data/lib/isodoc/iso/xref.rb
CHANGED
@@ -43,7 +43,7 @@ module IsoDoc
|
|
43
43
|
n = Counter.new
|
44
44
|
n = section_names(doc.at(ns("//clause[@type = 'scope']")), n, 1)
|
45
45
|
n = section_names(doc.at(ns(@klass.norm_ref_xpath)), n, 1)
|
46
|
-
doc.xpath(ns("//sections/clause[not(@type = 'scope')] | "\
|
46
|
+
doc.xpath(ns("//sections/clause[not(@type = 'scope')] | " \
|
47
47
|
"//sections/terms | //sections/definitions")).each do |c|
|
48
48
|
n = section_names(c, n, 1)
|
49
49
|
end
|
@@ -169,25 +169,29 @@ module IsoDoc
|
|
169
169
|
|
170
170
|
def modspec_table_xrefs(clause)
|
171
171
|
clause.xpath(ns(".//table[@class = 'modspec']")).noblank.each do |t|
|
172
|
-
(@anchors[t["id"]] && !@anchors[t["id"]][:modspec]) or next
|
173
172
|
n = @anchors[t["id"]][:xref]
|
174
|
-
|
175
|
-
@anchors[t["id"]][:xref] =
|
176
|
-
l10n("#{n}, #{@anchors_previous[t['id']][:xref_bare]}")
|
173
|
+
xref_to_modspec(t["id"], n) or next
|
177
174
|
modspec_table_components_xrefs(t, n)
|
178
175
|
end
|
179
176
|
end
|
180
177
|
|
181
178
|
def modspec_table_components_xrefs(table, table_label)
|
182
179
|
table.xpath(ns(".//tr[@id]")).each do |tr|
|
183
|
-
(
|
184
|
-
@anchors[tr["id"]][:modspec] = true
|
185
|
-
@anchors[tr["id"]][:xref] =
|
186
|
-
l10n("#{table_label}, #{@anchors_previous[tr['id']][:xref]}")
|
180
|
+
xref_to_modspec(tr["id"], table_label) or next
|
187
181
|
@anchors[tr["id"]].delete(:container)
|
188
182
|
end
|
189
183
|
end
|
190
184
|
|
185
|
+
def xref_to_modspec(id, table_label)
|
186
|
+
(@anchors[id] && !@anchors[id][:has_modspec]) or return
|
187
|
+
@anchors[id][:has_modspec] = true
|
188
|
+
x = @anchors_previous[id][:xref_bare] || @anchors_previous[id][:xref]
|
189
|
+
@anchors[id][:xref] = l10n("#{table_label}, #{x}")
|
190
|
+
@anchors[id][:modspec] = @anchors_previous[id][:modspec]
|
191
|
+
@anchors[id][:subtype] = "modspec" # prevents citetbl style from beign applied
|
192
|
+
true
|
193
|
+
end
|
194
|
+
|
191
195
|
def hierarchical_table_names(clause, _num)
|
192
196
|
super
|
193
197
|
modspec_table_xrefs(clause) if @anchors_previous
|
@@ -3,10 +3,9 @@ module IsoDoc
|
|
3
3
|
class Xref < IsoDoc::Xref
|
4
4
|
# we can reference 0-number clauses in introduction
|
5
5
|
def introduction_names(clause)
|
6
|
-
|
7
|
-
|
6
|
+
clause.nil? and return
|
8
7
|
clause.at(ns("./clause")) and
|
9
|
-
@anchors[clause["id"]] = { label:
|
8
|
+
@anchors[clause["id"]] = { label: nil, level: 1, type: "clause",
|
10
9
|
xref: clause.at(ns("./title"))&.text }
|
11
10
|
i = Counter.new
|
12
11
|
clause.xpath(ns("./clause")).each do |c|
|
@@ -43,7 +42,7 @@ module IsoDoc
|
|
43
42
|
@anchors[clause["id"]] =
|
44
43
|
{ label: num, level: level, xref: num, subtype: "clause" }
|
45
44
|
i = Counter.new
|
46
|
-
clause.xpath(ns("./clause | ./terms | ./term | ./definitions | "\
|
45
|
+
clause.xpath(ns("./clause | ./terms | ./term | ./definitions | " \
|
47
46
|
"./references"))
|
48
47
|
.each do |c|
|
49
48
|
i.increment(c)
|
@@ -571,6 +571,11 @@
|
|
571
571
|
<ref name="MultilingualRenderingType"/>
|
572
572
|
</attribute>
|
573
573
|
</optional>
|
574
|
+
<optional>
|
575
|
+
<attribute name="linenums">
|
576
|
+
<data type="boolean"/>
|
577
|
+
</attribute>
|
578
|
+
</optional>
|
574
579
|
<optional>
|
575
580
|
<ref name="tname"/>
|
576
581
|
</optional>
|
@@ -1238,6 +1243,11 @@
|
|
1238
1243
|
</define>
|
1239
1244
|
<define name="concept">
|
1240
1245
|
<element name="concept">
|
1246
|
+
<optional>
|
1247
|
+
<attribute name="bold">
|
1248
|
+
<data type="boolean"/>
|
1249
|
+
</attribute>
|
1250
|
+
</optional>
|
1241
1251
|
<optional>
|
1242
1252
|
<attribute name="ital">
|
1243
1253
|
<data type="boolean"/>
|
@@ -2653,6 +2663,7 @@
|
|
2653
2663
|
<value>full</value>
|
2654
2664
|
<value>short</value>
|
2655
2665
|
<value>id</value>
|
2666
|
+
<text/>
|
2656
2667
|
</choice>
|
2657
2668
|
</define>
|
2658
2669
|
<define name="erefTypeWithConnective">
|
@@ -3,15 +3,6 @@ module Metanorma
|
|
3
3
|
class Modspec
|
4
4
|
# Don't want to inherit from Metanorma::Requirements::Modspec
|
5
5
|
class Iso < ::Metanorma::Requirements::Modspec
|
6
|
-
def recommendation_label_xref(elem, label, xrefs, _type)
|
7
|
-
id = @reqtlabels[label]
|
8
|
-
number = xrefs.anchor(id, :xref_reqt2reqt, false)
|
9
|
-
number.nil? and return type
|
10
|
-
elem.ancestors("requirement, recommendation, permission").empty? and
|
11
|
-
return number
|
12
|
-
"<xref target='#{id}'>#{number}</xref>"
|
13
|
-
end
|
14
|
-
|
15
6
|
def recommendation_label(elem, type, xrefs)
|
16
7
|
lbl = super
|
17
8
|
title = elem.at(ns("./title"))
|
@@ -55,55 +46,13 @@ module Metanorma
|
|
55
46
|
|
56
47
|
def postprocess_anchor_struct(block, anchor)
|
57
48
|
super
|
58
|
-
anchor[:
|
49
|
+
anchor[:modspec] = anchor[:xref_bare]
|
59
50
|
if l = block.at(ns("./title"))
|
60
|
-
anchor[:
|
61
|
-
l10n("#{anchor[:
|
51
|
+
anchor[:modspec] =
|
52
|
+
l10n("#{anchor[:modspec]}: #{l.children.to_xml.strip}")
|
62
53
|
end
|
63
54
|
anchor
|
64
55
|
end
|
65
|
-
|
66
|
-
def reqt_ids(docxml)
|
67
|
-
docxml.xpath(ns("//requirement | //recommendation | //permission"))
|
68
|
-
.each_with_object({}) do |r, m|
|
69
|
-
id = r.at(ns("./identifier")) or next
|
70
|
-
m[id.text] =
|
71
|
-
{ id: r["id"],
|
72
|
-
lbl: @xrefs.anchor(r["id"], :xref_reqt2reqt, false) }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def reqt_links_test1(reqt, acc)
|
77
|
-
return unless %w(conformanceclass
|
78
|
-
verification).include?(reqt["type"])
|
79
|
-
|
80
|
-
subj = reqt_extract_target(reqt)
|
81
|
-
id = reqt.at(ns("./identifier")) or return
|
82
|
-
lbl = @xrefs.anchor(@reqt_ids[id.text.strip][:id], :xref_reqt2reqt,
|
83
|
-
false)
|
84
|
-
return unless subj
|
85
|
-
|
86
|
-
acc[subj.text] = { lbl: lbl, id: reqt["id"] }
|
87
|
-
end
|
88
|
-
|
89
|
-
def reqt_links_class(docxml)
|
90
|
-
docxml.xpath(ns("//requirement | //recommendation | //permission"))
|
91
|
-
.each_with_object({}) do |r, m|
|
92
|
-
next unless %w(class
|
93
|
-
conformanceclass).include?(r["type"])
|
94
|
-
|
95
|
-
id = r.at(ns("./identifier")) or next
|
96
|
-
r.xpath(ns("./requirement | ./recommendation | ./permission"))
|
97
|
-
.each do |r1|
|
98
|
-
id1 = r1.at(ns("./identifier")) or next
|
99
|
-
lbl = @xrefs.anchor(@reqt_ids[id.text.strip][:id],
|
100
|
-
:xref_reqt2reqt, false)
|
101
|
-
next unless lbl
|
102
|
-
|
103
|
-
m[id1.text] = { lbl: lbl, id: r["id"] }
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
56
|
end
|
108
57
|
end
|
109
58
|
end
|
@@ -23,6 +23,7 @@ template:
|
|
23
23
|
book: "<smallcap>{{ creatornames }}</smallcap> ({{role}}) . <em>{{ title }}</em> . {{ edition | capitalize_first }}. ({{ series }}). {% if place %}{{place}}{%else%}{{ labels['no_place']}}{%endif%}: {{publisher}}. {{date}}. {{size}}. {{extent}}. ._{{ labels['availablefrom'] }}:_<span_class='biburl'>{{ uri }}</span>. {{ labels['at'] | capitalize}}:_{{ access_location }}. [{{ labels['viewed'] }}:_{{date_accessed}}]."
|
24
24
|
booklet: book
|
25
25
|
manual: book
|
26
|
+
techreport: book
|
26
27
|
proceedings: book
|
27
28
|
inbook: "<smallcap>{{ creatornames }}</smallcap> ({{role}}) . {{ title }} . <em>{{host_title}}</em> ({{host_role}} {{ host_creatornames}}). {{ edition | capitalize_first }}. ({{ series }}). {% if place %}{{place}}{%else%}{{ labels['no_place']}}{%endif%}: {{publisher}}. {{date}}. {{size}}. {{extent}}. ._{{ labels['availablefrom'] }}:_<span_class='biburl'>{{ uri }}</span>. {{ labels['at'] | capitalize}}:_{{ access_location }}. [{{ labels['viewed'] }}:_{{date_accessed}}]."
|
28
29
|
inproceedings: inbook
|
data/metanorma-iso.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.test_files = `git ls-files -- {spec}/*`.split("\n")
|
33
33
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
34
34
|
|
35
|
-
spec.add_dependency "metanorma-standoc", "~> 2.
|
35
|
+
spec.add_dependency "metanorma-standoc", "~> 2.3.0"
|
36
36
|
spec.add_dependency "mnconvert", "~> 1.14"
|
37
37
|
spec.add_dependency "pubid-iso"
|
38
38
|
spec.add_dependency "ruby-jing"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma-iso
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: metanorma-standoc
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: 2.3.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: 2.3.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: mnconvert
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -415,7 +415,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
415
415
|
- !ruby/object:Gem::Version
|
416
416
|
version: '0'
|
417
417
|
requirements: []
|
418
|
-
rubygems_version: 3.3.
|
418
|
+
rubygems_version: 3.3.26
|
419
419
|
signing_key:
|
420
420
|
specification_version: 4
|
421
421
|
summary: metanorma-iso lets you write ISO standards in AsciiDoc.
|