Skip to content
This repository has been archived by the owner on Nov 18, 2017. It is now read-only.

Input object type #9

Merged
merged 3 commits into from
Mar 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/graphql-shorthand.pegjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
start
= WS* definitions:(Enum / Interface / Object)* WS*
= WS* definitions:(Enum / Interface / Object / InputObject)* WS*
{ return definitions; }

Ident = $([a-z]([a-z0-9_]i)*)
TypeIdent = $([A-Z]([a-z0-9_]i)*)
EnumIdent = $([A-Z][A-Z0-9_]*)
NumberIdent = $([.+-]?[0-9]+([.][0-9]+)?)

Enum
= description:Comment? "enum" SPACE name:TypeIdent BEGIN_BODY values:EnumIdentList CLOSE_BODY
Expand All @@ -18,6 +19,10 @@ Object
= description:Comment? "type" SPACE name:TypeIdent interfaces:(COLON list:TypeList { return list; })? BEGIN_BODY fields:FieldList CLOSE_BODY
{ return { type: "TYPE", name, ...(description && { description }), fields, ...(interfaces && { interfaces }) }; }

InputObject
= description:Comment? "input" SPACE name:TypeIdent interfaces:(COLON list:TypeList { return list; })? BEGIN_BODY fields:InputFieldList CLOSE_BODY
{ return { type: "INPUT", name, ...(description && { description }), fields, ...(interfaces && { interfaces }) }; }

ReturnType
= type:TypeIdent required:"!"?
{ return { type, ...(required && { required: !!required }) }; }
Expand All @@ -36,6 +41,14 @@ FieldList
= head:Field tail:(EOL_SEP field:Field { return field; })*
{ return [head, ...tail].reduce((result, field) => ({ ...result, ...field }), {}); }

InputField
= description:Comment? name:Ident args:(BEGIN_ARGS fields:FieldList CLOSE_ARGS { return fields; })? COLON type:ReturnType defaultValue:(EQUAL value:Literal { return value; })?
{ return { [name]: { ...type, ...(args && { args }), ...(description && { description }), ...(defaultValue && { defaultValue }) } }; }

InputFieldList
= head:InputField tail:(EOL_SEP field:InputField { return field; })*
{ return [head, ...tail].reduce((result, field) => ({ ...result, ...field }), {}); }

EnumIdentList
= head:EnumIdent tail:(EOL_SEP value:EnumIdent { return value; })*
{ return [head, ...tail]; }
Expand All @@ -46,6 +59,22 @@ Comment
/ "/*" comment:(!"*/" char:CHAR { return char; })* "*/" EOL_SEP
{ return comment.join("").replace(/\n\s*[*]?\s*/g, " ").replace(/\s+/, " ").trim(); }

Literal
= StringLiteral / BooleanLiteral / NumericLiteral

StringLiteral
= '"' chars:DoubleStringCharacter* '"' { return chars.join(""); }

DoubleStringCharacter
= !('"' / "\\" / EOL) . { return text(); }

BooleanLiteral
= "true" { return true }
/ "false" { return false }

NumericLiteral
= value:NumberIdent { return Number(value.replace(/^[.]/, '0.')); }

LINE_COMMENT = "#" / "//"

BEGIN_BODY = WS* "{" WS*
Expand All @@ -59,6 +88,7 @@ CHAR = .
WS = (SPACE / EOL)+

COLON = WS* ":" WS*
EQUAL = WS* "=" WS*

COMMA_SEP = WS* "," WS*
EOL_SEP = SPACE* EOL SPACE*
Expand Down
106 changes: 106 additions & 0 deletions test/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import test from "ava";
import { parse } from "..";

test("input definition", t => {
const [actual] = parse(`
// A Person
input Person {
id: String!
// The full name
name: String
}
`);

const expected = {
type: "INPUT",
name: "Person",
description: "A Person",
fields: {
id: { type: "String", required: true },
name: { type: "String", description: "The full name" }
}
};

return t.same(actual, expected);
});

test("input with boolean defaultValue", t => {
const [actual] = parse(`
input Person {
alive: Boolean = true
}
`);

const expected = {
type: "INPUT",
name: "Person",
fields: {
alive: { type: "Boolean", defaultValue: true },
}
};

return t.same(actual, expected);
});


test("input with string default values", t => {
const [actual] = parse(`
// A Person
input Person {
id: String!
firstname: String = "Hans"
lastname: String = "Wurst"
}
`);

const expected = {
type: "INPUT",
name: "Person",
description: "A Person",
fields: {
id: { type: "String", required: true },
firstname: { type: "String", defaultValue: "Hans" },
lastname: { type: "String", defaultValue: "Wurst" }
}
};

return t.same(actual, expected);
});

test("input with integer defaultValue", t => {
const [actual] = parse(`
input Person {
age: Int = 32
}
`);

const expected = {
type: "INPUT",
name: "Person",
fields: {
age: { type: "Int", defaultValue: 32 },
}
};

return t.same(actual, expected);
});

test("input with float defaultValue", t => {
const [actual] = parse(`
input Person {
height: Float = 1.82
iq: Float = .5
}
`);

const expected = {
type: "INPUT",
name: "Person",
fields: {
height: { type: "Float", defaultValue: 1.82 },
iq: { type: "Float", defaultValue: 0.5 },
}
};

return t.same(actual, expected);
});