Open mohsen1 opened 6 years ago
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.
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();
});
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.
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"
.