Browse Source

Variable uses are defined;

bjorn 9 years ago
parent
commit
afc95fcaef
2 changed files with 42 additions and 5 deletions
  1. 15 0
      rules.lua
  2. 27 5
      validate.lua

+ 15 - 0
rules.lua

@@ -438,4 +438,19 @@ function rules.variablesAreUsed(node, context)
   end
 end
 
+function rules.variablesAreDefined(node, context)
+  if context.variableReferences then
+    local variableMap = {}
+    for _, definition in ipairs(node.variableDefinitions or {}) do
+      variableMap[definition.variable.name.value] = true
+    end
+
+    for variable in pairs(context.variableReferences) do
+      if not variableMap[variable] then
+        error('Unknown variable "' .. variable .. '"')
+      end
+    end
+  end
+end
+
 return rules

+ 27 - 5
validate.lua

@@ -20,11 +20,13 @@ local visitors = {
   operation = {
     enter = function(node, context)
       table.insert(context.objects, context.schema.query)
+      context.currentOperation = node
       context.variableReferences = {}
     end,
 
     exit = function(node, context)
       table.remove(context.objects)
+      context.currentOperation = nil
       context.variableReferences = nil
     end,
 
@@ -39,7 +41,8 @@ local visitors = {
       rules.variablesHaveCorrectType,
       rules.variableDefaultValuesHaveCorrectType,
       exit = {
-        rules.variablesAreUsed
+        rules.variablesAreUsed,
+        rules.variablesAreDefined
       }
     }
   },
@@ -75,6 +78,12 @@ local visitors = {
         end
       end
 
+      if node.directives then
+        for i = 1, #node.directives do
+          table.insert(children, node.directives[i])
+        end
+      end
+
       if node.selectionSet then
         table.insert(children, node.selectionSet)
       end
@@ -131,7 +140,7 @@ local visitors = {
 
       table.insert(context.objects, fragmentType)
 
-      if context.variableReferences then
+      if context.currentOperation then
         local function collectTransitiveVariables(node)
           if not node then return end
 
@@ -179,7 +188,13 @@ local visitors = {
     end,
 
     children = function(node)
-      return { node.selectionSet }
+      local children = {}
+
+      for _, selection in ipairs(node.selectionSet) do
+        table.insert(children, selection)
+      end
+
+      return children
     end,
 
     rules = {
@@ -191,19 +206,25 @@ local visitors = {
 
   argument = {
     enter = function(node, context)
-      if context.variableReferences then
+      if context.currentOperation then
         local value = node.value
         while value.kind == 'listType' or value.kind == 'nonNullType' do
           value = value.type
         end
 
         if value.kind == 'variable' then
-          context.variablesUsed[value.name.value] = true
+          context.variableReferences[value.name.value] = true
         end
       end
     end,
 
     rules = { rules.uniqueInputObjectFields }
+  },
+
+  directive = {
+    children = function(node, context)
+      return node.arguments
+    end
   }
 }
 
@@ -215,6 +236,7 @@ return function(schema, tree)
     hasAnonymousOperation = false,
     usedFragments = {},
     objects = {},
+    currentOperation = nil,
     variableReferences = nil
   }