Example #1
0
func parseValueLiteral(parser *Parser, isConst bool) (ast.Value, error) {
	token := parser.Token
	switch token.Kind {
	case lexer.TokenKind[lexer.BRACKET_L]:
		return parseList(parser, isConst)
	case lexer.TokenKind[lexer.BRACE_L]:
		return parseObject(parser, isConst)
	case lexer.TokenKind[lexer.INT]:
		advance(parser)
		return ast.NewIntValue(&ast.IntValue{
			Value: token.Value,
			Loc:   loc(parser, token.Start),
		}), nil
	case lexer.TokenKind[lexer.FLOAT]:
		advance(parser)
		return ast.NewFloatValue(&ast.FloatValue{
			Value: token.Value,
			Loc:   loc(parser, token.Start),
		}), nil
	case lexer.TokenKind[lexer.STRING]:
		advance(parser)
		return ast.NewStringValue(&ast.StringValue{
			Value: token.Value,
			Loc:   loc(parser, token.Start),
		}), nil
	case lexer.TokenKind[lexer.NAME]:
		if token.Value == "true" || token.Value == "false" {
			advance(parser)
			value := true
			if token.Value == "false" {
				value = false
			}
			return ast.NewBooleanValue(&ast.BooleanValue{
				Value: value,
				Loc:   loc(parser, token.Start),
			}), nil
		} else if token.Value != "null" {
			advance(parser)
			return ast.NewEnumValue(&ast.EnumValue{
				Value: token.Value,
				Loc:   loc(parser, token.Start),
			}), nil
		}
	case lexer.TokenKind[lexer.DOLLAR]:
		if !isConst {
			return parseVariable(parser)
		}
	}
	if err := unexpected(parser, lexer.Token{}); err != nil {
		return nil, err
	}
	return nil, nil
}
Example #2
0
/**
 * Produces a GraphQL Value AST given a Golang value.
 *
 * Optionally, a GraphQL type may be provided, which will be used to
 * disambiguate between value primitives.
 *
 * | JSON Value    | GraphQL Value        |
 * | ------------- | -------------------- |
 * | Object        | Input Object         |
 * | Array         | List                 |
 * | Boolean       | Boolean              |
 * | String        | String / Enum Value  |
 * | Number        | Int / Float          |
 *
 */
func astFromValue(value interface{}, ttype Type) ast.Value {

	if ttype, ok := ttype.(*NonNull); ok {
		// Note: we're not checking that the result is non-null.
		// This function is not responsible for validating the input value.
		val := astFromValue(value, ttype.OfType)
		return val
	}
	if isNullish(value) {
		return nil
	}
	valueVal := reflect.ValueOf(value)
	if !valueVal.IsValid() {
		return nil
	}
	if valueVal.Type().Kind() == reflect.Ptr {
		valueVal = valueVal.Elem()
	}
	if !valueVal.IsValid() {
		return nil
	}

	// Convert Golang slice to GraphQL list. If the Type is a list, but
	// the value is not an array, convert the value using the list's item type.
	if ttype, ok := ttype.(*List); ok {
		if valueVal.Type().Kind() == reflect.Slice {
			itemType := ttype.OfType
			values := []ast.Value{}
			for i := 0; i < valueVal.Len(); i++ {
				item := valueVal.Index(i).Interface()
				itemAST := astFromValue(item, itemType)
				if itemAST != nil {
					values = append(values, itemAST)
				}
			}
			return ast.NewListValue(&ast.ListValue{
				Values: values,
			})
		} else {
			// Because GraphQL will accept single values as a "list of one" when
			// expecting a list, if there's a non-array value and an expected list type,
			// create an AST using the list's item type.
			val := astFromValue(value, ttype.OfType)
			return val
		}
	}

	if valueVal.Type().Kind() == reflect.Map {
		// TODO: implement astFromValue from Map to Value
	}

	if value, ok := value.(bool); ok {
		return ast.NewBooleanValue(&ast.BooleanValue{
			Value: value,
		})
	}
	if value, ok := value.(int); ok {
		if ttype == Float {
			return ast.NewIntValue(&ast.IntValue{
				Value: fmt.Sprintf("%v.0", value),
			})
		}
		return ast.NewIntValue(&ast.IntValue{
			Value: fmt.Sprintf("%v", value),
		})
	}
	if value, ok := value.(float32); ok {
		return ast.NewFloatValue(&ast.FloatValue{
			Value: fmt.Sprintf("%v", value),
		})
	}
	if value, ok := value.(float64); ok {
		return ast.NewFloatValue(&ast.FloatValue{
			Value: fmt.Sprintf("%v", value),
		})
	}

	if value, ok := value.(string); ok {
		if _, ok := ttype.(*Enum); ok {
			return ast.NewEnumValue(&ast.EnumValue{
				Value: fmt.Sprintf("%v", value),
			})
		}
		return ast.NewStringValue(&ast.StringValue{
			Value: fmt.Sprintf("%v", value),
		})
	}

	// fallback, treat as string
	return ast.NewStringValue(&ast.StringValue{
		Value: fmt.Sprintf("%v", value),
	})
}
Example #3
0
func TestParsesMultiByteCharacters_UnicodeText(t *testing.T) {

	doc := `
        # This comment has a фы世界 multi-byte character.
        { field(arg: "Has a фы世界 multi-byte character.") }
	`
	astDoc := parse(t, doc)

	expectedASTDoc := ast.NewDocument(&ast.Document{
		Loc: ast.NewLocation(&ast.Location{
			Start: 67,
			End:   121,
		}),
		Definitions: []ast.Node{
			ast.NewOperationDefinition(&ast.OperationDefinition{
				Loc: ast.NewLocation(&ast.Location{
					Start: 67,
					End:   119,
				}),
				Operation: "query",
				SelectionSet: ast.NewSelectionSet(&ast.SelectionSet{
					Loc: ast.NewLocation(&ast.Location{
						Start: 67,
						End:   119,
					}),
					Selections: []ast.Selection{
						ast.NewField(&ast.Field{
							Loc: ast.NewLocation(&ast.Location{
								Start: 67,
								End:   117,
							}),
							Name: ast.NewName(&ast.Name{
								Loc: ast.NewLocation(&ast.Location{
									Start: 69,
									End:   74,
								}),
								Value: "field",
							}),
							Arguments: []*ast.Argument{
								ast.NewArgument(&ast.Argument{
									Loc: ast.NewLocation(&ast.Location{
										Start: 75,
										End:   116,
									}),
									Name: ast.NewName(&ast.Name{

										Loc: ast.NewLocation(&ast.Location{
											Start: 75,
											End:   78,
										}),
										Value: "arg",
									}),
									Value: ast.NewStringValue(&ast.StringValue{

										Loc: ast.NewLocation(&ast.Location{
											Start: 80,
											End:   116,
										}),
										Value: "Has a фы世界 multi-byte character.",
									}),
								}),
							},
						}),
					},
				}),
			}),
		},
	})

	astDocQuery := printer.Print(astDoc)
	expectedASTDocQuery := printer.Print(expectedASTDoc)

	if !reflect.DeepEqual(astDocQuery, expectedASTDocQuery) {
		t.Fatalf("unexpected document, expected: %v, got: %v", astDocQuery, expectedASTDocQuery)
	}
}