Skip to content

Commit

Permalink
feat(hasura-allow-list):add config to change fragments definition order
Browse files Browse the repository at this point in the history
  • Loading branch information
shoma-mano committed Oct 16, 2023
1 parent 66b414e commit f9b3a73
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 2 deletions.
5 changes: 5 additions & 0 deletions packages/plugins/other/hasura-allow-list/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ export interface HasuraAllowListPluginConfig {
* @description Whether to source fragments per-document, or globally. If set, will enforce fragment name uniqueness
*/
globalFragments?: boolean;
/**
* @default definition
* @description Whether to order fragments by global definition order, or by definition order in the document
*/
fragmentsOrder?: 'global' | 'document';
}
15 changes: 13 additions & 2 deletions packages/plugins/other/hasura-allow-list/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,23 @@ function getOperationFragmentsRecursively(
operationDefinition: OperationDefinitionNode,
fragmentDefinitions: FragmentDefinitionNode[],
documentLocation: string,
config: HasuraAllowListPluginConfig,
): FragmentDefinitionNode[] {
const requiredFragmentNames = new Set<string>();

getRequiredFragments(operationDefinition);

// note: we first get a list of required fragments names, then filter the original list.
// this means order of fragments is preserved.
// note: we should choose fragmentsOrder config that is compatible with other graphql-codegen plugins we use.
const order = config.fragmentsOrder ?? 'global';

// order of fragments is determined by the order they are defined in the document.
if (order === 'document') {
return Array.from(requiredFragmentNames).map(name =>
fragmentDefinitions.find(definition => definition.name.value === name),
);
}

// order is determined by the global fragments definition order.
return fragmentDefinitions.filter(definition => requiredFragmentNames.has(definition.name.value));

/**
Expand Down Expand Up @@ -147,6 +157,7 @@ export const plugin: PluginFunction<HasuraAllowListPluginConfig> = async (
operation,
fragments,
document.location,
config,
);

// insert the operation and any fragments to our queries definition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,50 @@ describe('Hasura allow list', () => {

expect(content).toBe(expectedContent);
});
it('with globalFragments enabled and fragmentsOrder set to document, should define fragment by the order they are defined in the document.', async () => {
const expectedContent = `- name: allowed-queries
definition:
queries:
- name: MyQuery1
query: |-
query MyQuery1 {
field
...MyOtherFragment
...MyFragment
}
fragment MyOtherFragment on Query {
field
}
fragment MyFragment on Query {
field
}
`;
const document1 = parse(/* GraphQL */ `
query MyQuery1 {
field
...MyOtherFragment
...MyFragment
}
fragment MyFragment on Query {
field
}
`);
const document2 = parse(/* GraphQL */ `
fragment MyOtherFragment on Query {
field
}
`);
const content = await plugin(
null,
[
{ document: document1, location: '/dummy/location1' },
{ document: document2, location: '/dummy/location2' },
],
{ globalFragments: true, fragmentsOrder: 'document' },
);

expect(content).toBe(expectedContent);
});
it('with globalFragments enabled, should error on missing fragments', async () => {
const document1 = parse(/* GraphQL */ `
query MyQuery1 {
Expand Down

0 comments on commit f9b3a73

Please sign in to comment.