Files
test-repo/src/language-js/print/function.js
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

227 lines
5.7 KiB
JavaScript
Raw Normal View History

import * as assert from "#universal/assert";
2025-12-06 16:51:31 +08:00
import { group } from "../../document/index.js";
2026-01-28 12:36:39 +08:00
import { getCallArguments } from "../utilities/call-arguments.js";
2026-01-28 10:30:30 +08:00
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
2026-01-28 12:36:39 +08:00
import { getFunctionParameters } from "../utilities/function-parameters.js";
import { isMethod } from "../utilities/is-method.js";
2026-01-28 10:30:30 +08:00
import { isCallExpression } from "../utilities/node-types.js";
2022-02-21 15:53:02 +08:00
import {
printFunctionParameters,
shouldBreakFunctionParameters,
shouldGroupFunctionParameters,
2022-02-21 15:53:02 +08:00
} from "./function-parameters.js";
2026-01-21 10:08:06 +08:00
import { printKey } from "./key.js";
2025-12-06 14:39:00 +08:00
import { printDeclareToken } from "./miscellaneous.js";
import { printTypeAnnotationProperty } from "./type-annotation.js";
2022-02-21 15:53:02 +08:00
/**
2024-10-01 19:45:37 +08:00
* @import AstPath from "../../common/ast-path.js"
2025-11-03 01:52:26 +08:00
* @import {Doc} from "../../document/index.js"
*/
2024-02-03 20:50:44 +08:00
const isMethodValue = ({ node, key, parent }) =>
key === "value" &&
node.type === "FunctionExpression" &&
(parent.type === "ObjectMethod" ||
parent.type === "ClassMethod" ||
parent.type === "ClassPrivateMethod" ||
parent.type === "MethodDefinition" ||
parent.type === "TSAbstractMethodDefinition" ||
parent.type === "TSDeclareMethod" ||
(parent.type === "Property" && isMethod(parent)));
2023-01-25 11:03:02 +08:00
2023-01-14 10:53:24 +08:00
/*
2026-01-14 01:42:32 +08:00
- `FunctionDeclaration`
- `FunctionExpression`
2026-01-15 04:04:03 +08:00
- `HookDeclaration` (Flow)
2023-01-14 10:53:24 +08:00
- `TSDeclareFunction`(TypeScript)
*/
function printFunction(path, options, print, args) {
2023-01-25 11:03:02 +08:00
if (isMethodValue(path)) {
return printMethodValue(path, options, print);
}
const { node } = path;
2021-05-27 18:00:31 +08:00
2026-01-18 02:08:47 +08:00
let shouldExpandParameters = false;
if (node.type === "FunctionExpression" && args?.expandLastArg) {
const { parent } = path;
if (
isCallExpression(parent) &&
(getCallArguments(parent).length > 1 ||
getFunctionParameters(node).every(
(param) => param.type === "Identifier" && !param.typeAnnotation,
))
) {
2026-01-18 02:08:47 +08:00
shouldExpandParameters = true;
2021-05-27 18:00:31 +08:00
}
}
const parametersDoc = printFunctionParameters(
path,
options,
print,
2026-01-18 02:08:47 +08:00
shouldExpandParameters,
);
const returnTypeDoc = printReturnType(path, print);
2021-03-11 04:14:08 +08:00
const shouldGroupParameters = shouldGroupFunctionParameters(
node,
returnTypeDoc,
);
2026-01-15 04:04:03 +08:00
const isFlowHookDeclaration = node.type === "HookDeclaration";
const keyword = isFlowHookDeclaration ? "hook" : "function";
return [
printDeclareToken(path),
node.async ? "async " : "",
keyword,
node.generator ? "*" : "",
" ",
node.id ? print("id") : "",
2025-10-10 21:20:07 +08:00
print("typeParameters"),
group([
shouldGroupParameters ? group(parametersDoc) : parametersDoc,
returnTypeDoc,
]),
2021-03-11 04:14:08 +08:00
node.body ? " " : "",
2021-03-22 22:57:03 +08:00
print("body"),
2026-01-15 04:04:03 +08:00
options.semi && (node.declare || !node.body) ? ";" : "",
];
2020-11-19 23:27:58 +08:00
}
2023-01-25 11:03:02 +08:00
/*
2026-01-14 01:42:32 +08:00
- `FunctionDeclaration`
- `FunctionExpression`
- `TSDeclareFunction`(TypeScript)
2023-01-25 11:03:02 +08:00
- `ObjectMethod`
- `Property`
- `ObjectProperty`
- `ClassMethod`
- `ClassPrivateMethod`
- `MethodDefinition
- `TSAbstractMethodDefinition` (TypeScript)
- `TSDeclareMethod` (TypeScript)
*/
2020-11-19 23:27:58 +08:00
function printMethod(path, options, print) {
const { node } = path;
2020-11-19 23:27:58 +08:00
const { kind } = node;
const value = node.value || node;
const parts = [];
if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
if (value.async) {
parts.push("async ");
}
} else {
assert.ok(kind === "get" || kind === "set");
parts.push(kind, " ");
}
// A `getter`/`setter` can't be a generator, but it's recoverable
if (value.generator) {
parts.push("*");
}
parts.push(
2026-01-21 10:08:06 +08:00
printKey(path, options, print),
node.optional ? "?" : "",
2023-01-25 11:03:02 +08:00
node === value ? printMethodValue(path, options, print) : print("value"),
2020-11-19 23:27:58 +08:00
);
return parts;
2020-11-19 23:27:58 +08:00
}
2026-01-14 01:42:32 +08:00
/*
- `ObjectMethod`
- `Property`
- `ObjectProperty`
- `ClassMethod`
- `ClassPrivateMethod`
- `MethodDefinition
- `TSAbstractMethodDefinition` (TypeScript)
- `TSDeclareMethod` (TypeScript)
- `TSEmptyBodyFunctionExpression` (TypeScript)
*/
2023-01-25 11:03:02 +08:00
function printMethodValue(path, options, print) {
const { node } = path;
const parametersDoc = printFunctionParameters(path, options, print);
const returnTypeDoc = printReturnType(path, print);
const shouldBreakParameters = shouldBreakFunctionParameters(node);
const shouldGroupParameters = shouldGroupFunctionParameters(
node,
returnTypeDoc,
);
2020-11-19 23:27:58 +08:00
const parts = [
2025-10-10 21:20:07 +08:00
print("typeParameters"),
group([
shouldBreakParameters
? group(parametersDoc, { shouldBreak: true })
: shouldGroupParameters
? group(parametersDoc)
: parametersDoc,
returnTypeDoc,
]),
2020-11-19 23:27:58 +08:00
];
if (node.body) {
2021-03-22 22:57:03 +08:00
parts.push(" ", print("body"));
2020-11-19 23:27:58 +08:00
} else {
parts.push(options.semi ? ";" : "");
}
return parts;
2020-11-19 23:27:58 +08:00
}
function canPrintParamsWithoutParens(node) {
const parameters = getFunctionParameters(node);
return (
parameters.length === 1 &&
!node.typeParameters &&
2020-11-25 22:14:27 +08:00
!hasComment(node, CommentCheckFlags.Dangling) &&
2020-11-19 23:27:58 +08:00
parameters[0].type === "Identifier" &&
!parameters[0].typeAnnotation &&
2020-11-25 22:14:27 +08:00
!hasComment(parameters[0]) &&
2020-11-19 23:27:58 +08:00
!parameters[0].optional &&
!node.predicate &&
!node.returnType
);
}
function shouldPrintParamsWithoutParens(path, options) {
if (options.arrowParens === "always") {
return false;
}
if (options.arrowParens === "avoid") {
const { node } = path;
2020-11-19 23:27:58 +08:00
return canPrintParamsWithoutParens(node);
}
// Fallback default; should be unreachable
2022-10-22 23:33:08 +08:00
/* c8 ignore next */
2020-11-19 23:27:58 +08:00
return false;
}
/** @returns {Doc} */
function printReturnType(path, print) {
const { node } = path;
const returnType = printTypeAnnotationProperty(path, print, "returnType");
2020-11-19 23:27:58 +08:00
const parts = [returnType];
2021-03-11 04:14:08 +08:00
if (node.predicate) {
parts.push(print("predicate"));
2020-11-19 23:27:58 +08:00
}
return parts;
2020-11-19 23:27:58 +08:00
}
2022-02-21 15:53:02 +08:00
export {
2021-05-27 18:00:31 +08:00
printFunction,
2020-11-19 23:27:58 +08:00
printMethod,
2023-01-25 11:03:02 +08:00
printMethodValue,
printReturnType,
2020-11-19 23:27:58 +08:00
shouldPrintParamsWithoutParens,
};