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.
@@ -1,11 +1,11 @@
1
- import { SyntaxKind as n } from "ts-morph";
2
- import { Logger as c } from "../../utils/logger.mjs";
3
- import { resolveEndpointPath as E, findNodeImplementation as d, getValuesOfObjectLiteral as m, getShapeOfValidatorLiteral as y, getValidatorPropertyStringValue as f, getValidatorPropertyOptionality as x, getValidatorPropertyShape as L, getProperTypeShape as P } from "./nodeParsers.mjs";
4
- const w = (t, s) => {
5
- const o = t.getFirstDescendantByKind(n.PropertyAccessExpression).getText().split(".")[1].toUpperCase(), r = o === "DEL" ? "DELETE" : o, i = E(t) ?? "", l = {
6
- method: r,
7
- path: i,
8
- sourceFilePath: s,
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
- v(t).forEach((a) => {
22
- l[a.identifier] = a.value;
21
+ B(o.useApiEndpoint).forEach((g) => {
22
+ i[g.identifier] = g.value;
23
23
  });
24
- } catch (e) {
25
- c.error("Error", e);
24
+ } catch (s) {
25
+ l.error("Error", s);
26
26
  }
27
27
  try {
28
- l.requestPathParams = C(t, i);
29
- } catch (e) {
30
- c.error("Error", e);
28
+ i.requestPathParams = v(o.usePathParams, u);
29
+ } catch (s) {
30
+ l.error("Error", s);
31
31
  }
32
32
  try {
33
- l.requestQuery = p(t, "useQueryParams");
34
- } catch (e) {
35
- c.error("Error", e);
33
+ i.requestQuery = c(o.useQueryParams, "useQueryParams");
34
+ } catch (s) {
35
+ l.error("Error", s);
36
36
  }
37
37
  try {
38
- l.requestHeaders = p(t, "useHeaderParams");
39
- } catch (e) {
40
- c.error("Error", e);
38
+ i.requestHeaders = c(o.useHeaderParams, "useHeaderParams");
39
+ } catch (s) {
40
+ l.error("Error", s);
41
41
  }
42
42
  try {
43
- const e = K(t);
44
- e && (l.rawBody = e);
45
- } catch (e) {
46
- c.error("Error", e);
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
- l.objectBody = p(t, "useRequestBody");
50
- } catch (e) {
51
- c.error("Error", e);
49
+ i.objectBody = c(o.useRequestBody, "useRequestBody");
50
+ } catch (s) {
51
+ l.error("Error", s);
52
52
  }
53
53
  try {
54
- l.responses = N(t);
55
- } catch (e) {
56
- c.error("Error", e);
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 l;
59
- }, u = (t, s) => t.getDescendantsOfKind(n.CallExpression).filter((i) => i.getFirstChildByKind(n.Identifier)?.getText() === s)[0] ?? null, v = (t) => {
60
- const s = u(t, "useApiEndpoint");
61
- if (!s)
72
+ return n;
73
+ }, B = (t) => {
74
+ if (!t)
62
75
  return [];
63
- const o = s.getFirstChildByKind(n.SyntaxList), r = d(o.getLastChild());
64
- if (!r.isKind(n.ObjectLiteralExpression))
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 i = r.asKind(n.ObjectLiteralExpression);
67
- return m(i).filter((e) => e.value !== null);
68
- }, C = (t, s) => {
69
- const o = u(t, "usePathParams");
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 = o.getFirstChildByKind(n.SyntaxList), i = d(r.getLastChild());
73
- if (!i.isKind(n.ObjectLiteralExpression))
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 l = s.split("/").filter((a) => a.startsWith(":")).map((a) => ({
76
- name: a.substring(1).replace(/\?/, ""),
77
- optional: a.includes("?")
78
- })), e = i.asKind(n.ObjectLiteralExpression);
79
- return y(e).filter((a) => a.shape !== null).map((a) => ({
80
- identifier: a.identifier,
81
- signature: a.shape,
82
- optional: l.some((g) => g.name === a.identifier && g.optional),
83
- description: a.description,
84
- errorMessage: a.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
- const s = u(t, "useRequestRawBody");
88
- if (!s)
99
+ if (!t)
89
100
  return null;
90
- const o = s.getFirstChildByKind(n.SyntaxList), r = d(
91
- o.getLastChild((i) => !i.isKind(n.CommaToken))
101
+ const n = t.getFirstChildByKind(a.SyntaxList), r = d(
102
+ n.getLastChild((e) => !e.isKind(a.CommaToken))
92
103
  );
93
104
  return {
94
- signature: L(r),
95
- optional: x(r),
96
- description: f(r, "description"),
97
- errorMessage: f(r, "errorMessage")
105
+ signature: P(r),
106
+ optional: E(r),
107
+ description: h(r, "description"),
108
+ errorMessage: h(r, "errorMessage")
98
109
  };
99
- }, p = (t, s) => {
100
- const o = u(t, s);
101
- if (!o)
110
+ }, c = (t, n) => {
111
+ if (!t)
102
112
  return [];
103
- const r = o.getFirstChildByKind(n.SyntaxList), i = d(r.getLastChild());
104
- if (!i.isKind(n.ObjectLiteralExpression))
105
- throw new Error(`Non-literal type used in ${s}`);
106
- const l = i.asKind(n.ObjectLiteralExpression);
107
- return y(l).filter((e) => e.shape !== null).map((e) => ({
108
- identifier: e.identifier,
109
- signature: e.shape,
110
- optional: e.optional,
111
- description: e.description,
112
- errorMessage: e.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
- }, N = (t) => {
115
- const o = t.getFirstChildByKind(n.CallExpression).getFirstChildByKind(n.SyntaxList).getFirstChildByKind(n.ArrowFunction).getReturnType(), r = o.getText().startsWith("Promise") ? o.getTypeArguments()[0] : o, i = P(r, t);
116
- return h(i);
117
- }, h = (t) => {
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 h(t[0].shape);
139
+ return p(t[0].shape);
130
140
  if (t[0].role === "property" && t[0].identifier === "_isUseReturnValue") {
131
- const s = (() => {
132
- const r = t.find(
133
- (i) => i.role === "property" && i.identifier === "status"
141
+ const n = (() => {
142
+ const e = t.find(
143
+ (u) => u.role === "property" && u.identifier === "status"
134
144
  )?.shape;
135
- if (!r || typeof r == "string" || typeof r[0].shape != "string")
145
+ if (!e || typeof e == "string" || typeof e[0].shape != "string")
136
146
  throw new Error("Invalid useReturnValue hook");
137
- return parseInt(r[0].shape);
138
- })(), o = (() => {
139
- const r = t.find(
140
- (i) => i.role === "property" && i.identifier === "contentType"
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 (!r || typeof r == "string" || typeof r[0].shape != "string")
152
+ if (!e || typeof e == "string" || typeof e[0].shape != "string")
143
153
  throw new Error("Invalid useReturnValue hook");
144
- return r[0].shape;
154
+ return e[0].shape;
145
155
  })();
146
156
  return [
147
157
  {
148
- status: s,
149
- contentType: o,
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((s) => h([s])) : t[0].role === "buffer" ? [
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
- w as parseEndpoint
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moonflower",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "description": "",
5
5
  "author": "tenebrie",
6
6
  "license": "MIT",
@@ -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: getProperTypeShape(prop.getTypeAtLocation(atLocation), atLocation, nextStack),
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: getProperTypeShape(prop.getTypeAtLocation(atLocation), atLocation, nextStack),
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: 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 ${typeOrPromise.getText()}`)
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(node)
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(node, endpointPath)
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(node, 'useQueryParams')
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(node, 'useHeaderParams')
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(node)
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(node, 'useRequestBody')
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
- const getHookNode = (
136
- endpointNode: Node<ts.Node>,
137
- hookName:
138
- | 'useApiEndpoint'
139
- | 'usePathParams'
140
- | 'useQueryParams'
141
- | 'useHeaderParams'
142
- | 'useRequestBody'
143
- | 'useRequestRawBody',
144
- ) => {
145
- const callExpressions = endpointNode.getDescendantsOfKind(SyntaxKind.CallExpression)
146
- const matchingCallExpressions = callExpressions.filter((node) => {
147
- return node.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === hookName
148
- })
149
- return matchingCallExpressions[0] ?? null
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 = (node: Node<ts.Node>) => {
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 = (node: Node<ts.Node>, endpointPath: string): EndpointData['requestPathParams'] => {
174
- const hookNode = getHookNode(node, 'usePathParams')
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 = (node: Node<ts.Node>): NonNullable<EndpointData['rawBody']> | null => {
207
- const hookNode = getHookNode(node, 'useRequestRawBody')
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
- node: Node<ts.Node>,
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
  }