diff --git a/src/__tests__/__snapshots__/macro.test.js.snap b/src/__tests__/__snapshots__/macro.test.js.snap index b2cb53e..0957c4a 100644 --- a/src/__tests__/__snapshots__/macro.test.js.snap +++ b/src/__tests__/__snapshots__/macro.test.js.snap @@ -367,6 +367,183 @@ const query = { `; +exports[`macros [loader] with nested circular fragments: [loader] with nested circular fragments 1`] = ` + +import { loader } from 'graphql.macro'; +const query = loader('./fixtures/query3.graphql'); + + ↓ ↓ ↓ ↓ ↓ ↓ + +const query = { + "kind": "Document", + "definitions": [{ + "kind": "FragmentDefinition", + "name": { + "kind": "Name", + "value": "UserEntry1" + }, + "typeCondition": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "User" + } + }, + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [{ + "kind": "Field", + "name": { + "kind": "Name", + "value": "firstName" + }, + "arguments": [], + "directives": [] + }] + } + }, { + "kind": "FragmentDefinition", + "name": { + "kind": "Name", + "value": "UserEntry3" + }, + "typeCondition": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "User" + } + }, + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [{ + "kind": "Field", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "directives": [] + }] + } + }, { + "kind": "FragmentDefinition", + "name": { + "kind": "Name", + "value": "UserEntry5" + }, + "typeCondition": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "User" + } + }, + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [{ + "kind": "FragmentSpread", + "name": { + "kind": "Name", + "value": "UserEntry4" + }, + "directives": [] + }] + } + }, { + "kind": "FragmentDefinition", + "name": { + "kind": "Name", + "value": "UserEntry4" + }, + "typeCondition": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "User" + } + }, + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [{ + "kind": "FragmentSpread", + "name": { + "kind": "Name", + "value": "UserEntry1" + }, + "directives": [] + }, { + "kind": "FragmentSpread", + "name": { + "kind": "Name", + "value": "UserEntry5" + }, + "directives": [] + }] + } + }, { + "kind": "OperationDefinition", + "operation": "query", + "name": { + "kind": "Name", + "value": "User" + }, + "variableDefinitions": [], + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [{ + "kind": "Field", + "name": { + "kind": "Name", + "value": "user" + }, + "arguments": [{ + "kind": "Argument", + "name": { + "kind": "Name", + "value": "id" + }, + "value": { + "kind": "IntValue", + "value": "5" + } + }], + "directives": [], + "selectionSet": { + "kind": "SelectionSet", + "selections": [{ + "kind": "FragmentSpread", + "name": { + "kind": "Name", + "value": "UserEntry4" + }, + "directives": [] + }] + } + }] + } + }], + "loc": { + "start": 0, + "end": 371, + "source": { + "body": "fragment UserEntry1 on User {\\n firstName\\n}\\n\\nfragment UserEntry3 on User {\\n id\\n}\\n#import \\"./fragment3.graphql\\"\\n\\nfragment UserEntry5 on User {\\n ...UserEntry4\\n}\\n#import \\"./fragment1.graphql\\"\\n#import \\"./fragment4.graphql\\"\\n\\nfragment UserEntry4 on User {\\n ...UserEntry1\\n ...UserEntry5\\n}\\n#import './fragment3.graphql'\\n\\nquery User {\\n user(id: 5) {\\n ...UserEntry4\\n }\\n}\\n\\n", + "name": "GraphQL request", + "locationOffset": { + "line": 1, + "column": 1 + } + } + } +}; + +`; + exports[`macros [loader] without fragment: [loader] without fragment 1`] = ` import { loader } from 'graphql.macro'; diff --git a/src/__tests__/fixtures/fragment3.graphql b/src/__tests__/fixtures/fragment3.graphql new file mode 100644 index 0000000..85534da --- /dev/null +++ b/src/__tests__/fixtures/fragment3.graphql @@ -0,0 +1,7 @@ +#import "./fragment1.graphql" +#import "./fragment4.graphql" + +fragment UserEntry4 on User { + ...UserEntry1 + ...UserEntry5 +} diff --git a/src/__tests__/fixtures/fragment4.graphql b/src/__tests__/fixtures/fragment4.graphql new file mode 100644 index 0000000..a559461 --- /dev/null +++ b/src/__tests__/fixtures/fragment4.graphql @@ -0,0 +1,5 @@ +#import "./fragment3.graphql" + +fragment UserEntry5 on User { + ...UserEntry4 +} diff --git a/src/__tests__/fixtures/query3.graphql b/src/__tests__/fixtures/query3.graphql new file mode 100644 index 0000000..6515451 --- /dev/null +++ b/src/__tests__/fixtures/query3.graphql @@ -0,0 +1,8 @@ +#import './fragment3.graphql' + +query User { + user(id: 5) { + ...UserEntry4 + } +} + diff --git a/src/__tests__/macro.test.js b/src/__tests__/macro.test.js index e472d56..e1892b3 100644 --- a/src/__tests__/macro.test.js +++ b/src/__tests__/macro.test.js @@ -65,6 +65,13 @@ pluginTester({ const query = loader('./fixtures/query1.graphql'); `, }, + '[loader] with nested circular fragments': { + error: false, + code: ` + import { loader } from '../macro'; + const query = loader('./fixtures/query3.graphql'); + `, + }, // '[loader] multiple operations': { // error: false, // code: ` diff --git a/src/utils/expandImports.js b/src/utils/expandImports.js index c8c04f9..0262744 100644 --- a/src/utils/expandImports.js +++ b/src/utils/expandImports.js @@ -6,7 +6,10 @@ import fs from 'fs'; * import .graphql file directly * ref: https://github.com/apollographql/graphql-tag/blob/master/loader.js */ -export default function expandImports(queryPath: string): string { +export default function expandImports( + queryPath: string, + processedFiles: Set = new Set(), +): string { const source = fs.readFileSync(queryPath, 'utf8'); const lines = source.split(/\r\n|\r|\n/); const importContent = lines @@ -17,7 +20,13 @@ export default function expandImports(queryPath: string): string { .split(' ')[1] .replace(/('|")/g, ''); const relativeQueryPath = path.join(queryPath, '..', value); - const raw = fs.readFileSync(relativeQueryPath, 'utf8'); + + if (processedFiles.has(relativeQueryPath)) { + return ''; + } + + processedFiles.add(relativeQueryPath); + const raw = expandImports(relativeQueryPath, processedFiles); return raw; })