diff --git a/.changeset/slimy-rice-exercise.md b/.changeset/slimy-rice-exercise.md new file mode 100644 index 00000000000..9c469de133e --- /dev/null +++ b/.changeset/slimy-rice-exercise.md @@ -0,0 +1,6 @@ +--- +'@graphql-tools/graphql-tag-pluck': major +--- + +BREAKING CHANGE +- feat(graphql-tag-pluck): keep locationOffset and return graphql-js Source instead of string diff --git a/packages/graphql-tag-pluck/src/index.ts b/packages/graphql-tag-pluck/src/index.ts index 6dc84251358..2c1857ada4d 100644 --- a/packages/graphql-tag-pluck/src/index.ts +++ b/packages/graphql-tag-pluck/src/index.ts @@ -4,6 +4,7 @@ import { getExtNameFromFilePath } from './libs/extname'; import createVisitor, { PluckedContent } from './visitor'; import traverse from '@babel/traverse'; import { freeText } from './utils'; +import { Source } from 'graphql'; /** * Additional options for determining how a file is parsed. @@ -128,7 +129,7 @@ export const gqlPluckFromCodeString = async ( filePath: string, code: string, options: GraphQLTagPluckOptions = {} -): Promise => { +): Promise => { validate({ code, options }); const fileExt = extractExtension(filePath); @@ -137,9 +138,7 @@ export const gqlPluckFromCodeString = async ( code = await pluckVueFileScript(code); } - return parseCode({ code, filePath, options }) - .map(t => t.content) - .join('\n\n'); + return parseCode({ code, filePath, options }).map(t => new Source(t.content, filePath, t.loc.start)); }; /** @@ -155,7 +154,7 @@ export const gqlPluckFromCodeStringSync = ( filePath: string, code: string, options: GraphQLTagPluckOptions = {} -): string => { +): Source[] => { validate({ code, options }); const fileExt = extractExtension(filePath); @@ -164,9 +163,7 @@ export const gqlPluckFromCodeStringSync = ( code = pluckVueFileScriptSync(code); } - return parseCode({ code, filePath, options }) - .map(t => t.content) - .join('\n\n'); + return parseCode({ code, filePath, options }).map(t => new Source(t.content, filePath, t.loc.start)); }; export function parseCode({ diff --git a/packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts b/packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts index ef4d3ef8a2e..cd092de10f5 100644 --- a/packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts +++ b/packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts @@ -8,7 +8,7 @@ describe('graphql-tag-pluck', () => { sync: gqlPluckFromCodeStringSync })(pluck => { it('should allow to pluck without indentation changes', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import gql from 'graphql-tag' const fragment = gql(\` @@ -30,11 +30,11 @@ describe('graphql-tag-pluck', () => { skipIndent: true }); - expect(gqlString).toMatchSnapshot(); + expect(sources.map(source => source.body).join('\n\n')).toMatchSnapshot(); }); it('should pluck graphql-tag template literals from .js file', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import gql from 'graphql-tag' const fragment = gql(\` @@ -54,7 +54,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -68,7 +68,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .js file when it has alias', async () => { - const gqlString = await pluck('tmp-XXXXXX.ts', freeText(` + const sources = await pluck('tmp-XXXXXX.ts', freeText(` import { default as foo } from 'graphql-tag' const fragment = foo(\` @@ -95,7 +95,7 @@ describe('graphql-tag-pluck', () => { ] }); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -109,7 +109,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .js file and remove replacements', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import gql from 'graphql-tag' const fragment = gql(\` @@ -136,7 +136,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -155,7 +155,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .ts file', async () => { - const gqlString = await pluck('tmp-XXXXXX.ts', freeText(` + const sources = await pluck('tmp-XXXXXX.ts', freeText(` import gql from 'graphql-tag' import { Document } from 'graphql' @@ -182,7 +182,7 @@ describe('graphql-tag-pluck', () => { } `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -196,7 +196,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .tsx file', async () => { - const gqlString = await pluck('tmp-XXXXXX.tsx', freeText(` + const sources = await pluck('tmp-XXXXXX.tsx', freeText(` import * as React from 'react'; import gql from 'graphql-tag'; @@ -227,7 +227,7 @@ describe('graphql-tag-pluck', () => { // \`; `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -239,7 +239,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue JavaScript file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -278,7 +278,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -290,7 +290,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue TS/Pug/SCSS file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -329,7 +329,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -340,7 +340,7 @@ describe('graphql-tag-pluck', () => { `)); }); it('should pluck graphql-tag template literals from .vue 3 JavaScript file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -379,7 +379,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -391,7 +391,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue 3 TS/Pug/SCSS file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -430,7 +430,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -442,7 +442,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue 3 setup sugar JavaScript file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -483,7 +483,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -495,7 +495,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue 3 setup sugar TS/Pug/SCSS file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -535,7 +535,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -546,7 +546,7 @@ describe('graphql-tag-pluck', () => { `)); }); it('should pluck graphql-tag template literals from .vue 3 outside setup sugar JavaScript file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -585,7 +585,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -597,7 +597,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue 3 outside setup sugar TS/Pug/SCSS file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -636,7 +636,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -648,7 +648,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue 3 setup JavaScript file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -690,7 +690,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -702,7 +702,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .vue 3 setup TS/Pug/SCSS file', async () => { - const gqlString = await pluck('tmp-XXXXXX.vue', freeText(` + const sources = await pluck('tmp-XXXXXX.vue', freeText(` @@ -744,7 +744,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -756,7 +756,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .tsx file with generic jsx elements', async () => { - const gqlString = await pluck('tmp-XXXXXX.tsx', freeText(` + const sources = await pluck('tmp-XXXXXX.tsx', freeText(` import * as React from 'react'; import gql from 'graphql-tag'; import Generic from './Generic' @@ -784,7 +784,7 @@ describe('graphql-tag-pluck', () => { \`; `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query IndexQuery { site { siteMetadata { @@ -796,7 +796,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .ts file with the same const inside namespace and outside namespace', async () => { - const gqlString = await pluck('tmp-XXXXXX.ts', freeText(` + const sources = await pluck('tmp-XXXXXX.ts', freeText(` import gql from 'graphql-tag'; namespace Foo { @@ -829,7 +829,7 @@ describe('graphql-tag-pluck', () => { \`; `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` query myQueryInNamespace { fieldA } @@ -841,7 +841,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .flow file', async () => { - const gqlString = await pluck('tmp-XXXXXX.flow', freeText(` + const sources = await pluck('tmp-XXXXXX.flow', freeText(` import gql from 'graphql-tag' import { Document } from 'graphql' @@ -862,7 +862,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -876,7 +876,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .js file with @flow header', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` // @flow import gql from 'graphql-tag' @@ -899,7 +899,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -913,7 +913,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .js file with @flow strict-local', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` // @flow strict-local import gql from 'graphql-tag' @@ -936,7 +936,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -982,7 +982,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .flow.jsx file', async () => { - const gqlString = await pluck('tmp-XXXXXX.flow.jsx', freeText(` + const sources = await pluck('tmp-XXXXXX.flow.jsx', freeText(` import gql from 'graphql-tag' import { Document } from 'graphql' @@ -1003,7 +1003,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1017,7 +1017,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from .*.jsx file', async () => { - const gqlString = await pluck('tmp-XXXXXX.mutation.jsx', freeText(` + const sources = await pluck('tmp-XXXXXX.mutation.jsx', freeText(` import gql from 'graphql-tag' const fragment = gql\` @@ -1037,7 +1037,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1051,7 +1051,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals leaded by a magic comment from .js file', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` const Message = /* GraphQL */ \` enum MessageTypes { text @@ -1060,7 +1060,7 @@ describe('graphql-tag-pluck', () => { }\` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` enum MessageTypes { text media @@ -1070,7 +1070,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag expression statements leaded by a magic comment from .js file', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` /* GraphQL */ \` enum MessageTypes { text @@ -1079,7 +1079,7 @@ describe('graphql-tag-pluck', () => { }\` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` enum MessageTypes { text media @@ -1089,7 +1089,7 @@ describe('graphql-tag-pluck', () => { }); it(`should NOT pluck other template literals from a .js file`, async () => { - const gqlString = await pluck(`tmp-XXXXXX.js`, freeText(` + const sources = await pluck(`tmp-XXXXXX.js`, freeText(` test( \`test1\` ) @@ -1104,11 +1104,11 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(''); + expect(sources.map(source => source.body).join('\n\n')).toEqual(''); }); it('should pluck template literals when graphql-tag is imported differently', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import graphqltag from 'graphql-tag' const fragment = graphqltag(\` @@ -1128,7 +1128,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1142,7 +1142,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck template literals from gql by default even if not imported from graphql-tag', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` const fragment = gql(\` fragment Foo on FooType { id @@ -1160,7 +1160,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1174,7 +1174,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from code string', async () => { - const gqlString = await pluck('test.js', freeText(` + const sources = await pluck('test.js', freeText(` import gql from 'graphql-tag' const fragment = gql(\` @@ -1194,7 +1194,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1208,7 +1208,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql-tag template literals from a .js file', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import gql from 'graphql-tag' const fragment = gql(\` @@ -1228,7 +1228,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1242,7 +1242,7 @@ describe('graphql-tag-pluck', () => { }); it('should be able to specify the global GraphQL identifier name', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` const fragment = anothergql(\` fragment Foo on FooType { id @@ -1262,7 +1262,7 @@ describe('graphql-tag-pluck', () => { globalGqlIdentifierName: 'anothergql' }); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1276,7 +1276,7 @@ describe('graphql-tag-pluck', () => { }); it('should be able to specify the GraphQL magic comment to look for', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` const Message = /* GQL */ \` enum MessageTypes { text @@ -1287,7 +1287,7 @@ describe('graphql-tag-pluck', () => { gqlMagicComment: 'GQL' }); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` enum MessageTypes { text media @@ -1297,7 +1297,7 @@ describe('graphql-tag-pluck', () => { }); it('should be able to specify the package name of which the GraphQL identifier should be imported from', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import mygql from 'my-graphql-tag' const fragment = mygql(\` @@ -1321,7 +1321,7 @@ describe('graphql-tag-pluck', () => { ] }); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1335,7 +1335,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql template literal from gatsby package', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import {graphql} from 'gatsby' const fragment = graphql(\` @@ -1355,7 +1355,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1369,7 +1369,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck gql template literal from apollo-server-express package', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import { gql } from 'apollo-server-express' const fragment = gql(\` @@ -1389,7 +1389,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1403,7 +1403,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck gql template literal from @apollo/client package', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import { gql } from '@apollo/client' const fragment = gql(\` @@ -1423,7 +1423,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` fragment Foo on FooType { id } @@ -1437,12 +1437,12 @@ describe('graphql-tag-pluck', () => { }); it('should pluck magic comment template literals with a trailing semicolon', async () => { - const gqlString = await pluck('test.js', '/* GraphQL */ `{}`;'); - expect(gqlString).toEqual('{}'); + const sources = await pluck('test.js', '/* GraphQL */ `{}`;'); + expect(sources.map(source => source.body).join('\n\n')).toEqual('{}'); }); it('should pluck with comments having escaped backticks', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` import gql from 'graphql-tag'; export default gql\` @@ -1455,7 +1455,7 @@ describe('graphql-tag-pluck', () => { \` `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` type User { id: ID! "Choose a nice username, so users can \`@mention\` you." @@ -1466,7 +1466,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql template literal imported lazily', async () => { - const gqlString = await pluck('tmp-XXXXXX.js', freeText(` + const sources = await pluck('tmp-XXXXXX.js', freeText(` async function getUserType() { const graphql = await import('graphql-tag'); @@ -1481,7 +1481,7 @@ describe('graphql-tag-pluck', () => { } `)); - expect(gqlString).toEqual(freeText(` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(` type User { id: ID! "Choose a nice username, so users can \`@mention\` you." @@ -1492,7 +1492,7 @@ describe('graphql-tag-pluck', () => { }); it('should pluck graphql template literal in a code file that has decorators', async () => { - const gqlString = await pluck('tmp-XXXXXX.ts', freeText(` + const sources = await pluck('tmp-XXXXXX.ts', freeText(` const CurrentUserForProfile = gql\` query CurrentUserForProfile { currentUser { @@ -1523,7 +1523,7 @@ describe('graphql-tag-pluck', () => { `)); - expect(gqlString).toEqual(freeText(/* GraphQL */` + expect(sources.map(source => source.body).join('\n\n')).toEqual(freeText(/* GraphQL */` query CurrentUserForProfile { currentUser { login diff --git a/packages/loaders/code-file/src/index.ts b/packages/loaders/code-file/src/index.ts index a1a7a7eb266..1299c2c61f7 100644 --- a/packages/loaders/code-file/src/index.ts +++ b/packages/loaders/code-file/src/index.ts @@ -1,6 +1,6 @@ import type { GlobbyOptions } from 'globby'; -import { isSchema, GraphQLSchema, DocumentNode } from 'graphql'; +import { isSchema, GraphQLSchema, DocumentNode, concatAST, parse } from 'graphql'; import { SchemaPointerSingle, DocumentPointerSingle, @@ -129,10 +129,13 @@ export class CodeFileLoader implements UniversalLoader { if (!options.noPluck) { try { const content = await readFile(normalizedFilePath, { encoding: 'utf-8' }); - const sdl = await gqlPluckFromCodeString(normalizedFilePath, content, options.pluckConfig); + const sources = await gqlPluckFromCodeString(normalizedFilePath, content, options.pluckConfig); - if (sdl) { - return parseGraphQLSDL(pointer, sdl, options); + if (sources.length) { + return { + document: concatAST(sources.map(source => parse(source, options))), + location: pointer, + }; } } catch (e) { if (env['DEBUG']) { @@ -174,10 +177,13 @@ export class CodeFileLoader implements UniversalLoader { if (!options.noPluck) { try { const content = readFileSync(normalizedFilePath, { encoding: 'utf-8' }); - const sdl = gqlPluckFromCodeStringSync(normalizedFilePath, content, options.pluckConfig); + const sources = gqlPluckFromCodeStringSync(normalizedFilePath, content, options.pluckConfig); - if (sdl) { - return parseGraphQLSDL(pointer, sdl, options); + if (sources.length) { + return { + document: concatAST(sources.map(source => parse(source, options))), + location: pointer, + }; } } catch (e) { if (env['DEBUG']) { diff --git a/packages/loaders/git/src/index.ts b/packages/loaders/git/src/index.ts index c6d4384eced..f5b3af9ee35 100644 --- a/packages/loaders/git/src/index.ts +++ b/packages/loaders/git/src/index.ts @@ -8,7 +8,8 @@ import micromatch from 'micromatch'; import unixify from 'unixify'; import { loadFromGit, loadFromGitSync, readTreeAtRef, readTreeAtRefSync } from './load-git'; -import { parse } from './parse'; +import { parse as handleStuff } from './parse'; +import { concatAST, parse } from 'graphql'; // git:branch:path/to/file function extractData(pointer: string): { @@ -114,34 +115,38 @@ export class GitLoader implements UniversalLoader { async load(pointer: string, options: GitLoaderOptions) { const { ref, path } = extractData(pointer); const content = await loadFromGit({ ref, path }); - const parsed = parse({ path, options, pointer, content }); + const parsed = handleStuff({ path, options, pointer, content }); if (parsed) { return parsed; } - const rawSDL = await gqlPluckFromCodeString(pointer, content, options.pluckConfig); + const sources = await gqlPluckFromCodeString(pointer, content, options.pluckConfig); + + const documents = sources.map(source => parse(source, options)); return { location: pointer, - rawSDL, + document: concatAST(documents), }; } loadSync(pointer: string, options: GitLoaderOptions) { const { ref, path } = extractData(pointer); const content = loadFromGitSync({ ref, path }); - const parsed = parse({ path, options, pointer, content }); + const parsed = handleStuff({ path, options, pointer, content }); if (parsed) { return parsed; } - const rawSDL = gqlPluckFromCodeStringSync(pointer, content, options.pluckConfig); + const sources = gqlPluckFromCodeStringSync(pointer, content, options.pluckConfig); + + const documents = sources.map(source => parse(source, options)); return { location: pointer, - rawSDL, + document: concatAST(documents), }; } } diff --git a/packages/loaders/git/tests/__snapshots__/loader.spec.ts.snap b/packages/loaders/git/tests/__snapshots__/loader.spec.ts.snap new file mode 100644 index 00000000000..f196ba19681 --- /dev/null +++ b/packages/loaders/git/tests/__snapshots__/loader.spec.ts.snap @@ -0,0 +1,123 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GitLoader load async should load type definitions from a pluckable file 1`] = ` +Object { + "definitions": Array [ + Object { + "description": undefined, + "directives": Array [], + "fields": Array [ + Object { + "arguments": Array [], + "description": undefined, + "directives": Array [], + "kind": "FieldDefinition", + "loc": Object { + "end": 28, + "start": 15, + }, + "name": Object { + "kind": "Name", + "loc": Object { + "end": 20, + "start": 15, + }, + "value": "hello", + }, + "type": Object { + "kind": "NamedType", + "loc": Object { + "end": 28, + "start": 22, + }, + "name": Object { + "kind": "Name", + "loc": Object { + "end": 28, + "start": 22, + }, + "value": "String", + }, + }, + }, + ], + "interfaces": Array [], + "kind": "ObjectTypeDefinition", + "loc": Object { + "end": 30, + "start": 0, + }, + "name": Object { + "kind": "Name", + "loc": Object { + "end": 10, + "start": 5, + }, + "value": "Query", + }, + }, + ], + "kind": "Document", +} +`; + +exports[`GitLoader load sync should load type definitions from a pluckable file 1`] = ` +Object { + "definitions": Array [ + Object { + "description": undefined, + "directives": Array [], + "fields": Array [ + Object { + "arguments": Array [], + "description": undefined, + "directives": Array [], + "kind": "FieldDefinition", + "loc": Object { + "end": 28, + "start": 15, + }, + "name": Object { + "kind": "Name", + "loc": Object { + "end": 20, + "start": 15, + }, + "value": "hello", + }, + "type": Object { + "kind": "NamedType", + "loc": Object { + "end": 28, + "start": 22, + }, + "name": Object { + "kind": "Name", + "loc": Object { + "end": 28, + "start": 22, + }, + "value": "String", + }, + }, + }, + ], + "interfaces": Array [], + "kind": "ObjectTypeDefinition", + "loc": Object { + "end": 30, + "start": 0, + }, + "name": Object { + "kind": "Name", + "loc": Object { + "end": 10, + "start": 5, + }, + "value": "Query", + }, + }, + ], + "kind": "Document", +} +`; diff --git a/packages/loaders/git/tests/loader.spec.ts b/packages/loaders/git/tests/loader.spec.ts index c1e3f9bb9ff..ba4969380ef 100644 --- a/packages/loaders/git/tests/loader.spec.ts +++ b/packages/loaders/git/tests/loader.spec.ts @@ -59,7 +59,7 @@ describe('GitLoader', () => { it('should load type definitions from a pluckable file', async () => { const result: Source = await load(getPointer('pluckable.ts'), {}); - expect(result.rawSDL).toBeDefined(); + expect(result.document).toMatchSnapshot(); }); it('should throw when pointer is malformed', async () => { diff --git a/packages/loaders/github/src/index.ts b/packages/loaders/github/src/index.ts index 007b14c90fa..983f972b8b9 100644 --- a/packages/loaders/github/src/index.ts +++ b/packages/loaders/github/src/index.ts @@ -1,11 +1,10 @@ import { UniversalLoader, parseGraphQLSDL, parseGraphQLJSON, SingleFileOptions } from '@graphql-tools/utils'; import { fetch } from 'cross-fetch'; import { GraphQLTagPluckOptions, gqlPluckFromCodeString } from '@graphql-tools/graphql-tag-pluck'; +import { concatAST, parse } from 'graphql'; // github:owner/name#ref:path/to/file -function extractData( - pointer: string -): { +function extractData(pointer: string): { owner: string; name: string; ref: string; @@ -113,8 +112,11 @@ export class GithubLoader implements UniversalLoader { } if (path.endsWith('.tsx') || path.endsWith('.ts') || path.endsWith('.js') || path.endsWith('.jsx')) { - const rawSDL = await gqlPluckFromCodeString(pointer, content, options.pluckConfig); - return parseGraphQLSDL(path, rawSDL, options); + const sources = await gqlPluckFromCodeString(pointer, content, options.pluckConfig); + return { + location: path, + document: concatAST(sources.map(source => parse(source, options))), + }; } throw new Error(`Invalid file extension: ${path}`);