moonflower 1.4.6 → 1.4.8
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/dist/openapi/analyzerModule/analyzerModule.cjs +1 -1
- package/dist/openapi/analyzerModule/analyzerModule.cjs.map +1 -1
- package/dist/openapi/analyzerModule/analyzerModule.mjs +33 -32
- package/dist/openapi/analyzerModule/analyzerModule.mjs.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.cjs +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.cjs.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.mjs +320 -308
- package/dist/openapi/analyzerModule/nodeParsers.mjs.map +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.cjs +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.cjs.map +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.mjs +105 -95
- package/dist/openapi/analyzerModule/parseEndpoint.mjs.map +1 -1
- package/package.json +1 -1
- package/src/openapi/analyzerModule/analyzerModule.ts +1 -1
- package/src/openapi/analyzerModule/nodeParsers.ts +28 -5
- package/src/openapi/analyzerModule/parseEndpoint.ts +41 -29
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { SyntaxKind as
|
|
2
|
-
import { Logger as
|
|
3
|
-
import { resolveEndpointPath as
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
method:
|
|
7
|
-
path:
|
|
8
|
-
sourceFilePath:
|
|
1
|
+
import { SyntaxKind as a } from "ts-morph";
|
|
2
|
+
import { Logger as l } from "../../utils/logger.mjs";
|
|
3
|
+
import { resolveEndpointPath as y, findNodeImplementation as d, getValuesOfObjectLiteral as m, getShapeOfValidatorLiteral as f, getValidatorPropertyStringValue as h, getValidatorPropertyOptionality as E, getValidatorPropertyShape as P, getProperTypeShape as L } from "./nodeParsers.mjs";
|
|
4
|
+
const j = (t, n) => {
|
|
5
|
+
const r = t.getFirstDescendantByKind(a.PropertyAccessExpression).getText().split(".")[1].toUpperCase(), e = r === "DEL" ? "DELETE" : r, u = y(t) ?? "", i = {
|
|
6
|
+
method: e,
|
|
7
|
+
path: u,
|
|
8
|
+
sourceFilePath: n,
|
|
9
9
|
requestPathParams: [],
|
|
10
10
|
requestQuery: [],
|
|
11
11
|
requestHeaders: [],
|
|
@@ -16,105 +16,115 @@ const w = (t, s) => {
|
|
|
16
16
|
summary: void 0,
|
|
17
17
|
description: void 0,
|
|
18
18
|
tags: void 0
|
|
19
|
-
};
|
|
19
|
+
}, o = x(t);
|
|
20
20
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
B(o.useApiEndpoint).forEach((g) => {
|
|
22
|
+
i[g.identifier] = g.value;
|
|
23
23
|
});
|
|
24
|
-
} catch (
|
|
25
|
-
|
|
24
|
+
} catch (s) {
|
|
25
|
+
l.error("Error", s);
|
|
26
26
|
}
|
|
27
27
|
try {
|
|
28
|
-
|
|
29
|
-
} catch (
|
|
30
|
-
|
|
28
|
+
i.requestPathParams = v(o.usePathParams, u);
|
|
29
|
+
} catch (s) {
|
|
30
|
+
l.error("Error", s);
|
|
31
31
|
}
|
|
32
32
|
try {
|
|
33
|
-
|
|
34
|
-
} catch (
|
|
35
|
-
|
|
33
|
+
i.requestQuery = c(o.useQueryParams, "useQueryParams");
|
|
34
|
+
} catch (s) {
|
|
35
|
+
l.error("Error", s);
|
|
36
36
|
}
|
|
37
37
|
try {
|
|
38
|
-
|
|
39
|
-
} catch (
|
|
40
|
-
|
|
38
|
+
i.requestHeaders = c(o.useHeaderParams, "useHeaderParams");
|
|
39
|
+
} catch (s) {
|
|
40
|
+
l.error("Error", s);
|
|
41
41
|
}
|
|
42
42
|
try {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
} catch (
|
|
46
|
-
|
|
43
|
+
const s = K(o.useRequestRawBody);
|
|
44
|
+
s && (i.rawBody = s);
|
|
45
|
+
} catch (s) {
|
|
46
|
+
l.error("Error", s);
|
|
47
47
|
}
|
|
48
48
|
try {
|
|
49
|
-
|
|
50
|
-
} catch (
|
|
51
|
-
|
|
49
|
+
i.objectBody = c(o.useRequestBody, "useRequestBody");
|
|
50
|
+
} catch (s) {
|
|
51
|
+
l.error("Error", s);
|
|
52
52
|
}
|
|
53
53
|
try {
|
|
54
|
-
|
|
55
|
-
} catch (
|
|
56
|
-
|
|
54
|
+
i.responses = R(t);
|
|
55
|
+
} catch (s) {
|
|
56
|
+
l.error("Error", s);
|
|
57
|
+
}
|
|
58
|
+
return i;
|
|
59
|
+
}, x = (t) => {
|
|
60
|
+
const n = {
|
|
61
|
+
useApiEndpoint: null,
|
|
62
|
+
usePathParams: null,
|
|
63
|
+
useQueryParams: null,
|
|
64
|
+
useHeaderParams: null,
|
|
65
|
+
useRequestBody: null,
|
|
66
|
+
useRequestRawBody: null
|
|
67
|
+
};
|
|
68
|
+
for (const r of t.getDescendantsOfKind(a.CallExpression)) {
|
|
69
|
+
const e = r.getFirstChildByKind(a.Identifier)?.getText();
|
|
70
|
+
e && e in n && n[e] === null && (n[e] = r);
|
|
57
71
|
}
|
|
58
|
-
return
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
if (!s)
|
|
72
|
+
return n;
|
|
73
|
+
}, B = (t) => {
|
|
74
|
+
if (!t)
|
|
62
75
|
return [];
|
|
63
|
-
const
|
|
64
|
-
if (!r.isKind(
|
|
76
|
+
const n = t.getFirstChildByKind(a.SyntaxList), r = d(n.getLastChild());
|
|
77
|
+
if (!r.isKind(a.ObjectLiteralExpression))
|
|
65
78
|
throw new Error("Non-literal type used in useApiEndpoint");
|
|
66
|
-
const
|
|
67
|
-
return m(
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
if (!o)
|
|
79
|
+
const e = r.asKind(a.ObjectLiteralExpression);
|
|
80
|
+
return m(e).filter((i) => i.value !== null);
|
|
81
|
+
}, v = (t, n) => {
|
|
82
|
+
if (!t)
|
|
71
83
|
return [];
|
|
72
|
-
const r =
|
|
73
|
-
if (!
|
|
84
|
+
const r = t.getFirstChildByKind(a.SyntaxList), e = d(r.getLastChild());
|
|
85
|
+
if (!e.isKind(a.ObjectLiteralExpression))
|
|
74
86
|
throw new Error("Non-literal type used in usePathParams");
|
|
75
|
-
const
|
|
76
|
-
name:
|
|
77
|
-
optional:
|
|
78
|
-
})),
|
|
79
|
-
return
|
|
80
|
-
identifier:
|
|
81
|
-
signature:
|
|
82
|
-
optional:
|
|
83
|
-
description:
|
|
84
|
-
errorMessage:
|
|
87
|
+
const u = n.split("/").filter((o) => o.startsWith(":")).map((o) => ({
|
|
88
|
+
name: o.substring(1).replace(/\?/, ""),
|
|
89
|
+
optional: o.includes("?")
|
|
90
|
+
})), i = e.asKind(a.ObjectLiteralExpression);
|
|
91
|
+
return f(i).filter((o) => o.shape !== null).map((o) => ({
|
|
92
|
+
identifier: o.identifier,
|
|
93
|
+
signature: o.shape,
|
|
94
|
+
optional: u.some((s) => s.name === o.identifier && s.optional),
|
|
95
|
+
description: o.description,
|
|
96
|
+
errorMessage: o.errorMessage
|
|
85
97
|
}));
|
|
86
98
|
}, K = (t) => {
|
|
87
|
-
|
|
88
|
-
if (!s)
|
|
99
|
+
if (!t)
|
|
89
100
|
return null;
|
|
90
|
-
const
|
|
91
|
-
|
|
101
|
+
const n = t.getFirstChildByKind(a.SyntaxList), r = d(
|
|
102
|
+
n.getLastChild((e) => !e.isKind(a.CommaToken))
|
|
92
103
|
);
|
|
93
104
|
return {
|
|
94
|
-
signature:
|
|
95
|
-
optional:
|
|
96
|
-
description:
|
|
97
|
-
errorMessage:
|
|
105
|
+
signature: P(r),
|
|
106
|
+
optional: E(r),
|
|
107
|
+
description: h(r, "description"),
|
|
108
|
+
errorMessage: h(r, "errorMessage")
|
|
98
109
|
};
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
if (!o)
|
|
110
|
+
}, c = (t, n) => {
|
|
111
|
+
if (!t)
|
|
102
112
|
return [];
|
|
103
|
-
const r =
|
|
104
|
-
if (!
|
|
105
|
-
throw new Error(`Non-literal type used in ${
|
|
106
|
-
const
|
|
107
|
-
return
|
|
108
|
-
identifier:
|
|
109
|
-
signature:
|
|
110
|
-
optional:
|
|
111
|
-
description:
|
|
112
|
-
errorMessage:
|
|
113
|
+
const r = t.getFirstChildByKind(a.SyntaxList), e = d(r.getLastChild());
|
|
114
|
+
if (!e.isKind(a.ObjectLiteralExpression))
|
|
115
|
+
throw new Error(`Non-literal type used in ${n}`);
|
|
116
|
+
const u = e.asKind(a.ObjectLiteralExpression);
|
|
117
|
+
return f(u).filter((i) => i.shape !== null).map((i) => ({
|
|
118
|
+
identifier: i.identifier,
|
|
119
|
+
signature: i.shape,
|
|
120
|
+
optional: i.optional,
|
|
121
|
+
description: i.description,
|
|
122
|
+
errorMessage: i.errorMessage
|
|
113
123
|
}));
|
|
114
|
-
},
|
|
115
|
-
const
|
|
116
|
-
return
|
|
117
|
-
},
|
|
124
|
+
}, R = (t) => {
|
|
125
|
+
const r = t.getFirstChildByKind(a.CallExpression).getFirstChildByKind(a.SyntaxList).getFirstChildByKind(a.ArrowFunction).getReturnType(), e = r.getText().startsWith("Promise") ? r.getTypeArguments()[0] : r, u = L(e, t);
|
|
126
|
+
return p(u);
|
|
127
|
+
}, p = (t) => {
|
|
118
128
|
if (typeof t == "string")
|
|
119
129
|
return [
|
|
120
130
|
{
|
|
@@ -126,27 +136,27 @@ const w = (t, s) => {
|
|
|
126
136
|
}
|
|
127
137
|
];
|
|
128
138
|
if (t[0].role === "union_entry" || t[0].role === "literal_string")
|
|
129
|
-
return
|
|
139
|
+
return p(t[0].shape);
|
|
130
140
|
if (t[0].role === "property" && t[0].identifier === "_isUseReturnValue") {
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
(
|
|
141
|
+
const n = (() => {
|
|
142
|
+
const e = t.find(
|
|
143
|
+
(u) => u.role === "property" && u.identifier === "status"
|
|
134
144
|
)?.shape;
|
|
135
|
-
if (!
|
|
145
|
+
if (!e || typeof e == "string" || typeof e[0].shape != "string")
|
|
136
146
|
throw new Error("Invalid useReturnValue hook");
|
|
137
|
-
return parseInt(
|
|
138
|
-
})(),
|
|
139
|
-
const
|
|
140
|
-
(
|
|
147
|
+
return parseInt(e[0].shape);
|
|
148
|
+
})(), r = (() => {
|
|
149
|
+
const e = t.find(
|
|
150
|
+
(u) => u.role === "property" && u.identifier === "contentType"
|
|
141
151
|
)?.shape;
|
|
142
|
-
if (!
|
|
152
|
+
if (!e || typeof e == "string" || typeof e[0].shape != "string")
|
|
143
153
|
throw new Error("Invalid useReturnValue hook");
|
|
144
|
-
return
|
|
154
|
+
return e[0].shape;
|
|
145
155
|
})();
|
|
146
156
|
return [
|
|
147
157
|
{
|
|
148
|
-
status:
|
|
149
|
-
contentType:
|
|
158
|
+
status: n,
|
|
159
|
+
contentType: r,
|
|
150
160
|
signature: t,
|
|
151
161
|
description: "",
|
|
152
162
|
errorMessage: ""
|
|
@@ -161,7 +171,7 @@ const w = (t, s) => {
|
|
|
161
171
|
description: "",
|
|
162
172
|
errorMessage: ""
|
|
163
173
|
}
|
|
164
|
-
] : t[0].shape.flatMap((
|
|
174
|
+
] : t[0].shape.flatMap((n) => p([n])) : t[0].role === "buffer" ? [
|
|
165
175
|
{
|
|
166
176
|
status: 200,
|
|
167
177
|
contentType: "application/octet-stream",
|
|
@@ -180,6 +190,6 @@ const w = (t, s) => {
|
|
|
180
190
|
];
|
|
181
191
|
};
|
|
182
192
|
export {
|
|
183
|
-
|
|
193
|
+
j as parseEndpoint
|
|
184
194
|
};
|
|
185
195
|
//# sourceMappingURL=parseEndpoint.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseEndpoint.mjs","sources":["../../../src/openapi/analyzerModule/parseEndpoint.ts"],"sourcesContent":["import { Node, SyntaxKind, ts } from 'ts-morph'\n\nimport { ApiEndpointDocs } from '../../hooks/useApiEndpoint'\nimport { Logger } from '../../utils/logger'\nimport { EndpointData } from '../types'\nimport {\n\tfindNodeImplementation,\n\tgetProperTypeShape,\n\tgetShapeOfValidatorLiteral,\n\tgetValidatorPropertyOptionality,\n\tgetValidatorPropertyShape,\n\tgetValidatorPropertyStringValue,\n\tgetValuesOfObjectLiteral,\n\tresolveEndpointPath,\n} from './nodeParsers'\n\nexport const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {\n\tconst parsedEndpointMethod = node\n\t\t.getFirstDescendantByKind(SyntaxKind.PropertyAccessExpression)!\n\t\t.getText()\n\t\t.split('.')[1]\n\t\t.toUpperCase()\n\n\tconst endpointMethod = parsedEndpointMethod === 'DEL' ? 'DELETE' : parsedEndpointMethod\n\n\tconst endpointPath = resolveEndpointPath(node) ?? ''\n\n\tconst endpointData: EndpointData = {\n\t\tmethod: endpointMethod as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n\t\tpath: endpointPath,\n\t\tsourceFilePath,\n\t\trequestPathParams: [],\n\t\trequestQuery: [],\n\t\trequestHeaders: [],\n\t\trawBody: undefined,\n\t\tobjectBody: [],\n\t\tresponses: [],\n\t\tname: undefined,\n\t\tsummary: undefined,\n\t\tdescription: undefined,\n\t\ttags: undefined,\n\t}\n\n\tconst warningData: {\n\t\tsegment: string\n\t\terror: Error\n\t}[] = []\n\n\t// API documentation\n\ttry {\n\t\tconst entries = parseApiDocumentation(node)\n\t\tentries.forEach((param) => {\n\t\t\tendpointData[param.identifier] = param.value as string & string[]\n\t\t})\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'api',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request params\n\ttry {\n\t\tendpointData.requestPathParams = parseRequestParams(node, endpointPath)\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'path',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request query\n\ttry {\n\t\tendpointData.requestQuery = parseRequestObjectInput(node, 'useQueryParams')\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'query',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request headers\n\ttry {\n\t\tendpointData.requestHeaders = parseRequestObjectInput(node, 'useHeaderParams')\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'headers',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Raw request body\n\ttry {\n\t\tconst parsedBody = parseRequestRawBody(node)\n\t\tif (parsedBody) {\n\t\t\tendpointData.rawBody = parsedBody\n\t\t}\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'rawBody',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Object request body\n\ttry {\n\t\tendpointData.objectBody = parseRequestObjectInput(node, 'useRequestBody')\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'objectBody',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request response\n\ttry {\n\t\tendpointData.responses = parseRequestResponse(node)\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'response',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\treturn endpointData\n}\n\nconst getHookNode = (\n\tendpointNode: Node<ts.Node>,\n\thookName:\n\t\t| 'useApiEndpoint'\n\t\t| 'usePathParams'\n\t\t| 'useQueryParams'\n\t\t| 'useHeaderParams'\n\t\t| 'useRequestBody'\n\t\t| 'useRequestRawBody',\n) => {\n\tconst callExpressions = endpointNode.getDescendantsOfKind(SyntaxKind.CallExpression)\n\tconst matchingCallExpressions = callExpressions.filter((node) => {\n\t\treturn node.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === hookName\n\t})\n\treturn matchingCallExpressions[0] ?? null\n}\n\nconst parseApiDocumentation = (node: Node<ts.Node>) => {\n\tconst hookNode = getHookNode(node, 'useApiEndpoint')\n\tif (!hookNode) {\n\t\treturn []\n\t}\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(paramNode.getLastChild()!)\n\n\tif (!valueNode.isKind(SyntaxKind.ObjectLiteralExpression)) {\n\t\tthrow new Error('Non-literal type used in useApiEndpoint')\n\t}\n\n\tconst objectLiteral = valueNode.asKind(SyntaxKind.ObjectLiteralExpression)!\n\n\tconst values = getValuesOfObjectLiteral(objectLiteral).filter((param) => param.value !== null)\n\treturn values as {\n\t\tidentifier: keyof ApiEndpointDocs\n\t\tvalue: (typeof values)[number]['value']\n\t}[]\n}\n\nconst parseRequestParams = (node: Node<ts.Node>, endpointPath: string): EndpointData['requestPathParams'] => {\n\tconst hookNode = getHookNode(node, 'usePathParams')\n\tif (!hookNode) {\n\t\treturn []\n\t}\n\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(paramNode.getLastChild()!)\n\n\tif (!valueNode.isKind(SyntaxKind.ObjectLiteralExpression)) {\n\t\tthrow new Error('Non-literal type used in usePathParams')\n\t}\n\n\tconst declaredParams = endpointPath\n\t\t.split('/')\n\t\t.filter((segment) => segment.startsWith(':'))\n\t\t.map((segment) => ({\n\t\t\tname: segment.substring(1).replace(/\\?/, ''),\n\t\t\toptional: segment.includes('?'),\n\t\t}))\n\n\tconst objectLiteral = valueNode.asKind(SyntaxKind.ObjectLiteralExpression)!\n\treturn getShapeOfValidatorLiteral(objectLiteral)\n\t\t.filter((param) => param.shape !== null)\n\t\t.map((param) => ({\n\t\t\tidentifier: param.identifier,\n\t\t\tsignature: param.shape as string,\n\t\t\toptional: declaredParams.some((declared) => declared.name === param.identifier && declared.optional),\n\t\t\tdescription: param.description,\n\t\t\terrorMessage: param.errorMessage,\n\t\t}))\n}\n\nconst parseRequestRawBody = (node: Node<ts.Node>): NonNullable<EndpointData['rawBody']> | null => {\n\tconst hookNode = getHookNode(node, 'useRequestRawBody')\n\tif (!hookNode) {\n\t\treturn null\n\t}\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(\n\t\tparamNode.getLastChild((node) => !node.isKind(SyntaxKind.CommaToken))!,\n\t)\n\n\treturn {\n\t\tsignature: getValidatorPropertyShape(valueNode),\n\t\toptional: getValidatorPropertyOptionality(valueNode),\n\t\tdescription: getValidatorPropertyStringValue(valueNode, 'description'),\n\t\terrorMessage: getValidatorPropertyStringValue(valueNode, 'errorMessage'),\n\t}\n}\n\nconst parseRequestObjectInput = (\n\tnode: Node<ts.Node>,\n\tnodeName: 'useQueryParams' | 'useHeaderParams' | 'useRequestBody',\n): EndpointData['requestQuery'] | EndpointData['objectBody'] => {\n\tconst hookNode = getHookNode(node, nodeName)\n\tif (!hookNode) {\n\t\treturn []\n\t}\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(paramNode.getLastChild()!)\n\n\tif (!valueNode.isKind(SyntaxKind.ObjectLiteralExpression)) {\n\t\tthrow new Error(`Non-literal type used in ${nodeName}`)\n\t}\n\n\tconst objectLiteral = valueNode.asKind(SyntaxKind.ObjectLiteralExpression)!\n\treturn getShapeOfValidatorLiteral(objectLiteral)\n\t\t.filter((param) => param.shape !== null)\n\t\t.map((param) => ({\n\t\t\tidentifier: param.identifier,\n\t\t\tsignature: param.shape as string,\n\t\t\toptional: param.optional,\n\t\t\tdescription: param.description,\n\t\t\terrorMessage: param.errorMessage,\n\t\t}))\n}\n\nconst parseRequestResponse = (node: Node<ts.Node>): EndpointData['responses'] => {\n\tconst implementationNode = node\n\t\t.getFirstChildByKind(SyntaxKind.CallExpression)!\n\t\t.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\t\t.getFirstChildByKind(SyntaxKind.ArrowFunction)!\n\tconst returnType = implementationNode.getReturnType()\n\n\tconst actualType = (() => {\n\t\tif (returnType.getText().startsWith('Promise')) {\n\t\t\treturn returnType.getTypeArguments()[0]\n\t\t}\n\t\treturn returnType\n\t})()\n\n\tconst responseType = getProperTypeShape(actualType, node)\n\n\treturn parseResponseTypes(responseType)\n}\n\nconst parseResponseTypes = (\n\tresponseType: ReturnType<typeof getProperTypeShape>,\n): EndpointData['responses'] => {\n\t// TODO: Add support for response descriptions and errors\n\tif (typeof responseType === 'string') {\n\t\treturn [\n\t\t\t{\n\t\t\t\tstatus: responseType === 'void' || responseType === 'null' ? 204 : 200,\n\t\t\t\tcontentType: 'text/plain',\n\t\t\t\tsignature: responseType,\n\t\t\t\tdescription: '',\n\t\t\t\terrorMessage: '',\n\t\t\t},\n\t\t]\n\t}\n\n\tif (responseType[0].role === 'union_entry' || responseType[0].role === 'literal_string') {\n\t\treturn parseResponseTypes(responseType[0].shape)\n\t}\n\n\t// Response type is a useReturnValue hook\n\tif (responseType[0].role === 'property' && responseType[0].identifier === '_isUseReturnValue') {\n\t\tconst status = (() => {\n\t\t\tconst property = responseType.find(\n\t\t\t\t(response) => response.role === 'property' && response.identifier === 'status',\n\t\t\t)?.shape\n\t\t\tif (!property || typeof property === 'string' || typeof property[0].shape !== 'string') {\n\t\t\t\tthrow new Error('Invalid useReturnValue hook')\n\t\t\t}\n\t\t\treturn parseInt(property[0].shape)\n\t\t})()\n\t\tconst contentType = (() => {\n\t\t\tconst property = responseType.find(\n\t\t\t\t(response) => response.role === 'property' && response.identifier === 'contentType',\n\t\t\t)?.shape\n\t\t\tif (!property || typeof property === 'string' || typeof property[0].shape !== 'string') {\n\t\t\t\tthrow new Error('Invalid useReturnValue hook')\n\t\t\t}\n\t\t\treturn property[0].shape\n\t\t})()\n\t\treturn [\n\t\t\t{\n\t\t\t\tstatus,\n\t\t\t\tcontentType,\n\t\t\t\tsignature: responseType,\n\t\t\t\tdescription: '',\n\t\t\t\terrorMessage: '',\n\t\t\t},\n\t\t]\n\t}\n\n\tif (responseType[0].role === 'union') {\n\t\tif (typeof responseType[0].shape === 'string') {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tstatus: responseType[0].shape === 'void' || responseType[0].shape === 'null' ? 204 : 200,\n\t\t\t\t\tcontentType: 'application/json',\n\t\t\t\t\tsignature: responseType[0].shape,\n\t\t\t\t\tdescription: '',\n\t\t\t\t\terrorMessage: '',\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\n\t\treturn responseType[0].shape.flatMap((unionEntry) => {\n\t\t\treturn parseResponseTypes([unionEntry])\n\t\t})\n\t}\n\n\tif (responseType[0].role === 'buffer') {\n\t\treturn [\n\t\t\t{\n\t\t\t\tstatus: 200,\n\t\t\t\tcontentType: 'application/octet-stream',\n\t\t\t\tsignature: responseType,\n\t\t\t\tdescription: '',\n\t\t\t\terrorMessage: '',\n\t\t\t},\n\t\t]\n\t}\n\n\treturn [\n\t\t{\n\t\t\tstatus: 200,\n\t\t\tcontentType: 'application/json',\n\t\t\tsignature: responseType,\n\t\t\tdescription: '',\n\t\t\terrorMessage: '',\n\t\t},\n\t]\n}\n"],"names":["parseEndpoint","node","sourceFilePath","parsedEndpointMethod","SyntaxKind","endpointMethod","endpointPath","resolveEndpointPath","endpointData","parseApiDocumentation","param","err","Logger","parseRequestParams","parseRequestObjectInput","parsedBody","parseRequestRawBody","parseRequestResponse","getHookNode","endpointNode","hookName","hookNode","paramNode","valueNode","findNodeImplementation","objectLiteral","getValuesOfObjectLiteral","declaredParams","segment","getShapeOfValidatorLiteral","declared","getValidatorPropertyShape","getValidatorPropertyOptionality","getValidatorPropertyStringValue","nodeName","returnType","actualType","responseType","getProperTypeShape","parseResponseTypes","status","property","response","contentType","unionEntry"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"parseEndpoint.mjs","sources":["../../../src/openapi/analyzerModule/parseEndpoint.ts"],"sourcesContent":["import { Node, SyntaxKind, ts } from 'ts-morph'\n\nimport { ApiEndpointDocs } from '../../hooks/useApiEndpoint'\nimport { Logger } from '../../utils/logger'\nimport { EndpointData } from '../types'\nimport {\n\tfindNodeImplementation,\n\tgetProperTypeShape,\n\tgetShapeOfValidatorLiteral,\n\tgetValidatorPropertyOptionality,\n\tgetValidatorPropertyShape,\n\tgetValidatorPropertyStringValue,\n\tgetValuesOfObjectLiteral,\n\tresolveEndpointPath,\n} from './nodeParsers'\n\nexport const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {\n\tconst parsedEndpointMethod = node\n\t\t.getFirstDescendantByKind(SyntaxKind.PropertyAccessExpression)!\n\t\t.getText()\n\t\t.split('.')[1]\n\t\t.toUpperCase()\n\n\tconst endpointMethod = parsedEndpointMethod === 'DEL' ? 'DELETE' : parsedEndpointMethod\n\n\tconst endpointPath = resolveEndpointPath(node) ?? ''\n\n\tconst endpointData: EndpointData = {\n\t\tmethod: endpointMethod as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n\t\tpath: endpointPath,\n\t\tsourceFilePath,\n\t\trequestPathParams: [],\n\t\trequestQuery: [],\n\t\trequestHeaders: [],\n\t\trawBody: undefined,\n\t\tobjectBody: [],\n\t\tresponses: [],\n\t\tname: undefined,\n\t\tsummary: undefined,\n\t\tdescription: undefined,\n\t\ttags: undefined,\n\t}\n\n\tconst warningData: {\n\t\tsegment: string\n\t\terror: Error\n\t}[] = []\n\n\tconst hookNodes = getHookNodes(node)\n\n\t// API documentation\n\ttry {\n\t\tconst entries = parseApiDocumentation(hookNodes.useApiEndpoint)\n\t\tentries.forEach((param) => {\n\t\t\tendpointData[param.identifier] = param.value as string & string[]\n\t\t})\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'api',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request params\n\ttry {\n\t\tendpointData.requestPathParams = parseRequestParams(hookNodes.usePathParams, endpointPath)\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'path',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request query\n\ttry {\n\t\tendpointData.requestQuery = parseRequestObjectInput(hookNodes.useQueryParams, 'useQueryParams')\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'query',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request headers\n\ttry {\n\t\tendpointData.requestHeaders = parseRequestObjectInput(hookNodes.useHeaderParams, 'useHeaderParams')\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'headers',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Raw request body\n\ttry {\n\t\tconst parsedBody = parseRequestRawBody(hookNodes.useRequestRawBody)\n\t\tif (parsedBody) {\n\t\t\tendpointData.rawBody = parsedBody\n\t\t}\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'rawBody',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Object request body\n\ttry {\n\t\tendpointData.objectBody = parseRequestObjectInput(hookNodes.useRequestBody, 'useRequestBody')\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'objectBody',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\t// Request response\n\ttry {\n\t\tendpointData.responses = parseRequestResponse(node)\n\t} catch (err) {\n\t\twarningData.push({\n\t\t\tsegment: 'response',\n\t\t\terror: err as Error,\n\t\t})\n\t\tLogger.error('Error', err)\n\t}\n\n\treturn endpointData\n}\n\ntype HookName =\n\t| 'useApiEndpoint'\n\t| 'usePathParams'\n\t| 'useQueryParams'\n\t| 'useHeaderParams'\n\t| 'useRequestBody'\n\t| 'useRequestRawBody'\n\nconst getHookNodes = (endpointNode: Node<ts.Node>): Record<HookName, Node<ts.CallExpression> | null> => {\n\tconst result: Record<HookName, Node<ts.CallExpression> | null> = {\n\t\tuseApiEndpoint: null,\n\t\tusePathParams: null,\n\t\tuseQueryParams: null,\n\t\tuseHeaderParams: null,\n\t\tuseRequestBody: null,\n\t\tuseRequestRawBody: null,\n\t}\n\tfor (const node of endpointNode.getDescendantsOfKind(SyntaxKind.CallExpression)) {\n\t\tconst name = node.getFirstChildByKind(SyntaxKind.Identifier)?.getText() as HookName | undefined\n\t\tif (name && name in result && result[name] === null) {\n\t\t\tresult[name] = node\n\t\t}\n\t}\n\treturn result\n}\n\nconst parseApiDocumentation = (hookNode: Node<ts.CallExpression> | null) => {\n\tif (!hookNode) {\n\t\treturn []\n\t}\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(paramNode.getLastChild()!)\n\n\tif (!valueNode.isKind(SyntaxKind.ObjectLiteralExpression)) {\n\t\tthrow new Error('Non-literal type used in useApiEndpoint')\n\t}\n\n\tconst objectLiteral = valueNode.asKind(SyntaxKind.ObjectLiteralExpression)!\n\n\tconst values = getValuesOfObjectLiteral(objectLiteral).filter((param) => param.value !== null)\n\treturn values as {\n\t\tidentifier: keyof ApiEndpointDocs\n\t\tvalue: (typeof values)[number]['value']\n\t}[]\n}\n\nconst parseRequestParams = (\n\thookNode: Node<ts.CallExpression> | null,\n\tendpointPath: string,\n): EndpointData['requestPathParams'] => {\n\tif (!hookNode) {\n\t\treturn []\n\t}\n\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(paramNode.getLastChild()!)\n\n\tif (!valueNode.isKind(SyntaxKind.ObjectLiteralExpression)) {\n\t\tthrow new Error('Non-literal type used in usePathParams')\n\t}\n\n\tconst declaredParams = endpointPath\n\t\t.split('/')\n\t\t.filter((segment) => segment.startsWith(':'))\n\t\t.map((segment) => ({\n\t\t\tname: segment.substring(1).replace(/\\?/, ''),\n\t\t\toptional: segment.includes('?'),\n\t\t}))\n\n\tconst objectLiteral = valueNode.asKind(SyntaxKind.ObjectLiteralExpression)!\n\treturn getShapeOfValidatorLiteral(objectLiteral)\n\t\t.filter((param) => param.shape !== null)\n\t\t.map((param) => ({\n\t\t\tidentifier: param.identifier,\n\t\t\tsignature: param.shape as string,\n\t\t\toptional: declaredParams.some((declared) => declared.name === param.identifier && declared.optional),\n\t\t\tdescription: param.description,\n\t\t\terrorMessage: param.errorMessage,\n\t\t}))\n}\n\nconst parseRequestRawBody = (\n\thookNode: Node<ts.CallExpression> | null,\n): NonNullable<EndpointData['rawBody']> | null => {\n\tif (!hookNode) {\n\t\treturn null\n\t}\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(\n\t\tparamNode.getLastChild((node) => !node.isKind(SyntaxKind.CommaToken))!,\n\t)\n\n\treturn {\n\t\tsignature: getValidatorPropertyShape(valueNode),\n\t\toptional: getValidatorPropertyOptionality(valueNode),\n\t\tdescription: getValidatorPropertyStringValue(valueNode, 'description'),\n\t\terrorMessage: getValidatorPropertyStringValue(valueNode, 'errorMessage'),\n\t}\n}\n\nconst parseRequestObjectInput = (\n\thookNode: Node<ts.CallExpression> | null,\n\tnodeName: 'useQueryParams' | 'useHeaderParams' | 'useRequestBody',\n): EndpointData['requestQuery'] | EndpointData['objectBody'] => {\n\tif (!hookNode) {\n\t\treturn []\n\t}\n\tconst paramNode = hookNode.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\tconst valueNode = findNodeImplementation(paramNode.getLastChild()!)\n\n\tif (!valueNode.isKind(SyntaxKind.ObjectLiteralExpression)) {\n\t\tthrow new Error(`Non-literal type used in ${nodeName}`)\n\t}\n\n\tconst objectLiteral = valueNode.asKind(SyntaxKind.ObjectLiteralExpression)!\n\treturn getShapeOfValidatorLiteral(objectLiteral)\n\t\t.filter((param) => param.shape !== null)\n\t\t.map((param) => ({\n\t\t\tidentifier: param.identifier,\n\t\t\tsignature: param.shape as string,\n\t\t\toptional: param.optional,\n\t\t\tdescription: param.description,\n\t\t\terrorMessage: param.errorMessage,\n\t\t}))\n}\n\nconst parseRequestResponse = (node: Node<ts.Node>): EndpointData['responses'] => {\n\tconst implementationNode = node\n\t\t.getFirstChildByKind(SyntaxKind.CallExpression)!\n\t\t.getFirstChildByKind(SyntaxKind.SyntaxList)!\n\t\t.getFirstChildByKind(SyntaxKind.ArrowFunction)!\n\tconst returnType = implementationNode.getReturnType()\n\n\tconst actualType = (() => {\n\t\tif (returnType.getText().startsWith('Promise')) {\n\t\t\treturn returnType.getTypeArguments()[0]\n\t\t}\n\t\treturn returnType\n\t})()\n\n\tconst responseType = getProperTypeShape(actualType, node)\n\n\treturn parseResponseTypes(responseType)\n}\n\nconst parseResponseTypes = (\n\tresponseType: ReturnType<typeof getProperTypeShape>,\n): EndpointData['responses'] => {\n\t// TODO: Add support for response descriptions and errors\n\tif (typeof responseType === 'string') {\n\t\treturn [\n\t\t\t{\n\t\t\t\tstatus: responseType === 'void' || responseType === 'null' ? 204 : 200,\n\t\t\t\tcontentType: 'text/plain',\n\t\t\t\tsignature: responseType,\n\t\t\t\tdescription: '',\n\t\t\t\terrorMessage: '',\n\t\t\t},\n\t\t]\n\t}\n\n\tif (responseType[0].role === 'union_entry' || responseType[0].role === 'literal_string') {\n\t\treturn parseResponseTypes(responseType[0].shape)\n\t}\n\n\t// Response type is a useReturnValue hook\n\tif (responseType[0].role === 'property' && responseType[0].identifier === '_isUseReturnValue') {\n\t\tconst status = (() => {\n\t\t\tconst property = responseType.find(\n\t\t\t\t(response) => response.role === 'property' && response.identifier === 'status',\n\t\t\t)?.shape\n\t\t\tif (!property || typeof property === 'string' || typeof property[0].shape !== 'string') {\n\t\t\t\tthrow new Error('Invalid useReturnValue hook')\n\t\t\t}\n\t\t\treturn parseInt(property[0].shape)\n\t\t})()\n\t\tconst contentType = (() => {\n\t\t\tconst property = responseType.find(\n\t\t\t\t(response) => response.role === 'property' && response.identifier === 'contentType',\n\t\t\t)?.shape\n\t\t\tif (!property || typeof property === 'string' || typeof property[0].shape !== 'string') {\n\t\t\t\tthrow new Error('Invalid useReturnValue hook')\n\t\t\t}\n\t\t\treturn property[0].shape\n\t\t})()\n\t\treturn [\n\t\t\t{\n\t\t\t\tstatus,\n\t\t\t\tcontentType,\n\t\t\t\tsignature: responseType,\n\t\t\t\tdescription: '',\n\t\t\t\terrorMessage: '',\n\t\t\t},\n\t\t]\n\t}\n\n\tif (responseType[0].role === 'union') {\n\t\tif (typeof responseType[0].shape === 'string') {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tstatus: responseType[0].shape === 'void' || responseType[0].shape === 'null' ? 204 : 200,\n\t\t\t\t\tcontentType: 'application/json',\n\t\t\t\t\tsignature: responseType[0].shape,\n\t\t\t\t\tdescription: '',\n\t\t\t\t\terrorMessage: '',\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\n\t\treturn responseType[0].shape.flatMap((unionEntry) => {\n\t\t\treturn parseResponseTypes([unionEntry])\n\t\t})\n\t}\n\n\tif (responseType[0].role === 'buffer') {\n\t\treturn [\n\t\t\t{\n\t\t\t\tstatus: 200,\n\t\t\t\tcontentType: 'application/octet-stream',\n\t\t\t\tsignature: responseType,\n\t\t\t\tdescription: '',\n\t\t\t\terrorMessage: '',\n\t\t\t},\n\t\t]\n\t}\n\n\treturn [\n\t\t{\n\t\t\tstatus: 200,\n\t\t\tcontentType: 'application/json',\n\t\t\tsignature: responseType,\n\t\t\tdescription: '',\n\t\t\terrorMessage: '',\n\t\t},\n\t]\n}\n"],"names":["parseEndpoint","node","sourceFilePath","parsedEndpointMethod","SyntaxKind","endpointMethod","endpointPath","resolveEndpointPath","endpointData","hookNodes","getHookNodes","parseApiDocumentation","param","err","Logger","parseRequestParams","parseRequestObjectInput","parsedBody","parseRequestRawBody","parseRequestResponse","endpointNode","result","name","hookNode","paramNode","valueNode","findNodeImplementation","objectLiteral","getValuesOfObjectLiteral","declaredParams","segment","getShapeOfValidatorLiteral","declared","getValidatorPropertyShape","getValidatorPropertyOptionality","getValidatorPropertyStringValue","nodeName","returnType","actualType","responseType","getProperTypeShape","parseResponseTypes","status","property","response","contentType","unionEntry"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -209,9 +209,9 @@ export const analyzeSourceFileEndpoints = (
|
|
|
209
209
|
const joinedOperations = operations.join('|')
|
|
210
210
|
|
|
211
211
|
file.routers.named.forEach((routerName) => {
|
|
212
|
+
const routerPattern = new RegExp(`${routerName}\\.(?:${joinedOperations})`)
|
|
212
213
|
file.sourceFile.forEachChild((node) => {
|
|
213
214
|
const nodeText = node.getText()
|
|
214
|
-
const routerPattern = new RegExp(`${routerName}\\.(?:${joinedOperations})`)
|
|
215
215
|
|
|
216
216
|
if (routerPattern.test(nodeText)) {
|
|
217
217
|
const endpointPath = resolveEndpointPath(node) ?? ''
|
|
@@ -15,6 +15,8 @@ import { OpenApiManager } from '../manager/OpenApiManager'
|
|
|
15
15
|
import { ShapeOfProperty, ShapeOfType, ShapeOfUnionEntry } from './types'
|
|
16
16
|
|
|
17
17
|
const implementationCache = new WeakMap<Node, Node>()
|
|
18
|
+
const nodeShapeCache = new WeakMap<Node, ShapeOfType['shape']>()
|
|
19
|
+
const typeShapeCache = new WeakMap<object, ShapeOfType['shape']>()
|
|
18
20
|
|
|
19
21
|
export const findNodeImplementation = (node: Node): Node => {
|
|
20
22
|
const cached = implementationCache.get(node)
|
|
@@ -84,6 +86,16 @@ export const getTypeReferenceShape = (node: TypeReferenceNode): ShapeOfType['sha
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
export const getRecursiveNodeShape = (nodeOrReference: Node): ShapeOfType['shape'] => {
|
|
89
|
+
const cached = nodeShapeCache.get(nodeOrReference)
|
|
90
|
+
if (cached !== undefined) {
|
|
91
|
+
return cached
|
|
92
|
+
}
|
|
93
|
+
const result = computeRecursiveNodeShape(nodeOrReference)
|
|
94
|
+
nodeShapeCache.set(nodeOrReference, result)
|
|
95
|
+
return result
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const computeRecursiveNodeShape = (nodeOrReference: Node): ShapeOfType['shape'] => {
|
|
87
99
|
const typeName = nodeOrReference.getSymbol()?.getName()
|
|
88
100
|
if (typeName && OpenApiManager.getInstance().hasExposedModel(typeName)) {
|
|
89
101
|
return [
|
|
@@ -624,6 +636,17 @@ export const getProperTypeShape = (
|
|
|
624
636
|
return 'circular'
|
|
625
637
|
}
|
|
626
638
|
|
|
639
|
+
const cacheKey = type.compilerType
|
|
640
|
+
const cached = typeShapeCache.get(cacheKey)
|
|
641
|
+
if (cached !== undefined) {
|
|
642
|
+
return cached
|
|
643
|
+
}
|
|
644
|
+
const result = computeProperTypeShape(type, atLocation, stack)
|
|
645
|
+
typeShapeCache.set(cacheKey, result)
|
|
646
|
+
return result
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const computeProperTypeShape = (type: Type, atLocation: Node, stack: Type[]): ShapeOfType['shape'] => {
|
|
627
650
|
const nextStack = stack.concat(type)
|
|
628
651
|
|
|
629
652
|
if (type.getText() === 'void') {
|
|
@@ -806,11 +829,12 @@ export const getProperTypeShape = (
|
|
|
806
829
|
.getProperties()
|
|
807
830
|
.map((prop) => {
|
|
808
831
|
const valueDeclaration = prop.getValueDeclaration() || prop.getDeclarations()[0]!
|
|
832
|
+
const shape = getProperTypeShape(prop.getTypeAtLocation(atLocation), atLocation, nextStack)
|
|
809
833
|
if (!valueDeclaration) {
|
|
810
834
|
return {
|
|
811
835
|
role: 'property' as const,
|
|
812
836
|
identifier: prop.getName(),
|
|
813
|
-
shape
|
|
837
|
+
shape,
|
|
814
838
|
optional: false,
|
|
815
839
|
}
|
|
816
840
|
}
|
|
@@ -823,18 +847,17 @@ export const getProperTypeShape = (
|
|
|
823
847
|
return {
|
|
824
848
|
role: 'property' as const,
|
|
825
849
|
identifier: prop.getName(),
|
|
826
|
-
shape
|
|
850
|
+
shape,
|
|
827
851
|
optional: false,
|
|
828
852
|
}
|
|
829
853
|
}
|
|
830
854
|
|
|
831
855
|
const isOptional = prop.getTypeAtLocation(atLocation).isNullable()
|
|
832
856
|
|
|
833
|
-
const shape = getProperTypeShape(prop.getTypeAtLocation(atLocation), atLocation, nextStack)
|
|
834
857
|
return {
|
|
835
858
|
role: 'property' as const,
|
|
836
859
|
identifier: prop.getName(),
|
|
837
|
-
shape
|
|
860
|
+
shape,
|
|
838
861
|
optional: isOptional,
|
|
839
862
|
}
|
|
840
863
|
})
|
|
@@ -874,7 +897,7 @@ export const getProperTypeShape = (
|
|
|
874
897
|
}
|
|
875
898
|
|
|
876
899
|
const fileName = atLocation.getSourceFile().getFilePath().split('/').pop()
|
|
877
|
-
Logger.warn(`[${fileName}] Unknown type shape node ${
|
|
900
|
+
Logger.warn(`[${fileName}] Unknown type shape node ${type.getText()}`)
|
|
878
901
|
return 'unknown_5'
|
|
879
902
|
}
|
|
880
903
|
|
|
@@ -46,9 +46,11 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
46
46
|
error: Error
|
|
47
47
|
}[] = []
|
|
48
48
|
|
|
49
|
+
const hookNodes = getHookNodes(node)
|
|
50
|
+
|
|
49
51
|
// API documentation
|
|
50
52
|
try {
|
|
51
|
-
const entries = parseApiDocumentation(
|
|
53
|
+
const entries = parseApiDocumentation(hookNodes.useApiEndpoint)
|
|
52
54
|
entries.forEach((param) => {
|
|
53
55
|
endpointData[param.identifier] = param.value as string & string[]
|
|
54
56
|
})
|
|
@@ -62,7 +64,7 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
62
64
|
|
|
63
65
|
// Request params
|
|
64
66
|
try {
|
|
65
|
-
endpointData.requestPathParams = parseRequestParams(
|
|
67
|
+
endpointData.requestPathParams = parseRequestParams(hookNodes.usePathParams, endpointPath)
|
|
66
68
|
} catch (err) {
|
|
67
69
|
warningData.push({
|
|
68
70
|
segment: 'path',
|
|
@@ -73,7 +75,7 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
73
75
|
|
|
74
76
|
// Request query
|
|
75
77
|
try {
|
|
76
|
-
endpointData.requestQuery = parseRequestObjectInput(
|
|
78
|
+
endpointData.requestQuery = parseRequestObjectInput(hookNodes.useQueryParams, 'useQueryParams')
|
|
77
79
|
} catch (err) {
|
|
78
80
|
warningData.push({
|
|
79
81
|
segment: 'query',
|
|
@@ -84,7 +86,7 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
84
86
|
|
|
85
87
|
// Request headers
|
|
86
88
|
try {
|
|
87
|
-
endpointData.requestHeaders = parseRequestObjectInput(
|
|
89
|
+
endpointData.requestHeaders = parseRequestObjectInput(hookNodes.useHeaderParams, 'useHeaderParams')
|
|
88
90
|
} catch (err) {
|
|
89
91
|
warningData.push({
|
|
90
92
|
segment: 'headers',
|
|
@@ -95,7 +97,7 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
95
97
|
|
|
96
98
|
// Raw request body
|
|
97
99
|
try {
|
|
98
|
-
const parsedBody = parseRequestRawBody(
|
|
100
|
+
const parsedBody = parseRequestRawBody(hookNodes.useRequestRawBody)
|
|
99
101
|
if (parsedBody) {
|
|
100
102
|
endpointData.rawBody = parsedBody
|
|
101
103
|
}
|
|
@@ -109,7 +111,7 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
109
111
|
|
|
110
112
|
// Object request body
|
|
111
113
|
try {
|
|
112
|
-
endpointData.objectBody = parseRequestObjectInput(
|
|
114
|
+
endpointData.objectBody = parseRequestObjectInput(hookNodes.useRequestBody, 'useRequestBody')
|
|
113
115
|
} catch (err) {
|
|
114
116
|
warningData.push({
|
|
115
117
|
segment: 'objectBody',
|
|
@@ -132,25 +134,33 @@ export const parseEndpoint = (node: Node<ts.Node>, sourceFilePath: string) => {
|
|
|
132
134
|
return endpointData
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
137
|
+
type HookName =
|
|
138
|
+
| 'useApiEndpoint'
|
|
139
|
+
| 'usePathParams'
|
|
140
|
+
| 'useQueryParams'
|
|
141
|
+
| 'useHeaderParams'
|
|
142
|
+
| 'useRequestBody'
|
|
143
|
+
| 'useRequestRawBody'
|
|
144
|
+
|
|
145
|
+
const getHookNodes = (endpointNode: Node<ts.Node>): Record<HookName, Node<ts.CallExpression> | null> => {
|
|
146
|
+
const result: Record<HookName, Node<ts.CallExpression> | null> = {
|
|
147
|
+
useApiEndpoint: null,
|
|
148
|
+
usePathParams: null,
|
|
149
|
+
useQueryParams: null,
|
|
150
|
+
useHeaderParams: null,
|
|
151
|
+
useRequestBody: null,
|
|
152
|
+
useRequestRawBody: null,
|
|
153
|
+
}
|
|
154
|
+
for (const node of endpointNode.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
155
|
+
const name = node.getFirstChildByKind(SyntaxKind.Identifier)?.getText() as HookName | undefined
|
|
156
|
+
if (name && name in result && result[name] === null) {
|
|
157
|
+
result[name] = node
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return result
|
|
150
161
|
}
|
|
151
162
|
|
|
152
|
-
const parseApiDocumentation = (
|
|
153
|
-
const hookNode = getHookNode(node, 'useApiEndpoint')
|
|
163
|
+
const parseApiDocumentation = (hookNode: Node<ts.CallExpression> | null) => {
|
|
154
164
|
if (!hookNode) {
|
|
155
165
|
return []
|
|
156
166
|
}
|
|
@@ -170,8 +180,10 @@ const parseApiDocumentation = (node: Node<ts.Node>) => {
|
|
|
170
180
|
}[]
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
const parseRequestParams = (
|
|
174
|
-
|
|
183
|
+
const parseRequestParams = (
|
|
184
|
+
hookNode: Node<ts.CallExpression> | null,
|
|
185
|
+
endpointPath: string,
|
|
186
|
+
): EndpointData['requestPathParams'] => {
|
|
175
187
|
if (!hookNode) {
|
|
176
188
|
return []
|
|
177
189
|
}
|
|
@@ -203,8 +215,9 @@ const parseRequestParams = (node: Node<ts.Node>, endpointPath: string): Endpoint
|
|
|
203
215
|
}))
|
|
204
216
|
}
|
|
205
217
|
|
|
206
|
-
const parseRequestRawBody = (
|
|
207
|
-
|
|
218
|
+
const parseRequestRawBody = (
|
|
219
|
+
hookNode: Node<ts.CallExpression> | null,
|
|
220
|
+
): NonNullable<EndpointData['rawBody']> | null => {
|
|
208
221
|
if (!hookNode) {
|
|
209
222
|
return null
|
|
210
223
|
}
|
|
@@ -222,10 +235,9 @@ const parseRequestRawBody = (node: Node<ts.Node>): NonNullable<EndpointData['raw
|
|
|
222
235
|
}
|
|
223
236
|
|
|
224
237
|
const parseRequestObjectInput = (
|
|
225
|
-
|
|
238
|
+
hookNode: Node<ts.CallExpression> | null,
|
|
226
239
|
nodeName: 'useQueryParams' | 'useHeaderParams' | 'useRequestBody',
|
|
227
240
|
): EndpointData['requestQuery'] | EndpointData['objectBody'] => {
|
|
228
|
-
const hookNode = getHookNode(node, nodeName)
|
|
229
241
|
if (!hookNode) {
|
|
230
242
|
return []
|
|
231
243
|
}
|