Skip to content

Commit b1d5c4a

Browse files
authored
feat: generate fetchers only (#22)
* Extract getOperationTypes * Extract createOpertaionFetcherFnNodes * Add `generateFetchers` generator * Fix import config path resolution on linux * Add fetcher import declaration * Remove broken command
1 parent a1eaff8 commit b1d5c4a

File tree

13 files changed

+672
-329
lines changed

13 files changed

+672
-329
lines changed

cli/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
],
2525
"license": "MIT",
2626
"scripts": {
27-
"start": "node -r @swc-node/register src/cli.ts",
2827
"build": "tsc -p tsconfig.package.json",
2928
"prepublishOnly": "npm run build"
3029
},

cli/src/commands/GenerateCommand.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class GenerateCommand extends Command {
5858

5959
// Compute the result
6060
const { default: config } = await import(
61-
path.relative(slash(__filename), slash(transpiledPath).slice(3))
61+
path.relative(path.parse(slash(__filename)).dir, slash(transpiledPath))
6262
);
6363

6464
// Delete the transpiled file
@@ -68,7 +68,7 @@ export class GenerateCommand extends Command {
6868
return config;
6969
} else {
7070
return await import(
71-
path.relative(slash(__filename), slash(userConfigPath)).slice(3)
71+
path.relative(path.parse(slash(__filename)).dir, slash(userConfigPath))
7272
);
7373
}
7474
}

plugins/typescript/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ export const useBadassContext = (): BadassContext => {
100100

101101
You can also tweak `{filenamePrefix}Fetcher.ts`, especially the error management part, so everything fit the expected `ErrorType`.
102102

103+
### generateFetchers
104+
105+
Generate some generic fetchers, `{filenamePrefix}Fetcher.ts` can be customized to fit your needs.
106+
107+
`{filenamePrefix}Components.ts` will use this fetcher with the OpenAPI types passed as generic.
108+
103109
## Utils
104110

105111
### renameComponent
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { factory as f } from "typescript";
2+
3+
/**
4+
* Helper to create named imports.
5+
*
6+
* @param fnName functions to imports
7+
* @param filename path of the module
8+
* @returns ts.Node of the import declaration
9+
*/
10+
export const createNamedImport = (
11+
fnName: string | string[],
12+
filename: string
13+
) => {
14+
const fnNames = Array.isArray(fnName) ? fnName : [fnName];
15+
return f.createImportDeclaration(
16+
undefined,
17+
undefined,
18+
f.createImportClause(
19+
false,
20+
undefined,
21+
f.createNamedImports(
22+
fnNames.map((name) =>
23+
f.createImportSpecifier(false, undefined, f.createIdentifier(name))
24+
)
25+
)
26+
),
27+
f.createStringLiteral(filename),
28+
undefined
29+
);
30+
};
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { camel } from "case";
2+
import { OperationObject } from "openapi3-ts";
3+
import ts, { factory as f } from "typescript";
4+
5+
/**
6+
* Create the declaration of the fetcher function.
7+
*
8+
* @returns Array of nodes
9+
*/
10+
export const createOperationFetcherFnNodes = ({
11+
dataType,
12+
requestBodyType,
13+
queryParamsType,
14+
pathParamsType,
15+
headersType,
16+
variablesType,
17+
fetcherFn,
18+
operation,
19+
url,
20+
verb,
21+
name,
22+
}: {
23+
dataType: ts.TypeNode;
24+
requestBodyType: ts.TypeNode;
25+
headersType: ts.TypeNode;
26+
pathParamsType: ts.TypeNode;
27+
queryParamsType: ts.TypeNode;
28+
variablesType: ts.TypeNode;
29+
operation: OperationObject;
30+
fetcherFn: string;
31+
url: string;
32+
verb: string;
33+
name: string;
34+
}) => {
35+
const nodes: ts.Node[] = [];
36+
if (operation.description) {
37+
nodes.push(f.createJSDocComment(operation.description.trim(), []));
38+
}
39+
40+
nodes.push(
41+
f.createVariableStatement(
42+
[f.createModifier(ts.SyntaxKind.ExportKeyword)],
43+
f.createVariableDeclarationList(
44+
[
45+
f.createVariableDeclaration(
46+
f.createIdentifier(name),
47+
undefined,
48+
undefined,
49+
f.createArrowFunction(
50+
undefined,
51+
undefined,
52+
variablesType.kind !== ts.SyntaxKind.VoidKeyword
53+
? [
54+
f.createParameterDeclaration(
55+
undefined,
56+
undefined,
57+
undefined,
58+
f.createIdentifier("variables"),
59+
undefined,
60+
variablesType,
61+
undefined
62+
),
63+
]
64+
: [],
65+
undefined,
66+
f.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
67+
f.createCallExpression(
68+
f.createIdentifier(fetcherFn),
69+
[
70+
dataType,
71+
requestBodyType,
72+
headersType,
73+
queryParamsType,
74+
pathParamsType,
75+
],
76+
[
77+
f.createObjectLiteralExpression(
78+
[
79+
f.createPropertyAssignment(
80+
f.createIdentifier("url"),
81+
f.createStringLiteral(camelizedPathParams(url))
82+
),
83+
f.createPropertyAssignment(
84+
f.createIdentifier("method"),
85+
f.createStringLiteral(verb)
86+
),
87+
...(variablesType.kind !== ts.SyntaxKind.VoidKeyword
88+
? [
89+
f.createSpreadAssignment(
90+
f.createIdentifier("variables")
91+
),
92+
]
93+
: []),
94+
],
95+
false
96+
),
97+
]
98+
)
99+
)
100+
),
101+
],
102+
ts.NodeFlags.Const
103+
)
104+
)
105+
);
106+
return nodes;
107+
};
108+
109+
/**
110+
* Transform url params case to camel.
111+
*
112+
* @example
113+
* `pet/{pet_id}` -> `pet/{petId}`
114+
*/
115+
const camelizedPathParams = (url: string) =>
116+
url.replace(/\{\w*\}/g, (match) => `{${camel(match)}}`);

0 commit comments

Comments
 (0)