validate.lua 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. local rules = require 'rules'
  2. local visitors = {
  3. document = {
  4. children = function(node, context)
  5. return node.definitions
  6. end
  7. },
  8. operation = {
  9. enter = function(node, context)
  10. table.insert(context.objects, context.schema.query)
  11. end,
  12. exit = function(node, context)
  13. table.remove(context.objects)
  14. end,
  15. children = function(node)
  16. return { node.selectionSet }
  17. end,
  18. rules = {
  19. rules.uniqueOperationNames,
  20. rules.loneAnonymousOperation
  21. }
  22. },
  23. selectionSet = {
  24. children = function(node)
  25. return node.selections
  26. end,
  27. rules = { rules.unambiguousSelections }
  28. },
  29. field = {
  30. enter = function(node, context)
  31. local parentField = context.objects[#context.objects].fields[node.name.value]
  32. -- false is a special value indicating that the field was not present in the type definition.
  33. context.currentField = parentField and parentField.kind or false
  34. table.insert(context.objects, context.currentField)
  35. end,
  36. exit = function(node, context)
  37. table.remove(context.objects)
  38. context.currentField = nil
  39. end,
  40. children = function(node)
  41. if node.selectionSet then
  42. return {node.selectionSet}
  43. end
  44. end,
  45. rules = {
  46. rules.fieldsDefinedOnType,
  47. rules.argumentsDefinedOnType,
  48. rules.scalarFieldsAreLeaves,
  49. rules.compositeFieldsAreNotLeaves
  50. }
  51. },
  52. inlineFragment = {
  53. enter = function(node, context)
  54. local kind = false
  55. if node.typeCondition then
  56. kind = context.schema:getType(node.typeCondition.name.value) or false
  57. end
  58. table.insert(context.objects, kind)
  59. end,
  60. exit = function(node, context)
  61. table.remove(context.objects)
  62. end,
  63. children = function(node, context)
  64. if node.selectionSet then
  65. return {node.selectionSet}
  66. end
  67. end,
  68. rules = { rules.inlineFragmentValidTypeCondition }
  69. }
  70. }
  71. return function(schema, tree)
  72. local context = {
  73. operationNames = {},
  74. hasAnonymousOperation = false,
  75. objects = {},
  76. schema = schema
  77. }
  78. local function visit(node)
  79. local visitor = node.kind and visitors[node.kind]
  80. if not visitor then return end
  81. if visitor.enter then
  82. visitor.enter(node, context)
  83. end
  84. if visitor.rules then
  85. for i = 1, #visitor.rules do
  86. visitor.rules[i](node, context)
  87. end
  88. end
  89. if visitor.children then
  90. local children = visitor.children(node)
  91. if children then
  92. for _, child in ipairs(children) do
  93. visit(child)
  94. end
  95. end
  96. end
  97. if visitor.exit then
  98. visitor.exit(node, context)
  99. end
  100. end
  101. return visit(tree)
  102. end