Skip to content

Commit 178cadd

Browse files
committed
feat: add support for --default-client-callbacks option for the createAPIOperationClient()
1 parent 877e563 commit 178cadd

File tree

7 files changed

+287
-136
lines changed

7 files changed

+287
-136
lines changed

packages/react-client/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"typecheck": "tsc --noEmit",
1111
"lint": "eslint",
1212
"clean": "rimraf dist/",
13-
"codegen": "openapi-qraft --plugin tanstack-query-react --plugin openapi-typescript ../test-fixtures/openapi.json -rm -o src/tests/fixtures/api --openapi-types-file-name openapi.ts --explicit-import-extensions --filter-services '/approval_policies/**,/entities/**,/files/**,!/internal/**' --operation-predefined-parameters '/approval_policies/{approval_policy_id}/**:header.x-monite-entity-id' '/entities/{entity_id}/documents:header.x-monite-version' --operation-name-modifier '/files/list:[a-zA-Z]+List ==> findAll' && yarn _prettify-api",
13+
"codegen": "openapi-qraft --plugin tanstack-query-react --plugin openapi-typescript ../test-fixtures/openapi.json -rm -o src/tests/fixtures/api --openapi-types-file-name openapi.ts --explicit-import-extensions --filter-services '/approval_policies/**,/entities/**,/files/**,!/internal/**' --default-client-callbacks all --operation-predefined-parameters '/approval_policies/{approval_policy_id}/**:header.x-monite-entity-id' '/entities/{entity_id}/documents:header.x-monite-version' --operation-name-modifier '/files/list:[a-zA-Z]+List ==> findAll' && yarn _prettify-api",
1414
"_prettify-api": "prettier --write src/tests/fixtures/api/**/*.ts"
1515
},
1616
"sideEffects": false,

packages/tanstack-query-react-plugin/src/generateCode.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface OutputOptions extends OutputOptionsBase {
2323
explicitImportExtensions: '.js' | '.ts' | undefined;
2424
exportSchemaTypes: boolean | undefined;
2525
operationPredefinedParameters: Array<PredefinedParametersGlob> | undefined;
26+
defaultClientCallbacks: string[] | ['all'] | ['none'] | undefined;
2627
}
2728

2829
export const generateCode = async ({
@@ -184,7 +185,11 @@ const generateOperationClient = async (spinner: Ora, output: OutputOptions) => {
184185
const operationClientFiles: GeneratorFile[] = [];
185186

186187
try {
187-
const code = astToString(getOperationClientFactory());
188+
const code = astToString(
189+
getOperationClientFactory({
190+
defaultClientCallbacks: output.defaultClientCallbacks,
191+
})
192+
);
188193

189194
operationClientFiles.push({
190195
file: new URL('create-api-operation-client.ts', output.dir),

packages/tanstack-query-react-plugin/src/plugin.ts

+33
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { Ora } from 'ora';
2+
import process from 'node:process';
13
import { fileHeader } from '@openapi-qraft/plugin/lib/fileHeader';
24
import {
35
createPredefinedParametersGlobs,
@@ -7,6 +9,7 @@ import { QraftCommand } from '@openapi-qraft/plugin/lib/QraftCommand';
79
import { QraftCommandPlugin } from '@openapi-qraft/plugin/lib/QraftCommandPlugin';
810
import { Option } from 'commander';
911
import { generateCode } from './generateCode.js';
12+
import { getAllAvailableCallbackNames } from './ts-factory/getCallbackNames.js';
1013

1114
export const plugin: QraftCommandPlugin = {
1215
setupCommand(command: QraftCommand) {
@@ -31,7 +34,17 @@ export const plugin: QraftCommandPlugin = {
3134
return arg?.toLowerCase() !== 'false';
3235
}
3336
)
37+
.addOption(
38+
new Option(
39+
'--default-client-callbacks <callbacks...>',
40+
'List of default API client methods and hooks that will be available by default. These can be overridden at runtime if needed..'
41+
)
42+
.choices(['all', 'none', ...getAllAvailableCallbackNames()])
43+
.default(['all'])
44+
)
3445
.action(async ({ spinner, output, args, services, schema }, resolve) => {
46+
validateDefaultCallbacks(args.defaultClientCallbacks, spinner);
47+
3548
return void (await generateCode({
3649
spinner,
3750
services,
@@ -44,6 +57,9 @@ export const plugin: QraftCommandPlugin = {
4457
explicitImportExtensions: args.explicitImportExtensions,
4558
servicesDirName: 'services',
4659
exportSchemaTypes: args.exportOpenapiTypes,
60+
defaultClientCallbacks: args.defaultClientCallbacks
61+
.map((callbackName: string) => callbackName.trim())
62+
.filter(Boolean),
4763
operationPredefinedParameters: args.operationPredefinedParameters
4864
? createPredefinedParametersGlobs(
4965
schema,
@@ -57,3 +73,20 @@ export const plugin: QraftCommandPlugin = {
5773
});
5874
},
5975
};
76+
77+
function validateDefaultCallbacks(
78+
defaultCallbacks: string[],
79+
spinner: Ora
80+
): asserts defaultCallbacks is string[] | ['all'] | ['none'] {
81+
if (!defaultCallbacks || defaultCallbacks.length === 0) return;
82+
83+
const hasSpecialValue = defaultCallbacks.some(
84+
(cb) => cb === 'all' || cb === 'none'
85+
);
86+
if (hasSpecialValue && defaultCallbacks.length > 1) {
87+
spinner.fail(
88+
`When using "all" or "none" as a callback value, no other callbacks should be specified.`
89+
);
90+
process.exit(1);
91+
}
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import ts from 'typescript';
2+
import {
3+
createServicesMutationOperationNodes,
4+
createServicesQueryOperationNodes,
5+
} from './serviceOperationNodes.js';
6+
7+
/**
8+
* Extracts method names from interfaces in AST nodes
9+
*/
10+
function extractMethodNamesFromInterfaces(nodes: ts.Node[]): string[] {
11+
const methodNames: string[] = [];
12+
13+
// Recursive traversal to find interfaces
14+
function visitNode(node: ts.Node) {
15+
if (ts.isInterfaceDeclaration(node)) {
16+
// Extract method names from interface members
17+
node.members.forEach((member) => {
18+
if (ts.isMethodSignature(member) && ts.isIdentifier(member.name)) {
19+
methodNames.push(member.name.text);
20+
}
21+
});
22+
}
23+
24+
ts.forEachChild(node, visitNode);
25+
}
26+
27+
nodes.forEach(visitNode);
28+
29+
return [...new Set(methodNames)]; // Remove duplicates
30+
}
31+
32+
/**
33+
* Returns a list of all available callback function names
34+
*/
35+
export function getAllAvailableCallbackNames(): string[] {
36+
const queryNodes = createServicesQueryOperationNodes();
37+
const mutationNodes = createServicesMutationOperationNodes();
38+
39+
const queryMethodNames = extractMethodNamesFromInterfaces(queryNodes);
40+
const mutationMethodNames = extractMethodNamesFromInterfaces(mutationNodes);
41+
42+
return [...new Set([...queryMethodNames, ...mutationMethodNames])].sort();
43+
}

0 commit comments

Comments
 (0)