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 023aa09
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 0 deletions.
120 changes: 120 additions & 0 deletions src/utilities/__tests__/mergeAST-fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* 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: `
query Test {
id
}`,
mergedQuery: `
query Test {
id
}`,
},
{
desc: 'inlines simple nested fragment',
query: `
query Test {
...Fragment1
}
fragment Fragment1 on Test {
id
}`,
mergedQuery: `
query Test {
...on Test {
id
}
}`,
},
{
desc: 'inlines triple nested fragment',
query: `
query Test {
...Fragment1
}
fragment Fragment1 on Test {
...Fragment2
}
fragment Fragment2 on Test {
...Fragment3
}
fragment Fragment3 on Test {
id
}`,
mergedQuery: `
query Test {
...on Test {
...on Test {
...on Test {
id
}
}
}
}`,
},
{
desc: 'inlines multiple fragments',
query: `
query Test {
...Fragment1
...Fragment2
...Fragment3
}
fragment Fragment1 on Test {
id
}
fragment Fragment2 on Test {
id
}
fragment Fragment3 on Test {
id
}`,
mergedQuery: `
query Test {
...on Test {
id
}
...on Test {
id
}
...on Test {
id
}
}`,
},
{
desc: 'removes duplicate fragment spreads',
query: `
query Test {
...Fragment1
...Fragment1
}
fragment Fragment1 on Test {
id
}`,
mergedQuery: `
query Test {
...on Test {
id
}
}`,
},
];
27 changes: 27 additions & 0 deletions src/utilities/__tests__/mergeAST-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* 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 { parse, print } from '../../index';

import { mergeAST } from '../mergeAST';

import { fixtures } from './mergeAST-fixture';

describe.only('MergeAST', () => {
fixtures.forEach(fixture => {
it(fixture.desc, () => {
const result = print(mergeAST(parse(fixture.query))).replace(/\s/g, '');
expect(result).to.equal(fixture.mergedQuery.replace(/\s/g, ''));
});
});
});
57 changes: 57 additions & 0 deletions src/utilities/mergeAST.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* 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 { visit } from '../language/visitor';
import { print } from '../';
import {
type DocumentNode,
type FragmentDefinitionNode,
type FragmentSpreadNode,
} from '../language/ast';

/**
* Given a document AST, merge all fragments definitions into the
* operations using inline fragments.
*/

export function mergeAST(ast: DocumentNode): DocumentNode {
const fragmentDefinitions: { [name: string]: FragmentDefinitionNode } = {};
const inlinedFragments: { [name: string]: FragmentSpreadNode } = {};

visit(ast, {
FragmentDefinition(node) {
// collect the existing FragmentDefinition nodes
fragmentDefinitions[node.name.value] = node;
},
});

return visit(ast, {
FragmentSpread(node) {

// no repeats
if (inlinedFragments[node.name.value]) {
return null;
}

// otherwise, we are inlining a new fragment definition
inlinedFragments[node.name.value] = node;

// retrieve the original definition, and convert
// all FragmentSpread nodes to InlineFragment nodes
return {
...fragmentDefinitions[node.name.value],
kind: 'InlineFragment',
};
},
FragmentDefinition(node) {
// remove the original FragmentDefinition nodes
return null;
},
});
}

0 comments on commit 023aa09

Please sign in to comment.