@avantstay/graphql-ts-client 10.8.0 → 10.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/chunk-I4QOADOI.mjs +27 -0
- package/dist/endpoint.d.ts +9 -9
- package/dist/endpoint.mjs +275 -0
- package/dist/index.d.ts +17 -20
- package/dist/index.js +57 -46
- package/dist/index.mjs +527 -0
- package/dist/types-23d2d6aa.d.ts +75 -0
- package/dist/{types-85e628f6.d.ts → types-4ada662b.d.ts} +67 -66
- package/package.json +43 -42
- package/src/__testClient.d.ts +16 -4
- package/src/__testClient.js +26 -1
- package/src/endpoint.ts +5 -9
- package/src/generateTypescriptClient.test.ts +3 -3
- package/src/generateTypescriptClient.ts +28 -18
- package/src/graphqlRequest.test.ts +3 -4
- package/src/jsonToGraphQLQuery.ts +10 -7
- package/src/types.ts +32 -22
|
@@ -1,69 +1,70 @@
|
|
|
1
|
-
type Maybe<T> = null | undefined | T;
|
|
2
|
-
type Defined<T> = Exclude<T, undefined>;
|
|
3
|
-
type ResponseData = {
|
|
4
|
-
data: any;
|
|
5
|
-
warnings: any;
|
|
6
|
-
headers: any;
|
|
7
|
-
status?: number;
|
|
8
|
-
errors: {
|
|
9
|
-
message: string;
|
|
10
|
-
}[];
|
|
11
|
-
};
|
|
12
|
-
type ResponseListenerInfo = {
|
|
13
|
-
queryName: string;
|
|
14
|
-
query: string;
|
|
15
|
-
variables: any;
|
|
16
|
-
response: ResponseData;
|
|
17
|
-
};
|
|
18
|
-
type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
|
|
19
|
-
type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
|
|
20
|
-
type
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
type
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
get
|
|
1
|
+
type Maybe<T> = null | undefined | T;
|
|
2
|
+
type Defined<T> = Exclude<T, undefined>;
|
|
3
|
+
type ResponseData = {
|
|
4
|
+
data: any;
|
|
5
|
+
warnings: any;
|
|
6
|
+
headers: any;
|
|
7
|
+
status?: number;
|
|
8
|
+
errors: {
|
|
9
|
+
message: string;
|
|
10
|
+
}[];
|
|
11
|
+
};
|
|
12
|
+
type ResponseListenerInfo = {
|
|
13
|
+
queryName: string;
|
|
14
|
+
query: string;
|
|
15
|
+
variables: any;
|
|
16
|
+
response: ResponseData;
|
|
17
|
+
};
|
|
18
|
+
type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
|
|
19
|
+
type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
|
|
20
|
+
type Primitive = Date | string | number | boolean | null | undefined;
|
|
21
|
+
type Projection<Selection, Base, E = never> = Base extends Array<any> ? ArrayElement<Base> extends Primitive | E ? ArrayElement<Base>[] : Projection<Defined<Selection>, ArrayElement<Base>, E>[] : Base extends Primitive | E ? Selection extends undefined ? Base | undefined : Base : {
|
|
22
|
+
[k in keyof Selection & keyof Base]: Selection[k] extends boolean ? Base[k] : Base[k] extends Array<infer A> ? Projection<Defined<Selection[k]>, A, E>[] : Projection<Defined<Selection[k]>, Base[k], E>;
|
|
23
|
+
};
|
|
24
|
+
type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
|
|
25
|
+
type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
|
|
26
|
+
type DeepReplace<T, Ignore, M extends [any, any]> = {
|
|
27
|
+
[P in keyof T]: T[P] extends M[0] ? T[P] extends Ignore ? T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P] : Replacement<M, T[P]> : T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P];
|
|
28
|
+
};
|
|
29
|
+
type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
|
|
30
|
+
data: Projection<S, O, E>;
|
|
31
|
+
errors: any[];
|
|
32
|
+
warnings: any[];
|
|
33
|
+
headers: any;
|
|
34
|
+
status: any;
|
|
35
|
+
}>;
|
|
36
|
+
type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
|
|
37
|
+
type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
|
|
38
|
+
memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
|
|
39
|
+
memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
|
|
40
|
+
raw: RawEndpoint<I, JsonOutput<O, E>, E>;
|
|
41
|
+
};
|
|
42
|
+
type ClientConfig = {
|
|
43
|
+
url: string;
|
|
44
|
+
headers: {
|
|
45
|
+
[key: string]: string;
|
|
46
|
+
};
|
|
47
|
+
retryConfig: {
|
|
48
|
+
max: number;
|
|
49
|
+
waitBeforeRetry?: number;
|
|
50
|
+
before: IResponseListener;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
type LogInfo = {
|
|
54
|
+
query: string;
|
|
55
|
+
variables: any;
|
|
56
|
+
formatGraphQL: any;
|
|
57
|
+
kind: string;
|
|
58
|
+
queryName: string;
|
|
59
|
+
response?: any;
|
|
60
|
+
error?: Error;
|
|
61
|
+
duration: number;
|
|
62
|
+
};
|
|
63
|
+
declare class GraphQLClientError extends Error {
|
|
64
|
+
responseData: ResponseData;
|
|
65
|
+
constructor(responseData: ResponseData);
|
|
66
|
+
get message(): string;
|
|
67
|
+
get response(): ResponseData;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IResponseListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, Unpacked as U, ResponseListenerInfo as a, Replacement as b, DeepReplace as c, RawEndpoint as d };
|
package/package.json
CHANGED
|
@@ -1,57 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avantstay/graphql-ts-client",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.9.0",
|
|
4
4
|
"description": "GraphQL Typescript Client Generator",
|
|
5
|
-
"
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"typings": "dist/index.d.ts",
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "tsup src/index.ts src/endpoint.ts --dts",
|
|
11
|
-
"test": "cross-env GQL_CLIENT_DIST_PATH='.' jest --watch",
|
|
12
|
-
"prepublishOnly": "yarn build"
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"src"
|
|
17
|
-
],
|
|
18
|
-
"engines": {
|
|
19
|
-
"node": ">=12"
|
|
20
|
-
},
|
|
5
|
+
"homepage": "https://github.com/avantstay/graphql-ts-client",
|
|
21
6
|
"bugs": {
|
|
22
7
|
"url": "https://github.com/avantstay/graphql-ts-client/issues"
|
|
23
8
|
},
|
|
24
|
-
"homepage": "https://github.com/avantstay/graphql-ts-client#readme",
|
|
25
9
|
"repository": {
|
|
26
10
|
"type": "git",
|
|
27
11
|
"url": "git+https://github.com/avantstay/graphql-ts-client.git"
|
|
28
12
|
},
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"endOfLine": "lf",
|
|
40
|
-
"printWidth": 130,
|
|
41
|
-
"htmlWhitespaceSensitivity": "ignore",
|
|
42
|
-
"jsxSingleQuote": false
|
|
43
|
-
},
|
|
44
|
-
"module": "dist/graphql-ts-client.esm.js",
|
|
45
|
-
"size-limit": [
|
|
46
|
-
{
|
|
47
|
-
"path": "dist/graphql-ts-client.cjs.production.min.js",
|
|
48
|
-
"limit": "10 KB"
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Wellington Guimaraes",
|
|
15
|
+
"contributors": [
|
|
16
|
+
"Felipe Pinheiro <felipe.pinheiro.90@hotmail.com>"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": "./dist/index.mjs",
|
|
21
|
+
"require": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts"
|
|
49
23
|
},
|
|
50
|
-
{
|
|
51
|
-
"
|
|
52
|
-
"
|
|
24
|
+
"./dist/endpoint": {
|
|
25
|
+
"import": "./dist/endpoint.mjs",
|
|
26
|
+
"require": "./dist/endpoint.js",
|
|
27
|
+
"types": "./dist/endpoint.d.ts"
|
|
53
28
|
}
|
|
29
|
+
},
|
|
30
|
+
"main": "dist/index.js",
|
|
31
|
+
"module": "dist/index.mjs",
|
|
32
|
+
"typings": "dist/index.d.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"src"
|
|
54
36
|
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup src/index.ts src/endpoint.ts --dts --format cjs,esm",
|
|
39
|
+
"prepublishOnly": "yarn build",
|
|
40
|
+
"test": "cross-env GQL_CLIENT_DIST_PATH='.' jest --watch"
|
|
41
|
+
},
|
|
55
42
|
"dependencies": {
|
|
56
43
|
"@types/md5": "^2.3.2",
|
|
57
44
|
"axios": "^0.24.0",
|
|
@@ -87,7 +74,21 @@
|
|
|
87
74
|
"tsup": "^6.5.0",
|
|
88
75
|
"typescript": "^4.9.4"
|
|
89
76
|
},
|
|
77
|
+
"peerDependencies": {},
|
|
78
|
+
"engines": {
|
|
79
|
+
"node": ">=12"
|
|
80
|
+
},
|
|
90
81
|
"publishConfig": {
|
|
91
82
|
"@avantstay:registry": "https://registry.npmjs.org/"
|
|
92
|
-
}
|
|
83
|
+
},
|
|
84
|
+
"size-limit": [
|
|
85
|
+
{
|
|
86
|
+
"path": "dist/graphql-ts-client.cjs.production.min.js",
|
|
87
|
+
"limit": "10 KB"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"path": "dist/graphql-ts-client.esm.js",
|
|
91
|
+
"limit": "10 KB"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
93
94
|
}
|
package/src/__testClient.d.ts
CHANGED
|
@@ -39,6 +39,16 @@ export interface Book {
|
|
|
39
39
|
author?: string
|
|
40
40
|
type?: BookType
|
|
41
41
|
dateCreated?: ISODate
|
|
42
|
+
sequence?: BookSequence
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
export interface BookSequence {
|
|
50
|
+
previousBook?: Book
|
|
51
|
+
nextBook?: Book
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
/**
|
|
@@ -78,6 +88,12 @@ export interface BookSelection {
|
|
|
78
88
|
author?: boolean
|
|
79
89
|
type?: boolean
|
|
80
90
|
dateCreated?: boolean
|
|
91
|
+
sequence?: BookSequenceSelection
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface BookSequenceSelection {
|
|
95
|
+
previousBook?: BookSelection
|
|
96
|
+
nextBook?: BookSelection
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
export interface BookSearchParamsAllOptionalSelection {
|
|
@@ -107,7 +123,6 @@ export declare const myApiClient: {
|
|
|
107
123
|
__headers?: { [key: string]: string }
|
|
108
124
|
__retry?: boolean
|
|
109
125
|
__alias?: string
|
|
110
|
-
__url?: string
|
|
111
126
|
} & BookSelection,
|
|
112
127
|
DeepRequired<Book[]>,
|
|
113
128
|
AllEnums
|
|
@@ -117,7 +132,6 @@ export declare const myApiClient: {
|
|
|
117
132
|
__headers?: { [key: string]: string }
|
|
118
133
|
__retry?: boolean
|
|
119
134
|
__alias?: string
|
|
120
|
-
__url?: string
|
|
121
135
|
__args?: BooksWithOptionalParamsArgs
|
|
122
136
|
} & BookSelection,
|
|
123
137
|
DeepRequired<Book[]>,
|
|
@@ -128,7 +142,6 @@ export declare const myApiClient: {
|
|
|
128
142
|
__headers?: { [key: string]: string }
|
|
129
143
|
__retry?: boolean
|
|
130
144
|
__alias?: string
|
|
131
|
-
__url?: string
|
|
132
145
|
__args: BooksWithRequiredParamsArgs
|
|
133
146
|
} & BookSelection,
|
|
134
147
|
DeepRequired<Book[]>,
|
|
@@ -139,7 +152,6 @@ export declare const myApiClient: {
|
|
|
139
152
|
__headers?: { [key: string]: string }
|
|
140
153
|
__retry?: boolean
|
|
141
154
|
__alias?: string
|
|
142
|
-
__url?: string
|
|
143
155
|
__args: FailingQueryArgs
|
|
144
156
|
},
|
|
145
157
|
string,
|
package/src/__testClient.js
CHANGED
|
@@ -39,6 +39,7 @@ const typesTree = {
|
|
|
39
39
|
Query: {
|
|
40
40
|
get booksWithOptionalParams() {
|
|
41
41
|
return {
|
|
42
|
+
__fields: typesTree.Book,
|
|
42
43
|
__args: {
|
|
43
44
|
params: "BookSearchParamsAllOptional!"
|
|
44
45
|
}
|
|
@@ -46,6 +47,7 @@ const typesTree = {
|
|
|
46
47
|
},
|
|
47
48
|
get booksWithRequiredParams() {
|
|
48
49
|
return {
|
|
50
|
+
__fields: typesTree.Book,
|
|
49
51
|
__args: {
|
|
50
52
|
params: "BookSearchParamsSomeRequired!"
|
|
51
53
|
}
|
|
@@ -58,7 +60,30 @@ const typesTree = {
|
|
|
58
60
|
}
|
|
59
61
|
};
|
|
60
62
|
},
|
|
61
|
-
booksWithoutParams
|
|
63
|
+
get booksWithoutParams() {
|
|
64
|
+
return {
|
|
65
|
+
__fields: typesTree.Book
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
Book: {
|
|
70
|
+
get sequence() {
|
|
71
|
+
return {
|
|
72
|
+
__fields: typesTree.BookSequence
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
BookSequence: {
|
|
77
|
+
get previousBook() {
|
|
78
|
+
return {
|
|
79
|
+
__fields: typesTree.Book
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
get nextBook() {
|
|
83
|
+
return {
|
|
84
|
+
__fields: typesTree.Book
|
|
85
|
+
};
|
|
86
|
+
}
|
|
62
87
|
}
|
|
63
88
|
};
|
|
64
89
|
let verbose = false;
|
package/src/endpoint.ts
CHANGED
|
@@ -2,14 +2,10 @@ import memoize from 'moize'
|
|
|
2
2
|
import { graphqlRequest } from './graphqlRequest'
|
|
3
3
|
import { jsonToGraphQLQuery } from './jsonToGraphQLQuery'
|
|
4
4
|
import { logRequest } from './logging'
|
|
5
|
-
import {ClientConfig, Endpoint, GraphQLClientError, IResponseListener, Projection, ResponseListenerInfo} from './types'
|
|
5
|
+
import { ClientConfig, Endpoint, GraphQLClientError, IResponseListener, Projection, ResponseListenerInfo } from './types'
|
|
6
6
|
|
|
7
7
|
const executeListeners = (listeners: IResponseListener[], data: ResponseListenerInfo) =>
|
|
8
|
-
setTimeout(() =>
|
|
9
|
-
listeners.forEach(runResponseListener =>
|
|
10
|
-
runResponseListener(data)
|
|
11
|
-
)
|
|
12
|
-
)
|
|
8
|
+
setTimeout(() => listeners.forEach(runResponseListener => runResponseListener(data)))
|
|
13
9
|
|
|
14
10
|
export const getApiEndpointCreator =
|
|
15
11
|
(apiConfig: {
|
|
@@ -61,11 +57,11 @@ export const getApiEndpointCreator =
|
|
|
61
57
|
shouldRetry,
|
|
62
58
|
failureMode,
|
|
63
59
|
queryName: alias,
|
|
64
|
-
client: {...clientConfig, url },
|
|
60
|
+
client: { ...clientConfig, url },
|
|
65
61
|
requestHeaders,
|
|
66
62
|
query,
|
|
67
63
|
variables,
|
|
68
|
-
errorsParser: apiConfig.errorsParser
|
|
64
|
+
errorsParser: apiConfig.errorsParser,
|
|
69
65
|
})
|
|
70
66
|
|
|
71
67
|
const response = { data, warnings, headers, status, errors }
|
|
@@ -78,7 +74,7 @@ export const getApiEndpointCreator =
|
|
|
78
74
|
})
|
|
79
75
|
}
|
|
80
76
|
|
|
81
|
-
executeListeners(apiConfig.responseListeners,{
|
|
77
|
+
executeListeners(apiConfig.responseListeners, {
|
|
82
78
|
...responseListenerData,
|
|
83
79
|
response,
|
|
84
80
|
})
|
|
@@ -125,12 +125,12 @@ describe('Generated Client', () => {
|
|
|
125
125
|
expect(responseData?.response.errors.length).toBeGreaterThan(0)
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
-
it('should generate proper code from SDL', ()=>{
|
|
128
|
+
it('should generate proper code from SDL', () => {
|
|
129
129
|
const sdlString = `
|
|
130
130
|
type Query {
|
|
131
131
|
hello: String
|
|
132
132
|
}
|
|
133
|
-
|
|
134
|
-
expect(generateTypescriptClientFromSDL(sdlString, {endpoint: 'https://sample.endpoint.com/graphl'})).toMatchSnapshot()
|
|
133
|
+
`
|
|
134
|
+
expect(generateTypescriptClientFromSDL(sdlString, { endpoint: 'https://sample.endpoint.com/graphl' })).toMatchSnapshot()
|
|
135
135
|
})
|
|
136
136
|
})
|
|
@@ -6,8 +6,8 @@ import * as fs from 'fs'
|
|
|
6
6
|
import { PathLike } from 'fs'
|
|
7
7
|
import {
|
|
8
8
|
buildSchema,
|
|
9
|
-
graphqlSync,
|
|
10
9
|
getIntrospectionQuery,
|
|
10
|
+
graphqlSync,
|
|
11
11
|
IntrospectionEnumType,
|
|
12
12
|
IntrospectionField,
|
|
13
13
|
IntrospectionInputObjectType,
|
|
@@ -25,6 +25,7 @@ import os from 'os'
|
|
|
25
25
|
import path from 'path'
|
|
26
26
|
import * as prettier from 'prettier'
|
|
27
27
|
import pkg from '../package.json'
|
|
28
|
+
import { TypescriptClientOutput } from './types'
|
|
28
29
|
|
|
29
30
|
const tempDir = fs.realpathSync(os.tmpdir())
|
|
30
31
|
|
|
@@ -153,10 +154,9 @@ function gqlEndpointToCode(kind: 'mutation' | 'query', endpoint: IntrospectionFi
|
|
|
153
154
|
}${selectionType ? ` & ${selectionType}` : ''}`
|
|
154
155
|
|
|
155
156
|
const outputType = gqlTypeToTypescript(endpoint.type, { required: true })
|
|
156
|
-
const wrappedOutputType = /^(string|number|boolean)$/.test(outputType) ? outputType : `DeepRequired<${outputType}>`
|
|
157
157
|
|
|
158
158
|
return codeOutputType === 'ts'
|
|
159
|
-
? `${endpoint.name}: Endpoint<${inputType}, ${
|
|
159
|
+
? `${endpoint.name}: Endpoint<${inputType}, ${outputType}, AllEnums>`
|
|
160
160
|
: `${endpoint.name}: apiEndpoint('${kind}', '${endpoint.name}')`
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -315,7 +315,7 @@ type IClientOptions = {
|
|
|
315
315
|
errorsParser?: (errors: any[]) => any
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
-
type FetchIntrospectionOptions = Omit<
|
|
318
|
+
type FetchIntrospectionOptions = Omit<IClientOptions, 'output' | 'introspectionEndpoint'>
|
|
319
319
|
|
|
320
320
|
function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Omit<IClientOptions, 'output'>) {
|
|
321
321
|
const typesHash = md5(`${JSON.stringify(options)}__${JSON.stringify(types)}`)
|
|
@@ -323,7 +323,11 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
|
|
|
323
323
|
const clientCacheFilePath = path.resolve(tempDir, clientCacheFileName)
|
|
324
324
|
|
|
325
325
|
if (!options.skipCache && fs.existsSync(clientCacheFilePath)) {
|
|
326
|
-
|
|
326
|
+
const output: Partial<TypescriptClientOutput> = JSON.parse(fs.readFileSync(clientCacheFilePath, { encoding: 'utf8' }))
|
|
327
|
+
|
|
328
|
+
if (output.js && output.mjs && output.typings) {
|
|
329
|
+
return output as TypescriptClientOutput
|
|
330
|
+
}
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
const queries = (<IntrospectionObjectType>types.find(it => it.name === 'Query'))?.fields || []
|
|
@@ -473,8 +477,9 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
|
|
|
473
477
|
|
|
474
478
|
export default ${clientName}`
|
|
475
479
|
|
|
476
|
-
const output = {
|
|
480
|
+
const output: TypescriptClientOutput = {
|
|
477
481
|
js: esbuild.transformSync(jsCode, { format: 'cjs', loader: 'js' }).code,
|
|
482
|
+
mjs: esbuild.transformSync(jsCode, { format: 'esm', loader: 'js' }).code,
|
|
478
483
|
typings: prettier.format(typingsCode, { semi: false, parser: 'typescript' }),
|
|
479
484
|
}
|
|
480
485
|
|
|
@@ -501,7 +506,7 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
|
|
|
501
506
|
},
|
|
502
507
|
}
|
|
503
508
|
)
|
|
504
|
-
.catch(
|
|
509
|
+
.catch(e => {
|
|
505
510
|
const errorMessage = `The GraphQL introspection request failed (${endpoint})`
|
|
506
511
|
if (fs.existsSync(introspectionCacheFilePath)) {
|
|
507
512
|
const cachedSchema = JSON.parse(fs.readFileSync(introspectionCacheFilePath, { encoding: 'utf8' }))
|
|
@@ -527,10 +532,11 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
|
|
|
527
532
|
return types
|
|
528
533
|
}
|
|
529
534
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
535
|
+
function generateClient(
|
|
536
|
+
introspectionTypes: ReadonlyArray<IntrospectionType>,
|
|
537
|
+
{ output, ...restOptions }: IClientOptions
|
|
538
|
+
): TypescriptClientOutput {
|
|
539
|
+
const { js, mjs, typings } = generateClientCode(introspectionTypes, restOptions)
|
|
534
540
|
|
|
535
541
|
if (output && typeof output === 'string') {
|
|
536
542
|
const outputDir = path.dirname(output)
|
|
@@ -541,12 +547,16 @@ function generateClient(introspectionTypes: ReadonlyArray<IntrospectionType>, {o
|
|
|
541
547
|
|
|
542
548
|
fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.d.ts'), typings, { encoding: 'utf8' })
|
|
543
549
|
fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.js'), js, { encoding: 'utf8' })
|
|
550
|
+
fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.mjs'), mjs, { encoding: 'utf8' })
|
|
544
551
|
}
|
|
545
552
|
|
|
546
|
-
return { js, typings }
|
|
553
|
+
return { js, mjs, typings }
|
|
547
554
|
}
|
|
548
555
|
|
|
549
|
-
export async function generateTypescriptClient({
|
|
556
|
+
export async function generateTypescriptClient({
|
|
557
|
+
introspectionEndpoint,
|
|
558
|
+
...options
|
|
559
|
+
}: IClientOptions): Promise<TypescriptClientOutput> {
|
|
550
560
|
console.log(`Generating TypeScript client (name: ${options.clientName ?? 'n/a'})`)
|
|
551
561
|
|
|
552
562
|
axiosRetry(axios, { retries: 5, retryDelay: retryCount => 1000 * 2 ** retryCount })
|
|
@@ -557,14 +567,14 @@ export async function generateTypescriptClient({ introspectionEndpoint, ...optio
|
|
|
557
567
|
})
|
|
558
568
|
|
|
559
569
|
return generateClient(introspectionTypes, options)
|
|
560
|
-
|
|
561
570
|
}
|
|
562
571
|
|
|
563
|
-
export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions):
|
|
564
|
-
console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? 'n/a'})`)
|
|
572
|
+
export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions): TypescriptClientOutput {
|
|
573
|
+
console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? 'n/a'})`)
|
|
565
574
|
|
|
566
|
-
const graphqlSchemaObj = buildSchema(SDL)
|
|
567
|
-
const introspectionTypes = graphqlSync(graphqlSchemaObj, new Source(getIntrospectionQuery())).data?.__schema
|
|
575
|
+
const graphqlSchemaObj = buildSchema(SDL)
|
|
576
|
+
const introspectionTypes = graphqlSync(graphqlSchemaObj, new Source(getIntrospectionQuery())).data?.__schema
|
|
577
|
+
.types as IntrospectionType[]
|
|
568
578
|
|
|
569
579
|
return generateClient(introspectionTypes, options)
|
|
570
580
|
}
|
|
@@ -2,10 +2,10 @@ import { graphqlRequest } from './graphqlRequest'
|
|
|
2
2
|
|
|
3
3
|
describe('GraphQLRequest', () => {
|
|
4
4
|
it('Should request have proper structure', async () => {
|
|
5
|
-
let request: any
|
|
5
|
+
let request: any
|
|
6
6
|
|
|
7
7
|
const mockedAxios = {
|
|
8
|
-
post: function() {
|
|
8
|
+
post: function () {
|
|
9
9
|
request = arguments
|
|
10
10
|
return {
|
|
11
11
|
status: 200,
|
|
@@ -19,7 +19,7 @@ describe('GraphQLRequest', () => {
|
|
|
19
19
|
axios: mockedAxios,
|
|
20
20
|
queryName: 'sampleQueryName',
|
|
21
21
|
query: 'sampleQuery',
|
|
22
|
-
variables: {foo:'bar',bar:'foo'},
|
|
22
|
+
variables: { foo: 'bar', bar: 'foo' },
|
|
23
23
|
client: {
|
|
24
24
|
url: 'https://whatever.com',
|
|
25
25
|
headers: {},
|
|
@@ -51,7 +51,6 @@ describe('GraphQLRequest', () => {
|
|
|
51
51
|
} as any
|
|
52
52
|
|
|
53
53
|
const result = await graphqlRequest({
|
|
54
|
-
|
|
55
54
|
failureMode: 'loud',
|
|
56
55
|
axios: mockedAxios,
|
|
57
56
|
queryName: 'whatever',
|
|
@@ -31,14 +31,17 @@ export function jsonToGraphQLQuery({
|
|
|
31
31
|
parentType: kind === 'query' ? typesTree.Query : typesTree.Mutation,
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
const variableItems = Object.values(variablesData).reduce(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const variableItems = Object.values(variablesData).reduce(
|
|
35
|
+
(variablesObj, variables) => {
|
|
36
|
+
variables.forEach((variable, index) => {
|
|
37
|
+
const name = variable.update(variables.length > 1 ? index : undefined)
|
|
38
|
+
variablesObj[name] = { type: variable.type, value: variable.value }
|
|
39
|
+
})
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
return variablesObj
|
|
42
|
+
},
|
|
43
|
+
{} as Record<string, Variable>
|
|
44
|
+
)
|
|
42
45
|
|
|
43
46
|
const variablesQuery = Object.keys(variableItems).length
|
|
44
47
|
? `(${entries(variableItems)
|