diff --git a/README.md b/README.md index cab3f02..9b365ba 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ ## Contents - [JavaScript](#javascript) +- [TypeScript](#typescript) - [Ruby](#ruby) - [Python](#python) - [Go](#go) @@ -22,6 +23,10 @@ - [graphql-binding](https://github.com/dotansimha/graphql-binding): graphql-binding allows you to invoke a binding function which constructs a GraphQL request. - [mst-gql](https://github.com/mobxjs/mst-gql): mst-gql allows type reuse between GraphQL and MobX-state-tree, and generates a query builder for chaining. +# TypeScript + +- [tql](https://github.com/timkendall/tql): Write type-safe GraphQL queries with TypeScript. | [Example](https://github.com/hasura/awesome-fluent-graphql/tree/master/example-tql) + # Ruby - [GQLi](https://github.com/contentful-labs/gqli.rb): A GraphQL consumer domain-specific language that allows you to write GraphQL queries in native Ruby. | [Blog post](https://www.contentful.com/blog/2018/11/20/graphql-ruby-love-backend-developer/) diff --git a/example-tql/.gitignore b/example-tql/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/example-tql/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/example-tql/generated/starwars.api.ts b/example-tql/generated/starwars.api.ts new file mode 100644 index 0000000..279962c --- /dev/null +++ b/example-tql/generated/starwars.api.ts @@ -0,0 +1,907 @@ +import { + NamedType, + Argument, + Value, + Field, + InlineFragment, + Operation, + Selection, + SelectionSet, + Variable, +} from "@timkendall/tql"; + +export enum Episode { + NEWHOPE = "NEWHOPE", + EMPIRE = "EMPIRE", + JEDI = "JEDI", +} + +export enum LengthUnit { + METER = "METER", + FOOT = "FOOT", + CUBIT = "CUBIT", +} + +export interface ReviewInput { + stars: number; + commentary?: string; + favorite_color?: ColorInput; +} + +export interface ColorInput { + red: number; + green: number; + blue: number; +} + +type ISearchResult = IHuman | IDroid | IStarship; + +interface SearchResultSelector { + __typename: () => Field<"__typename">; + + on: , F extends "Human" | "Droid" | "Starship">( + type: F, + select: ( + t: F extends "Human" + ? HumanSelector + : F extends "Droid" + ? DroidSelector + : F extends "Starship" + ? StarshipSelector + : never + ) => T + ) => InlineFragment, SelectionSet>; +} + +export const SearchResult: SearchResultSelector = { + __typename: () => new Field("__typename"), + + on: (type, select) => { + switch (type) { + case "Human": { + return new InlineFragment( + new NamedType("Human") as any, + new SelectionSet(select(Human as any)) + ); + } + + case "Droid": { + return new InlineFragment( + new NamedType("Droid") as any, + new SelectionSet(select(Droid as any)) + ); + } + + case "Starship": { + return new InlineFragment( + new NamedType("Starship") as any, + new SelectionSet(select(Starship as any)) + ); + } + + default: + throw new Error("Unknown type!"); + } + }, +}; + +export interface IQuery { + hero: ICharacter; + reviews: IReview[]; + search: ISearchResult[]; + character: ICharacter; + droid: IDroid; + human: IHuman; + starship: IStarship; +} + +interface QuerySelector { + __typename: () => Field<"__typename">; + + hero: >( + variables: { episode?: Variable<"episode"> | Episode }, + select: (t: CharacterSelector) => T + ) => Field< + "hero", + [Argument<"episode", Variable<"episode"> | Episode>], + SelectionSet + >; + + reviews: >( + variables: { episode?: Variable<"episode"> | Episode }, + select: (t: ReviewSelector) => T + ) => Field< + "reviews", + [Argument<"episode", Variable<"episode"> | Episode>], + SelectionSet + >; + + search: >( + variables: { text?: Variable<"text"> | string }, + select: (t: SearchResultSelector) => T + ) => Field< + "search", + [Argument<"text", Variable<"text"> | string>], + SelectionSet + >; + + character: >( + variables: { id?: Variable<"id"> | string }, + select: (t: CharacterSelector) => T + ) => Field< + "character", + [Argument<"id", Variable<"id"> | string>], + SelectionSet + >; + + droid: >( + variables: { id?: Variable<"id"> | string }, + select: (t: DroidSelector) => T + ) => Field< + "droid", + [Argument<"id", Variable<"id"> | string>], + SelectionSet + >; + + human: >( + variables: { id?: Variable<"id"> | string }, + select: (t: HumanSelector) => T + ) => Field< + "human", + [Argument<"id", Variable<"id"> | string>], + SelectionSet + >; + + starship: >( + variables: { id?: Variable<"id"> | string }, + select: (t: StarshipSelector) => T + ) => Field< + "starship", + [Argument<"id", Variable<"id"> | string>], + SelectionSet + >; +} + +export const Query: QuerySelector = { + __typename: () => new Field("__typename"), + + hero: (variables, select) => + new Field( + "hero", + [new Argument("episode", variables.episode, Episode)], + new SelectionSet(select(Character)) + ), + + reviews: (variables, select) => + new Field( + "reviews", + [new Argument("episode", variables.episode, Episode)], + new SelectionSet(select(Review)) + ), + + search: (variables, select) => + new Field( + "search", + [new Argument("text", variables.text)], + new SelectionSet(select(SearchResult)) + ), + + character: (variables, select) => + new Field( + "character", + [new Argument("id", variables.id)], + new SelectionSet(select(Character)) + ), + + droid: (variables, select) => + new Field( + "droid", + [new Argument("id", variables.id)], + new SelectionSet(select(Droid)) + ), + + human: (variables, select) => + new Field( + "human", + [new Argument("id", variables.id)], + new SelectionSet(select(Human)) + ), + + starship: (variables, select) => + new Field( + "starship", + [new Argument("id", variables.id)], + new SelectionSet(select(Starship)) + ), +}; + +export interface IMutation { + createReview: IReview; +} + +interface MutationSelector { + __typename: () => Field<"__typename">; + + createReview: >( + variables: { + episode?: Variable<"episode"> | Episode; + review?: Variable<"review"> | ReviewInput; + }, + select: (t: ReviewSelector) => T + ) => Field< + "createReview", + [ + Argument<"episode", Variable<"episode"> | Episode>, + Argument<"review", Variable<"review"> | ReviewInput> + ], + SelectionSet + >; +} + +export const Mutation: MutationSelector = { + __typename: () => new Field("__typename"), + + createReview: (variables, select) => + new Field( + "createReview", + [ + new Argument("episode", variables.episode, Episode), + new Argument("review", variables.review), + ], + new SelectionSet(select(Review)) + ), +}; + +export interface ICharacter { + __typename: string; + id: string; + name: string; + friends: ICharacter[]; + friendsConnection: IFriendsConnection; + appearsIn: Episode[]; +} + +interface CharacterSelector { + __typename: () => Field<"__typename">; + + /** + * @description The ID of the character + */ + + id: () => Field<"id">; + + /** + * @description The name of the character + */ + + name: () => Field<"name">; + + /** + * @description The friends of the character, or an empty list if they have none + */ + + friends: >( + select: (t: CharacterSelector) => T + ) => Field<"friends", never, SelectionSet>; + + /** + * @description The friends of the character exposed as a connection with edges + */ + + friendsConnection: >( + variables: { + first?: Variable<"first"> | number; + after?: Variable<"after"> | string; + }, + select: (t: FriendsConnectionSelector) => T + ) => Field< + "friendsConnection", + [ + Argument<"first", Variable<"first"> | number>, + Argument<"after", Variable<"after"> | string> + ], + SelectionSet + >; + + /** + * @description The movies this character appears in + */ + + appearsIn: () => Field<"appearsIn">; + + on: , F extends "Human" | "Droid">( + type: F, + select: ( + t: F extends "Human" + ? HumanSelector + : F extends "Droid" + ? DroidSelector + : never + ) => T + ) => InlineFragment, SelectionSet>; +} + +export const Character: CharacterSelector = { + __typename: () => new Field("__typename"), + + /** + * @description The ID of the character + */ + id: () => new Field("id"), + + /** + * @description The name of the character + */ + name: () => new Field("name"), + + /** + * @description The friends of the character, or an empty list if they have none + */ + + friends: (select) => + new Field( + "friends", + undefined as never, + new SelectionSet(select(Character)) + ), + + /** + * @description The friends of the character exposed as a connection with edges + */ + + friendsConnection: (variables, select) => + new Field( + "friendsConnection", + [ + new Argument("first", variables.first), + new Argument("after", variables.after), + ], + new SelectionSet(select(FriendsConnection)) + ), + + /** + * @description The movies this character appears in + */ + appearsIn: () => new Field("appearsIn"), + + on: (type, select) => { + switch (type) { + case "Human": { + return new InlineFragment( + new NamedType("Human") as any, + new SelectionSet(select(Human as any)) + ); + } + + case "Droid": { + return new InlineFragment( + new NamedType("Droid") as any, + new SelectionSet(select(Droid as any)) + ); + } + + default: + throw new Error("Unknown type!"); + } + }, +}; + +export interface IHuman extends ICharacter { + __typename: "Human"; + homePlanet: string; + height: number; + mass: number; + starships: IStarship[]; +} + +interface HumanSelector { + __typename: () => Field<"__typename">; + + /** + * @description The ID of the human + */ + + id: () => Field<"id">; + + /** + * @description What this human calls themselves + */ + + name: () => Field<"name">; + + /** + * @description The home planet of the human, or null if unknown + */ + + homePlanet: () => Field<"homePlanet">; + + /** + * @description Height in the preferred unit, default is meters + */ + + height: (variables: { unit: unknown }) => Field<"height", [/* @todo */]>; + + /** + * @description Mass in kilograms, or null if unknown + * @deprecated Weight is a sensitive subject! + */ + + mass: () => Field<"mass">; + + /** + * @description This human's friends, or an empty list if they have none + */ + + friends: >( + select: (t: CharacterSelector) => T + ) => Field<"friends", never, SelectionSet>; + + /** + * @description The friends of the human exposed as a connection with edges + */ + + friendsConnection: >( + variables: { + first?: Variable<"first"> | number; + after?: Variable<"after"> | string; + }, + select: (t: FriendsConnectionSelector) => T + ) => Field< + "friendsConnection", + [ + Argument<"first", Variable<"first"> | number>, + Argument<"after", Variable<"after"> | string> + ], + SelectionSet + >; + + /** + * @description The movies this human appears in + */ + + appearsIn: () => Field<"appearsIn">; + + /** + * @description A list of starships this person has piloted, or an empty list if none + */ + + starships: >( + select: (t: StarshipSelector) => T + ) => Field<"starships", never, SelectionSet>; +} + +export const isHuman = ( + object: Record +): object is Partial => { + return object.__typename === "Human"; +}; + +export const Human: HumanSelector = { + __typename: () => new Field("__typename"), + + /** + * @description The ID of the human + */ + id: () => new Field("id"), + + /** + * @description What this human calls themselves + */ + name: () => new Field("name"), + + /** + * @description The home planet of the human, or null if unknown + */ + homePlanet: () => new Field("homePlanet"), + + /** + * @description Height in the preferred unit, default is meters + */ + height: (variables) => new Field("height"), + + /** + * @description Mass in kilograms, or null if unknown + * @deprecated Weight is a sensitive subject! + */ + mass: () => new Field("mass"), + + /** + * @description This human's friends, or an empty list if they have none + */ + + friends: (select) => + new Field( + "friends", + undefined as never, + new SelectionSet(select(Character)) + ), + + /** + * @description The friends of the human exposed as a connection with edges + */ + + friendsConnection: (variables, select) => + new Field( + "friendsConnection", + [ + new Argument("first", variables.first), + new Argument("after", variables.after), + ], + new SelectionSet(select(FriendsConnection)) + ), + + /** + * @description The movies this human appears in + */ + appearsIn: () => new Field("appearsIn"), + + /** + * @description A list of starships this person has piloted, or an empty list if none + */ + + starships: (select) => + new Field( + "starships", + undefined as never, + new SelectionSet(select(Starship)) + ), +}; + +export interface IDroid extends ICharacter { + __typename: "Droid"; + primaryFunction: string; +} + +interface DroidSelector { + __typename: () => Field<"__typename">; + + /** + * @description The ID of the droid + */ + + id: () => Field<"id">; + + /** + * @description What others call this droid + */ + + name: () => Field<"name">; + + /** + * @description This droid's friends, or an empty list if they have none + */ + + friends: >( + select: (t: CharacterSelector) => T + ) => Field<"friends", never, SelectionSet>; + + /** + * @description The friends of the droid exposed as a connection with edges + */ + + friendsConnection: >( + variables: { + first?: Variable<"first"> | number; + after?: Variable<"after"> | string; + }, + select: (t: FriendsConnectionSelector) => T + ) => Field< + "friendsConnection", + [ + Argument<"first", Variable<"first"> | number>, + Argument<"after", Variable<"after"> | string> + ], + SelectionSet + >; + + /** + * @description The movies this droid appears in + */ + + appearsIn: () => Field<"appearsIn">; + + /** + * @description This droid's primary function + */ + + primaryFunction: () => Field<"primaryFunction">; +} + +export const isDroid = ( + object: Record +): object is Partial => { + return object.__typename === "Droid"; +}; + +export const Droid: DroidSelector = { + __typename: () => new Field("__typename"), + + /** + * @description The ID of the droid + */ + id: () => new Field("id"), + + /** + * @description What others call this droid + */ + name: () => new Field("name"), + + /** + * @description This droid's friends, or an empty list if they have none + */ + + friends: (select) => + new Field( + "friends", + undefined as never, + new SelectionSet(select(Character)) + ), + + /** + * @description The friends of the droid exposed as a connection with edges + */ + + friendsConnection: (variables, select) => + new Field( + "friendsConnection", + [ + new Argument("first", variables.first), + new Argument("after", variables.after), + ], + new SelectionSet(select(FriendsConnection)) + ), + + /** + * @description The movies this droid appears in + */ + appearsIn: () => new Field("appearsIn"), + + /** + * @description This droid's primary function + */ + primaryFunction: () => new Field("primaryFunction"), +}; + +export interface IFriendsConnection { + totalCount: number; + edges: IFriendsEdge[]; + friends: ICharacter[]; + pageInfo: IPageInfo; +} + +interface FriendsConnectionSelector { + __typename: () => Field<"__typename">; + + /** + * @description The total number of friends + */ + + totalCount: () => Field<"totalCount">; + + /** + * @description The edges for each of the character's friends. + */ + + edges: >( + select: (t: FriendsEdgeSelector) => T + ) => Field<"edges", never, SelectionSet>; + + /** + * @description A list of the friends, as a convenience when edges are not needed. + */ + + friends: >( + select: (t: CharacterSelector) => T + ) => Field<"friends", never, SelectionSet>; + + /** + * @description Information for paginating this connection + */ + + pageInfo: >( + select: (t: PageInfoSelector) => T + ) => Field<"pageInfo", never, SelectionSet>; +} + +export const FriendsConnection: FriendsConnectionSelector = { + __typename: () => new Field("__typename"), + + /** + * @description The total number of friends + */ + totalCount: () => new Field("totalCount"), + + /** + * @description The edges for each of the character's friends. + */ + + edges: (select) => + new Field( + "edges", + undefined as never, + new SelectionSet(select(FriendsEdge)) + ), + + /** + * @description A list of the friends, as a convenience when edges are not needed. + */ + + friends: (select) => + new Field( + "friends", + undefined as never, + new SelectionSet(select(Character)) + ), + + /** + * @description Information for paginating this connection + */ + + pageInfo: (select) => + new Field( + "pageInfo", + undefined as never, + new SelectionSet(select(PageInfo)) + ), +}; + +export interface IFriendsEdge { + cursor: string; + node: ICharacter; +} + +interface FriendsEdgeSelector { + __typename: () => Field<"__typename">; + + /** + * @description A cursor used for pagination + */ + + cursor: () => Field<"cursor">; + + /** + * @description The character represented by this friendship edge + */ + + node: >( + select: (t: CharacterSelector) => T + ) => Field<"node", never, SelectionSet>; +} + +export const FriendsEdge: FriendsEdgeSelector = { + __typename: () => new Field("__typename"), + + /** + * @description A cursor used for pagination + */ + cursor: () => new Field("cursor"), + + /** + * @description The character represented by this friendship edge + */ + + node: (select) => + new Field("node", undefined as never, new SelectionSet(select(Character))), +}; + +export interface IPageInfo { + startCursor: string; + endCursor: string; + hasNextPage: boolean; +} + +interface PageInfoSelector { + __typename: () => Field<"__typename">; + + startCursor: () => Field<"startCursor">; + + endCursor: () => Field<"endCursor">; + + hasNextPage: () => Field<"hasNextPage">; +} + +export const PageInfo: PageInfoSelector = { + __typename: () => new Field("__typename"), + + startCursor: () => new Field("startCursor"), + endCursor: () => new Field("endCursor"), + hasNextPage: () => new Field("hasNextPage"), +}; + +export interface IReview { + stars: number; + commentary: string; +} + +interface ReviewSelector { + __typename: () => Field<"__typename">; + + /** + * @description The number of stars this review gave, 1-5 + */ + + stars: () => Field<"stars">; + + /** + * @description Comment about the movie + */ + + commentary: () => Field<"commentary">; +} + +export const Review: ReviewSelector = { + __typename: () => new Field("__typename"), + + /** + * @description The number of stars this review gave, 1-5 + */ + stars: () => new Field("stars"), + + /** + * @description Comment about the movie + */ + commentary: () => new Field("commentary"), +}; + +export interface IStarship { + id: string; + name: string; + length: number; + coordinates: number[]; +} + +interface StarshipSelector { + __typename: () => Field<"__typename">; + + /** + * @description The ID of the starship + */ + + id: () => Field<"id">; + + /** + * @description The name of the starship + */ + + name: () => Field<"name">; + + /** + * @description Length of the starship, along the longest axis + */ + + length: (variables: { unit: unknown }) => Field<"length", [/* @todo */]>; + + coordinates: () => Field<"coordinates">; +} + +export const Starship: StarshipSelector = { + __typename: () => new Field("__typename"), + + /** + * @description The ID of the starship + */ + id: () => new Field("id"), + + /** + * @description The name of the starship + */ + name: () => new Field("name"), + + /** + * @description Length of the starship, along the longest axis + */ + length: (variables) => new Field("length"), + coordinates: () => new Field("coordinates"), +}; + +export const query = >( + name: string, + select: (t: typeof Query) => T +): Operation> => + new Operation(name, "query", new SelectionSet(select(Query))); + +export const mutation = >( + name: string, + select: (t: typeof Mutation) => T +): Operation> => + new Operation(name, "mutation", new SelectionSet(select(Mutation))); diff --git a/example-tql/index.ts b/example-tql/index.ts new file mode 100644 index 0000000..1ebdcb3 --- /dev/null +++ b/example-tql/index.ts @@ -0,0 +1,36 @@ +import { query, Episode } from './generated/starwars.api' + +const example = query("Example", (t) => [ + t.search({ text: "han" }, (t) => [ + t.__typename(), + + t.on("Human", (t) => [t.id(), t.name()]), + ]), + + t.reviews({ episode: Episode.EMPIRE }, (t) => [t.stars(), t.commentary()]), + + t.human({ id: "1002" }, (t) => [ + t.__typename(), + t.id(), + t.name(), + t.appearsIn(), + t.homePlanet(), + + // @note Deprecated field should be properly picked-up by VSCode! + t.mass(), + + t.friends((t) => [ + t.__typename(), + t.id(), + t.name(), + t.appearsIn(), + + t.on("Human", (t) => [t.homePlanet()]), + t.on("Droid", (t) => [t.primaryFunction()]), + ]), + + t.starships((t) => [t.id(), t.name()]), + ]), +]); + +console.log(example.toString()) \ No newline at end of file diff --git a/example-tql/package-lock.json b/example-tql/package-lock.json new file mode 100644 index 0000000..0551096 --- /dev/null +++ b/example-tql/package-lock.json @@ -0,0 +1,257 @@ +{ + "name": "example-tql", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@timkendall/tql": { + "version": "0.1.0-alpha.4", + "resolved": "https://registry.npmjs.org/@timkendall/tql/-/tql-0.1.0-alpha.4.tgz", + "integrity": "sha512-xPow3AxnHedBHHuNsBG2f6HuF+HEiqptD45p9NwD5D9VB+g6eIGFaU/sgs4EO7zJYXypG7Ij+3z9eilIZm6WAw==", + "requires": { + "fs-extra": "^9.0.1", + "node-fetch": "^2.6.1", + "prettier": "^2.1.2", + "typescript": "^4.1.3", + "yargs": "^16.1.0" + } + }, + "@types/node": { + "version": "14.14.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", + "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==" + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "graphql": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.4.0.tgz", + "integrity": "sha512-EB3zgGchcabbsU9cFe1j+yxdzKQKAbGUWRb13DsrsMN1yyfmmIq+2+L5MqVWcDCE4V89R5AyUOi7sMOGxdsYtA==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==" + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } +} diff --git a/example-tql/package.json b/example-tql/package.json new file mode 100644 index 0000000..d62326a --- /dev/null +++ b/example-tql/package.json @@ -0,0 +1,18 @@ +{ + "name": "example-tql", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "start": "ts-node index.ts" + }, + "license": "ISC", + "dependencies": { + "@timkendall/tql": "^0.1.0-alpha.4", + "@types/node": "^14.14.14", + "graphql": "^15.4.0", + "ts-node": "^9.1.1", + "typescript": "^4.1.3" + }, + "devDependencies": {}, + "description": "" +}