Giter Site home page Giter Site logo

gql2ts's People

Contributors

adiramsalem avatar brandonhermanavant avatar brettjurgens avatar eboto avatar epicallan avatar fezvrasta avatar greenkeeper[bot] avatar greenkeeperio-bot avatar kristianmandrup avatar mikfoo avatar neelance avatar nmn avatar orta avatar raysuelzer avatar salbertson avatar tomaba avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gql2ts's Issues

Define function type for root resolvers of queries, mutations, and subscriptions.

Let's say I have a schema something like this...

type Query {
  user(userId: Int!): User! 
}

type User { ... }

schema {
  query: Query
}

I would like to generate the type definition of the actual resolver functions themselves for queries, mutations, and subscriptions.

interface IQuery {
    user(parent: any, args: { userId: number }, context: any, info: any): User;
}

This would allow simple typechecking of resolvers (or other things)...

const query: IQuery = {
  user(_, { userId }): User { /* ... */ } 
}

This way if your schema file changes but someone forgets to update the resolvers, mutations, etc then you're covered.

Thoughts?

Support Importing Fragments

brought up by @zamiang here: #127 (comment)

essentially, in a query that looks like:

#import "./path/to/fragment"

query DoSomething {
  ...FragmentFromImport
}

should import the fragment & generate the appropriate typings

TypeError: type.getFields is not a function

I used 1.0.2. The problem only occurs when I install gql2ts with npm i gql2ts without -g option.

node_modules/@gql2ts/from-schema/dist/index.js:120
        const f1 = type.getFields();
                        ^

TypeError: type.getFields is not a function
    at typeToInterface (/xxx/node_modules/@gql2ts/from-schema/dist/index.js:120:25)
    at typeArr.filter.filter.map.type (/xxx/node_modules/@gql2ts/from-schema/dist/index.js:156:26)
    at Array.map (native)
    at typesToInterfaces (/xxx/node_modules/@gql2ts/from-schema/dist/index.js:156:14)
    at run (/xxx/node_modules/@gql2ts/from-schema/dist/index.js:162:12)
    at Object.exports.schemaToInterfaces (/xxx/node_modules/@gql2ts/from-schema/dist/index.js:164:63)
    at Object.exports.generateNamespace (/xxx/node_modules/@gql2ts/from-schema/dist/index.js:167:85)
    at run (/xxx/node_modules/gql2ts/dist/index.js:38:35)
    at Socket.process.stdin.on (/xxx/node_modules/gql2ts/dist/index.js:54:35)
    at emitNone (events.js:110:20)

-e flag does not work

There is an error in the genereateNamespace method on 'from-schema' in the Object.assign which causes the external language options to be ignored when an ES module is specificed.

This line of code:
https://github.com/avantcredit/gql2ts/blob/master/packages/from-schema/src/index.ts#L293

results in an call to Object.assign. However, due the ES6 module definition you will end up with overrides being something like

{
 default: {},
  DEFAULT_OPTIONS {...}
}

The code should do something like:


export const generateNamespace: GenerateNamespace = (namespace, schema, options = {}, overrides = {}) => {
  const formatters: IFromQueryOptions = { ...DEFAULT_OPTIONS, ...overrides.DEFAULT_OPTIONS };
  return formatters.postProcessor(formatters.generateNamespace(namespace, schemaToInterfaces(schema, options, formatters)));
};

The other, perhaps better, option is to change the line in the CLI that calls require to get the 'default' export.

Comments on fields

Seems like currently there are no docblocks generated for comments on fields, only for types

Better Fragment Handling

from this comment by @BinaryMuse #76 (comment):

export interface MyTestQuery {
  resource:
    | SelectionOnResource &
        Partial<IFragmentIssue> &
        Partial<IFragmentOrganization>
    | null;
}

export interface IFragmentIssue {
  __typename: string;
  id: string;
  title: string;
  author: SelectionOnAuthor | null;
}

export interface IFragmentOrganization {
  __typename: string;
  orgName: string | null;
}

but since we know statically what all the typenames are, it could be something like

export interface MyTestQuery {
  resource:
    | IFragmentIssue
    | IFragmentOrganization
    | DefaultSelectionOnResource
}

export interface IFragmentIssue {
  __typename: "Issue";
  id: string;
  title: string;
  author: SelectionOnAuthor | null;
}

export interface IFragmentOrganization {
  __typename: "Organization";
  orgName: string | null;
}

export interface DefaultSelectionOnResource {
  __typename: string;
}

Lacking input types

This is what I get as a type for a query:

  interface IQuery {
    __typename: string;
    someQuery: ISomeType | null;
  }

Why? Shouldn't I expect this package to generate types for the arguments as well?

Weird nested interface syntax generated for fragments?

I’m seeing weird syntax in the exported TypeScript definitions when using fragments in queries. Interfaces are nested inside each other like this:

export interface Main {
  IFragmentSidebar
  windowState: SelectionOnWindowState;
  profile: SelectionOnProfile;
}

Is this intentional? I've never encountered this syntax before. The TypeScript compiler doesn't seem to know what to do with it. It doesn't throw an error but it seems like it interprets it as IFragmentSidebar: any;.

TypeError: type.getFields is not a function

Hi there, great work on this project so far! I ran across an issue in typeToInterface in fromSchema/index.ts. If a GraphQLUnionType is used in the schema, it throws TypeError: type.getFields is not a function at Line 173 in :

    let isInput: boolean = type instanceof GraphQLInputObjectType;
    const f1: GraphQLInputFieldMap | GraphQLFieldMap<any, any> =
      (type instanceof GraphQLInputObjectType) ? type.getFields() : ((type as GraphQLObjectType).getFields)();
    let f: Array<GraphQLField<any, any> | GraphQLInputField> = Object.keys(f1).map(k => f1[k]);

stdin mode prepends usage to output

When reading from stdin and writing to stdout the usage information of gql2ts is prepended to the output. This does not happen when an output file is specified.

Overwriting TypeMaps

I'm working on a new language package, and want to override the types in the DEFAULT_TYPE_MAP, but no matter what I do, everything seems to use the default type map.

e.g.

export const typeMap: ITypeMap = { ...DEFAULT_TYPE_MAP, DateTime: 'DateTime' };

seems to have no impact. Overriding the DEFAULT_TYPE_MAP also doesn't seem to do anything:

export const DEFAULT_TYPE_MAP: IDefaultTypeMap = { ID: 'string', String: 'string', Boolean: 'bool', Float: 'float', Int: 'int', __DEFAULT: 'object' };

This still maps default to 'any' instead of 'object',

and all ints and floats to number. Looking at the code for from-schema, it looks like it imports the TS defaults, but also tries to inject the options from the new package.

Right now I'm forcing the issue by utilizing a post-processor that does a LOT of replaces.

Gist of the code

Output ES6 module

I'd like to be able to import generated interfaces using ES6 syntax rather than triple-slash references.

This could be as simple as emitting

declare module 'GQL' { ... }

instead of

declare namespace GQL { ... }

__typename not added to all types

After updating to the latest version, I get this diff on my schema:

@@ -24,7 +24,7 @@ declare namespace GQL {
   interface IQuery {
     __typename: "Query";
     root: IRoot;
-    node: INode | null;
+    node: Node | null;
   }
 
   /*
@@ -90,6 +90,11 @@ declare namespace GQL {
   /*
     description: null
   */
+  type Node = IRepository | ICommit;
+
+  /*
+    description: null
+  */
   interface INode {
     __typename: "Node";
     id: string;
@@ -320,23 +325,21 @@ declare namespace GQL {
     description: null
   */
   interface ISearchQuery {
-    __typename: "SearchQuery";
     pattern: string;
     isRegExp: boolean;
     isWordMatch: boolean;
     isCaseSensitive: boolean;
     fileMatchLimit: number;
-    includePattern: string | null;
-    excludePattern: string | null;
+    includePattern?: string | null;
+    excludePattern?: string | null;
   }
 
   /*
     description: null
   */
   interface IRepositoryRevision {
-    __typename: "RepositoryRevision";
     repo: string;
-    rev: string | null;
+    rev?: string | null;
   }

How to deal with Field Aliases?

In a GraphQL query we can alias fields, which I’m wondering how one should deal with in TypeScript and a tool like this.

Seeing as it really is related to a query, rather than just the schema, I’m thinking that this should be dealt with by implementing something like #30.

The only other issue, in our case, is that we use Relay, so it would be ideal if we could somehow plug into the compiler, extract the query from the Relay fragments, generate the type interfaces, and then actually compile the rest of the file. (This may well be beyond the scope of this tool.)

(Filing this here for visibility, but my colleague @orta said he was going to take a look at this.)

Promise support on all fields

Hi,

Would be super useful if each field of a record accepted either the type itself or a promise to the type. e.g. given a schema:

type Author {
  id: Int!
  firstName: String
  lastName: String
  posts: [Post] # the list of Posts by this author
}

type Post {
  id: Int!
  title: String
  author: Author
  votes: Int
}

The generated code currently looks like this:

interface IPost {
  __typename: string;
  id: number;
  title: string | null;
  author: IAuthor | null;
  votes: number | null;
}

When using Apollo it would be nice on the server side for the generated IPost interface to look more like:

interface IPost {
  ...
  author: Author | null | Promise<Author | null>;
  ...
}

What would you think of such a change?

Why are Graphql Types converted into interfaces ?

Here's a snippet from one of my flow exports

flowtypes.js

  export type AnalyticsSetResult = IConversationMetricResult | IBotUpdateMetricResult;

  export interface IAnalyticsSetResult = {
    __typename: "AnalyticsSetResult";
    id: string;
    sets: Array<AnalyticsSet> | null;
}

schema.graphql

interface AnalyticsSetResult {
  id: ID!
  sets: [AnalyticsSet]
}

type ConversationMetricResult implements AnalyticsSetResult {
  id: ID!
  sets: [ConversationMetricSet]
}

I can sort of see why this decision was made - you wanted a concrete type with the name of the interface that is a union of all the types implementing that interface. So to get around that you moved all graphql types to be interfaces and only generate types for these unions. It seems unnecessary and its confusing to have different names between code types and graphql types.

generated TypeScript interfaces file doesn't have any exported entities

Command-line: gql2ts schema.json -o src/app/interfaces.ts

declare namespace GQL {
  interface IGraphQLResponseRoot {
    data?: IQuery | IMutation;
    errors?: Array<IGraphQLResponseError>;
  }
}

The types and namespace is in the generated interfaces.ts file, but how can I use those interfaces, since they are not exported.

type.getFields strikes again

I know there have been several issues on this in the past (I've been through this before!) and all had been fixed. But it appears that Graphql 0.13 may break this again

I'm on version 1.4.1 of gql2ts and all was working. But upon upgrading relay-compiler to version 1.5 everything started breaking. On further inspection, relay-compiler 1.4.0requires graphql^0.11.3and version1.5ups that to version^0.13.0`.

If I downgrade relay to 1.4, all works again.

const enums for enums

It would be awesome if GraphQL enums were converted to const enum instead of union types. That way we could write GitHubGQL.IStatusStateEnum.SUCCESS as a value instead of 'SUCCESS'

TypeScript 2.7 breaks cli

the typescriptPrettify module depends on the typescript.formatter.RulesProvider it seems this was removed in a recent release of TypeScript.

Since the CLI pulls this module in, I'm not able to use it on [email protected]

language-typescript declares its typescript depdency as ^2.2.2 which means it will automatically install 2.7.

I think the version needs to be locked to 2.2.2 (ie, no ^ in the dependency), or the prettifier should be updated to 2.7.

Alternatively, lock typescript to the last working version which seems to be 2.6

Handle attributes with no inputFields or fields

We have an enum with no fields, or inputFields in the schema.json

        {
          "kind": "UNION",
          "name": "PartnerTypes",
          "description": null,
          "fields": null,
          "inputFields": null,
          "interfaces": null,
          "enumValues": null,
          "possibleTypes": [
            {
              "kind": "OBJECT",
              "name": "Partner",
              "ofType": null
            },
            {
              "kind": "OBJECT",
              "name": "ExternalPartner",
              "ofType": null
            }
          ]
        },

This currently crashes the process. Will send a PR.

Autogenerate a JS file to make imports easier

There should be an option to auto generate a .js file which contains the original query.

Technically it would create two files — .d.ts and a .js file. This will make life much easier because then u can simply import the file. The corresponding .d.ts file will also have to contain an additional typings as follow —

export const GQL: string`

I'd be happy to send a PR !

How would you feel about a PR for adding a glob functionality for .gql & .graphql files

My graphql schema types are in individual files and I don't export them out as strings.
I had some logic in my code that would merge them together and then feed them into the generateNamespace function of the fromSchema package to generate typescript types.

I have gotten to a point where I want to do this using the CLI.
The CLI API currently supports only taking in one schema type file for generating types which wouldn't be ideal for my use case where I have multiple types files.
I have added a glob feature to the lib for the CLI that merges different .gql types into one.
I can submit a pull request of this feature for review if this something you wouldn't mind supporting.

Typescript Formatter

Per #131, typescript has changed their formatting api.

Moving forward, we should find a better option.

Some options of the top of my head:

  1. remove formatter from the core language package and continue with the previous "best effort" approach
    • Users might not like the formatting looking weird
    • Faster & cleaner code
    • Current setup allows for user provide their own formatter anyway
  2. support the TS2.7 API in addition to the <=2.6 API
    • Requires more code
    • More brittle, as these are mostly undocumented APIs (pre 2.7 at least)
  3. use prettier
    • Best formatting option (in my opinion)
    • Unfortunately, will probably bring in a bunch of new dependencies

Certainly open to other suggestions

Enums break .d.ts typings

Unfortunately the use of real enums means the typings cannot be generated anymore referencing the enums will fail at runtime with Uncaught ReferenceError: GQL is not defined. I think using const enums might work, but I think the better solution here is to generate a proper .ts module. That however gets hairy to combine with external modules, as the current file doesn't export anything and it can't be imported.

I would propose to add a new flag --module that makes gql2ts output an external module (exporting the types) instead of a declare namespace.

Bug: Creates duplicate types when case is different

A schema can have two types that only vary by case. E.g.

type fooBar {
  id: Int
}

type FooBar {
  id: Float
  name: String
}

This is valid in graphql...but gql2ts seems to change the case, and not check for duplicates, resulting in an invalid schema.

Field ID of type int is not converted to int but any

See pull request #10. And just close this here ;)

I have a schema part like:

{
              "name": "rowId",
              "description": "Checks for equality with the object’s `rowId` field.",
              "type": {
                "kind": "SCALAR",
                "name": "Int",
                "ofType": null
              },
              "defaultValue": null
},

and it is converted to: rowId?: any;

Is it easy to convert it to number instead?

Feature: Add enum support

Currently the code does not handle GraphQL Enums. I think the wanted generator is a string literal union.
For example, the following enum:

enum UserType {
  ADMIN
  SELLER
  CUSTOMER
}

Will become:

export type UserType = 'ADMIN' | 'SELLER' | 'CUSTOMER';

@brettjurgens LMK if this a good option in you opinion.

Thanks ahead!

INode

Hi, first thanks for this repo. It's awesome :D
A problem which I have is that field names may not used in different table more than once. Otherwise I get following warning:

Interface 'INode' cannot simultaneously extend types 'IQuery' and 'IMyTable'.
Named property 'title' of types 'IQuery' and 'IMyTable' are not identical.

In IQuery is a title function which gives me an MyTable row back but in MyTable itself is a field named title. So interface INode extends IQuery, IMyTable... complains.

Add string literal as __typename

When doing a query like this

query {
  search(text: "cat") {
    ... on Movie {
      director
    }
    ... on Book {
      author
    }
  }
}

on a schema like this

union SearchResult = Movie | Book

type Query {
  search(text: String!): [SearchResult]!
}

you need to do a type check in the TS code to find out what type the results are, like this

if (item.__typename === 'Movie') {
  show(item.director)
} else {
  show(item.author)
}

TypeScript supports this through discriminated unions if the schema in TS looks like this:

type SearchResult = Movie | Book
interface Movie {
  __typename: 'Movie'
  director: string
}
interface Book {
  __typename: 'Book'
  author: string
}

but it currently looks like this:

type SearchResult = Movie | Book
interface Movie {
  __typename: string
  director: string
}
interface Book {
  __typename: string
  author: string
}

Support for schemas by URLs

Would you be interested in supporting passing in a URL as opposed to only a filename?

That way, we could do something like:

gpl2ts http://example.com/graphql

and get our generated types.

https://www.npmjs.com/package/fetch-graphql-schema supports taking a URL and returning JSON, so most of the work is already done.

I'd be willing to do a PR if this was something you were interested in. For now, I can do it in 2 steps (use the mentioned package to create the file, and then pass that file as input), but it'd be a lot nicer in our workflow to not have to create the intermediate file.

Allow option to omit __typename from generated interfaces

So I'm using gql2ts to generate interfaces to statically typecheck my resolver functions. One issue is that those functions should not populate the __typename field in the objects they return but then the returned objects fail to typecheck.

Would there be interest in adding an option to omit the __typename fields or possibly include them in a subtype? If so, I'll write and send a PR.

so, instead of:

interface IUser {
    __typename: string;
    id: string;
    email: string;
}

we'd have something like:

interface IUser_NoTypename {
    id: string;
    email: string;
}

interface IUser extends IUser_NoTypename {
    __typename: string;
}

TypeError: type.getFields is not a function

Getting this error when running gql2ts from an introspection query:

$ get-graphql-schema http://localhost:3080/.api/graphql --json | gql2ts -o gqlschema.d.ts
/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:123
        const f1 = type.getFields();
                        ^

TypeError: type.getFields is not a function
    at typeToInterface (/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:123:25)
    at typeArr.filter.filter.map.type (/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:159:26)
    at Array.map (native)
    at typesToInterfaces (/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:159:14)
    at run (/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:165:12)
    at Object.exports.schemaToInterfaces (/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:167:73)
    at Object.exports.generateNamespace (/Users/felix/.../node_modules/@gql2ts/from-schema/dist/index.js:170:85)
    at run (/Users/felix/.../node_modules/gql2ts/dist/index.js:39:35)
    at Socket.process.stdin.on (/Users/felix/.../node_modules/gql2ts/dist/index.js:55:35)
    at emitNone (events.js:91:20)

This started happening after I added a union type. Could that be related?

Don't use STDIN if file name is provided even if not a TTY

When running gql2ts as part of certain task runners STDIN will not be a TTY.
This causes this code here:

https://github.com/avantcredit/gql2ts/blob/4e36bd52fc81a3c8fbffd5685a0a3933a3474f5b/packages/cli/src/index.ts#L64-L74

to read from STDIN even if a filename is provided, which ultimately will result in the hard-to-debug error
GraphQLError: Syntax Error GraphQL request (1:1) Unexpected <EOF>
because the STDIN is empty.

I would propose to always read from file when a file name is given.

Roadmap to 2.0

  • Improve Documentation across the project (it can definitely be cryptic at times)
  • Create more sensible names for the formatters (also probably rename "formatter" to "printer")
  • First-class Flow support
  • Extract a lot of the logic to the printers, in order to handle inconsistencies across language targets (i.e. Language X doesn't have interfaces, Language Y doesn't have Partial, etc.)
  • Figure out better way of handling Fragments as seen in #162
  • Custom directive support
  • Correct type for defer directive
  • Remove Legacy TS Support (force strict nullability) #174
  • Add more tests now that more public schemas are available (github, yelp, etc.)
  • Create better interfaces to pass to Printers
  • Create webpack loader #127
  • Allow providing custom types apart from the typemap
    • i.e. query.customer.something resolves to type any but should be { a: number; b: string }
    • another use case would be if we have a union/interface and know that it will only be one type
      • i.e. query.me is of type Admin | Customer | Service but we know that it can only ever be Admin on the admin application, Customer on the customer, etc.
  • Investigate better enum support with const enums #179
  • Fix Unions in 2.0.0
  • Fix Introspection in 2.0.0

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml
  • The new Node.js version is in-range for the engines in 1 of your package.json files, so that was left alone

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.