123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- return function(schema, tree)
- local context = {
- operationNames = {},
- hasAnonymousOperation = false,
- typeStack = {}
- }
- local visitors = {
- document = function(node)
- return node.definitions
- end,
- operation = function(node)
- local name = node.name and node.name.value
- if name then
- if context.operationNames[name] then
- error('Multiple operations exist named "' .. name .. '"')
- else
- context.operationNames[name] = true
- end
- else
- if context.hasAnonymousOperation or next(context.operationNames) then
- error('Cannot have more than one operation when using anonymous operations')
- end
- context.hasAnonymousOperation = true
- end
- return {node.selectionSet}
- end,
- selectionSet = function(node)
- return node.selections
- end,
- field = function(node)
- local currentType = context.typeStack[#context.typeStack].__type
- if currentType == 'Scalar' and node.selectionSet then
- error('Scalar values cannot have subselections')
- end
- local isCompositeType = currentType == 'Object' or currentType == 'Interface' or currentType == 'Union'
- if isCompositeType and not node.selectionSet then
- error('Composite types must have subselections')
- end
- if node.selectionSet then
- return {node.selectionSet}
- end
- end,
- inlineFragment = function(node)
- if node.selectionSet then
- return {node.selectionSet}
- end
- end
- }
- local root = schema.query
- local function visit(node)
- if node.kind and visitors[node.kind] then
- if node.kind == 'operation' then
- table.insert(context.typeStack, schema.query)
- elseif node.kind == 'field' then
- local parent = context.typeStack[#context.typeStack]
- if parent.fields[node.name.value] then
- table.insert(context.typeStack, parent.fields[node.name.value].kind)
- else
- error('Field "' .. node.name.value .. '" is not defined on type "' .. parent.name .. '"')
- end
- elseif node.kind == 'inlineFragment' then
- if node.typeCondition then
- local kind = schema:getType(node.typeCondition.name.value)
- if not kind then
- error('Inline fragment type condition refers to non-existent type')
- end
- if kind and kind.__type ~= 'Object' and kind.__type ~= 'Interface' and kind.__type ~= 'Union' then
- error('Inline fragment type condition was not an Object, Interface, or Union')
- end
- table.insert(context.typeStack, kind)
- end
- end
- local targets = visitors[node.kind](node)
- if targets then
- for _, target in ipairs(targets) do
- visit(target)
- end
- end
- end
- end
- visit(tree)
- end
|