no_empty_function

package
v0.1.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2025 License: MIT Imports: 3 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var NoEmptyFunctionRule = rule.CreateRule(rule.Rule{
	Name: "no-empty-function",
	Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
		opts := NoEmptyFunctionOptions{
			Allow: []string{},
		}
		if options != nil {
			var optsMap map[string]interface{}
			if optsArray, ok := options.([]interface{}); ok && len(optsArray) > 0 {
				if opts, ok := optsArray[0].(map[string]interface{}); ok {
					optsMap = opts
				}
			} else if opts, ok := options.(map[string]interface{}); ok {
				optsMap = opts
			}

			if optsMap != nil {
				if allow, ok := optsMap["allow"].([]interface{}); ok {
					for _, a := range allow {
						if str, ok := a.(string); ok {
							opts.Allow = append(opts.Allow, str)
						}
					}
				}
			}
		}

		isAllowed := func(allowType string) bool {
			for _, a := range opts.Allow {
				if a == allowType {
					return true
				}
			}
			return false
		}

		isBodyEmpty := func(node *ast.Node) bool {
			switch node.Kind {
			case ast.KindFunctionDeclaration:
				fn := node.AsFunctionDeclaration()
				if fn == nil || fn.Body == nil {
					return false
				}
				return len(fn.Body.Statements()) == 0
			case ast.KindFunctionExpression:
				fn := node.AsFunctionExpression()
				if fn == nil || fn.Body == nil {
					return false
				}
				return len(fn.Body.Statements()) == 0
			case ast.KindArrowFunction:
				fn := node.AsArrowFunction()
				if fn == nil || fn.Body == nil {
					return false
				}

				if fn.Body.Kind != ast.KindBlock {
					return false
				}
				block := fn.Body.AsBlock()
				if block == nil || block.Statements == nil {
					return false
				}
				return len(block.Statements.Nodes) == 0
			case ast.KindConstructor:
				constructor := node.AsConstructorDeclaration()
				if constructor == nil || constructor.Body == nil {
					return false
				}
				return len(constructor.Body.Statements()) == 0
			case ast.KindMethodDeclaration:
				method := node.AsMethodDeclaration()
				if method == nil || method.Body == nil {
					return false
				}
				return len(method.Body.Statements()) == 0
			case ast.KindGetAccessor:
				accessor := node.AsGetAccessorDeclaration()
				if accessor == nil || accessor.Body == nil {
					return false
				}
				return len(accessor.Body.Statements()) == 0
			case ast.KindSetAccessor:
				accessor := node.AsSetAccessorDeclaration()
				if accessor == nil || accessor.Body == nil {
					return false
				}
				return len(accessor.Body.Statements()) == 0
			default:
				return false
			}
		}

		hasParameterProperties := func(node *ast.Node) bool {
			var params []*ast.Node
			switch node.Kind {
			case ast.KindFunctionDeclaration:
				fn := node.AsFunctionDeclaration()
				if fn != nil && fn.Parameters != nil {
					params = fn.Parameters.Nodes
				}
			case ast.KindFunctionExpression:
				fn := node.AsFunctionExpression()
				if fn != nil && fn.Parameters != nil {
					params = fn.Parameters.Nodes
				}
			case ast.KindArrowFunction:
				fn := node.AsArrowFunction()
				if fn != nil && fn.Parameters != nil {
					params = fn.Parameters.Nodes
				}
			case ast.KindConstructor:
				constructor := node.AsConstructorDeclaration()
				if constructor != nil && constructor.Parameters != nil {
					params = constructor.Parameters.Nodes
				}
			}

			for _, param := range params {
				if param.Kind == ast.KindParameter {

					if ast.GetCombinedModifierFlags(param)&(ast.ModifierFlagsPublic|ast.ModifierFlagsPrivate|ast.ModifierFlagsProtected|ast.ModifierFlagsReadonly) != 0 {
						return true
					}
				}
			}
			return false
		}

		getBodyNode := func(node *ast.Node) *ast.Node {
			switch node.Kind {
			case ast.KindFunctionDeclaration:
				fn := node.AsFunctionDeclaration()
				if fn != nil {
					return fn.Body
				}
			case ast.KindFunctionExpression:
				fn := node.AsFunctionExpression()
				if fn != nil {
					return fn.Body
				}
			case ast.KindArrowFunction:
				fn := node.AsArrowFunction()
				if fn != nil && fn.Body != nil && fn.Body.Kind == ast.KindBlock {
					return fn.Body
				}
			case ast.KindConstructor:
				constructor := node.AsConstructorDeclaration()
				if constructor != nil {
					return constructor.Body
				}
			case ast.KindMethodDeclaration:
				method := node.AsMethodDeclaration()
				if method != nil {
					return method.Body
				}
			case ast.KindGetAccessor:
				accessor := node.AsGetAccessorDeclaration()
				if accessor != nil {
					return accessor.Body
				}
			case ast.KindSetAccessor:
				accessor := node.AsSetAccessorDeclaration()
				if accessor != nil {
					return accessor.Body
				}
			}
			return nil
		}

		getFunctionName := func(node *ast.Node) string {
			switch node.Kind {
			case ast.KindFunctionDeclaration:
				fn := node.AsFunctionDeclaration()
				if fn != nil && fn.Name() != nil && fn.Name().Kind == ast.KindIdentifier {
					ident := fn.Name().AsIdentifier()
					if ident != nil {
						return "function '" + ident.Text + "'"
					}
				}
				return "function"
			case ast.KindConstructor:
				return "constructor"
			case ast.KindMethodDeclaration:
				method := node.AsMethodDeclaration()
				if method != nil && method.Name() != nil {
					name, _ := utils.GetNameFromMember(ctx.SourceFile, method.Name())
					return "method '" + name + "'"
				}
				return "method"
			case ast.KindGetAccessor:
				accessor := node.AsGetAccessorDeclaration()
				if accessor != nil && accessor.Name() != nil {
					name, _ := utils.GetNameFromMember(ctx.SourceFile, accessor.Name())
					return "getter '" + name + "'"
				}
				return "getter"
			case ast.KindSetAccessor:
				accessor := node.AsSetAccessorDeclaration()
				if accessor != nil && accessor.Name() != nil {
					name, _ := utils.GetNameFromMember(ctx.SourceFile, accessor.Name())
					return "setter '" + name + "'"
				}
				return "setter"
			case ast.KindFunctionExpression:
				parent := node.Parent
				if parent != nil {
					switch parent.Kind {
					case ast.KindMethodDeclaration:
						method := parent.AsMethodDeclaration()
						if method != nil && method.Name() != nil {
							name, _ := utils.GetNameFromMember(ctx.SourceFile, method.Name())
							if method.Kind == ast.KindGetAccessor {
								return "getter '" + name + "'"
							}
							if method.Kind == ast.KindSetAccessor {
								return "setter '" + name + "'"
							}
							return "method '" + name + "'"
						}
					case ast.KindPropertyDeclaration:
						prop := parent.AsPropertyDeclaration()
						if prop != nil && prop.Name() != nil {
							name, _ := utils.GetNameFromMember(ctx.SourceFile, prop.Name())
							if name != "" {
								return "function '" + name + "'"
							}
						}
					case ast.KindPropertyAssignment:
						prop := parent.AsPropertyAssignment()
						if prop != nil && prop.Name() != nil {
							name, _ := utils.GetNameFromMember(ctx.SourceFile, prop.Name())
							if name != "" {
								return "function '" + name + "'"
							}
						}
					case ast.KindVariableDeclaration:
						decl := parent.AsVariableDeclaration()
						if decl != nil && decl.Name() != nil && decl.Name().Kind == ast.KindIdentifier {
							ident := decl.Name().AsIdentifier()
							if ident != nil {
								return "function '" + ident.Text + "'"
							}
						}
					}
				}
				return "function"
			case ast.KindArrowFunction:
				parent := node.Parent
				if parent != nil && parent.Kind == ast.KindVariableDeclaration {
					decl := parent.AsVariableDeclaration()
					if decl != nil && decl.Name() != nil && decl.Name().Kind == ast.KindIdentifier {
						ident := decl.Name().AsIdentifier()
						if ident != nil {
							return "arrow function '" + ident.Text + "'"
						}
					}
				}
				return "arrow function"
			default:
				return "function"
			}
		}

		checkFunction := func(node *ast.Node) {
			if !isBodyEmpty(node) {
				return
			}

			parent := node.Parent
			isAsync := false
			isGenerator := false

			switch node.Kind {
			case ast.KindFunctionDeclaration:
				fn := node.AsFunctionDeclaration()
				if fn != nil {
					isAsync = ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
					isGenerator = fn.AsteriskToken != nil
				}
			case ast.KindFunctionExpression:
				fn := node.AsFunctionExpression()
				if fn != nil {
					isAsync = ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
					isGenerator = fn.AsteriskToken != nil
				}
			case ast.KindArrowFunction:
				isAsync = ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
			case ast.KindMethodDeclaration:
				method := node.AsMethodDeclaration()
				if method != nil {
					isAsync = ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
					isGenerator = method.AsteriskToken != nil
				}
			case ast.KindGetAccessor:
				isAsync = ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
			case ast.KindSetAccessor:
				isAsync = ast.HasSyntacticModifier(node, ast.ModifierFlagsAsync)
			case ast.KindConstructor:

				hasPrivate := ast.HasSyntacticModifier(node, ast.ModifierFlagsPrivate)
				hasProtected := ast.HasSyntacticModifier(node, ast.ModifierFlagsProtected)

				if isAllowed("constructors") {
					return
				}
				if hasPrivate && isAllowed("private-constructors") {
					return
				}
				if hasProtected && isAllowed("protected-constructors") {
					return
				}

				if hasParameterProperties(node) {
					return
				}
			}

			if node.Kind == ast.KindArrowFunction && isAllowed("arrowFunctions") {
				return
			}

			if isAsync && isAllowed("asyncFunctions") {
				return
			}
			if isGenerator && isAllowed("generatorFunctions") {
				return
			}
			if node.Kind == ast.KindFunctionDeclaration || node.Kind == ast.KindFunctionExpression {
				if isAllowed("functions") {
					return
				}
			}

			if node.Kind == ast.KindMethodDeclaration {

				if ast.GetCombinedModifierFlags(node)&ast.ModifierFlagsDecorator != 0 && isAllowed("decoratedFunctions") {
					return
				}

				if ast.HasSyntacticModifier(node, ast.ModifierFlagsOverride) && isAllowed("overrideMethods") {
					return
				}

				if isAsync && isAllowed("asyncMethods") {
					return
				}
				if isGenerator && isAllowed("generatorMethods") {
					return
				}
				if isAllowed("methods") {
					return
				}
			}

			if node.Kind == ast.KindGetAccessor && isAllowed("getters") {
				return
			}
			if node.Kind == ast.KindSetAccessor && isAllowed("setters") {
				return
			}

			if parent != nil && parent.Kind == ast.KindMethodDeclaration {
				method := parent.AsMethodDeclaration()
				if method != nil {

					if method.Kind == ast.KindGetAccessor && isAllowed("getters") {
						return
					}
					if method.Kind == ast.KindSetAccessor && isAllowed("setters") {
						return
					}

					if ast.GetCombinedModifierFlags(parent)&ast.ModifierFlagsDecorator != 0 && isAllowed("decoratedFunctions") {
						return
					}

					if ast.HasSyntacticModifier(parent, ast.ModifierFlagsOverride) && isAllowed("overrideMethods") {
						return
					}

					if method.Kind == ast.KindMethodSignature || method.Kind == ast.KindMethodDeclaration {
						if isAsync && isAllowed("asyncMethods") {
							return
						}
						if isGenerator && isAllowed("generatorMethods") {
							return
						}
						if isAllowed("methods") {
							return
						}
					}
				}
			} else {

				if node.Kind == ast.KindArrowFunction && isAllowed("arrowFunctions") {
					return
				}
				if isAsync && isAllowed("asyncFunctions") {
					return
				}
				if isGenerator && isAllowed("generatorFunctions") {
					return
				}
				if isAllowed("functions") {
					return
				}
			}

			funcName := getFunctionName(node)
			bodyNode := getBodyNode(node)
			if bodyNode != nil {
				ctx.ReportNode(bodyNode, rule.RuleMessage{
					Id:          "unexpected",
					Description: "Unexpected empty " + funcName + ".",
				})
			} else {

				ctx.ReportNode(node, rule.RuleMessage{
					Id:          "unexpected",
					Description: "Unexpected empty " + funcName + ".",
				})
			}
		}

		return rule.RuleListeners{
			ast.KindFunctionDeclaration: checkFunction,
			ast.KindFunctionExpression:  checkFunction,
			ast.KindArrowFunction:       checkFunction,
			ast.KindConstructor:         checkFunction,
			ast.KindMethodDeclaration:   checkFunction,
			ast.KindGetAccessor:         checkFunction,
			ast.KindSetAccessor:         checkFunction,
		}
	},
})

Functions

This section is empty.

Types

type NoEmptyFunctionOptions

type NoEmptyFunctionOptions struct {
	Allow []string `json:"allow"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL