Skip to content

Commit

Permalink
Merge pull request #1235 from Quramy/allow_to_transform_callexpression
Browse files Browse the repository at this point in the history
fix: Allow to transform CallExpression
  • Loading branch information
Quramy committed Mar 15, 2024
2 parents e6ced8d + 951dd5b commit 4e1eac8
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 20 deletions.
60 changes: 60 additions & 0 deletions src/transformer/__snapshots__/transformer.test.ts.snap
Expand Up @@ -15,6 +15,16 @@ exports[`transformer GraphQL document transformation should ignore TemplateExpre
"
`;

exports[`transformer GraphQL document transformation should ignore arguments which are not template literal in CallExpression node even if the node matches tag name 1`] = `
"const query = hoge('abc', 100);
"
`;

exports[`transformer GraphQL document transformation should ignore template argument in CallExpression when the node does not matche tag name 1`] = `
"const query = hoge(\`abc\`);
"
`;

exports[`transformer GraphQL document transformation should transform NoSubstitutionTemplateLiteral 1`] = `
"const query = {
kind: "Document",
Expand Down Expand Up @@ -115,6 +125,56 @@ exports[`transformer GraphQL document transformation should transform TemplateEx
"
`;

exports[`transformer GraphQL document transformation should transform first template argument in CallExpression when the node matches tag name 1`] = `
"const query = {
kind: "Document",
definitions: [{
kind: "OperationDefinition",
operation: "query",
variableDefinitions: [],
directives: [],
selectionSet: {
kind: "SelectionSet",
selections: [{
kind: "Field",
name: {
kind: "Name",
value: "hello"
},
arguments: [],
directives: []
}]
}
}]
};
"
`;

exports[`transformer GraphQL document transformation should transform first template expression argument in CallExpression when the node matches tag name 1`] = `
"const query = {
kind: "Document",
definitions: [{
kind: "OperationDefinition",
operation: "query",
variableDefinitions: [],
directives: [],
selectionSet: {
kind: "SelectionSet",
selections: [{
kind: "Field",
name: {
kind: "Name",
value: "hello"
},
arguments: [],
directives: []
}]
}
}]
};
"
`;

exports[`transformer GraphQL document transformation should transform inner document with documentTransformers 1`] = `
"const query = {
kind: "Document",
Expand Down
72 changes: 70 additions & 2 deletions src/transformer/transformer.test.ts
@@ -1,7 +1,7 @@
import ts from 'typescript';
import { DocumentNode, parse, visit } from 'graphql';

import { parseTagConfig } from '../ts-ast-util';
import { parseTagConfig, type TagConfig } from '../ts-ast-util';
import { getTransformer } from './transformer';

function transformAndPrint({
Expand All @@ -13,7 +13,7 @@ function transformAndPrint({
documentTransformers = [],
enabled = true,
}: {
tag?: string;
tag?: TagConfig;
target: 'text' | 'object';
docContent: string;
tsContent: string;
Expand Down Expand Up @@ -153,6 +153,74 @@ describe('transformer', () => {
).toMatchSnapshot();
});

it('should transform first template argument in CallExpression when the node matches tag name', () => {
expect(
transformAndPrint({
tsContent: `
const query = hoge(\`abc\`);
`,
tag: { name: 'hoge', ignoreFunctionCallExpression: false },
docContent: `
query {
hello
}
`,
target: 'object',
}),
).toMatchSnapshot();
});

it('should transform first template expression argument in CallExpression when the node matches tag name', () => {
expect(
transformAndPrint({
tsContent: `
const query = hoge(\`abc\${def}\`);
`,
tag: { name: 'hoge', ignoreFunctionCallExpression: false },
docContent: `
query {
hello
}
`,
target: 'object',
}),
).toMatchSnapshot();
});

it('should ignore template argument in CallExpression when the node does not matche tag name', () => {
expect(
transformAndPrint({
tsContent: `
const query = hoge(\`abc\`);
`,
tag: { name: 'foo', ignoreFunctionCallExpression: false },
docContent: `
query {
hello
}
`,
target: 'object',
}),
).toMatchSnapshot();
});

it('should ignore arguments which are not template literal in CallExpression node even if the node matches tag name', () => {
expect(
transformAndPrint({
tsContent: `
const query = hoge('abc', 100);
`,
tag: { name: 'hoge', ignoreFunctionCallExpression: false },
docContent: `
query {
hello
}
`,
target: 'object',
}),
).toMatchSnapshot();
});

it('should transform to 0 literal when removeFragmentDefinitions: true and document has only fragments', () => {
expect(
transformAndPrint({
Expand Down
12 changes: 5 additions & 7 deletions src/transformer/transformer.ts
Expand Up @@ -44,18 +44,16 @@ export function getTransformer({
return (ctx: ts.TransformationContext) => {
const visit = (node: ts.Node): ts.Node | undefined => {
if (!getEnabled()) return node;
if (tag.names.length > 1) return node;
let templateNode: ts.NoSubstitutionTemplateLiteral | ts.TemplateExpression | undefined = undefined;

if (ts.isImportDeclaration(node) && tag.names[0]) {
return removeAliasFromImportDeclaration(node, tag.names[0]);
if (ts.isImportDeclaration(node) && tag.names.length > 0) {
return removeAliasFromImportDeclaration(node, tag.names);
}

if (
ts.isTaggedTemplateExpression(node) &&
(!tag.names.length || !!getTemplateNodeUnder(node, { ...tag, allowFunctionCallExpression: false }))
) {
if (ts.isTaggedTemplateExpression(node) && (!tag.names.length || !!getTemplateNodeUnder(node, tag))) {
templateNode = node.template;
} else if (ts.isCallExpression(node) && !!getTemplateNodeUnder(node, tag)) {
templateNode = node.arguments[0] as ts.TemplateLiteral;
} else if (tag.allowNotTaggedTemplate && ts.isNoSubstitutionTemplateLiteral(node)) {
templateNode = node;
} else if (tag.allowNotTaggedTemplate && ts.isTemplateExpression(node)) {
Expand Down
4 changes: 2 additions & 2 deletions src/ts-ast-util/utilily-functions.test.ts
Expand Up @@ -309,9 +309,9 @@ describe(removeAliasFromImportDeclaration, () => {
function remove(text: string, name: string) {
const inputSource = ts.createSourceFile('input.ts', text, ts.ScriptTarget.Latest);
const statements = inputSource.statements as ts.NodeArray<ts.ImportDeclaration>;
const out = removeAliasFromImportDeclaration(statements[0], name);
const out = removeAliasFromImportDeclaration(statements[0], [name]);
if (!out) return undefined;
return printNode(removeAliasFromImportDeclaration(statements[0], name)).trim();
return printNode(removeAliasFromImportDeclaration(statements[0], [name])).trim();
}

it('should return base statement when name does not match', () => {
Expand Down
18 changes: 9 additions & 9 deletions src/ts-ast-util/utilily-functions.ts
Expand Up @@ -10,11 +10,11 @@ function mergeNamedBinding(base: ts.NamedImportBindings | undefined, head: ts.Na
return astf.updateNamedImports(base, [...base.elements, ...head.elements]);
}

function removeFromNamedBinding(base: ts.NamedImportBindings | undefined, name: string) {
function removeFromNamedBinding(base: ts.NamedImportBindings | undefined, names: string[]) {
if (!base) return undefined;
// treat namedImports only
if (ts.isNamespaceImport(base)) return base;
const elements = base.elements.filter(elm => elm.name.text !== name);
const elements = base.elements.filter(elm => !names.includes(elm.name.text));
if (elements.length === 0) return undefined;
return astf.updateNamedImports(base, elements);
}
Expand All @@ -29,12 +29,12 @@ function mergeImportClause(base: ts.ImportClause | undefined, head: ts.ImportCla
return astf.updateImportClause(base, isTypeOnly, name, namedBindings);
}

function removeFromImportClause(base: ts.ImportClause | undefined, name: string) {
function removeFromImportClause(base: ts.ImportClause | undefined, names: string[]) {
if (!base) return undefined;
const namedBindings = removeFromNamedBinding(base.namedBindings, name);
const nameId = base.name?.text !== name ? base.name : undefined;
if (!nameId && !namedBindings) return undefined;
return astf.updateImportClause(base, base.isTypeOnly, nameId, namedBindings);
const namedBindings = removeFromNamedBinding(base.namedBindings, names);
const nameIdentifier = base.name && names.includes(base.name.text) ? undefined : base.name;
if (!nameIdentifier && !namedBindings) return undefined;
return astf.updateImportClause(base, base.isTypeOnly, nameIdentifier, namedBindings);
}

export function findNode(sourceFile: ts.SourceFile, position: number): ts.Node | undefined {
Expand Down Expand Up @@ -121,9 +121,9 @@ export function mergeImportDeclarationsWithSameModules(base: ts.ImportDeclaratio
return astf.updateImportDeclaration(base, modifiers, importClause, base.moduleSpecifier, undefined);
}

export function removeAliasFromImportDeclaration(base: ts.ImportDeclaration, name: string) {
export function removeAliasFromImportDeclaration(base: ts.ImportDeclaration, names: string[]) {
const modifiers = base.modifiers;
const importClause = removeFromImportClause(base.importClause, name);
const importClause = removeFromImportClause(base.importClause, names);
if (!importClause) return undefined;
return astf.updateImportDeclaration(base, modifiers, importClause, base.moduleSpecifier, undefined);
}

0 comments on commit 4e1eac8

Please sign in to comment.