import * as gql from 'graphql'; import fs from 'fs'; const schema = fs.readFileSync( '../api-client-schema/src/schema.graphql', 'utf8' ); const operations = fs.readFileSync('operations.graphql', 'utf8'); const gqlSchema = gql.buildSchema(schema); const gqlOperations = gql.parse(operations); function generateOperationsModule() { const typeInfo = new gql.TypeInfo(gqlSchema); const outputProgram = gql.visit( gqlOperations, gql.visitWithTypeInfo(typeInfo, visitor(gqlSchema, typeInfo)) ); const modules = ['Fragment', 'Mutation', 'Query'] .map( (moduleName) => `module ${moduleName}\n${outputProgram .filter((x) => x.moduleName === moduleName) .map((x) => x.element) .join('\n\n')}\nend` ) .join('\n'); return `# frozen_string_literal: true\n\nmodule Stigg\n${modules}\nend`; } function findFragments(node, results = new Set()) { if (node.kind === 'FragmentSpread') { results.add(node.name.value); gqlOperations.definitions.find((def) => { if ( def.kind === 'FragmentDefinition' && def.name.value === node.name.value ) { findFragments(def, results); } }); } node.selectionSet?.selections?.forEach((node) => findFragments(node, results) ); return results; } function visitor(schema, typeInfo) { return { enter(node) { typeInfo.enter(node); }, leave(node) { typeInfo.leave(node); switch (node.kind) { case 'Document': return node.definitions; case 'OperationDefinition': { const results = findFragments(node); const rawQuery = node.loc.source.body.substring( node.loc.start, node.loc.end ); const namelessQuery = rawQuery.replace( `${node.operation} ${node.name.value}`, `${node.operation} ` ); const includedFragments = [...results] .map((x) => `#{Fragment::${x}}\n`) .join(''); const constantName = node.name.value[0].toUpperCase() + node.name.value.slice(1); return { moduleName: node.operation === 'mutation' ? 'Mutation' : 'Query', element: `${constantName} = <<-GRAPHQL\n${namelessQuery}\n${includedFragments}GRAPHQL`, }; } case 'FragmentDefinition': { const querySource = node.loc.source.body.substring( node.loc.start, node.loc.end ); return { moduleName: 'Fragment', element: `${node.name.value} = <<-GRAPHQL\n${querySource}\nGRAPHQL`, }; } } }, }; } const module = generateOperationsModule(); fs.writeFileSync('lib/stigg/generated/operations.rb', module);