Class: Metanorma::Standoc::Validate

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Image, Schema, Section, Table, Term
Defined in:
lib/metanorma/validate/term.rb,
lib/metanorma/validate/image.rb,
lib/metanorma/validate/table.rb,
lib/metanorma/validate/schema.rb,
lib/metanorma/validate/section.rb,
lib/metanorma/validate/validate.rb

Defined Under Namespace

Modules: Image, Schema, Section, Table, Term

Constant Summary collapse

MATHML_NS =
"http://www.w3.org/1998/Math/MathML".freeze

Constants included from Schema

Schema::SVG_NS, Schema::WILDCARD_ATTRS

Constants included from Utils

Utils::SECTION_CONTAINERS, Utils::SUBCLAUSE_XPATH

Constants included from Term

Term::SOURCELOCALITY

Constants included from Image

Image::SVG_NS

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Schema

#add_ns_to_fragment, #formattedstr_strip, #fragment_schema, #schema_file, #schema_location, #schema_validate, #schema_validate1, #schema_validate_with_retry, #validate_document_fragment

Methods included from Utils

#add_id, #add_id_text, #add_noko_elem, adoc2xml, #asciimath_key, #attr_code, #complete_and_compare_dates, #complete_iso_date, #complete_year_month, #complete_year_only, #convert, #csv_split, #dl_to_attrs, #dl_to_elems, #document_ns_attributes, #grkletters, #insert_before, #isodoc, #isolated_asciidoctor_convert, #kv_parse, #link_unwrap, #noko, #parse_complete_date, #parse_partial_date, #processor, #quoted_csv_split, #refid?, #section_containers, #separate_numbering_footnotes, #term_expr, #textcleanup, #to_xml, #wrap_in_para, #xml_encode

Methods included from Term

#concept_validate, #concept_validate_ids, #concept_validate_msg, #find_illegal_designations, #iev_validate, #iev_validate1, #init_iev, #preferred_validate, #preferred_validate_report, #termsect_validate

Methods included from Table

#empty_table_validate, #max_td_count, #maxcols_check, #maxcols_validate1, #maxrowcols_validate, #maxrowcols_validate0, #maxrows_validate, #table_tracker_update, #table_validate

Methods included from Section

#asset_style, #asset_title_style, #callouts_error, #hanging_para_style, #norm_ref_validate, #reject_metanorma_extension, #section_validate, #sourcecode_style, #style_warning

Methods included from Image

#expand_path, #image_exists, #image_toobig, #image_validate, #png_validate, #png_validate1, #save_dataimage, #save_dataimage_prep, #svg_error, #svg_error_locations, #svg_reference_violations, #svg_remed_log, #svg_remediate, #svg_validate, #svg_validate1, #svg_validate_fix

Constructor Details

#initialize(converter) ⇒ Validate

Returns a new instance of Validate.



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/metanorma/validate/validate.rb', line 31

def initialize(converter)
  @conv= converter
  @log = converter.log
  @files_to_delete = converter.files_to_delete
  copied_instance_variables.each do |var|
    instance_variable_set("@#{var}",
                          converter.instance_variable_get("@#{var}"))
  end
  @doc_ids = {}
  @doc_anchors = {}
  @doc_xrefs = {}
end

Class Attribute Details

._fileObject

Returns the value of attribute _file.



45
46
47
# File 'lib/metanorma/validate/validate.rb', line 45

def _file
  @_file
end

Instance Attribute Details

#doc_anchor_seqObject (readonly)

Returns the value of attribute doc_anchor_seq.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_anchor_seq
  @doc_anchor_seq
end

#doc_anchor_seq_hashObject (readonly)

Returns the value of attribute doc_anchor_seq_hash.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_anchor_seq_hash
  @doc_anchor_seq_hash
end

#doc_anchorsObject (readonly)

Returns the value of attribute doc_anchors.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_anchors
  @doc_anchors
end

#doc_id_seqObject (readonly)

Returns the value of attribute doc_id_seq.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_id_seq
  @doc_id_seq
end

#doc_id_seq_hashObject (readonly)

Returns the value of attribute doc_id_seq_hash.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_id_seq_hash
  @doc_id_seq_hash
end

#doc_idsObject (readonly)

Returns the value of attribute doc_ids.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_ids
  @doc_ids
end

#doc_xrefsObject (readonly)

Returns the value of attribute doc_xrefs.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def doc_xrefs
  @doc_xrefs
end

#files_to_deleteObject (readonly)

Returns the value of attribute files_to_delete.



21
22
23
# File 'lib/metanorma/validate/validate.rb', line 21

def files_to_delete
  @files_to_delete
end

Class Method Details

.inherited(konv) ⇒ Object

rubocop:disable Lint/MissingSuper



48
49
50
# File 'lib/metanorma/validate/validate.rb', line 48

def self.inherited(konv) # rubocop:disable Lint/MissingSuper
  konv._file = caller_locations(1..1).first.absolute_path
end

Instance Method Details

#all_empty_block_validate(doc) ⇒ Object



240
241
242
243
244
245
246
247
248
249
# File 'lib/metanorma/validate/validate.rb', line 240

def all_empty_block_validate(doc)
  %w(note example admonition figure quote pre).each do |tag|
    empty_block_validate(doc, "//#{tag}", nil)
  end
  empty_block_validate(doc, "//sourcecode", "body")
  empty_block_validate(doc, "//formula", "stem")
  empty_block_validate(doc, "//ol", "li")
  empty_block_validate(doc, "//ul", "li")
  empty_block_validate(doc, "//dl", "dt")
end

#block_validate(doc) ⇒ Object



235
236
237
238
# File 'lib/metanorma/validate/validate.rb', line 235

def block_validate(doc)
  nested_asset_validate(doc)
  all_empty_block_validate(doc)
end

#content_validate(doc) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/metanorma/validate/validate.rb', line 52

def content_validate(doc)
  @doctype = doc.at("//bibdata/ext/doctype")&.text
  repeat_id_validate(doc.root) # feeds xref_validate, termsect_validate
  xref_validate(doc) # feeds nested_asset_validate
  section_validate(doc)
  norm_ref_validate(doc)
  # iev_validate(doc.root) # disabled, access restrictions
  concept_validate(doc, "concept", "refterm")
  concept_validate(doc, "related", "preferred//name")
  preferred_validate(doc)
  termsect_validate(doc)
  table_validate(doc)
  @conv.requirement_validate(doc)
  image_validate(doc)
  block_validate(doc)
  math_validate(doc)
  fatalerrors = @log.abort_messages
  fatalerrors.empty? or
    @conv.clean_abort("\n\nFATAL ERRORS:\n\n#{fatalerrors.join("\n\n")}",
                      doc)
end

#copied_instance_variablesObject

Instance variables to copy from converter



26
27
28
29
# File 'lib/metanorma/validate/validate.rb', line 26

def copied_instance_variables
  %i[localdir dataurimaxsize svg_conform_profile no_isobib iev_globalname
     iev_localname c lang script locale i18n doctype]
end

#empty_block?(block) ⇒ Boolean

Returns:

  • (Boolean)


260
261
262
263
264
265
266
267
# File 'lib/metanorma/validate/validate.rb', line 260

def empty_block?(block)
  block.nil? and return
  content = block.children.reject { |n| n.name == "name" }
  content.map do |n|
    %w(image xref eref).include?(n.name) ? n.name : n
  end
  content.map(&:to_s).join.strip.empty?
end

#empty_block_validate(doc, tag, body) ⇒ Object



251
252
253
254
255
256
257
258
# File 'lib/metanorma/validate/validate.rb', line 251

def empty_block_validate(doc, tag, body)
  # require "debug"; binding.b
  doc.xpath(tag).each do |t|
    body and t = t.at("./#{body}")
    empty_block?(t) or next
    @log.add("STANDOC_39", t, params: [tag.sub(/^\/\//, "")])
  end
end

#get_anchors_between(start_id, end_id) ⇒ Object

Retrieve anchors between two nominated values (exclusive of start_id AND exclusive of end_id)



194
195
196
197
198
199
200
# File 'lib/metanorma/validate/validate.rb', line 194

def get_anchors_between(start_id, end_id)
  start_index = @doc_anchor_seq_hash[start_id]
  end_index = @doc_anchor_seq_hash[end_id]
  start_index.nil? || end_index.nil? and return []
  start_index >= end_index and return []
  @doc_anchor_seq[start_index...end_index]
end

#math_validate(doc) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/metanorma/validate/validate.rb', line 76

def math_validate(doc)
  doc.xpath("//m:math", "m" => MATHML_NS).each do |m|
    if m.parent["validate"] == "false"
      m.parent.delete("validate")
    else
      math = mathml_sanitise(m.dup)
      Plurimath::Math.parse(math, "mathml").to_mathml
    end
  rescue StandardError => e
    math_validate_error(math, m, e)
  end
end

#math_validate_error(math, elem, error) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/metanorma/validate/validate.rb', line 94

def math_validate_error(math, elem, error)
  a = elem.parent.at("./asciimath")
  l = elem.parent.at("./latexmath")
  orig = ""
  a and orig += "\n\tAsciimath original: #{@c.decode(a.children.to_xml)}"
  l and orig += "\n\tLatexmath original: #{@c.decode(l.children.to_xml)}"
  @log.add("STANDOC_33", elem, params: [math, error, orig])
end

#mathml_sanitise(math) ⇒ Object



89
90
91
92
# File 'lib/metanorma/validate/validate.rb', line 89

def mathml_sanitise(math)
  math.to_xml(encoding: "US-ASCII").gsub(/ xmlns=["'][^"']+["']/, "")
    .gsub(%r{<[^:/>]+:}, "<").gsub(%r{</[^:/>]+:}, "</")
end

#nested_asset_report(outer, inner, doc) ⇒ Object



125
126
127
128
129
130
# File 'lib/metanorma/validate/validate.rb', line 125

def nested_asset_report(outer, inner, doc)
  outer.name == "figure" && inner.name == "figure" and return
  outer.name == "table" && inner.name == "example" and return
  @log.add("STANDOC_34", inner, params: [inner.name, outer.name])
  nested_asset_xref_report(outer, inner, doc)
end

#nested_asset_validate(doc) ⇒ Object



103
104
105
106
# File 'lib/metanorma/validate/validate.rb', line 103

def nested_asset_validate(doc)
  nested_asset_validate_basic(doc)
  nested_note_validate(doc)
end

#nested_asset_validate_basic(doc) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/metanorma/validate/validate.rb', line 108

def nested_asset_validate_basic(doc)
  a = "//example | //figure | //termnote | //termexample | //table"
  doc.xpath("#{a} | //note").each do |m|
    m.xpath(a.gsub(%r{//}, ".//")).each do |n|
      nested_asset_report(m, n, doc)
    end
  end
end

#nested_asset_xref_report(outer, inner, _doc) ⇒ Object



132
133
134
135
136
# File 'lib/metanorma/validate/validate.rb', line 132

def nested_asset_xref_report(outer, inner, _doc)
  i = @doc_xrefs[inner["anchor"]] or return
  @log.add("STANDOC_35", i,
           params: [inner.name, outer.name, i.to_xml])
end

#nested_note_validate(doc) ⇒ Object



117
118
119
120
121
122
123
# File 'lib/metanorma/validate/validate.rb', line 117

def nested_note_validate(doc)
  doc.xpath("//termnote | //note").each do |m|
    m.xpath(".//note").each do |n|
      nested_asset_report(m, n, doc)
    end
  end
end

#process_range_location(to_location) ⇒ Object



226
227
228
229
230
231
232
233
# File 'lib/metanorma/validate/validate.rb', line 226

def process_range_location(to_location)
  # Get the preceding location element if it exists
  from = to_location.previous_element
  from && from.name == "location" or return
  from["target"] && to_location["target"] or return
  get_anchors_between(from["target"], to_location["target"])
    .each { |id| @doc_xrefs[id] = from }
end

#repeat_anchor_validate1(elem) ⇒ Object



156
157
158
159
160
161
162
163
164
165
# File 'lib/metanorma/validate/validate.rb', line 156

def repeat_anchor_validate1(elem)
  if @doc_anchors[elem["anchor"]]
    @log.add("STANDOC_36", elem,
             params: [elem["anchor"], @doc_anchors[elem["anchor"]][:line]])
  else
    @doc_anchors[elem["anchor"]] =
      { line: elem.line, id: elem["id"] }
    @doc_anchor_seq << elem["anchor"]
  end
end

#repeat_id_validate(doc) ⇒ Object

Check should never happen with content ids, but will check it anyway



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/metanorma/validate/validate.rb', line 168

def repeat_id_validate(doc)
  repeat_id_validate_prep
  doc.xpath("//*[@id]").each do |x|
    @doc_id_seq << x["id"]
    repeat_id_validate1(x)
    x["anchor"] and repeat_anchor_validate1(x)
  end
  @doc_id_seq_hash = @doc_id_seq.each_with_index
    .with_object({}) do |(x, i), m|
      m[x] = i
  end
  @doc_anchor_seq_hash = @doc_anchor_seq.each_with_index
    .with_object({}) do |(x, i), m|
      m[x] = i
  end
end

#repeat_id_validate1(elem) ⇒ Object

Check should never happen with content ids, but will check it anyway since consequences are so catastrophic



146
147
148
149
150
151
152
153
154
# File 'lib/metanorma/validate/validate.rb', line 146

def repeat_id_validate1(elem)
  if @doc_ids[elem["id"]]
    @log.add("STANDOC_36", elem,
             params: [elem["id"], @doc_ids[elem["id"]][:line]])
  else
    @doc_ids[elem["id"]] =
      { line: elem.line, anchor: elem["anchor"] }.compact
  end
end

#repeat_id_validate_prepObject



185
186
187
188
189
190
# File 'lib/metanorma/validate/validate.rb', line 185

def repeat_id_validate_prep
  @doc_ids = {} # hash of all ids in document to line number, anchor
  @doc_anchors = {} # hash of all anchors in document to line number, id
  @doc_id_seq = [] # ordered list of all ids in document
  @doc_anchor_seq = [] # ordered list of all anchors in document
end

#validate(doc) ⇒ Object



138
139
140
141
142
# File 'lib/metanorma/validate/validate.rb', line 138

def validate(doc)
  @log.add_error_ranges(doc)
  content_validate(doc)
  schema_validate(formattedstr_strip(doc.dup), schema_location)
end

#xref_range_record(doc) ⇒ Object

If there is an xref range, record the IDs between the two targets



220
221
222
223
224
# File 'lib/metanorma/validate/validate.rb', line 220

def xref_range_record(doc)
  doc.xpath("//xref//location[@connective = 'to']").each do |to|
    process_range_location(to)
  end
end

#xref_validate(doc) ⇒ Object

manually check for xref/@target et sim. integrity



203
204
205
206
# File 'lib/metanorma/validate/validate.rb', line 203

def xref_validate(doc)
  xref_validate_exists(doc)
  xref_range_record(doc)
end

#xref_validate_exists(doc) ⇒ Object



208
209
210
211
212
213
214
215
216
217
# File 'lib/metanorma/validate/validate.rb', line 208

def xref_validate_exists(doc)
  @doc_xrefs = {}
  Metanorma::Utils::anchor_attributes.each do |a|
    doc.xpath("//#{a[0]}/@#{a[1]}").each do |x|
      @doc_xrefs[x.text] = x.parent
      @doc_anchors[x.text] and next
      @log.add("STANDOC_38", x.parent, params: [x.text])
    end
  end
end