Skip to content

Commit

Permalink
add mergeAST from GraphiQL, refactor using visit()
Browse files Browse the repository at this point in the history
  • Loading branch information
acao committed Jun 4, 2019
1 parent c3dd670 commit 8d1d14c
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ export {
isValidLiteralValue,
// Concatenates multiple AST together.
concatAST,
// Inline named fragments from AST
inlineNamedFragments,
// Separates an AST into an AST per Operation.
separateOperations,
// Strips characters that are not significant to the validity or execution
Expand Down
31 changes: 31 additions & 0 deletions src/jsutils/uniqueBy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/

/**
* Returns an array of unique values based on iteratee
* which is invoked for each element in array to generate
* the criterion by which uniqueness is computed.
*
* Simiar to _.uniqBy from lodash.
*/
export function uniqueBy(
array: $ReadOnlyArray<any>,
iteratee: (item: any) => any,
) {
const FilteredMap = new Map();
const result = [];
for (const item of array) {
const uniqeValue = iteratee(item);
if (!FilteredMap.has(uniqeValue)) {
FilteredMap.set(uniqeValue, true);
result.push(item);
}
}
return result;
}
189 changes: 189 additions & 0 deletions src/utilities/__tests__/inlineNamedFragments-fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*
*/

export const fixtures = [
{
desc: 'does not modify query with no fragments',
query: `
{
id
}`,
resultQuery: `
{
id
}
`,
},
{
desc: 'inlines simple nested fragment',
query: `
{
...Fragment1
}
fragment Fragment1 on Test {
id
}`,
resultQuery: `
{
... on Test {
id
}
}
`,
},
{
desc: 'inlines triple nested fragment',
query: `
{
...Fragment1
}
fragment Fragment1 on Test {
...Fragment2
}
fragment Fragment2 on Test {
...Fragment3
}
fragment Fragment3 on Test {
id
}`,
resultQuery: `
{
... on Test {
... on Test {
... on Test {
id
}
}
}
}
`,
},
{
desc: 'inlines multiple fragments',
query: `
{
...Fragment1
...Fragment2
...Fragment3
}
fragment Fragment1 on Test {
id
}
fragment Fragment2 on Test {
id
}
fragment Fragment3 on Test {
id
}`,
resultQuery: `
{
... on Test {
id
}
... on Test {
id
}
... on Test {
id
}
}
`,
},
{
desc: 'inlines multiple fragments on multiple queries',
query: `
{
...Fragment4
...Fragment5
}
fragment Fragment5 on Test1 {
...Fragment4
}
fragment Fragment4 on Test1 {
id
}`,
resultQuery: `
{
... on Test1 {
id
}
... on Test1 {
... on Test1 {
id
}
}
}
`,
},
{
desc: 'reuses the same fragment',
query: `
fragment ProfileInfo on Person {
name
title
phone
}
{
person {
...ProfileInfo
friend {
...ProfileInfo
}
}
}`,
resultQuery: `
{
person {
... on Person {
name
title
phone
}
friend {
... on Person {
name
title
phone
}
}
}
}
`,
},
{
desc: 'removes duplicate fragment spreads',
query: `
{
...Fragment1
...Fragment1
}
fragment Fragment1 on Test {
id
}`,
resultQuery: `
{
... on Test {
id
}
}
`,
},
];
25 changes: 25 additions & 0 deletions src/utilities/__tests__/inlineNamedFragments-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/

import { expect } from 'chai';
import { describe, it } from 'mocha';
import dedent from '../../jsutils/dedent';
import { parse } from '../../language/parser';
import { print } from '../../language/printer';
import { inlineNamedFragments } from '../inlineNamedFragments';
import { fixtures } from './inlineNamedFragments-fixture';

describe.only('inlineNamedFragments', () => {
fixtures.forEach(fixture => {
it(fixture.desc, () => {
const result = print(inlineNamedFragments(parse(fixture.query)));
expect(result).to.equal(dedent(fixture.resultQuery));
});
});
});
3 changes: 3 additions & 0 deletions src/utilities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ export { isValidLiteralValue } from './isValidLiteralValue';
// Concatenates multiple AST together.
export { concatAST } from './concatAST';

// Inline named fragments from AST
export { inlineNamedFragments } from './inlineNamedFragments';

// Separates an AST into an AST per Operation.
export { separateOperations } from './separateOperations';

Expand Down
52 changes: 52 additions & 0 deletions src/utilities/inlineNamedFragments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
*/

import { type ObjMap } from '../jsutils/ObjMap';
import { uniqueBy } from '../jsutils/uniqueBy';
import { visit } from '../language/visitor';
import {
type DocumentNode,
type FragmentDefinitionNode,
} from '../language/ast';

/**
* Given a document AST, inline all named fragment definitions
*/
export function inlineNamedFragments(documentAST: DocumentNode): DocumentNode {
const fragmentDefinitions: ObjMap<FragmentDefinitionNode> = Object.create(
null,
);

for (const definition of documentAST.definitions) {
if (definition.kind === 'FragmentDefinition') {
fragmentDefinitions[definition.name.value] = definition;
}
}

return visit(documentAST, {
FragmentSpread(node) {
return {
...fragmentDefinitions[node.name.value],
kind: 'InlineFragment',
};
},
SelectionSet(node) {
return {
...node,
selections: uniqueBy(
node.selections,
selection => selection.name.value,
),
};
},
FragmentDefinition() {
return null;
},
});
}

0 comments on commit 8d1d14c

Please sign in to comment.