@graphql-codegen/typescript-solid-query 1.0.0-alpha-20240201110240-bdef5b40fe364d6a5b0276786062c582bd60d3cc
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/cjs/config.js +0 -0
- package/cjs/fetcher-custom-mapper.js +82 -0
- package/cjs/fetcher-fetch-hardcoded.js +81 -0
- package/cjs/fetcher-fetch.js +76 -0
- package/cjs/fetcher-graphql-request.js +123 -0
- package/cjs/fetcher.js +191 -0
- package/cjs/index.js +47 -0
- package/cjs/package.json +1 -0
- package/cjs/visitor.js +157 -0
- package/esm/config.js +0 -0
- package/esm/fetcher-custom-mapper.js +77 -0
- package/esm/fetcher-fetch-hardcoded.js +76 -0
- package/esm/fetcher-fetch.js +71 -0
- package/esm/fetcher-graphql-request.js +118 -0
- package/esm/fetcher.js +186 -0
- package/esm/index.js +42 -0
- package/esm/visitor.js +152 -0
- package/package.json +48 -0
- package/typings/config.d.cts +115 -0
- package/typings/config.d.ts +115 -0
- package/typings/fetcher-custom-mapper.d.cts +15 -0
- package/typings/fetcher-custom-mapper.d.ts +15 -0
- package/typings/fetcher-fetch-hardcoded.d.cts +15 -0
- package/typings/fetcher-fetch-hardcoded.d.ts +15 -0
- package/typings/fetcher-fetch.d.cts +11 -0
- package/typings/fetcher-fetch.d.ts +11 -0
- package/typings/fetcher-graphql-request.d.cts +13 -0
- package/typings/fetcher-graphql-request.d.ts +13 -0
- package/typings/fetcher.d.cts +75 -0
- package/typings/fetcher.d.ts +75 -0
- package/typings/index.d.cts +6 -0
- package/typings/index.d.ts +6 -0
- package/typings/visitor.d.cts +21 -0
- package/typings/visitor.d.ts +21 -0
package/esm/fetcher.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import autoBind from 'auto-bind';
|
|
2
|
+
export class FetcherRenderer {
|
|
3
|
+
constructor(visitor) {
|
|
4
|
+
this.visitor = visitor;
|
|
5
|
+
autoBind(this);
|
|
6
|
+
}
|
|
7
|
+
createQueryMethodMap(isSuspense = false) {
|
|
8
|
+
const suspenseText = isSuspense ? 'Suspense' : '';
|
|
9
|
+
const queryMethodMap = {
|
|
10
|
+
infiniteQuery: {
|
|
11
|
+
getHook: (operationName = 'Query') => `create${suspenseText}Infinite${operationName}`,
|
|
12
|
+
getOptions: () => `Create${suspenseText}InfiniteQueryOptions`,
|
|
13
|
+
getOtherTypes: () => ({ infiniteData: 'InfiniteData' }),
|
|
14
|
+
},
|
|
15
|
+
query: {
|
|
16
|
+
getHook: (operationName = 'Query') => `create${suspenseText}${operationName}`,
|
|
17
|
+
getOptions: () => `Create${suspenseText}QueryOptions`,
|
|
18
|
+
},
|
|
19
|
+
mutation: {
|
|
20
|
+
getHook: (operationName = 'Mutation') => `create${operationName}`,
|
|
21
|
+
getOptions: () => `CreateMutationOptions`,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
return queryMethodMap;
|
|
25
|
+
}
|
|
26
|
+
generateInfiniteQueryHelper(config, isSuspense) {
|
|
27
|
+
const { operationResultType, operationName } = config;
|
|
28
|
+
const { infiniteQuery } = this.createQueryMethodMap(isSuspense);
|
|
29
|
+
this.visitor.solidQueryHookIdentifiersInUse.add(infiniteQuery.getHook());
|
|
30
|
+
this.visitor.solidQueryOptionsIdentifiersInUse.add(infiniteQuery.getOptions());
|
|
31
|
+
this.visitor.solidQueryOptionsIdentifiersInUse.add(infiniteQuery.getOtherTypes().infiniteData);
|
|
32
|
+
const variables = this.generateInfiniteQueryVariablesSignature(config);
|
|
33
|
+
const options = this.generateInfiniteQueryOptionsSignature(config, isSuspense);
|
|
34
|
+
const generateBaseInfiniteQueryHook = (hookConfig) => {
|
|
35
|
+
const { implArguments, implHookOuter = '', implFetcher } = hookConfig;
|
|
36
|
+
const argumentsResult = implArguments !== null && implArguments !== void 0 ? implArguments : `
|
|
37
|
+
${variables},
|
|
38
|
+
${options}
|
|
39
|
+
`;
|
|
40
|
+
return `export const ${infiniteQuery.getHook(operationName)} = <
|
|
41
|
+
TData = ${`${infiniteQuery.getOtherTypes().infiniteData}<${operationResultType}>`},
|
|
42
|
+
TError = ${this.visitor.config.errorType}
|
|
43
|
+
>(${argumentsResult}) => {
|
|
44
|
+
${implHookOuter}
|
|
45
|
+
return ${infiniteQuery.getHook()}<${operationResultType}, TError, TData>(
|
|
46
|
+
${this.generateInfiniteQueryFormattedParameters(this.generateInfiniteQueryKey(config, isSuspense), implFetcher)}
|
|
47
|
+
)};`;
|
|
48
|
+
};
|
|
49
|
+
return { generateBaseInfiniteQueryHook, variables, options };
|
|
50
|
+
}
|
|
51
|
+
generateQueryHelper(config, isSuspense) {
|
|
52
|
+
const { operationName, operationResultType } = config;
|
|
53
|
+
const { query } = this.createQueryMethodMap(isSuspense);
|
|
54
|
+
this.visitor.solidQueryHookIdentifiersInUse.add(query.getHook());
|
|
55
|
+
this.visitor.solidQueryOptionsIdentifiersInUse.add(query.getOptions());
|
|
56
|
+
const variables = this.generateQueryVariablesSignature(config);
|
|
57
|
+
const options = this.generateQueryOptionsSignature(config, isSuspense);
|
|
58
|
+
const generateBaseQueryHook = (hookConfig) => {
|
|
59
|
+
const { implArguments, implHookOuter = '', implFetcher } = hookConfig;
|
|
60
|
+
const argumentsResult = implArguments !== null && implArguments !== void 0 ? implArguments : `
|
|
61
|
+
${variables},
|
|
62
|
+
${options}
|
|
63
|
+
`;
|
|
64
|
+
return `export const ${query.getHook(operationName)} = <
|
|
65
|
+
TData = ${operationResultType},
|
|
66
|
+
TError = ${this.visitor.config.errorType}
|
|
67
|
+
>(${argumentsResult}) => {
|
|
68
|
+
${implHookOuter}
|
|
69
|
+
return ${query.getHook()}<${operationResultType}, TError, TData>(
|
|
70
|
+
${this.generateQueryFormattedParameters(this.generateQueryKey(config, isSuspense), implFetcher)}
|
|
71
|
+
)};`;
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
generateBaseQueryHook,
|
|
75
|
+
variables,
|
|
76
|
+
options,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
generateMutationHelper(config) {
|
|
80
|
+
const { operationResultType, operationVariablesTypes, operationName } = config;
|
|
81
|
+
const { mutation } = this.createQueryMethodMap();
|
|
82
|
+
this.visitor.solidQueryHookIdentifiersInUse.add(mutation.getHook());
|
|
83
|
+
this.visitor.solidQueryOptionsIdentifiersInUse.add(mutation.getOptions());
|
|
84
|
+
const variables = `variables?: ${operationVariablesTypes}`;
|
|
85
|
+
const options = `options?: ${mutation.getOptions()}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>`;
|
|
86
|
+
const generateBaseMutationHook = (hookConfig) => {
|
|
87
|
+
const { implArguments, implHookOuter = '', implFetcher } = hookConfig;
|
|
88
|
+
const argumentsResult = implArguments !== null && implArguments !== void 0 ? implArguments : `${options}`;
|
|
89
|
+
return `export const ${mutation.getHook(operationName)} = <
|
|
90
|
+
TError = ${this.visitor.config.errorType},
|
|
91
|
+
TContext = unknown
|
|
92
|
+
>(${argumentsResult}) => {
|
|
93
|
+
${implHookOuter}
|
|
94
|
+
return ${mutation.getHook()}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
|
|
95
|
+
${this.generateMutationFormattedParameters(this.generateMutationKey(config), implFetcher)}
|
|
96
|
+
)};`;
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
generateBaseMutationHook,
|
|
100
|
+
variables,
|
|
101
|
+
options,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
generateQueryVariablesSignature({ hasRequiredVariables, operationVariablesTypes, }) {
|
|
105
|
+
return `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
|
|
106
|
+
}
|
|
107
|
+
generateQueryOptionsSignature({ operationResultType }, isSuspense) {
|
|
108
|
+
const { query } = this.createQueryMethodMap(isSuspense);
|
|
109
|
+
return `options?: Omit<${query.getOptions()}<${operationResultType}, TError, TData>, 'queryKey'> & { queryKey?: ${query.getOptions()}<${operationResultType}, TError, TData>['queryKey'] }`;
|
|
110
|
+
}
|
|
111
|
+
generateInfiniteQueryVariablesSignature(config) {
|
|
112
|
+
return `variables: ${config.operationVariablesTypes}`;
|
|
113
|
+
}
|
|
114
|
+
generateInfiniteQueryOptionsSignature({ operationResultType }, isSuspense) {
|
|
115
|
+
const { infiniteQuery } = this.createQueryMethodMap(isSuspense);
|
|
116
|
+
return `options: Omit<${infiniteQuery.getOptions()}<${operationResultType}, TError, TData>, 'queryKey'> & { queryKey?: ${infiniteQuery.getOptions()}<${operationResultType}, TError, TData>['queryKey'] }`;
|
|
117
|
+
}
|
|
118
|
+
generateInfiniteQueryKey(config, isSuspense) {
|
|
119
|
+
const identifier = isSuspense ? 'infiniteSuspense' : 'infinite';
|
|
120
|
+
if (config.hasRequiredVariables)
|
|
121
|
+
return `['${config.node.name.value}.${identifier}', variables]`;
|
|
122
|
+
return `variables === undefined ? ['${config.node.name.value}.${identifier}'] : ['${config.node.name.value}.${identifier}', variables]`;
|
|
123
|
+
}
|
|
124
|
+
generateInfiniteQueryOutput(config, isSuspense = false) {
|
|
125
|
+
const { infiniteQuery } = this.createQueryMethodMap(isSuspense);
|
|
126
|
+
const signature = this.generateQueryVariablesSignature(config);
|
|
127
|
+
const { operationName, node } = config;
|
|
128
|
+
return {
|
|
129
|
+
hook: this.generateInfiniteQueryHook(config, isSuspense),
|
|
130
|
+
getKey: `${infiniteQuery.getHook(operationName)}.getKey = (${signature}) => ${this.generateInfiniteQueryKey(config, isSuspense)};`,
|
|
131
|
+
rootKey: `${infiniteQuery.getHook(operationName)}.rootKey = '${node.name.value}.infinite';`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
generateQueryKey(config, isSuspense) {
|
|
135
|
+
const identifier = isSuspense ? `${config.node.name.value}Suspense` : config.node.name.value;
|
|
136
|
+
if (config.hasRequiredVariables)
|
|
137
|
+
return `['${identifier}', variables]`;
|
|
138
|
+
return `variables === undefined ? ['${identifier}'] : ['${identifier}', variables]`;
|
|
139
|
+
}
|
|
140
|
+
generateQueryOutput(config, isSuspense = false) {
|
|
141
|
+
const { query } = this.createQueryMethodMap(isSuspense);
|
|
142
|
+
const signature = this.generateQueryVariablesSignature(config);
|
|
143
|
+
const { operationName, node, documentVariableName } = config;
|
|
144
|
+
return {
|
|
145
|
+
hook: this.generateQueryHook(config, isSuspense),
|
|
146
|
+
document: `${query.getHook(operationName)}.document = ${documentVariableName};`,
|
|
147
|
+
getKey: `${query.getHook(operationName)}.getKey = (${signature}) => ${this.generateQueryKey(config, isSuspense)};`,
|
|
148
|
+
rootKey: `${query.getHook(operationName)}.rootKey = '${node.name.value}';`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
generateMutationKey({ node }) {
|
|
152
|
+
return `['${node.name.value}']`;
|
|
153
|
+
}
|
|
154
|
+
generateMutationOutput(config) {
|
|
155
|
+
const { mutation } = this.createQueryMethodMap();
|
|
156
|
+
const { operationName } = config;
|
|
157
|
+
return {
|
|
158
|
+
hook: this.generateMutationHook(config),
|
|
159
|
+
getKey: `${mutation.getHook(operationName)}.getKey = () => ${this.generateMutationKey(config)};`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
generateInfiniteQueryFormattedParameters(queryKey, queryFn) {
|
|
163
|
+
return `(() => {
|
|
164
|
+
const { queryKey: optionsQueryKey, ...restOptions } = options;
|
|
165
|
+
return () => ({
|
|
166
|
+
queryKey: optionsQueryKey ?? ${queryKey},
|
|
167
|
+
queryFn: ${queryFn},
|
|
168
|
+
...restOptions
|
|
169
|
+
}
|
|
170
|
+
}))()`;
|
|
171
|
+
}
|
|
172
|
+
generateQueryFormattedParameters(queryKey, queryFn) {
|
|
173
|
+
return `() => ({
|
|
174
|
+
queryKey: ${queryKey},
|
|
175
|
+
queryFn: ${queryFn},
|
|
176
|
+
...options
|
|
177
|
+
})`;
|
|
178
|
+
}
|
|
179
|
+
generateMutationFormattedParameters(mutationKey, mutationFn) {
|
|
180
|
+
return `() => ({
|
|
181
|
+
mutationKey: ${mutationKey},
|
|
182
|
+
mutationFn: ${mutationFn},
|
|
183
|
+
...options
|
|
184
|
+
})`;
|
|
185
|
+
}
|
|
186
|
+
}
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { extname } from 'path';
|
|
2
|
+
import { concatAST, Kind } from 'graphql';
|
|
3
|
+
import { oldVisit } from '@graphql-codegen/plugin-helpers';
|
|
4
|
+
import { SolidQueryVisitor } from './visitor.js';
|
|
5
|
+
export const plugin = (schema, documents, config) => {
|
|
6
|
+
const allAst = concatAST(documents.map(v => v.document));
|
|
7
|
+
const allFragments = [
|
|
8
|
+
...allAst.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION).map(fragmentDef => ({
|
|
9
|
+
node: fragmentDef,
|
|
10
|
+
name: fragmentDef.name.value,
|
|
11
|
+
onType: fragmentDef.typeCondition.name.value,
|
|
12
|
+
isExternal: false,
|
|
13
|
+
})),
|
|
14
|
+
...(config.externalFragments || []),
|
|
15
|
+
];
|
|
16
|
+
const visitor = new SolidQueryVisitor(schema, allFragments, config, documents);
|
|
17
|
+
const visitorResult = oldVisit(allAst, { leave: visitor });
|
|
18
|
+
if (visitor.hasOperations) {
|
|
19
|
+
return {
|
|
20
|
+
prepend: [...visitor.getImports(), visitor.getFetcherImplementation()],
|
|
21
|
+
content: [
|
|
22
|
+
'',
|
|
23
|
+
visitor.fragments,
|
|
24
|
+
...visitorResult.definitions.filter(t => typeof t === 'string'),
|
|
25
|
+
].join('\n'),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
prepend: [...visitor.getImports()],
|
|
30
|
+
content: [
|
|
31
|
+
'',
|
|
32
|
+
visitor.fragments,
|
|
33
|
+
...visitorResult.definitions.filter(t => typeof t === 'string'),
|
|
34
|
+
].join('\n'),
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export const validate = async (schema, documents, config, outputFile) => {
|
|
38
|
+
if (extname(outputFile) !== '.ts' && extname(outputFile) !== '.tsx') {
|
|
39
|
+
throw new Error(`Plugin "typescript-solid-query" requires extension to be ".ts" or ".tsx"!`);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export { SolidQueryVisitor };
|
package/esm/visitor.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import autoBind from 'auto-bind';
|
|
2
|
+
import { pascalCase } from 'change-case-all';
|
|
3
|
+
import { ClientSideBaseVisitor, DocumentMode, getConfigValue, } from '@graphql-codegen/visitor-plugin-common';
|
|
4
|
+
import { CustomMapperFetcher } from './fetcher-custom-mapper.js';
|
|
5
|
+
import { HardcodedFetchFetcher } from './fetcher-fetch-hardcoded.js';
|
|
6
|
+
import { FetchFetcher } from './fetcher-fetch.js';
|
|
7
|
+
import { GraphQLRequestClientFetcher } from './fetcher-graphql-request.js';
|
|
8
|
+
export class SolidQueryVisitor extends ClientSideBaseVisitor {
|
|
9
|
+
constructor(schema, fragments, rawConfig, documents) {
|
|
10
|
+
super(schema, fragments, rawConfig, {
|
|
11
|
+
documentMode: DocumentMode.string,
|
|
12
|
+
errorType: getConfigValue(rawConfig.errorType, 'unknown'),
|
|
13
|
+
exposeDocument: getConfigValue(rawConfig.exposeDocument, false),
|
|
14
|
+
exposeQueryKeys: getConfigValue(rawConfig.exposeQueryKeys, false),
|
|
15
|
+
exposeQueryRootKeys: getConfigValue(rawConfig.exposeQueryRootKeys, false),
|
|
16
|
+
exposeMutationKeys: getConfigValue(rawConfig.exposeMutationKeys, false),
|
|
17
|
+
exposeFetcher: getConfigValue(rawConfig.exposeFetcher, false),
|
|
18
|
+
addInfiniteQuery: getConfigValue(rawConfig.addInfiniteQuery, false),
|
|
19
|
+
addSuspenseQuery: getConfigValue(rawConfig.addSuspenseQuery, false),
|
|
20
|
+
solidQueryImportFrom: getConfigValue(rawConfig.solidQueryImportFrom, ''),
|
|
21
|
+
});
|
|
22
|
+
this.rawConfig = rawConfig;
|
|
23
|
+
this.solidQueryHookIdentifiersInUse = new Set();
|
|
24
|
+
this.solidQueryOptionsIdentifiersInUse = new Set();
|
|
25
|
+
this._externalImportPrefix = this.config.importOperationTypesFrom
|
|
26
|
+
? `${this.config.importOperationTypesFrom}.`
|
|
27
|
+
: '';
|
|
28
|
+
this._documents = documents;
|
|
29
|
+
this.fetcher = this.createFetcher(rawConfig.fetcher || 'fetch');
|
|
30
|
+
autoBind(this);
|
|
31
|
+
}
|
|
32
|
+
get imports() {
|
|
33
|
+
return this._imports;
|
|
34
|
+
}
|
|
35
|
+
createFetcher(raw) {
|
|
36
|
+
if (raw === 'fetch') {
|
|
37
|
+
return new FetchFetcher(this);
|
|
38
|
+
}
|
|
39
|
+
if (typeof raw === 'object' && 'endpoint' in raw) {
|
|
40
|
+
return new HardcodedFetchFetcher(this, raw);
|
|
41
|
+
}
|
|
42
|
+
if (raw === 'graphql-request' || (typeof raw === 'object' && 'clientImportPath' in raw)) {
|
|
43
|
+
return new GraphQLRequestClientFetcher(this, raw);
|
|
44
|
+
}
|
|
45
|
+
return new CustomMapperFetcher(this, raw);
|
|
46
|
+
}
|
|
47
|
+
get hasOperations() {
|
|
48
|
+
return this._collectedOperations.length > 0;
|
|
49
|
+
}
|
|
50
|
+
getImports() {
|
|
51
|
+
const baseImports = super.getImports();
|
|
52
|
+
if (!this.hasOperations) {
|
|
53
|
+
return baseImports;
|
|
54
|
+
}
|
|
55
|
+
const hookAndTypeImports = [
|
|
56
|
+
...Array.from(this.solidQueryHookIdentifiersInUse),
|
|
57
|
+
...Array.from(this.solidQueryOptionsIdentifiersInUse).map(identifier => `${this.config.useTypeImports ? 'type ' : ''}${identifier}`),
|
|
58
|
+
];
|
|
59
|
+
const moduleName = this.config.solidQueryImportFrom
|
|
60
|
+
? this.config.solidQueryImportFrom
|
|
61
|
+
: '@tanstack/solid-query';
|
|
62
|
+
return [...baseImports, `import { ${hookAndTypeImports.join(', ')} } from '${moduleName}';`];
|
|
63
|
+
}
|
|
64
|
+
getFetcherImplementation() {
|
|
65
|
+
return this.fetcher.generateFetcherImplementation();
|
|
66
|
+
}
|
|
67
|
+
_getHookSuffix(name, operationType) {
|
|
68
|
+
if (this.config.omitOperationSuffix) {
|
|
69
|
+
return '';
|
|
70
|
+
}
|
|
71
|
+
if (!this.config.dedupeOperationSuffix) {
|
|
72
|
+
return pascalCase(operationType);
|
|
73
|
+
}
|
|
74
|
+
if (name.includes('Query') || name.includes('Mutation') || name.includes('Subscription')) {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
return pascalCase(operationType);
|
|
78
|
+
}
|
|
79
|
+
buildOperation(node, documentVariableName, operationType, operationResultType, operationVariablesTypes, hasRequiredVariables) {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
|
|
82
|
+
const suffix = this._getHookSuffix(nodeName, operationType);
|
|
83
|
+
const operationName = this.convertName(nodeName, {
|
|
84
|
+
suffix,
|
|
85
|
+
useTypesPrefix: false,
|
|
86
|
+
useTypesSuffix: false,
|
|
87
|
+
});
|
|
88
|
+
const generateConfig = {
|
|
89
|
+
node,
|
|
90
|
+
documentVariableName,
|
|
91
|
+
operationResultType,
|
|
92
|
+
operationVariablesTypes,
|
|
93
|
+
hasRequiredVariables,
|
|
94
|
+
operationName,
|
|
95
|
+
};
|
|
96
|
+
operationResultType = this._externalImportPrefix + operationResultType;
|
|
97
|
+
operationVariablesTypes = this._externalImportPrefix + operationVariablesTypes;
|
|
98
|
+
const queries = [];
|
|
99
|
+
const getOutputFromQueries = () => `\n${queries.join('\n\n')}\n`;
|
|
100
|
+
if (operationType === 'Query') {
|
|
101
|
+
const addQuery = (generateConfig, isSuspense = false) => {
|
|
102
|
+
const { hook, getKey, rootKey, document } = this.fetcher.generateQueryOutput(generateConfig, isSuspense);
|
|
103
|
+
queries.push(hook);
|
|
104
|
+
if (this.config.exposeDocument)
|
|
105
|
+
queries.push(document);
|
|
106
|
+
if (this.config.exposeQueryKeys)
|
|
107
|
+
queries.push(getKey);
|
|
108
|
+
if (this.config.exposeQueryRootKeys)
|
|
109
|
+
queries.push(rootKey);
|
|
110
|
+
};
|
|
111
|
+
addQuery(generateConfig);
|
|
112
|
+
if (this.config.addSuspenseQuery)
|
|
113
|
+
addQuery(generateConfig, true);
|
|
114
|
+
if (this.config.addInfiniteQuery) {
|
|
115
|
+
const addInfiniteQuery = (generateConfig, isSuspense = false) => {
|
|
116
|
+
const { hook, getKey, rootKey } = this.fetcher.generateInfiniteQueryOutput(generateConfig, isSuspense);
|
|
117
|
+
queries.push(hook);
|
|
118
|
+
if (this.config.exposeQueryKeys)
|
|
119
|
+
queries.push(getKey);
|
|
120
|
+
if (this.config.exposeQueryRootKeys)
|
|
121
|
+
queries.push(rootKey);
|
|
122
|
+
};
|
|
123
|
+
addInfiniteQuery(generateConfig);
|
|
124
|
+
if (this.config.addSuspenseQuery) {
|
|
125
|
+
addInfiniteQuery(generateConfig, true);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// The reason we're looking at the private field of the CustomMapperFetcher to see if it's a solid hook
|
|
129
|
+
// is to prevent calling generateFetcherFetch for each query since all the queries won't be able to generate
|
|
130
|
+
// a fetcher field anyways.
|
|
131
|
+
if (this.config.exposeFetcher && !this.fetcher._isSolidHook) {
|
|
132
|
+
queries.push(this.fetcher.generateFetcherFetch(generateConfig));
|
|
133
|
+
}
|
|
134
|
+
return getOutputFromQueries();
|
|
135
|
+
}
|
|
136
|
+
if (operationType === 'Mutation') {
|
|
137
|
+
const { hook, getKey } = this.fetcher.generateMutationOutput(generateConfig);
|
|
138
|
+
queries.push(hook);
|
|
139
|
+
if (this.config.exposeMutationKeys)
|
|
140
|
+
queries.push(getKey);
|
|
141
|
+
if (this.config.exposeFetcher && !this.fetcher._isSolidHook) {
|
|
142
|
+
queries.push(this.fetcher.generateFetcherFetch(generateConfig));
|
|
143
|
+
}
|
|
144
|
+
return getOutputFromQueries();
|
|
145
|
+
}
|
|
146
|
+
if (operationType === 'Subscription') {
|
|
147
|
+
// eslint-disable-next-line no-console
|
|
148
|
+
console.warn(`Plugin "typescript-solid-query" does not support GraphQL Subscriptions at the moment! Ignoring "${node.name.value}"...`);
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@graphql-codegen/typescript-solid-query",
|
|
3
|
+
"version": "1.0.0-alpha-20240201110240-bdef5b40fe364d6a5b0276786062c582bd60d3cc",
|
|
4
|
+
"description": "GraphQL Code Generator plugin for generating a ready-to-use Solid-Query Hooks based on GraphQL operations",
|
|
5
|
+
"peerDependencies": {
|
|
6
|
+
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@graphql-codegen/plugin-helpers": "^3.0.0",
|
|
10
|
+
"@graphql-codegen/visitor-plugin-common": "2.13.1",
|
|
11
|
+
"auto-bind": "~4.0.0",
|
|
12
|
+
"change-case-all": "1.0.15",
|
|
13
|
+
"tslib": "~2.6.0"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/dotansimha/graphql-code-generator-community.git",
|
|
18
|
+
"directory": "packages/plugins/typescript/solid-query"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">= 18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"main": "cjs/index.js",
|
|
25
|
+
"module": "esm/index.js",
|
|
26
|
+
"typings": "typings/index.d.ts",
|
|
27
|
+
"typescript": {
|
|
28
|
+
"definition": "typings/index.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"type": "module",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"require": {
|
|
34
|
+
"types": "./typings/index.d.cts",
|
|
35
|
+
"default": "./cjs/index.js"
|
|
36
|
+
},
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./typings/index.d.ts",
|
|
39
|
+
"default": "./esm/index.js"
|
|
40
|
+
},
|
|
41
|
+
"default": {
|
|
42
|
+
"types": "./typings/index.d.ts",
|
|
43
|
+
"default": "./esm/index.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { RawClientSideBasePluginConfig } from '@graphql-codegen/visitor-plugin-common';
|
|
2
|
+
export type HardcodedFetch = {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
fetchParams?: string | Record<string, any>;
|
|
5
|
+
};
|
|
6
|
+
export type CustomFetch = {
|
|
7
|
+
func: string;
|
|
8
|
+
isSolidHook?: boolean;
|
|
9
|
+
} | string;
|
|
10
|
+
export type GraphQlRequest = 'graphql-request' | {
|
|
11
|
+
clientImportPath: string;
|
|
12
|
+
};
|
|
13
|
+
export interface BaseSolidQueryPluginConfig {
|
|
14
|
+
/**
|
|
15
|
+
* @default unknown
|
|
16
|
+
* @description Changes the default "TError" generic type.
|
|
17
|
+
*/
|
|
18
|
+
errorType?: string;
|
|
19
|
+
/**
|
|
20
|
+
* @default false
|
|
21
|
+
* @description For each generate query hook adds `document` field with a
|
|
22
|
+
* corresponding GraphQL query. Useful for `queryClient.fetchQuery`.
|
|
23
|
+
* @exampleMarkdown
|
|
24
|
+
* ```ts
|
|
25
|
+
* queryClient.fetchQuery(
|
|
26
|
+
* useUserDetailsQuery.getKey(variables),
|
|
27
|
+
* () => gqlRequest(useUserDetailsQuery.document, variables)
|
|
28
|
+
* )
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
exposeDocument?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* @default false
|
|
34
|
+
* @description For each generate query hook adds getKey(variables: QueryVariables) function. Useful for cache updates. If addInfiniteQuery is true, it will also add a getKey function to each infinite query.
|
|
35
|
+
* @exampleMarkdown
|
|
36
|
+
* ```ts
|
|
37
|
+
* const query = useUserDetailsQuery(...)
|
|
38
|
+
* const key = useUserDetailsQuery.getKey({ id: theUsersId })
|
|
39
|
+
* // use key in a cache update after a mutation
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
exposeQueryKeys?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* @default false
|
|
45
|
+
* @description For each generate query hook adds rootKey. Useful for cache updates.
|
|
46
|
+
* @exampleMarkdown
|
|
47
|
+
* ```ts
|
|
48
|
+
* const query = useUserDetailsQuery(...)
|
|
49
|
+
* const key = useUserDetailsQuery.rootKey
|
|
50
|
+
* // use key in a cache update after a mutation
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
exposeQueryRootKeys?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* @default false
|
|
56
|
+
* @description For each generate mutation hook adds getKey() function. Useful for call outside of functional component.
|
|
57
|
+
* @exampleMarkdown
|
|
58
|
+
* ```ts
|
|
59
|
+
* const mutation = useUserDetailsMutation(...)
|
|
60
|
+
* const key = useUserDetailsMutation.getKey()
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
exposeMutationKeys?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* @default false
|
|
66
|
+
* @description For each generate query hook adds `fetcher` field with a corresponding GraphQL query using the fetcher.
|
|
67
|
+
* It is useful for `queryClient.fetchQuery` and `queryClient.prefetchQuery`.
|
|
68
|
+
* @exampleMarkdown
|
|
69
|
+
* ```ts
|
|
70
|
+
* await queryClient.prefetchQuery(userQuery.getKey(), () => userQuery.fetcher())
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
exposeFetcher?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* @default false
|
|
76
|
+
* @description Adds an Infinite Query along side the standard one
|
|
77
|
+
*/
|
|
78
|
+
addInfiniteQuery?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* @default false
|
|
81
|
+
* @description Adds a Suspense Query along side the standard one
|
|
82
|
+
*/
|
|
83
|
+
addSuspenseQuery?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* @default empty
|
|
86
|
+
* @description Add custom import for solid-query.
|
|
87
|
+
* It can be used to import from `@tanstack/solid-query` instead of `solid-query`. But make sure it include createQuery, CreateQueryOptions, createMutation, CreateMutationOptions, createInfiniteQuery, CreateInfiniteQueryOptions
|
|
88
|
+
*
|
|
89
|
+
* The following options are available to use:
|
|
90
|
+
*
|
|
91
|
+
* - "src/your-own-solid-query-customized": import { createQuery, CreateQueryOptions, createMutation, CreateMutationOptions, createInfiniteQuery, CreateInfiniteQueryOptions } from your own solid-query customized package.
|
|
92
|
+
*/
|
|
93
|
+
solidQueryImportFrom?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @description This plugin generates `Solid-Query` Hooks with TypeScript typings.
|
|
97
|
+
*
|
|
98
|
+
* It extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.
|
|
99
|
+
*
|
|
100
|
+
* > **If you are using the `solid-query` package instead of the `@tanstack/solid-query` package in your project, please set the `legacyMode` option to `true`.**
|
|
101
|
+
*
|
|
102
|
+
*/
|
|
103
|
+
export interface SolidQueryRawPluginConfig extends Omit<RawClientSideBasePluginConfig, 'documentMode' | 'noGraphQLTag' | 'gqlImport' | 'documentNodeImport' | 'noExport' | 'importOperationTypesFrom' | 'importDocumentNodeExternallyFrom' | 'useTypeImports' | 'legacyMode'>, BaseSolidQueryPluginConfig {
|
|
104
|
+
/**
|
|
105
|
+
* @description Customize the fetcher you wish to use in the generated file. Solid-Query is agnostic to the data-fetching layer, so you should provide it, or use a custom one.
|
|
106
|
+
*
|
|
107
|
+
* The following options are available to use:
|
|
108
|
+
*
|
|
109
|
+
* - 'fetch' - requires you to specify endpoint and headers on each call, and uses `fetch` to do the actual http call.
|
|
110
|
+
* - `{ endpoint: string, fetchParams: RequestInit }`: hardcode your endpoint and fetch options into the generated output, using the environment `fetch` method. You can also use `process.env.MY_VAR` as endpoint or header value.
|
|
111
|
+
* - `file#identifier` - You can use custom fetcher method that should implement the exported `SolidQueryFetcher` interface. Example: `./my-fetcher#myCustomFetcher`.
|
|
112
|
+
* - `graphql-request`: Will generate each hook with `client` argument, where you should pass your own `GraphQLClient` (created from `graphql-request`).
|
|
113
|
+
*/
|
|
114
|
+
fetcher?: 'fetch' | HardcodedFetch | GraphQlRequest | CustomFetch;
|
|
115
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { RawClientSideBasePluginConfig } from '@graphql-codegen/visitor-plugin-common';
|
|
2
|
+
export type HardcodedFetch = {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
fetchParams?: string | Record<string, any>;
|
|
5
|
+
};
|
|
6
|
+
export type CustomFetch = {
|
|
7
|
+
func: string;
|
|
8
|
+
isSolidHook?: boolean;
|
|
9
|
+
} | string;
|
|
10
|
+
export type GraphQlRequest = 'graphql-request' | {
|
|
11
|
+
clientImportPath: string;
|
|
12
|
+
};
|
|
13
|
+
export interface BaseSolidQueryPluginConfig {
|
|
14
|
+
/**
|
|
15
|
+
* @default unknown
|
|
16
|
+
* @description Changes the default "TError" generic type.
|
|
17
|
+
*/
|
|
18
|
+
errorType?: string;
|
|
19
|
+
/**
|
|
20
|
+
* @default false
|
|
21
|
+
* @description For each generate query hook adds `document` field with a
|
|
22
|
+
* corresponding GraphQL query. Useful for `queryClient.fetchQuery`.
|
|
23
|
+
* @exampleMarkdown
|
|
24
|
+
* ```ts
|
|
25
|
+
* queryClient.fetchQuery(
|
|
26
|
+
* useUserDetailsQuery.getKey(variables),
|
|
27
|
+
* () => gqlRequest(useUserDetailsQuery.document, variables)
|
|
28
|
+
* )
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
exposeDocument?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* @default false
|
|
34
|
+
* @description For each generate query hook adds getKey(variables: QueryVariables) function. Useful for cache updates. If addInfiniteQuery is true, it will also add a getKey function to each infinite query.
|
|
35
|
+
* @exampleMarkdown
|
|
36
|
+
* ```ts
|
|
37
|
+
* const query = useUserDetailsQuery(...)
|
|
38
|
+
* const key = useUserDetailsQuery.getKey({ id: theUsersId })
|
|
39
|
+
* // use key in a cache update after a mutation
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
exposeQueryKeys?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* @default false
|
|
45
|
+
* @description For each generate query hook adds rootKey. Useful for cache updates.
|
|
46
|
+
* @exampleMarkdown
|
|
47
|
+
* ```ts
|
|
48
|
+
* const query = useUserDetailsQuery(...)
|
|
49
|
+
* const key = useUserDetailsQuery.rootKey
|
|
50
|
+
* // use key in a cache update after a mutation
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
exposeQueryRootKeys?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* @default false
|
|
56
|
+
* @description For each generate mutation hook adds getKey() function. Useful for call outside of functional component.
|
|
57
|
+
* @exampleMarkdown
|
|
58
|
+
* ```ts
|
|
59
|
+
* const mutation = useUserDetailsMutation(...)
|
|
60
|
+
* const key = useUserDetailsMutation.getKey()
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
exposeMutationKeys?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* @default false
|
|
66
|
+
* @description For each generate query hook adds `fetcher` field with a corresponding GraphQL query using the fetcher.
|
|
67
|
+
* It is useful for `queryClient.fetchQuery` and `queryClient.prefetchQuery`.
|
|
68
|
+
* @exampleMarkdown
|
|
69
|
+
* ```ts
|
|
70
|
+
* await queryClient.prefetchQuery(userQuery.getKey(), () => userQuery.fetcher())
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
exposeFetcher?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* @default false
|
|
76
|
+
* @description Adds an Infinite Query along side the standard one
|
|
77
|
+
*/
|
|
78
|
+
addInfiniteQuery?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* @default false
|
|
81
|
+
* @description Adds a Suspense Query along side the standard one
|
|
82
|
+
*/
|
|
83
|
+
addSuspenseQuery?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* @default empty
|
|
86
|
+
* @description Add custom import for solid-query.
|
|
87
|
+
* It can be used to import from `@tanstack/solid-query` instead of `solid-query`. But make sure it include createQuery, CreateQueryOptions, createMutation, CreateMutationOptions, createInfiniteQuery, CreateInfiniteQueryOptions
|
|
88
|
+
*
|
|
89
|
+
* The following options are available to use:
|
|
90
|
+
*
|
|
91
|
+
* - "src/your-own-solid-query-customized": import { createQuery, CreateQueryOptions, createMutation, CreateMutationOptions, createInfiniteQuery, CreateInfiniteQueryOptions } from your own solid-query customized package.
|
|
92
|
+
*/
|
|
93
|
+
solidQueryImportFrom?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @description This plugin generates `Solid-Query` Hooks with TypeScript typings.
|
|
97
|
+
*
|
|
98
|
+
* It extends the basic TypeScript plugins: `@graphql-codegen/typescript`, `@graphql-codegen/typescript-operations` - and thus shares a similar configuration.
|
|
99
|
+
*
|
|
100
|
+
* > **If you are using the `solid-query` package instead of the `@tanstack/solid-query` package in your project, please set the `legacyMode` option to `true`.**
|
|
101
|
+
*
|
|
102
|
+
*/
|
|
103
|
+
export interface SolidQueryRawPluginConfig extends Omit<RawClientSideBasePluginConfig, 'documentMode' | 'noGraphQLTag' | 'gqlImport' | 'documentNodeImport' | 'noExport' | 'importOperationTypesFrom' | 'importDocumentNodeExternallyFrom' | 'useTypeImports' | 'legacyMode'>, BaseSolidQueryPluginConfig {
|
|
104
|
+
/**
|
|
105
|
+
* @description Customize the fetcher you wish to use in the generated file. Solid-Query is agnostic to the data-fetching layer, so you should provide it, or use a custom one.
|
|
106
|
+
*
|
|
107
|
+
* The following options are available to use:
|
|
108
|
+
*
|
|
109
|
+
* - 'fetch' - requires you to specify endpoint and headers on each call, and uses `fetch` to do the actual http call.
|
|
110
|
+
* - `{ endpoint: string, fetchParams: RequestInit }`: hardcode your endpoint and fetch options into the generated output, using the environment `fetch` method. You can also use `process.env.MY_VAR` as endpoint or header value.
|
|
111
|
+
* - `file#identifier` - You can use custom fetcher method that should implement the exported `SolidQueryFetcher` interface. Example: `./my-fetcher#myCustomFetcher`.
|
|
112
|
+
* - `graphql-request`: Will generate each hook with `client` argument, where you should pass your own `GraphQLClient` (created from `graphql-request`).
|
|
113
|
+
*/
|
|
114
|
+
fetcher?: 'fetch' | HardcodedFetch | GraphQlRequest | CustomFetch;
|
|
115
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CustomFetch } from './config.cjs';
|
|
2
|
+
import { FetcherRenderer, type GenerateConfig } from './fetcher.cjs';
|
|
3
|
+
import { SolidQueryVisitor } from './visitor.cjs';
|
|
4
|
+
export declare class CustomMapperFetcher extends FetcherRenderer {
|
|
5
|
+
protected visitor: SolidQueryVisitor;
|
|
6
|
+
private _mapper;
|
|
7
|
+
private _isSolidHook;
|
|
8
|
+
constructor(visitor: SolidQueryVisitor, customFetcher: CustomFetch);
|
|
9
|
+
private getFetcherFnName;
|
|
10
|
+
generateFetcherImplementation(): string;
|
|
11
|
+
generateInfiniteQueryHook(config: GenerateConfig, isSuspense?: boolean): string;
|
|
12
|
+
generateQueryHook(config: GenerateConfig, isSuspense?: boolean): string;
|
|
13
|
+
generateMutationHook(config: GenerateConfig): string;
|
|
14
|
+
generateFetcherFetch(config: GenerateConfig): string;
|
|
15
|
+
}
|