Skip to content

Commit

Permalink
Support matching template literals which are declared 'as const' (#4877)
Browse files Browse the repository at this point in the history
* Support matching template literals which are declared 'as const'

* Add changeset

---------

Co-authored-by: Tristan Menzel <tristanmenzel@gmail.com>
  • Loading branch information
tristanmenzel and tristanmenzel committed Feb 13, 2023
1 parent 6a1f239 commit 42ad8df
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/weak-tomatoes-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-tools/graphql-tag-pluck': minor
---

Adds support for matching graphql queries declared with typescript's 'as const' expression. eg. graphql(`query myQuery(...)` as const)
25 changes: 23 additions & 2 deletions packages/graphql-tag-pluck/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import {
isTemplateLiteral,
isImportDefaultSpecifier,
isImportSpecifier,
isTSAsExpression,
isTSTypeReference,
TSAsExpression,
} from '@babel/types';
import { asArray } from '@graphql-tools/utils';
import { Visitor } from '@babel/traverse';
Expand Down Expand Up @@ -261,10 +264,28 @@ export default (code: string, out: any, options: GraphQLTagPluckOptions = {}) =>
return;
}

// Checks to see if a node represents a typescript '<expression> as const' expression
function isTSAsConstExpression(node: object | null | undefined): node is TSAsExpression {
return (
isTSAsExpression(node) &&
isTSTypeReference(node.typeAnnotation) &&
isIdentifier(node.typeAnnotation.typeName) &&
node.typeAnnotation.typeName.name === 'const'
);
}

// Extract template literal from as const expression if applicable
// e.g. gql(`query myQuery {}` as const)
const unwrappedExpression = isTSAsConstExpression(arg0) ? arg0.expression : arg0;

// Push strings template literals to gql calls
// e.g. gql(`query myQuery {}`) -> query myQuery {}
if (isIdentifier(path.node.callee) && isValidIdentifier(path.node.callee.name) && isTemplateLiteral(arg0)) {
const { start, end, loc } = arg0;
if (
isIdentifier(path.node.callee) &&
isValidIdentifier(path.node.callee.name) &&
isTemplateLiteral(unwrappedExpression)
) {
const { start, end, loc } = unwrappedExpression;
if (start != null && end != null && start != null && loc != null) {
const gqlTemplateLiteral = pluckStringFromFile({ start, end });

Expand Down
38 changes: 38 additions & 0 deletions packages/graphql-tag-pluck/tests/graphql-tag-pluck.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,44 @@ describe('graphql-tag-pluck', () => {
);
});

it("should pluck graphql template literals from .ts that use an 'as const' assertion", async () => {
const sources = await pluck(
'tmp-XXXXXX.ts',
freeText(`
import { graphql } from '../somewhere'
import { Document } from 'graphql'
const fragment: Document = graphql(\`
fragment Foo on FooType {
id
}
\`as const)
const doc: Document = graphql(\`
query foo {
foo {
...Foo
}
}
\` as const)
`)
);

expect(sources.map(source => source.body).join('\n\n')).toEqual(
freeText(`
fragment Foo on FooType {
id
}
query foo {
foo {
...Foo
}
}
`)
);
});

it('should pluck graphql-tag template literals from .ts file', async () => {
const sources = await pluck(
'tmp-XXXXXX.ts',
Expand Down

0 comments on commit 42ad8df

Please sign in to comment.