@avantstay/graphql-ts-client 10.7.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 +1 -1
- package/dist/endpoint.js +8 -3
- package/dist/endpoint.mjs +275 -0
- package/dist/index.d.ts +4 -7
- package/dist/index.js +63 -51
- package/dist/index.mjs +527 -0
- package/dist/types-23d2d6aa.d.ts +75 -0
- package/dist/types-4ada662b.d.ts +70 -0
- package/package.json +43 -42
- package/src/__snapshots__/generateTypescriptClient.test.ts.snap +3 -2
- package/src/__testClient.d.ts +164 -0
- package/src/__testClient.js +135 -0
- package/src/endpoint.ts +8 -9
- package/src/generateTypescriptClient.test.ts +3 -3
- package/src/generateTypescriptClient.ts +32 -20
- package/src/graphqlRequest.test.ts +3 -4
- package/src/jsonToGraphQLQuery.ts +11 -8
- package/src/types.ts +32 -22
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
|
}
|
|
@@ -29,7 +29,7 @@ __export(exports, {
|
|
|
29
29
|
client: () => client,
|
|
30
30
|
default: () => stdin_default
|
|
31
31
|
});
|
|
32
|
-
var import_endpoint = __toModule(require("
|
|
32
|
+
var import_endpoint = __toModule(require("./endpoint"));
|
|
33
33
|
const formatGraphQL = (query) => query;
|
|
34
34
|
const typesTree = {};
|
|
35
35
|
let verbose = false;
|
|
@@ -79,7 +79,7 @@ var stdin_default = client;
|
|
|
79
79
|
",
|
|
80
80
|
"typings": "// noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
|
|
81
81
|
import { DeepRequired } from "ts-essentials"
|
|
82
|
-
import { Maybe, IResponseListener, Endpoint } from "
|
|
82
|
+
import { Maybe, IResponseListener, Endpoint } from "."
|
|
83
83
|
|
|
84
84
|
// Scalars
|
|
85
85
|
export type IDate = string | Date
|
|
@@ -119,6 +119,7 @@ export declare const client: {
|
|
|
119
119
|
__headers?: { [key: string]: string }
|
|
120
120
|
__retry?: boolean
|
|
121
121
|
__alias?: string
|
|
122
|
+
__url?: string
|
|
122
123
|
},
|
|
123
124
|
string,
|
|
124
125
|
AllEnums
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
|
|
2
|
+
import { DeepRequired } from "ts-essentials"
|
|
3
|
+
import { Maybe, IResponseListener, Endpoint } from "."
|
|
4
|
+
|
|
5
|
+
// Scalars
|
|
6
|
+
export type IDate = string | Date
|
|
7
|
+
export declare type ISODate = IDate
|
|
8
|
+
|
|
9
|
+
// Enums
|
|
10
|
+
|
|
11
|
+
export declare enum BookType {
|
|
12
|
+
dolor = "DOLOR",
|
|
13
|
+
ipsum = "IPSUM",
|
|
14
|
+
sit = "SIT",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type AllEnums = BookType
|
|
18
|
+
|
|
19
|
+
// Args
|
|
20
|
+
export interface BooksWithoutParamsArgs {}
|
|
21
|
+
export interface BooksWithOptionalParamsArgs {
|
|
22
|
+
params?: BookSearchParamsAllOptional
|
|
23
|
+
}
|
|
24
|
+
export interface BooksWithRequiredParamsArgs {
|
|
25
|
+
params: BookSearchParamsSomeRequired
|
|
26
|
+
}
|
|
27
|
+
export interface FailingQueryArgs {
|
|
28
|
+
id: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Input/Output Types
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
export interface Book {
|
|
38
|
+
title?: string
|
|
39
|
+
author?: string
|
|
40
|
+
type?: BookType
|
|
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
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export interface BookSearchParamsAllOptional {
|
|
59
|
+
title?: string
|
|
60
|
+
author?: string
|
|
61
|
+
createdAfter?: ISODate
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
export interface BookSearchParamsSomeRequired {
|
|
69
|
+
title: string
|
|
70
|
+
author?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
export interface Query {
|
|
78
|
+
booksWithoutParams?: Book[]
|
|
79
|
+
booksWithOptionalParams?: Book[]
|
|
80
|
+
booksWithRequiredParams?: Book[]
|
|
81
|
+
failingQuery?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Selection Types
|
|
85
|
+
|
|
86
|
+
export interface BookSelection {
|
|
87
|
+
title?: boolean
|
|
88
|
+
author?: boolean
|
|
89
|
+
type?: boolean
|
|
90
|
+
dateCreated?: boolean
|
|
91
|
+
sequence?: BookSequenceSelection
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface BookSequenceSelection {
|
|
95
|
+
previousBook?: BookSelection
|
|
96
|
+
nextBook?: BookSelection
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface BookSearchParamsAllOptionalSelection {
|
|
100
|
+
title?: boolean
|
|
101
|
+
author?: boolean
|
|
102
|
+
createdAfter?: boolean
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface BookSearchParamsSomeRequiredSelection {
|
|
106
|
+
title?: boolean
|
|
107
|
+
author?: boolean
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export declare const myApiClient: {
|
|
111
|
+
addResponseListener: (listener: IResponseListener) => void
|
|
112
|
+
setHeader: (key: string, value: string) => void
|
|
113
|
+
setHeaders: (newHeaders: { [k: string]: string }) => void
|
|
114
|
+
setUrl: (url: string) => void
|
|
115
|
+
setRetryConfig: (options: {
|
|
116
|
+
max: number
|
|
117
|
+
waitBeforeRetry?: number
|
|
118
|
+
before?: IResponseListener
|
|
119
|
+
}) => void
|
|
120
|
+
queries: {
|
|
121
|
+
booksWithoutParams: Endpoint<
|
|
122
|
+
{
|
|
123
|
+
__headers?: { [key: string]: string }
|
|
124
|
+
__retry?: boolean
|
|
125
|
+
__alias?: string
|
|
126
|
+
} & BookSelection,
|
|
127
|
+
DeepRequired<Book[]>,
|
|
128
|
+
AllEnums
|
|
129
|
+
>
|
|
130
|
+
booksWithOptionalParams: Endpoint<
|
|
131
|
+
{
|
|
132
|
+
__headers?: { [key: string]: string }
|
|
133
|
+
__retry?: boolean
|
|
134
|
+
__alias?: string
|
|
135
|
+
__args?: BooksWithOptionalParamsArgs
|
|
136
|
+
} & BookSelection,
|
|
137
|
+
DeepRequired<Book[]>,
|
|
138
|
+
AllEnums
|
|
139
|
+
>
|
|
140
|
+
booksWithRequiredParams: Endpoint<
|
|
141
|
+
{
|
|
142
|
+
__headers?: { [key: string]: string }
|
|
143
|
+
__retry?: boolean
|
|
144
|
+
__alias?: string
|
|
145
|
+
__args: BooksWithRequiredParamsArgs
|
|
146
|
+
} & BookSelection,
|
|
147
|
+
DeepRequired<Book[]>,
|
|
148
|
+
AllEnums
|
|
149
|
+
>
|
|
150
|
+
failingQuery: Endpoint<
|
|
151
|
+
{
|
|
152
|
+
__headers?: { [key: string]: string }
|
|
153
|
+
__retry?: boolean
|
|
154
|
+
__alias?: string
|
|
155
|
+
__args: FailingQueryArgs
|
|
156
|
+
},
|
|
157
|
+
string,
|
|
158
|
+
AllEnums
|
|
159
|
+
>
|
|
160
|
+
}
|
|
161
|
+
mutations: {}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export default myApiClient
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
__markAsModule(target);
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __reExport = (target, module2, desc) => {
|
|
14
|
+
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(module2))
|
|
16
|
+
if (!__hasOwnProp.call(target, key) && key !== "default")
|
|
17
|
+
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
21
|
+
var __toModule = (module2) => {
|
|
22
|
+
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
|
|
23
|
+
};
|
|
24
|
+
__export(exports, {
|
|
25
|
+
BookType: () => BookType,
|
|
26
|
+
default: () => stdin_default,
|
|
27
|
+
myApiClient: () => myApiClient
|
|
28
|
+
});
|
|
29
|
+
var import_endpoint = __toModule(require("./endpoint"));
|
|
30
|
+
var import_standalone = __toModule(require("prettier/standalone"));
|
|
31
|
+
var import_parser_graphql = __toModule(require("prettier/parser-graphql"));
|
|
32
|
+
const formatGraphQL = (query) => (0, import_standalone.format)(query, { parser: "graphql", plugins: [import_parser_graphql.default] });
|
|
33
|
+
const BookType = {
|
|
34
|
+
dolor: "DOLOR",
|
|
35
|
+
ipsum: "IPSUM",
|
|
36
|
+
sit: "SIT"
|
|
37
|
+
};
|
|
38
|
+
const typesTree = {
|
|
39
|
+
Query: {
|
|
40
|
+
get booksWithOptionalParams() {
|
|
41
|
+
return {
|
|
42
|
+
__fields: typesTree.Book,
|
|
43
|
+
__args: {
|
|
44
|
+
params: "BookSearchParamsAllOptional!"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
get booksWithRequiredParams() {
|
|
49
|
+
return {
|
|
50
|
+
__fields: typesTree.Book,
|
|
51
|
+
__args: {
|
|
52
|
+
params: "BookSearchParamsSomeRequired!"
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
get failingQuery() {
|
|
57
|
+
return {
|
|
58
|
+
__args: {
|
|
59
|
+
id: "String!"
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
},
|
|
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
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
let verbose = false;
|
|
90
|
+
let headers = {};
|
|
91
|
+
let url = "http://localhost:4123/graphql";
|
|
92
|
+
let retryConfig = {
|
|
93
|
+
max: 0,
|
|
94
|
+
before: void 0,
|
|
95
|
+
waitBeforeRetry: 0
|
|
96
|
+
};
|
|
97
|
+
let responseListeners = [];
|
|
98
|
+
let errorsParser = void 0;
|
|
99
|
+
let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
|
|
100
|
+
getClient: () => ({ url, headers, retryConfig }),
|
|
101
|
+
responseListeners,
|
|
102
|
+
maxAge: 3e4,
|
|
103
|
+
verbose,
|
|
104
|
+
typesTree,
|
|
105
|
+
formatGraphQL,
|
|
106
|
+
errorsParser
|
|
107
|
+
});
|
|
108
|
+
const myApiClient = {
|
|
109
|
+
addResponseListener: (listener) => responseListeners.push(listener),
|
|
110
|
+
setHeader: (key, value) => {
|
|
111
|
+
headers[key] = value;
|
|
112
|
+
},
|
|
113
|
+
setHeaders: (newHeaders) => {
|
|
114
|
+
headers = newHeaders;
|
|
115
|
+
},
|
|
116
|
+
setRetryConfig: (options) => {
|
|
117
|
+
if (!Number.isInteger(options.max) || options.max < 0) {
|
|
118
|
+
throw new Error("retryOptions.max should be a non-negative integer");
|
|
119
|
+
}
|
|
120
|
+
retryConfig = {
|
|
121
|
+
max: options.max,
|
|
122
|
+
waitBeforeRetry: options.waitBeforeRetry,
|
|
123
|
+
before: options.before
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
setUrl: (_url) => url = _url,
|
|
127
|
+
queries: {
|
|
128
|
+
booksWithoutParams: apiEndpoint("query", "booksWithoutParams"),
|
|
129
|
+
booksWithOptionalParams: apiEndpoint("query", "booksWithOptionalParams"),
|
|
130
|
+
booksWithRequiredParams: apiEndpoint("query", "booksWithRequiredParams"),
|
|
131
|
+
failingQuery: apiEndpoint("query", "failingQuery")
|
|
132
|
+
},
|
|
133
|
+
mutations: {}
|
|
134
|
+
};
|
|
135
|
+
var stdin_default = myApiClient;
|
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: {
|
|
@@ -32,7 +28,10 @@ export const getApiEndpointCreator =
|
|
|
32
28
|
headers: any
|
|
33
29
|
status: any
|
|
34
30
|
}> => {
|
|
31
|
+
const clientConfig = apiConfig.getClient()
|
|
32
|
+
|
|
35
33
|
const alias = (jsonQuery as any)?.__alias ?? queryName
|
|
34
|
+
const url = (jsonQuery as any)?.__url ?? clientConfig.url
|
|
36
35
|
const shouldRetry = (jsonQuery as any)?.__retry ?? true
|
|
37
36
|
const requestHeaders = (jsonQuery as any)?.__headers ?? {}
|
|
38
37
|
const { query, variables } = jsonToGraphQLQuery({ kind, queryName, jsonQuery, typesTree: apiConfig.typesTree })
|
|
@@ -58,11 +57,11 @@ export const getApiEndpointCreator =
|
|
|
58
57
|
shouldRetry,
|
|
59
58
|
failureMode,
|
|
60
59
|
queryName: alias,
|
|
61
|
-
client:
|
|
60
|
+
client: { ...clientConfig, url },
|
|
62
61
|
requestHeaders,
|
|
63
62
|
query,
|
|
64
63
|
variables,
|
|
65
|
-
errorsParser: apiConfig.errorsParser
|
|
64
|
+
errorsParser: apiConfig.errorsParser,
|
|
66
65
|
})
|
|
67
66
|
|
|
68
67
|
const response = { data, warnings, headers, status, errors }
|
|
@@ -75,7 +74,7 @@ export const getApiEndpointCreator =
|
|
|
75
74
|
})
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
executeListeners(apiConfig.responseListeners,{
|
|
77
|
+
executeListeners(apiConfig.responseListeners, {
|
|
79
78
|
...responseListenerData,
|
|
80
79
|
response,
|
|
81
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,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
IntrospectionType,
|
|
18
18
|
Source,
|
|
19
19
|
} from 'graphql'
|
|
20
|
-
import
|
|
20
|
+
import kebabCase from 'lodash/kebabCase'
|
|
21
21
|
import orderBy from 'lodash/orderBy'
|
|
22
22
|
import set from 'lodash/set'
|
|
23
23
|
import md5 from 'md5'
|
|
@@ -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
|
|
|
@@ -108,7 +109,7 @@ function gqlFieldToTypescript(
|
|
|
108
109
|
})
|
|
109
110
|
)
|
|
110
111
|
|
|
111
|
-
fieldTypeDefinition = `{ __headers?: {[key: string]: string}; __retry?: boolean; __alias?: string; __args${
|
|
112
|
+
fieldTypeDefinition = `{ __headers?: {[key: string]: string}; __retry?: boolean; __alias?: string; __url?: string; __args${
|
|
112
113
|
fieldsOnArgs.every(arg => arg.isOptional) ? '?' : ''
|
|
113
114
|
}: { ${fieldsOnArgs.map(arg => arg.code).join(', ')} }}${fieldTypeDefinition ? ` & ${fieldTypeDefinition}` : ''}`
|
|
114
115
|
}
|
|
@@ -148,14 +149,14 @@ function gqlEndpointToCode(kind: 'mutation' | 'query', endpoint: IntrospectionFi
|
|
|
148
149
|
__headers?: {[key: string]: string};
|
|
149
150
|
__retry?: boolean;
|
|
150
151
|
__alias?: string;
|
|
152
|
+
__url?: string;
|
|
151
153
|
${argsType ? `__args${argsType.optional ? '?' : ''}: ${argsType.alias}` : ''}
|
|
152
154
|
}${selectionType ? ` & ${selectionType}` : ''}`
|
|
153
155
|
|
|
154
156
|
const outputType = gqlTypeToTypescript(endpoint.type, { required: true })
|
|
155
|
-
const wrappedOutputType = /^(string|number|boolean)$/.test(outputType) ? outputType : `DeepRequired<${outputType}>`
|
|
156
157
|
|
|
157
158
|
return codeOutputType === 'ts'
|
|
158
|
-
? `${endpoint.name}: Endpoint<${inputType}, ${
|
|
159
|
+
? `${endpoint.name}: Endpoint<${inputType}, ${outputType}, AllEnums>`
|
|
159
160
|
: `${endpoint.name}: apiEndpoint('${kind}', '${endpoint.name}')`
|
|
160
161
|
}
|
|
161
162
|
|
|
@@ -314,7 +315,7 @@ type IClientOptions = {
|
|
|
314
315
|
errorsParser?: (errors: any[]) => any
|
|
315
316
|
}
|
|
316
317
|
|
|
317
|
-
type FetchIntrospectionOptions = Omit<
|
|
318
|
+
type FetchIntrospectionOptions = Omit<IClientOptions, 'output' | 'introspectionEndpoint'>
|
|
318
319
|
|
|
319
320
|
function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Omit<IClientOptions, 'output'>) {
|
|
320
321
|
const typesHash = md5(`${JSON.stringify(options)}__${JSON.stringify(types)}`)
|
|
@@ -322,7 +323,11 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
|
|
|
322
323
|
const clientCacheFilePath = path.resolve(tempDir, clientCacheFileName)
|
|
323
324
|
|
|
324
325
|
if (!options.skipCache && fs.existsSync(clientCacheFilePath)) {
|
|
325
|
-
|
|
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
|
+
}
|
|
326
331
|
}
|
|
327
332
|
|
|
328
333
|
const queries = (<IntrospectionObjectType>types.find(it => it.name === 'Query'))?.fields || []
|
|
@@ -472,8 +477,9 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
|
|
|
472
477
|
|
|
473
478
|
export default ${clientName}`
|
|
474
479
|
|
|
475
|
-
const output = {
|
|
480
|
+
const output: TypescriptClientOutput = {
|
|
476
481
|
js: esbuild.transformSync(jsCode, { format: 'cjs', loader: 'js' }).code,
|
|
482
|
+
mjs: esbuild.transformSync(jsCode, { format: 'esm', loader: 'js' }).code,
|
|
477
483
|
typings: prettier.format(typingsCode, { semi: false, parser: 'typescript' }),
|
|
478
484
|
}
|
|
479
485
|
|
|
@@ -500,7 +506,7 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
|
|
|
500
506
|
},
|
|
501
507
|
}
|
|
502
508
|
)
|
|
503
|
-
.catch(
|
|
509
|
+
.catch(e => {
|
|
504
510
|
const errorMessage = `The GraphQL introspection request failed (${endpoint})`
|
|
505
511
|
if (fs.existsSync(introspectionCacheFilePath)) {
|
|
506
512
|
const cachedSchema = JSON.parse(fs.readFileSync(introspectionCacheFilePath, { encoding: 'utf8' }))
|
|
@@ -508,6 +514,7 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
|
|
|
508
514
|
console.warn(`Successfully restored from local cache.`)
|
|
509
515
|
return { data: cachedSchema }
|
|
510
516
|
} else {
|
|
517
|
+
console.error(e)
|
|
511
518
|
return Promise.reject(errorMessage)
|
|
512
519
|
}
|
|
513
520
|
})
|
|
@@ -525,10 +532,11 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
|
|
|
525
532
|
return types
|
|
526
533
|
}
|
|
527
534
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
535
|
+
function generateClient(
|
|
536
|
+
introspectionTypes: ReadonlyArray<IntrospectionType>,
|
|
537
|
+
{ output, ...restOptions }: IClientOptions
|
|
538
|
+
): TypescriptClientOutput {
|
|
539
|
+
const { js, mjs, typings } = generateClientCode(introspectionTypes, restOptions)
|
|
532
540
|
|
|
533
541
|
if (output && typeof output === 'string') {
|
|
534
542
|
const outputDir = path.dirname(output)
|
|
@@ -539,12 +547,16 @@ function generateClient(introspectionTypes: ReadonlyArray<IntrospectionType>, {o
|
|
|
539
547
|
|
|
540
548
|
fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.d.ts'), typings, { encoding: 'utf8' })
|
|
541
549
|
fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.js'), js, { encoding: 'utf8' })
|
|
550
|
+
fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.mjs'), mjs, { encoding: 'utf8' })
|
|
542
551
|
}
|
|
543
552
|
|
|
544
|
-
return { js, typings }
|
|
553
|
+
return { js, mjs, typings }
|
|
545
554
|
}
|
|
546
555
|
|
|
547
|
-
export async function generateTypescriptClient({
|
|
556
|
+
export async function generateTypescriptClient({
|
|
557
|
+
introspectionEndpoint,
|
|
558
|
+
...options
|
|
559
|
+
}: IClientOptions): Promise<TypescriptClientOutput> {
|
|
548
560
|
console.log(`Generating TypeScript client (name: ${options.clientName ?? 'n/a'})`)
|
|
549
561
|
|
|
550
562
|
axiosRetry(axios, { retries: 5, retryDelay: retryCount => 1000 * 2 ** retryCount })
|
|
@@ -555,14 +567,14 @@ export async function generateTypescriptClient({ introspectionEndpoint, ...optio
|
|
|
555
567
|
})
|
|
556
568
|
|
|
557
569
|
return generateClient(introspectionTypes, options)
|
|
558
|
-
|
|
559
570
|
}
|
|
560
571
|
|
|
561
|
-
export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions):
|
|
562
|
-
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'})`)
|
|
563
574
|
|
|
564
|
-
const graphqlSchemaObj = buildSchema(SDL)
|
|
565
|
-
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[]
|
|
566
578
|
|
|
567
579
|
return generateClient(introspectionTypes, options)
|
|
568
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',
|