Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codegen: Also generate a definition file for .graphql fils #604

Open
mohsen1 opened this issue Sep 25, 2018 · 3 comments
Open

Codegen: Also generate a definition file for .graphql fils #604

mohsen1 opened this issue Sep 25, 2018 · 3 comments
Labels
🤖 component - codegen related to the codegen core packages

Comments

@mohsen1
Copy link

mohsen1 commented Sep 25, 2018

Similar to typed-css-modules the codegen can generate declaration files for existing query files that has list of exported queries and mutations.

This will help TypeScript enforce correct names when importing queries from .graphql file using "graphql-tag/loader".

@stevenpetryk
Copy link

stevenpetryk commented Oct 25, 2018

This would be nice. It would allow for something like this:

import React from 'react'
import { Query } from 'react-apollo'

import PersonQuery, {
  PersonQueryData,
  PersonQueryVariables,
} from 'queries/Person.gql'

// side-note: TSX really needs to support generics on components because this is annoying
class PersonQueryComponent extends Query<PersonQueryData, PersonQueryVariables> {}

export default () => (
  <PersonQueryComponent query={PersonQuery}>
    {/* ... */}
  </PersonQueryComponent>
)

It seems like it would not be too hard of a modification to apollo-codegen-typescript. I might give it a shot.

@mohsen1
Copy link
Author

mohsen1 commented Oct 28, 2018

I wrote a very simple and dumb script to get the job done but would be nice if this was part of apollo-codegen-typescript:

#!/usr/bin/env node

/* eslint-disable */

const fs = require('fs');
const path = require('path');
const walk = require('walk');
const { EOL } = require('os');

/**
 * Generate a definition file of exported members when importing a GraphQL file with
 * graphql-tag/loader.
 *
 * Note: this is different from Apollo CodeGen types. The generated type definition file
 * is good for enforcing named import correctness only.
 *
 * @param {string} file Raw GraphQL file
 */
function generateExportDefinition(file = '') {
  const lines = file.split(EOL);

  let output = [
    '/* tslint:disable */',
    '/* eslint-disable */',
    '// This file was automatically generated and should not be edited.',
    '',
    "import { DocumentNode } from 'graphql';",
  ];

  /**
   * Process a specific GraphQL keyword
   * @param {string} keyword
   * @param {RegExp} regex
   * @param {string} comment
   */
  function processKeyword(keyword, regex, comment) {
    const keywordNames = lines
      .filter((line) => line.startsWith(keyword) && line.match(regex))
      .map((line) => line.match(regex)[1])
      .filter(Boolean);

    if (keywordNames.length) {
      output = [
        ...output,
        '',
        '// ====================================================',
        '// ' + comment,
        '// ====================================================',
      ];
    }

    for (const keywordName of keywordNames) {
      output.push(`/** \`${keywordName}\` ${keyword} */`);
      output.push(`export const ${keywordName}: DocumentNode;`);
      output.push('');
    }
  }

  processKeyword('query', /query\s+([A-z]+)/, 'Queries');
  processKeyword('mutation', /mutation\s+([A-z]+)/, 'Mutations');
  processKeyword('fragment', /fragment\s+([A-z]+)/, 'Fragments');
  processKeyword('input', /input\s+([A-z]+)/, 'Inputs');

  return output.join(EOL);
}

const walker = walk.walk(path.join(__dirname, 'src'), {
  filters: ['node_modules', 'build'],
});

walker.on('file', (root, fileStats, next) => {
  if (fileStats.name.endsWith('.graphql')) {
    const fullPath = path.join(root, fileStats.name);
    const input = fs.readFileSync(fullPath).toString();
    const output = generateExportDefinition(input);
    fs.writeFileSync(fullPath + '.d.ts', output);
  }
  next();
});

@JakeDawkins JakeDawkins added the 🤖 component - codegen related to the codegen core packages label Jul 9, 2019
@andymrussell
Copy link

I agree, this would clean up code nicely.
I had a look at graphql-typescript-definitions which works as described above. Only issue is that it cant handle local state queries with @client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤖 component - codegen related to the codegen core packages
Projects
None yet
Development

No branches or pull requests

4 participants