validator.lua 3.0 KB

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