Skip to content

Commit

Permalink
Fixes for near-operation-file preset (#2099)
Browse files Browse the repository at this point in the history
* try to fix fragments issues with near-operation-file

* fix for prettier

* fixes for fragments imports
  • Loading branch information
dotansimha authored Jul 4, 2019
1 parent ccac3a4 commit 9f27ef9
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 11 deletions.
20 changes: 20 additions & 0 deletions dev-test/test/codegen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

schema:
- 'schema.graphql'
documents:
- './src/**/*.graphql'
config:
namingConvention: change-case#pascalCase
withHooks: true
generates:
src/gql/__generated__/types.ts:
- 'typescript'
src/:
preset: near-operation-file
presetConfig:
extension: .generated.tsx
baseTypesPath: gql/__generated__/types.ts
plugins:
- add: /* eslint-disable */
- typescript-operations
- typescript-react-apollo
23 changes: 23 additions & 0 deletions dev-test/test/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

type TypeB {
param1: String
param2: String
}

type TypeA {
field1: String
field2: String
field3: String
field4: String
field5: String
field6: String
field7: TypeB
}

type Query {
things: TypeA!
}

schema {
query: Query
}
10 changes: 10 additions & 0 deletions dev-test/test/src/ComponentA/document.generated.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable */
import * as Types from '../gql/__generated__/types';

import gql from 'graphql-tag';
export type ComponentA_TypeAFragment = { __typename?: 'TypeA' } & Pick<Types.TypeA, 'field1'>;
export const ComponentA_TypeAFragmentDoc = gql`
fragment ComponentA_TypeA on TypeA {
field1
}
`;
3 changes: 3 additions & 0 deletions dev-test/test/src/ComponentA/document.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fragment ComponentA_TypeA on TypeA {
field1
}
25 changes: 25 additions & 0 deletions dev-test/test/src/ComponentB/document.generated.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable */
import * as Types from '../gql/__generated__/types';

import gql from 'graphql-tag';
export type ComponentB_TypeBFragment = { __typename?: 'TypeB' } & Pick<Types.TypeB, 'param1' | 'param2'>;

export type ComponentB_TypeAFragment = { __typename?: 'TypeA' } & Pick<Types.TypeA, 'field3' | 'field4' | 'field5' | 'field6'> & { field7: Types.Maybe<{ __typename?: 'TypeB' } & ComponentB_TypeBFragment> };
export const ComponentB_TypeBFragmentDoc = gql`
fragment ComponentB_TypeB on TypeB {
param1
param2
}
`;
export const ComponentB_TypeAFragmentDoc = gql`
fragment ComponentB_TypeA on TypeA {
field3
field4
field5
field6
field7 {
...ComponentB_TypeB
}
}
${ComponentB_TypeBFragmentDoc}
`;
14 changes: 14 additions & 0 deletions dev-test/test/src/ComponentB/document.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
fragment ComponentB_TypeB on TypeB {
param1
param2
}

fragment ComponentB_TypeA on TypeA {
field3
field4
field5
field6
field7 {
...ComponentB_TypeB
}
}
48 changes: 48 additions & 0 deletions dev-test/test/src/document.generated.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/* eslint-disable */
import * as Types from './gql/__generated__/types';

import { ComponentB_TypeAFragment } from './ComponentB/document.generated';
import { ComponentA_TypeAFragment } from './ComponentA/document.generated';
import gql from 'graphql-tag';
import { ComponentA_TypeAFragmentDoc } from './ComponentA/document.generated';
import { ComponentB_TypeAFragmentDoc } from './ComponentB/document.generated';
import * as React from 'react';
import * as ReactApollo from 'react-apollo';
import * as ReactApolloHooks from 'react-apollo-hooks';
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
export type ComponentC_FetchThingsQueryVariables = {};

export type ComponentC_FetchThingsQuery = { __typename?: 'Query' } & { things: { __typename?: 'TypeA' } & ComponentC_TypeAFragment };

export type ComponentC_TypeAFragment = { __typename?: 'TypeA' } & (ComponentA_TypeAFragment & ComponentB_TypeAFragment);
export const ComponentC_TypeAFragmentDoc = gql`
fragment ComponentC_TypeA on TypeA {
...ComponentA_TypeA
...ComponentB_TypeA
}
${ComponentA_TypeAFragmentDoc}
${ComponentB_TypeAFragmentDoc}
`;
export const ComponentC_FetchThingsDocument = gql`
query ComponentC_FetchThings {
things {
...ComponentC_TypeA
}
}
${ComponentC_TypeAFragmentDoc}
`;
export type ComponentC_FetchThingsComponentProps = Omit<ReactApollo.QueryProps<ComponentC_FetchThingsQuery, ComponentC_FetchThingsQueryVariables>, 'query'>;

export const ComponentC_FetchThingsComponent = (props: ComponentC_FetchThingsComponentProps) => <ReactApollo.Query<ComponentC_FetchThingsQuery, ComponentC_FetchThingsQueryVariables> query={ComponentC_FetchThingsDocument} {...props} />;

export type ComponentC_FetchThingsProps<TChildProps = {}> = Partial<ReactApollo.DataProps<ComponentC_FetchThingsQuery, ComponentC_FetchThingsQueryVariables>> & TChildProps;
export function withComponentC_FetchThings<TProps, TChildProps = {}>(operationOptions?: ReactApollo.OperationOption<TProps, ComponentC_FetchThingsQuery, ComponentC_FetchThingsQueryVariables, ComponentC_FetchThingsProps<TChildProps>>) {
return ReactApollo.withQuery<TProps, ComponentC_FetchThingsQuery, ComponentC_FetchThingsQueryVariables, ComponentC_FetchThingsProps<TChildProps>>(ComponentC_FetchThingsDocument, {
alias: 'withComponentC_FetchThings',
...operationOptions,
});
}

export function useComponentC_FetchThingsQuery(baseOptions?: ReactApolloHooks.QueryHookOptions<ComponentC_FetchThingsQueryVariables>) {
return ReactApolloHooks.useQuery<ComponentC_FetchThingsQuery, ComponentC_FetchThingsQueryVariables>(ComponentC_FetchThingsDocument, baseOptions);
}
12 changes: 12 additions & 0 deletions dev-test/test/src/document.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
query ComponentC_FetchThings {
things {
...ComponentC_TypeA # We're using it before declare
# Causing self imports and then duplicate declare
}
}

fragment ComponentC_TypeA on TypeA {
...ComponentA_TypeA
...ComponentB_TypeA # Fragments that this fragment is
# uses are getting imported with no usage.
}
31 changes: 31 additions & 0 deletions dev-test/test/src/gql/__generated__/types.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@
"typescript": "3.5.2"
},
"lint-staged": {
"*.{ts,tsx}": [
"packages/**/*.{ts,tsx}": [
"tslint --fix",
"git add"
],
"*.{js,json,css,md,ts,tsx}": [
"packages/**/*.{js,json,css,md,ts,tsx}": [
"prettier --write",
"git add -f"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export class ClientSideBaseVisitor<TRawConfig extends RawClientSideBasePluginCon
}

(this._fragments || [])
.filter(f => f.isExternal && f.importFrom)
.filter(f => f.isExternal && f.importFrom && (!f['level'] || (f['level'] !== undefined && f['level'] === 0)))
.forEach(externalFragment => {
const identifierName = this._getFragmentName(externalFragment.name);

Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/other/visitor-plugin-common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface NamingConventionMap {
transformUnderscore?: boolean;
}

export type LoadedFragment = { name: string; onType: string; node: FragmentDefinitionNode; isExternal: boolean; importFrom?: string | null };
export type LoadedFragment<AdditionalFields = {}> = { name: string; onType: string; node: FragmentDefinitionNode; isExternal: boolean; importFrom?: string | null } & AdditionalFields;

export type DeclarationKind = 'type' | 'interface';

Expand Down
8 changes: 5 additions & 3 deletions packages/presets/near-operation-file/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,25 @@ export const preset: Types.OutputPreset<NearOperationFileConfig> = {
const config = {
...options.config,
namespacedImportName: importTypesNamespace,
externalFragments: [] as LoadedFragment[],
externalFragments: [] as (LoadedFragment<{ level: number }>)[],
};

for (const fragmentName of fragmentsInUse) {
for (const fragmentName of Object.keys(fragmentsInUse)) {
const level = fragmentsInUse[fragmentName];
const fragmentDetails = fragmentNameToFile[fragmentName];

if (fragmentDetails) {
const absFragmentFilePath = resolve(baseDir, fragmentDetails.filePath);
const fragmentImportPath = resolveRelativeImport(absGeneratedFilePath, absFragmentFilePath);

if (!options.config.globalNamespace) {
if (!options.config.globalNamespace && level === 0) {
plugins.unshift({
add: `import { ${fragmentDetails.importName} } from '${fragmentImportPath}';`,
});
}

config.externalFragments.push({
level,
isExternal: true,
importFrom: fragmentImportPath,
name: fragmentName,
Expand Down
19 changes: 15 additions & 4 deletions packages/presets/near-operation-file/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,31 @@ export function clearExtension(path: string): string {
return join(parsedPath.dir, parsedPath.name).replace(/\\/g, '/');
}

export function extractExternalFragmentsInUse(documentNode: DocumentNode | FragmentDefinitionNode, fragmentNameToFile: FragmentNameToFile, result: Set<string> = new Set(), ignoreList: Set<string> = new Set()): Set<string> {
export function extractExternalFragmentsInUse(
documentNode: DocumentNode | FragmentDefinitionNode,
fragmentNameToFile: FragmentNameToFile,
result: { [fragmentName: string]: number } = {},
ignoreList: Set<string> = new Set(),
level = 0
): { [fragmentName: string]: number } {
// First, take all fragments definition from the current file, and mark them as ignored
visit(documentNode, {
enter: {
FragmentDefinition: (node: FragmentDefinitionNode) => {
ignoreList.add(node.name.value);
},
},
leave: {
});

// Then, look for all used fragments in this document
visit(documentNode, {
enter: {
FragmentSpread: (node: FragmentSpreadNode) => {
if (!ignoreList.has(node.name.value)) {
result.add(node.name.value);
result[node.name.value] = level;

if (fragmentNameToFile[node.name.value]) {
extractExternalFragmentsInUse(fragmentNameToFile[node.name.value].node, fragmentNameToFile, result, ignoreList);
extractExternalFragmentsInUse(fragmentNameToFile[node.name.value].node, fragmentNameToFile, result, ignoreList, level + 1);
}
}
},
Expand Down

0 comments on commit 9f27ef9

Please sign in to comment.