validator.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. local pp = require "pl.pretty"
  2. local term = require "volksdata.term"
  3. local pkar = require "pocket_archive"
  4. local model = require "pocket_archive.model"
  5. local logger = pkar.logger
  6. local dbg = require "debugger"
  7. local E_TYPE = "Type error"
  8. local E_CARD = "Cardinality error"
  9. local E_RANGE = "Range error"
  10. local M = {}
  11. M.validate = function(gr, s)
  12. _, ctype = next(gr:attr(s, pkar.CONTENT_TYPE_P))
  13. local rmod = model.parse_model(ctype.data)
  14. if not rmod then error("No type definition for ", ctype.data) end
  15. local report = {notices = {}, warnings = {}, errors = {}}
  16. for fname, rules in pairs(rmod.properties or NT) do
  17. local values
  18. values = gr:attr(s, term.new_iriref_ns(fname))
  19. -- Cardinality
  20. local card = 0
  21. for _, v in pairs(values) do card = card + 1 end
  22. if rules.min_cardinality or rules.max_cardinality then
  23. min_card = rules.min_cardinality or 0
  24. if card < min_card then
  25. table.insert(report.errors, {
  26. E_CARD,
  27. ("Too few values for %s: expected %d, got %d"):format(
  28. fname, min_card, card)
  29. })
  30. end
  31. max_card = rules.max_cardinality or math.huge
  32. if card > max_card then
  33. table.insert(report.errors, {
  34. E_CARD,
  35. ("Too many values for %s: expected %d, got %d"):format(
  36. fname, max_card, card)
  37. })
  38. end
  39. end
  40. -- From this point on, if there are no values, skip other criteria.
  41. if card == 0 then goto skip_prop end
  42. -- Type
  43. if rules.type then
  44. -- String type accepts any value.
  45. if rules.type == "number" then
  46. for v in pairs(values) do
  47. if type(v) ~= "number" then
  48. table.insert(
  49. report.errors, {
  50. E_TYPE,
  51. ("Number expected for %s; got: %s")
  52. :format(fname, v)
  53. })
  54. end
  55. end
  56. elseif rules.type == "resource" then
  57. for _, v in ipairs(values) do
  58. if v:sub(1,4) ~= "par" then
  59. table.insert(
  60. report.errors, {
  61. E_TYPE,
  62. ("`par:` prefix expected for %s; got: %s")
  63. :format(fname, v)
  64. })
  65. end
  66. end
  67. end
  68. end
  69. -- Range
  70. if rules.range then
  71. for _, v in ipairs(values) do
  72. end
  73. end
  74. ::skip_prop::
  75. end
  76. if #report.errors > 0 then report.max_level = "ERROR"
  77. elseif #report.warnings > 0 then report.max_level = "WARN"
  78. elseif #report.notices > 0 then report.max_level = "NOTICE" end
  79. return report
  80. end
  81. return M