|
1 | | -import type { ArrowFunctionExpression, Expression, Identifier, ImportDeclaration, MemberExpression, Pattern, RestElement, Statement, TSEntityName, TSType } from "@babel/types"; |
| 1 | +import type { ArrowFunctionExpression, ClassMethod, ClassPrivateMethod, Expression, FunctionDeclaration, FunctionExpression, Identifier, ImportDeclaration, MemberExpression, ObjectMethod, Pattern, RestElement, Statement, TSEntityName, TSType, TSTypeAnnotation } from "@babel/types"; |
2 | 2 | import type { NodePath, PluginObj, PluginPass } from "@babel/core"; |
3 | | -import { assignTypeAnnotation, assignTypeParameters, importName, isTS } from "./utils.js"; |
| 3 | +import { assignReturnType, assignTypeAnnotation, assignTypeParameters, importName, isTS } from "./utils.js"; |
4 | 4 | import { AnalysisError, analyzeBody, analyzeHead, ComponentBody, ComponentHead, needsProps, LibRef } from "./analysis.js"; |
5 | 5 |
|
6 | 6 | type Options = {}; |
@@ -213,34 +213,28 @@ function transformClass(head: ComponentHead, body: ComponentBody, options: { ts: |
213 | 213 | // Method definitions. |
214 | 214 | if (field.init.type === "method") { |
215 | 215 | const methNode = field.init.path.node; |
216 | | - preamble.push(t.functionDeclaration( |
217 | | - t.identifier(field.localName!), |
218 | | - methNode.params as (Identifier | RestElement | Pattern)[], |
219 | | - methNode.body, |
220 | | - methNode.generator, |
221 | | - methNode.async, |
222 | | - )); |
| 216 | + preamble.push(functionDeclarationFrom(babel, methNode, t.identifier(field.localName!))); |
223 | 217 | } else { |
224 | 218 | const methNode = field.init.initPath.node; |
225 | | - if (methNode.type === "ArrowFunctionExpression") { |
226 | | - preamble.push(t.functionDeclaration( |
227 | | - t.identifier(field.localName!), |
228 | | - methNode.params, |
229 | | - methNode.body.type === "BlockStatement" |
230 | | - ? methNode.body |
231 | | - : t.blockStatement([ |
232 | | - t.returnStatement(methNode.body) |
233 | | - ]), |
234 | | - methNode.generator, |
235 | | - methNode.async, |
236 | | - )); |
| 219 | + if ( |
| 220 | + methNode.type === "FunctionExpression" |
| 221 | + && !field.typeAnnotation |
| 222 | + ) { |
| 223 | + preamble.push(functionDeclarationFrom(babel, methNode, t.identifier(field.localName!))); |
237 | 224 | } else { |
238 | | - preamble.push(t.functionDeclaration( |
239 | | - t.identifier(field.localName!), |
240 | | - methNode.params, |
241 | | - methNode.body, |
242 | | - methNode.generator, |
243 | | - methNode.async, |
| 225 | + const expr = |
| 226 | + methNode.type === "FunctionExpression" |
| 227 | + ? functionExpressionFrom(babel, methNode) |
| 228 | + : arrowFunctionExpressionFrom(babel, methNode); |
| 229 | + preamble.push(t.variableDeclaration( |
| 230 | + "const", |
| 231 | + [t.variableDeclarator( |
| 232 | + assignTypeAnnotation( |
| 233 | + t.identifier(field.localName!), |
| 234 | + field.typeAnnotation ? t.tsTypeAnnotation(field.typeAnnotation.node) : undefined |
| 235 | + ), |
| 236 | + expr |
| 237 | + )] |
244 | 238 | )); |
245 | 239 | } |
246 | 240 | } |
@@ -353,6 +347,75 @@ function getReactImport( |
353 | 347 | return t.identifier(newName); |
354 | 348 | } |
355 | 349 |
|
| 350 | +type FunctionLike = FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | ClassMethod | ClassPrivateMethod | ObjectMethod; |
| 351 | + |
| 352 | +function functionName(node: FunctionLike): Identifier | undefined { |
| 353 | + switch (node.type) { |
| 354 | + case "FunctionDeclaration": |
| 355 | + case "FunctionExpression": |
| 356 | + return node.id ?? undefined; |
| 357 | + } |
| 358 | +} |
| 359 | + |
| 360 | +function functionDeclarationFrom( |
| 361 | + babel: typeof import("@babel/core"), |
| 362 | + node: FunctionLike, |
| 363 | + name?: Identifier | null |
| 364 | +) { |
| 365 | + const { types: t } = babel; |
| 366 | + return assignReturnType( |
| 367 | + t.functionDeclaration( |
| 368 | + name ?? functionName(node), |
| 369 | + node.params as (Identifier | RestElement | Pattern)[], |
| 370 | + node.body.type === "BlockStatement" |
| 371 | + ? node.body |
| 372 | + : t.blockStatement([ |
| 373 | + t.returnStatement(node.body) |
| 374 | + ]), |
| 375 | + node.generator, |
| 376 | + node.async, |
| 377 | + ), |
| 378 | + node.returnType |
| 379 | + ); |
| 380 | +} |
| 381 | + |
| 382 | +function functionExpressionFrom( |
| 383 | + babel: typeof import("@babel/core"), |
| 384 | + node: FunctionLike, |
| 385 | + name?: Identifier | null |
| 386 | +) { |
| 387 | + const { types: t } = babel; |
| 388 | + return assignReturnType( |
| 389 | + t.functionExpression( |
| 390 | + name ?? functionName(node), |
| 391 | + node.params as (Identifier | RestElement | Pattern)[], |
| 392 | + node.body.type === "BlockStatement" |
| 393 | + ? node.body |
| 394 | + : t.blockStatement([ |
| 395 | + t.returnStatement(node.body) |
| 396 | + ]), |
| 397 | + node.generator, |
| 398 | + node.async, |
| 399 | + ), |
| 400 | + node.returnType |
| 401 | + ); |
| 402 | +} |
| 403 | + |
| 404 | +function arrowFunctionExpressionFrom( |
| 405 | + babel: typeof import("@babel/core"), |
| 406 | + node: FunctionLike |
| 407 | +) { |
| 408 | + const { types: t } = babel; |
| 409 | + return assignReturnType( |
| 410 | + t.arrowFunctionExpression( |
| 411 | + node.params as (Identifier | RestElement | Pattern)[], |
| 412 | + node.body, |
| 413 | + node.async, |
| 414 | + ), |
| 415 | + node.returnType |
| 416 | + ); |
| 417 | +} |
| 418 | + |
356 | 419 | /** |
357 | 420 | * Refreshes recast's internal state to force generically printing comments. |
358 | 421 | */ |
|
0 commit comments