@graphql-codegen/client-preset
Version:
GraphQL Code Generator preset for client.
65 lines (64 loc) • 2.99 kB
JavaScript
import * as path from 'path';
import { declare } from '@babel/helper-plugin-utils';
import template from '@babel/template';
import { ClientSideBaseVisitor } from '@graphql-codegen/visitor-plugin-common';
import { buildSchema, parse } from 'graphql';
const noopSchema = buildSchema(`type Query { _: Int }`);
export default declare((api, opts) => {
const visitor = new ClientSideBaseVisitor(noopSchema, [], {}, {});
const artifactDirectory = opts['artifactDirectory'] ?? '';
const gqlTagName = opts['gqlTagName'] || 'gql';
let program;
return {
name: 'client-preset',
visitor: {
Program(path) {
program = path;
},
CallExpression(path, state) {
if (path.node.callee.type !== 'Identifier' || path.node.callee.name !== gqlTagName) {
return;
}
const [argument] = path.node.arguments;
if (argument == null) {
return;
}
if (argument.type !== 'TemplateLiteral') {
return;
}
const [content] = argument.quasis;
const ast = parse(content.value.raw);
const [firstDefinition] = ast.definitions;
if (firstDefinition.kind !== 'FragmentDefinition' && firstDefinition.kind !== 'OperationDefinition') {
return;
}
if (firstDefinition.name == null) {
return;
}
const operationOrFragmentName = firstDefinition.kind === 'OperationDefinition'
? visitor.getOperationVariableName(firstDefinition)
: visitor.getFragmentVariableName(firstDefinition);
const importPath = getRelativeImportPath(state, artifactDirectory);
const importDeclaration = template.smart(`
import { %%importName%% } from %%importPath%%
`);
program.unshiftContainer('body', importDeclaration({
importName: api.types.identifier(operationOrFragmentName),
importPath: api.types.stringLiteral(importPath),
}));
path.replaceWith(api.types.identifier(operationOrFragmentName));
},
},
};
});
function getRelativeImportPath(state, artifactDirectory, fileToRequire = 'graphql') {
if (state.file == null) {
throw new Error('Babel state is missing expected file name');
}
const { filename } = state.file.opts;
const relative = path.relative(path.dirname(filename), path.resolve(artifactDirectory));
const relativeReference = relative.length === 0 || !relative.startsWith('.') ? './' : '';
const platformSpecificPath = relativeReference + path.join(relative, fileToRequire);
// ensure windows paths are written as unix paths
return platformSpecificPath.split(path.sep).join(path.posix.sep);
}