Repository: gajus/babel-plugin-graphql-tag Branch: master Commit: 5d0ed35588e7 Files: 84 Total size: 39.6 KB Directory structure: gitextract_7arzgge2/ ├── .editorconfig ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── babel.config.js ├── jest.config.js ├── package.json ├── src/ │ └── index.js └── test/ ├── fixtures/ │ ├── apollov3/ │ │ ├── converts inline gql tag to a compiled version/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── converts inline gql tag with fragment interpolation/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── does not transpile template literals without a tag/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── does not transpile template literals without gql tag/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── handles different imports based on options/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── preserves imports when cannot parse query/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── preserves other imports from graphql-tag package/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── strips ignored characters from source/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── transpiles a single unnamed query/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ ├── transpiles a single unnamed query with require/ │ │ │ ├── input.js │ │ │ ├── options.json │ │ │ └── output.mjs │ │ └── transpiles a single unnamed query with require and other tool/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ └── graphql-tag/ │ ├── allows a custom tag identifier/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── converts inline gql tag to a compiled version/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── converts inline gql tag with fragment interpolation/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── does not transpile template literals without a tag/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── does not transpile template literals without gql tag/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── handles different imports based on options/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── handles gql tag with alternative names/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── preserves imports when cannot parse query/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── preserves other imports from graphql-tag package/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── strips ignored characters from source/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ ├── transpiles a single unnamed query/ │ │ ├── input.js │ │ ├── options.json │ │ └── output.mjs │ └── transpiles a single unnamed query with require/ │ ├── input.js │ ├── options.json │ └── output.mjs ├── index.test.js ├── package.json └── unnamed-query.test.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true ================================================ FILE: .eslintrc ================================================ { "extends": [ "canonical" ], "root": true } ================================================ FILE: .flowconfig ================================================ [ignore] /node_modules/config-chain/test/broken.json /node_modules/conventional-changelog-core/test/fixtures/_malformation.json /node_modules/npmconf/test/fixtures/package.json ================================================ FILE: .gitignore ================================================ coverage dist node_modules *.log .* !.babelrc !.editorconfig !.eslintrc !.flowconfig !.gitignore !.npmignore !.README !.travis.yml ================================================ FILE: .npmignore ================================================ src test coverage .* *.log ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - 14 script: - npm run lint - npm run build - npm run test after_success: - NODE_ENV=production npm run build - semantic-release notifications: email: false sudo: false ================================================ FILE: LICENSE ================================================ Copyright (c) 2016, Gajus Kuizinas (http://gajus.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Gajus Kuizinas (http://gajus.com/) nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # babel-plugin-graphql-tag [![GitSpo Mentions](https://gitspo.com/badges/mentions/gajus/babel-plugin-graphql-tag?style=flat-square)](https://gitspo.com/mentions/gajus/babel-plugin-graphql-tag) [![Travis build status](http://img.shields.io/travis/gajus/babel-plugin-graphql-tag/master.svg?style=flat-square)](https://travis-ci.org/gajus/babel-plugin-graphql-tag) [![NPM version](http://img.shields.io/npm/v/babel-plugin-graphql-tag.svg?style=flat-square)](https://www.npmjs.org/package/babel-plugin-graphql-tag) [![Canonical Code Style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical) [![Twitter Follow](https://img.shields.io/twitter/follow/kuizinas.svg?style=social&label=Follow)](https://twitter.com/kuizinas) Compiles GraphQL tagged template strings using [graphql-tag](https://github.com/apollographql/graphql-tag). ## Motivation Compiling GraphQL queries at the build time: * reduces the script initialization time; and * removes the `graphql-tag` dependency Removing the `graphql-tag` dependency from the bundle saves approx. 50 KB. ## Implementation * Searches for imports of `graphql-tag` and removes them. * Searches for [tagged template literals](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals) with `gql` identifier and compiles them using `graphql-tag`. ## Example compilation Input: ```js import gql from 'graphql-tag'; // if using apollo v3 import { gql } from '@apollo/client'; const foo = gql`query {bar}`; ``` Output: ```js const foo = { "definitions": [ { "directives": [ ], "kind": "OperationDefinition", "operation": "query", "selectionSet": { "kind": "SelectionSet", "selections": [ { "alias": null, "arguments": [ ], "directives": [ ], "kind": "Field", "name": { "kind": "Name", "value": "bar" }, "selectionSet": null } ] }, "variableDefinitions": [ ] } ], "kind": "Document", "loc": { "end": 11, "start": 0 } }; ``` **NOTE: require() is also supported.** ### Using fragments Using GraphQL [fragments](http://graphql.org/learn/queries/#fragments) requires to: 1. Define a fragment using `graphql-tag`. 2. Append the referenced fragment as a variable to the end of the GraphQL query. Example: ```js import gql from 'graphql-tag'; const bar = gql` fragment barFragment on Foo { field1 field2 } `; const foo = gql` query foo { foo { ...barFragment } } ${bar} `; ``` ### Options - `importSources` - An array of names for modules to import (default = `["graphql-tag", "@apollo/client"]`) - `onlyMatchImportSuffix` - Matches the end of the import instead of the entire name. Useful for relative imports, e.g. `./utils/graphql` (default = false) - `strip` - Strips insignificant characters such as whitespace from the original GraphQL string literal to reduce the size of compiled AST (default = false) - `transform` - By default, graphql query strings will be replaced with their AST representations, but you can override that behavior and do whatever you like. One possible use case would be to implement persisted queries: - `gqlTagIdentifiers` - An array of names for gql tag identifiers (default = `["gql"]`) ```js // babel.config.js plugins: [ [ "babel-plugin-graphql-tag", { strip: true, transform: (source, ast) => { const h = hash(source); // use your favorite hashing method graphqlAstHashes[h] = ast; // write this to a file when compilation is complete return { queryId: h }; } } ] ] ``` ### Known Issues Some cases are really hard to track down: ``` const apolloClient = require('@apollo/client'); // or import apolloClient from '@apollo/client'; const { gql } = apolloClient; const foo = gql`...`; ``` If you have this kind of syntax, this plugin won't work for you. ================================================ FILE: babel.config.js ================================================ module.exports = { presets: [ [ '@babel/preset-env', { modules: 'commonjs', targets: { node: 8 } } ], '@babel/preset-flow' ] }; ================================================ FILE: jest.config.js ================================================ module.exports = { testEnvironment: 'node' }; ================================================ FILE: package.json ================================================ { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/parser": "^7.3.2", "babel-literal-to-ast": "^2.1.0", "debug": "^4.1.1" }, "description": "Compiles GraphQL tagged template strings using graphql-tag", "devDependencies": { "@apollo/client": "^3.1.0", "@babel/cli": "^7.2.3", "@babel/core": "^7.2.2", "@babel/helper-transform-fixture-test-runner": "^7.1.2", "@babel/preset-env": "^7.3.1", "@babel/preset-flow": "^7.0.0", "cross-env": "^7.0.2", "eslint": "^7.0.0", "eslint-config-canonical": "^21.0.2", "flow-bin": "^0.93.0", "graphql": "^14.3.0", "graphql-tag": "^2.10.1", "husky": "^1.3.1", "jest": "^24.1.0", "semantic-release": "^17.1.2" }, "husky": { "hooks": { "pre-commit": "npm run lint && npm run test" } }, "main": "dist/index.js", "name": "babel-plugin-graphql-tag", "peerDependencies": { "@babel/core": "^7.0.0", "graphql-tag": "^2.10.1", "graphql": "^14.0.0 || ^15.0.0" }, "repository": { "type": "git", "url": "git+https://github.com/gajus/babel-plugin-graphql-tag.git" }, "resolutions": { "jest": "^24.1.0" }, "scripts": { "build": "rm -fr ./dist && cross-env NODE_ENV=production babel ./src --out-dir ./dist --source-maps --copy-files", "lint": "eslint ./src && flow", "test": "cross-env NODE_ENV=test jest" }, "version": "3.1.0" } ================================================ FILE: src/index.js ================================================ /* eslint-disable prefer-exponentiation-operator */ // @flow import {types} from '@babel/core'; import {declare} from '@babel/helper-plugin-utils'; import {parseExpression} from '@babel/parser'; import parseLiteral from 'babel-literal-to-ast'; import gql from 'graphql-tag'; import createDebug from 'debug'; import {stripIgnoredCharacters} from 'graphql'; const debug = createDebug('babel-plugin-graphql-tag'); const { addComment, cloneDeep, isIdentifier, isMemberExpression, isImportSpecifier, isImportDefaultSpecifier, variableDeclaration, variableDeclarator, memberExpression, callExpression, identifier, isObjectPattern, } = types; const PURE_ANNOTATION = '#__PURE__'; // eslint-disable-next-line no-restricted-syntax const uniqueFn = parseExpression(` (definitions) => { const names = {}; return definitions.filter(definition => { if (definition.kind !== 'FragmentDefinition') { return true; } const name = definition.name.value; if (names[name]) { return false; } else { names[name] = true; return true; } }); } `); export default declare((api, options) => { api.assertVersion(7); const { importSources = ['graphql-tag', '@apollo/client'], gqlTagIdentifiers = ['gql'], onlyMatchImportSuffix = false, strip = false, } = options; const gqlTagIdentifiersSet = new Set(gqlTagIdentifiers); const compile = (path: Object, uniqueId) => { // eslint-disable-next-line unicorn/no-reduce const source = path.node.quasis.reduce((head, quasi) => { return head + quasi.value.raw; }, ''); const expressions = path.get('expressions'); expressions.forEach((expr) => { if (!isIdentifier(expr) && !isMemberExpression(expr)) { throw expr.buildCodeFrameError( 'Only identifiers or member expressions are allowed by this plugin as an interpolation in a graphql template literal.', ); } }); debug('compiling a GraphQL query', source); const finalSource = strip ? stripIgnoredCharacters(source) : source; let queryDocument = gql(strip ? stripIgnoredCharacters(finalSource) : finalSource); // If a document contains only one operation, that operation may be unnamed: // https://facebook.github.io/graphql/#sec-Language.Query-Document if (queryDocument.definitions.length > 1) { for (const definition of queryDocument.definitions) { if (!definition.name) { throw new Error('GraphQL query must have name.'); } } } if (options.transform && options.transform) { queryDocument = options.transform(finalSource, queryDocument); } const body = parseLiteral(queryDocument); let uniqueUsed = false; if (expressions.length) { const definitionsProperty = body.properties.find((property) => { return property.key.value === 'definitions'; }); const definitionsArray = definitionsProperty.value; const extraDefinitions = expressions.map((expr) => { return memberExpression(expr.node, identifier('definitions')); }); const allDefinitions = callExpression( memberExpression(definitionsArray, identifier('concat')), extraDefinitions, ); definitionsProperty.value = callExpression(uniqueId, [allDefinitions]); // Marking these function calls with an annotation indicating that // they're pure will allow bundlers like Webpack and Rollup to more // aggressively remove unused queries from bundles. addComment(allDefinitions, 'leading', PURE_ANNOTATION); addComment(definitionsProperty.value, 'leading', PURE_ANNOTATION); uniqueUsed = true; } debug('created a static representation', body); return [body, uniqueUsed]; }; return { visitor: { Program (programPath: Object) { const tagNames = []; const pendingDeletion = []; const uniqueId = programPath.scope.generateUidIdentifier('unique'); let uniqueUsed = false; let hasError = false; programPath.traverse({ CallExpression: { enter (nodePath) { const callee = nodePath.get('callee'); const {arguments: args} = nodePath.node; if (callee.isIdentifier() && callee.equals('name', 'require')) { const [{value: pathValue}] = args; if (importSources.some((source) => { return onlyMatchImportSuffix ? pathValue.endsWith(source) : pathValue === source; })) { if (nodePath.parentPath.isVariableDeclarator()) { const gqlDeclaration = nodePath.parentPath.parent.declarations[0]; if (isObjectPattern(gqlDeclaration.id)) { const gqlProperty = gqlDeclaration.id.properties.find((property) => { return gqlTagIdentifiersSet.has(property.key.name); }); tagNames.push(gqlProperty.key.name); if (gqlDeclaration.id.properties.length === 1) { pendingDeletion.push({ defaultSpecifier: null, path: nodePath.parentPath, }); } gqlDeclaration.id.properties = gqlDeclaration.id.properties.filter((property) => { return !gqlTagIdentifiersSet.has(property.key.name); }); return; } tagNames.push(gqlDeclaration.id.name); pendingDeletion.push({ defaultSpecifier: null, path: nodePath.parentPath, }); } } } }, }, ImportDeclaration (path: Object) { const pathValue = path.node.source.value; const gqlSpecifier = path.node.specifiers.find((specifier) => { if (isImportSpecifier(specifier)) { return gqlTagIdentifiersSet.has(specifier.local.name); } if (isImportDefaultSpecifier(specifier)) { return importSources.some((source) => { return onlyMatchImportSuffix ? pathValue.endsWith(source) : pathValue === source; }); } return null; }); if (gqlSpecifier) { tagNames.push(gqlSpecifier.local.name); pendingDeletion.push({ defaultSpecifier: gqlSpecifier, path, }); } }, TaggedTemplateExpression (path: Object) { if ( tagNames.some((name) => { return isIdentifier(path.node.tag, {name}); }) ) { try { debug('quasi', path.node.quasi); const [body, used] = compile(path.get('quasi'), uniqueId); uniqueUsed = uniqueUsed || used; path.replaceWith(cloneDeep(body)); } catch (error) { // eslint-disable-next-line no-console console.error('error', error); hasError = true; } } }, }); // Only delete import statement or specifier when there is no error if (!hasError) { for (const {defaultSpecifier, path: pathForDeletion} of pendingDeletion) { if (defaultSpecifier === null) { pathForDeletion.remove(); continue; } if (pathForDeletion.node.specifiers.length === 1) { pathForDeletion.remove(); } else { pathForDeletion.node.specifiers = pathForDeletion.node.specifiers.filter((specifier) => { return specifier !== defaultSpecifier; }); } } } if (uniqueUsed) { programPath.unshiftContainer( 'body', variableDeclaration('const', [variableDeclarator(uniqueId, cloneDeep(uniqueFn))]), ); } }, }, }; }); ================================================ FILE: test/fixtures/apollov3/converts inline gql tag to a compiled version/input.js ================================================ import { gql } from '@apollo/client'; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/converts inline gql tag to a compiled version/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/converts inline gql tag to a compiled version/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/converts inline gql tag with fragment interpolation/input.js ================================================ import { gql } from '@apollo/client'; const bar = gql` fragment barFragment on Foo { field1 field2 } `; const baz = { fragments: { foo: gql` fragment bazFragment on Foo { field2 field3 } ` } }; const foo = gql` query foo { foo { ...barFragment ...bazFragment } } ${bar} ${baz.fragments.foo} `; ================================================ FILE: test/fixtures/apollov3/converts inline gql tag with fragment interpolation/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/converts inline gql tag with fragment interpolation/output.mjs ================================================ const _unique = definitions => { const names = {}; return definitions.filter(definition => { if (definition.kind !== 'FragmentDefinition') { return true; } const name = definition.name.value; if (names[name]) { return false; } else { names[name] = true; return true; } }); }; const bar = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "barFragment" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Foo" } }, "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "field1" }, "arguments": [], "directives": [] }, { "kind": "Field", "name": { "kind": "Name", "value": "field2" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 59, "source": { "body": "\n fragment barFragment on Foo {\n field1\n field2\n }\n", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; const baz = { fragments: { foo: { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "bazFragment" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Foo" } }, "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "field2" }, "arguments": [], "directives": [] }, { "kind": "Field", "name": { "kind": "Name", "value": "field3" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 79, "source": { "body": "\n fragment bazFragment on Foo {\n field2\n field3\n }\n ", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } } } }; const foo = { "kind": "Document", "definitions": /*#__PURE__*/_unique( /*#__PURE__*/[{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "barFragment" }, "directives": [] }, { "kind": "FragmentSpread", "name": { "kind": "Name", "value": "bazFragment" }, "directives": [] }] } }] } }].concat(bar.definitions, baz.fragments.foo.definitions)), "loc": { "start": 0, "end": 84, "source": { "body": "\n query foo {\n foo {\n ...barFragment\n ...bazFragment\n }\n }\n\n \n \n", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/does not transpile template literals without a tag/input.js ================================================ import { gql } from '@apollo/client'; const foo = `query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/does not transpile template literals without a tag/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/does not transpile template literals without a tag/output.mjs ================================================ const foo = `query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/does not transpile template literals without gql tag/input.js ================================================ import { gql } from '@apollo/client'; const foo = bar`query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/does not transpile template literals without gql tag/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/does not transpile template literals without gql tag/output.mjs ================================================ const foo = bar`query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/handles different imports based on options/input.js ================================================ import { gql } from "../../../node_modules/@apollo/client"; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/handles different imports based on options/options.json ================================================ { "plugins": [ [ "../../../../src", { "importName": "@apollo/client", "onlyMatchImportSuffix": true } ] ] } ================================================ FILE: test/fixtures/apollov3/handles different imports based on options/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/preserves imports when cannot parse query/input.js ================================================ import { gql } from '@apollo/client'; const bar = gql`query foo {`; ================================================ FILE: test/fixtures/apollov3/preserves imports when cannot parse query/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/preserves imports when cannot parse query/output.mjs ================================================ import { gql } from '@apollo/client'; const bar = gql`query foo {`; ================================================ FILE: test/fixtures/apollov3/preserves other imports from graphql-tag package/input.js ================================================ import { gql, other } from '@apollo/client'; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/preserves other imports from graphql-tag package/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/preserves other imports from graphql-tag package/output.mjs ================================================ import { other } from '@apollo/client'; const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/strips ignored characters from source/input.js ================================================ import { gql } from '@apollo/client'; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/apollov3/strips ignored characters from source/options.json ================================================ { "plugins": [ [ "../../../../src", { "importName": "@apollo/client", "strip": true } ] ] } ================================================ FILE: test/fixtures/apollov3/strips ignored characters from source/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 14, "source": { "body": "query foo{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query/input.js ================================================ import { gql } from '@apollo/client'; const foo = gql`{foo}`; ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 5, "source": { "body": "{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query with require/input.js ================================================ const { gql } = require('@apollo/client'); const foo = gql`{foo}`; ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query with require/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query with require/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 5, "source": { "body": "{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query with require and other tool/input.js ================================================ const { gql, useQuery } = require('@apollo/client'); const foo = gql`{foo}`; ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query with require and other tool/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/apollov3/transpiles a single unnamed query with require and other tool/output.mjs ================================================ const { useQuery } = require('@apollo/client'); const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 5, "source": { "body": "{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/allows a custom tag identifier/input.js ================================================ import { gqlTagPrimaryGateway } from 'primary-gateway-graphql-tag'; const foo = gqlTagPrimaryGateway`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/allows a custom tag identifier/options.json ================================================ { "plugins": [ [ "../../../../src", { "importSources": ["@apollo/client", "primary-gateway-graphql-tag"], "gqlTagIdentifiers": ["gql", "gqlTagPrimaryGateway"], "strip": true } ] ] } ================================================ FILE: test/fixtures/graphql-tag/allows a custom tag identifier/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 14, "source": { "body": "query foo{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/converts inline gql tag to a compiled version/input.js ================================================ import gql from 'graphql-tag'; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/converts inline gql tag to a compiled version/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/converts inline gql tag to a compiled version/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/converts inline gql tag with fragment interpolation/input.js ================================================ import gql from 'graphql-tag'; const bar = gql` fragment barFragment on Foo { field1 field2 } `; const baz = { fragments: { foo: gql` fragment bazFragment on Foo { field2 field3 } ` } }; const foo = gql` query foo { foo { ...barFragment ...bazFragment } } ${bar} ${baz.fragments.foo} `; ================================================ FILE: test/fixtures/graphql-tag/converts inline gql tag with fragment interpolation/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/converts inline gql tag with fragment interpolation/output.mjs ================================================ const _unique = definitions => { const names = {}; return definitions.filter(definition => { if (definition.kind !== 'FragmentDefinition') { return true; } const name = definition.name.value; if (names[name]) { return false; } else { names[name] = true; return true; } }); }; const bar = { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "barFragment" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Foo" } }, "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "field1" }, "arguments": [], "directives": [] }, { "kind": "Field", "name": { "kind": "Name", "value": "field2" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 59, "source": { "body": "\n fragment barFragment on Foo {\n field1\n field2\n }\n", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; const baz = { fragments: { foo: { "kind": "Document", "definitions": [{ "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "bazFragment" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Foo" } }, "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "field2" }, "arguments": [], "directives": [] }, { "kind": "Field", "name": { "kind": "Name", "value": "field3" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 79, "source": { "body": "\n fragment bazFragment on Foo {\n field2\n field3\n }\n ", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } } } }; const foo = { "kind": "Document", "definitions": /*#__PURE__*/_unique( /*#__PURE__*/[{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "barFragment" }, "directives": [] }, { "kind": "FragmentSpread", "name": { "kind": "Name", "value": "bazFragment" }, "directives": [] }] } }] } }].concat(bar.definitions, baz.fragments.foo.definitions)), "loc": { "start": 0, "end": 84, "source": { "body": "\n query foo {\n foo {\n ...barFragment\n ...bazFragment\n }\n }\n\n \n \n", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/does not transpile template literals without a tag/input.js ================================================ import gql from 'graphql-tag'; const foo = `query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/does not transpile template literals without a tag/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/does not transpile template literals without a tag/output.mjs ================================================ const foo = `query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/does not transpile template literals without gql tag/input.js ================================================ import gql from 'graphql-tag'; const foo = bar`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/does not transpile template literals without gql tag/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/does not transpile template literals without gql tag/output.mjs ================================================ const foo = bar`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/handles different imports based on options/input.js ================================================ import gql from "../../../node_modules/graphql-tag"; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/handles different imports based on options/options.json ================================================ { "plugins": [ [ "../../../../src", { "onlyMatchImportSuffix": true } ] ] } ================================================ FILE: test/fixtures/graphql-tag/handles different imports based on options/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/handles gql tag with alternative names/input.js ================================================ import first from 'graphql-tag'; import second from 'graphql-tag'; const foo = first`query foo {foo}`; const bar = second`query bar {bar}`; ================================================ FILE: test/fixtures/graphql-tag/handles gql tag with alternative names/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/handles gql tag with alternative names/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; const bar = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "bar" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "bar" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query bar {bar}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/preserves imports when cannot parse query/input.js ================================================ import gql from 'graphql-tag'; const bar = gql`query foo {`; ================================================ FILE: test/fixtures/graphql-tag/preserves imports when cannot parse query/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/preserves imports when cannot parse query/output.mjs ================================================ import gql from 'graphql-tag'; const bar = gql`query foo {`; ================================================ FILE: test/fixtures/graphql-tag/preserves other imports from graphql-tag package/input.js ================================================ import gql, { other } from 'graphql-tag'; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/preserves other imports from graphql-tag package/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/preserves other imports from graphql-tag package/output.mjs ================================================ import { other } from 'graphql-tag'; const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 15, "source": { "body": "query foo {foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/strips ignored characters from source/input.js ================================================ import gql from 'graphql-tag'; const foo = gql`query foo {foo}`; ================================================ FILE: test/fixtures/graphql-tag/strips ignored characters from source/options.json ================================================ { "plugins": [ [ "../../../../src", { "strip": true } ] ] } ================================================ FILE: test/fixtures/graphql-tag/strips ignored characters from source/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "foo" }, "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 14, "source": { "body": "query foo{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/transpiles a single unnamed query/input.js ================================================ import gql from 'graphql-tag'; const foo = gql`{foo}`; ================================================ FILE: test/fixtures/graphql-tag/transpiles a single unnamed query/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/transpiles a single unnamed query/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 5, "source": { "body": "{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/fixtures/graphql-tag/transpiles a single unnamed query with require/input.js ================================================ const gql = require('graphql-tag'); const foo = gql`{foo}`; ================================================ FILE: test/fixtures/graphql-tag/transpiles a single unnamed query with require/options.json ================================================ { "plugins": [ [ "../../../../src" ] ] } ================================================ FILE: test/fixtures/graphql-tag/transpiles a single unnamed query with require/output.mjs ================================================ const foo = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "variableDefinitions": [], "directives": [], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "foo" }, "arguments": [], "directives": [] }] } }], "loc": { "start": 0, "end": 5, "source": { "body": "{foo}", "name": "GraphQL request", "locationOffset": { "line": 1, "column": 1 } } } }; ================================================ FILE: test/index.test.js ================================================ const path = require('path'); const runner = require("@babel/helper-transform-fixture-test-runner").default; runner( __dirname + "/fixtures", path.basename(path.dirname(__dirname)), {}, { sourceType: 'module' }, ); ================================================ FILE: test/package.json ================================================ { "name": "bar", "version": "1.0.0" } ================================================ FILE: test/unnamed-query.test.js ================================================ import {transform} from '@babel/core'; import assert from 'assert'; const fixture = ` import gql from 'graphql-tag'; gql\`type Widget { name: String } query {widget}\`; `; describe('When given an unnamed query', () => { let originalError; beforeEach(function() { originalError = console.error; }); afterEach(function() { console.error = originalError; }); it('fails when there are other definitions', () => { const calls = []; console.error = (...args) => calls.push(args.join(' ')); transform(fixture, { plugins: [['./src']], }); assert.equal(calls.length, 1); assert.equal(calls[0], 'error Error: GraphQL query must have name.'); }); });