Skip to content

Commit

Permalink
feat: add fragment concat support
Browse files Browse the repository at this point in the history
Add fragment concat support
  • Loading branch information
gajus authored Sep 18, 2017
2 parents c4ebf10 + 1e0ba3c commit f5001f4
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 4 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,35 @@ const foo = {
};

```

### Using fragments

Using GraphQL [fragments](http://graphql.org/learn/queries/#fragments) requires to:

1. Define a fragment using `graphql-tag`.
2. Append the referenced fragment as a variable to the end of the GraphQL query.

Example:

```js
import gql from 'graphql-tag';

const bar = gql`
fragment barFragment on Foo {
field1
field2
}
`;

const foo = gql`
query foo {
foo {
...barFragment
}
}
${bar}
`;

```

36 changes: 32 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import {
isIdentifier,
TemplateLiteral
isMemberExpression,
memberExpression,
callExpression,
identifier
} from 'babel-types';
import parse from 'babel-literal-to-ast';
import gql from 'graphql-tag';
Expand All @@ -11,11 +14,19 @@ import createDebug from 'debug';
const debug = createDebug('babel-plugin-graphql-tag');

export default () => {
const compile = (node: TemplateLiteral) => {
const source = node.quasis.reduce((head, quasi) => {
const compile = (path: Object) => {
const source = path.node.quasis.reduce((head, quasi) => {
return head + quasi.value.raw;
}, '');

const expressions = path.get('expressions');

expressions.forEach((expr) => {
if (!isIdentifier(expr) && !isMemberExpression(expr)) {
throw expr.buildCodeFrameError('Only identifiers or member expressions are allowed by this plugin as an interpolation in a graphql template literal.');
}
});

debug('compiling a GraphQL query', source);

const queryDocument = gql(source);
Expand All @@ -28,6 +39,23 @@ export default () => {

const body = parse(queryDocument);

if (expressions.length) {
const definitionsProperty = body.properties.find((property) => {
return property.key.value === 'definitions';
});

const definitionsArray = definitionsProperty.value;

const extraDefinitions = expressions.map((expr) => {
return memberExpression(expr.node, identifier('definitions'));
});

definitionsProperty.value = callExpression(
memberExpression(definitionsArray, identifier('concat')),
extraDefinitions
);
}

debug('created a static representation', body);

return body;
Expand All @@ -47,7 +75,7 @@ export default () => {
try {
debug('quasi', path.node.quasi);

const body = compile(path.node.quasi);
const body = compile(path.get('quasi'));

path.replaceWith(body);
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import gql from 'graphql-tag';

const bar = gql`
fragment barFragment on Foo {
field1
field2
}
`;

const baz = {
fragments: {
foo: gql`
fragment bazFragment on Foo {
field2
field3
}
`
}
};

const foo = gql`
query foo {
foo {
...barFragment
...bazFragment
}
}
${bar}
${baz.fragments.foo}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
const bar = {
'kind': 'Document',
'definitions': [{
'kind': 'FragmentDefinition',
'name': {
'kind': 'Name',
'value': 'barFragment'
},
'typeCondition': {
'kind': 'NamedType',
'name': {
'kind': 'Name',
'value': 'Foo'
}
},
'directives': [],
'selectionSet': {
'kind': 'SelectionSet',
'selections': [{
'kind': 'Field',
'alias': null,
'name': {
'kind': 'Name',
'value': 'field1'
},
'arguments': [],
'directives': [],
'selectionSet': null
}, {
'kind': 'Field',
'alias': null,
'name': {
'kind': 'Name',
'value': 'field2'
},
'arguments': [],
'directives': [],
'selectionSet': null
}]
}
}],
'loc': {
'start': 0,
'end': 59,
'source': {
'body': '\n fragment barFragment on Foo {\n field1\n field2\n }\n',
'name': 'GraphQL request',
'locationOffset': {
'line': 1,
'column': 1
}
}
}
};

const baz = {
fragments: {
foo: {
'kind': 'Document',
'definitions': [{
'kind': 'FragmentDefinition',
'name': {
'kind': 'Name',
'value': 'bazFragment'
},
'typeCondition': {
'kind': 'NamedType',
'name': {
'kind': 'Name',
'value': 'Foo'
}
},
'directives': [],
'selectionSet': {
'kind': 'SelectionSet',
'selections': [{
'kind': 'Field',
'alias': null,
'name': {
'kind': 'Name',
'value': 'field2'
},
'arguments': [],
'directives': [],
'selectionSet': null
}, {
'kind': 'Field',
'alias': null,
'name': {
'kind': 'Name',
'value': 'field3'
},
'arguments': [],
'directives': [],
'selectionSet': null
}]
}
}],
'loc': {
'start': 0,
'end': 79,
'source': {
'body': '\n fragment bazFragment on Foo {\n field2\n field3\n }\n ',
'name': 'GraphQL request',
'locationOffset': {
'line': 1,
'column': 1
}
}
}
}
}
};

const foo = {
'kind': 'Document',
'definitions': [{
'kind': 'OperationDefinition',
'operation': 'query',
'name': {
'kind': 'Name',
'value': 'foo'
},
'variableDefinitions': [],
'directives': [],
'selectionSet': {
'kind': 'SelectionSet',
'selections': [{
'kind': 'Field',
'alias': null,
'name': {
'kind': 'Name',
'value': 'foo'
},
'arguments': [],
'directives': [],
'selectionSet': {
'kind': 'SelectionSet',
'selections': [{
'kind': 'FragmentSpread',
'name': {
'kind': 'Name',
'value': 'barFragment'
},
'directives': []
}, {
'kind': 'FragmentSpread',
'name': {
'kind': 'Name',
'value': 'bazFragment'
},
'directives': []
}]
}
}]
}
}].concat(bar.definitions, baz.fragments.foo.definitions),
'loc': {
'start': 0,
'end': 84,
'source': {
'body': '\n query foo {\n foo {\n ...barFragment\n ...bazFragment\n }\n }\n\n \n \n',
'name': 'GraphQL request',
'locationOffset': {
'line': 1,
'column': 1
}
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"plugins": [
[
"../../../../src"
]
]
}

0 comments on commit f5001f4

Please sign in to comment.