| /** |
| * @fileoverview Rule to enforce a particular function style |
| * @author Nicholas C. Zakas |
| */ |
| "use strict"; |
| |
| //------------------------------------------------------------------------------ |
| // Rule Definition |
| //------------------------------------------------------------------------------ |
| |
| /** @type {import('../types').Rule.RuleModule} */ |
| module.exports = { |
| meta: { |
| type: "suggestion", |
| |
| defaultOptions: [ |
| "expression", |
| { |
| allowArrowFunctions: false, |
| overrides: {}, |
| }, |
| ], |
| |
| docs: { |
| description: |
| "Enforce the consistent use of either `function` declarations or expressions assigned to variables", |
| recommended: false, |
| frozen: true, |
| url: "https://eslint.org/docs/latest/rules/func-style", |
| }, |
| |
| schema: [ |
| { |
| enum: ["declaration", "expression"], |
| }, |
| { |
| type: "object", |
| properties: { |
| allowArrowFunctions: { |
| type: "boolean", |
| }, |
| overrides: { |
| type: "object", |
| properties: { |
| namedExports: { |
| enum: ["declaration", "expression", "ignore"], |
| }, |
| }, |
| additionalProperties: false, |
| }, |
| }, |
| additionalProperties: false, |
| }, |
| ], |
| |
| messages: { |
| expression: "Expected a function expression.", |
| declaration: "Expected a function declaration.", |
| }, |
| }, |
| |
| create(context) { |
| const [style, { allowArrowFunctions, overrides }] = context.options; |
| const enforceDeclarations = style === "declaration"; |
| const { namedExports: exportFunctionStyle } = overrides; |
| const stack = []; |
| |
| const nodesToCheck = { |
| FunctionDeclaration(node) { |
| stack.push(false); |
| |
| if ( |
| !enforceDeclarations && |
| node.parent.type !== "ExportDefaultDeclaration" && |
| (typeof exportFunctionStyle === "undefined" || |
| node.parent.type !== "ExportNamedDeclaration") |
| ) { |
| context.report({ node, messageId: "expression" }); |
| } |
| |
| if ( |
| node.parent.type === "ExportNamedDeclaration" && |
| exportFunctionStyle === "expression" |
| ) { |
| context.report({ node, messageId: "expression" }); |
| } |
| }, |
| "FunctionDeclaration:exit"() { |
| stack.pop(); |
| }, |
| |
| FunctionExpression(node) { |
| stack.push(false); |
| |
| if ( |
| enforceDeclarations && |
| node.parent.type === "VariableDeclarator" && |
| (typeof exportFunctionStyle === "undefined" || |
| node.parent.parent.parent.type !== |
| "ExportNamedDeclaration") |
| ) { |
| context.report({ |
| node: node.parent, |
| messageId: "declaration", |
| }); |
| } |
| |
| if ( |
| node.parent.type === "VariableDeclarator" && |
| node.parent.parent.parent.type === |
| "ExportNamedDeclaration" && |
| exportFunctionStyle === "declaration" |
| ) { |
| context.report({ |
| node: node.parent, |
| messageId: "declaration", |
| }); |
| } |
| }, |
| "FunctionExpression:exit"() { |
| stack.pop(); |
| }, |
| |
| "ThisExpression, Super"() { |
| if (stack.length > 0) { |
| stack[stack.length - 1] = true; |
| } |
| }, |
| }; |
| |
| if (!allowArrowFunctions) { |
| nodesToCheck.ArrowFunctionExpression = function () { |
| stack.push(false); |
| }; |
| |
| nodesToCheck["ArrowFunctionExpression:exit"] = function (node) { |
| const hasThisOrSuperExpr = stack.pop(); |
| |
| if ( |
| !hasThisOrSuperExpr && |
| node.parent.type === "VariableDeclarator" |
| ) { |
| if ( |
| enforceDeclarations && |
| (typeof exportFunctionStyle === "undefined" || |
| node.parent.parent.parent.type !== |
| "ExportNamedDeclaration") |
| ) { |
| context.report({ |
| node: node.parent, |
| messageId: "declaration", |
| }); |
| } |
| |
| if ( |
| node.parent.parent.parent.type === |
| "ExportNamedDeclaration" && |
| exportFunctionStyle === "declaration" |
| ) { |
| context.report({ |
| node: node.parent, |
| messageId: "declaration", |
| }); |
| } |
| } |
| }; |
| } |
| |
| return nodesToCheck; |
| }, |
| }; |