-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add mergeAST from GraphiQL, refactor using visit()
- Loading branch information
Showing
3 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
}`, | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, '')); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* 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 fragment definitions into the | ||
* provided 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; | ||
}, | ||
}); | ||
} |