class_literal_property_style

package
v0.1.10 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2025 License: MIT Imports: 4 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ClassLiteralPropertyStyleRule = rule.CreateRule(rule.Rule{
	Name: "class-literal-property-style",
	Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
		style := "fields"

		if options != nil {
			switch opts := options.(type) {
			case string:
				style = opts
			case []interface{}:
				if len(opts) > 0 {
					if s, ok := opts[0].(string); ok {
						style = s
					}
				}
			}
		}

		var propertiesInfoStack []*propertiesInfo

		listeners := rule.RuleListeners{}

		if style == "fields" {
			listeners[ast.KindGetAccessor] = func(node *ast.Node) {
				getter := node.AsGetAccessorDeclaration()

				if ast.HasSyntacticModifier(node, ast.ModifierFlagsOverride) {
					return
				}

				if getter.Body == nil {
					return
				}

				if !ast.IsBlock(getter.Body) {
					return
				}

				block := getter.Body.AsBlock()
				if block == nil || len(block.Statements.Nodes) == 0 {
					return
				}

				if len(block.Statements.Nodes) != 1 {
					return
				}

				stmt := block.Statements.Nodes[0]
				if !ast.IsReturnStatement(stmt) {
					return
				}

				returnStmt := stmt.AsReturnStatement()
				if returnStmt.Expression == nil || !isSupportedLiteral(returnStmt.Expression) {
					return
				}

				name := getStaticMemberAccessValue(ctx, node)

				if name != "" && node.Parent != nil {
					members := node.Parent.Members()
					for _, member := range members {
						if ast.IsSetAccessorDeclaration(member) && isStaticMemberAccessOfValue(ctx, member, name) {
							return
						}
					}
				}

				nameNode := getter.Name()
				var nameText string
				if nameNode.Kind == ast.KindComputedPropertyName {

					nameText = strings.TrimSpace(ctx.SourceFile.Text()[nameNode.Pos():nameNode.End()])
				} else {

					nameText = nameNode.Text()
				}

				valueText := strings.TrimSpace(ctx.SourceFile.Text()[returnStmt.Expression.Pos():returnStmt.Expression.End()])

				var fixText string
				fixText += printNodeModifiers(node, "readonly")
				fixText += nameText
				fixText += fmt.Sprintf(" = %s;", valueText)

				reportNode := getter.Name()
				if reportNode.Kind == ast.KindComputedPropertyName {
					computed := reportNode.AsComputedPropertyName()
					if computed.Expression != nil {
						reportNode = computed.Expression
					}
				}
				ctx.ReportNodeWithSuggestions(reportNode, buildPreferFieldStyleMessage(),
					rule.RuleSuggestion{
						Message: buildPreferFieldStyleSuggestionMessage(),
						FixesArr: []rule.RuleFix{
							rule.RuleFixReplace(ctx.SourceFile, node, fixText),
						},
					})
			}
		}

		if style == "getters" {
			enterClassBody := func() {
				propertiesInfoStack = append(propertiesInfoStack, &propertiesInfo{
					excludeSet: make(map[string]bool),
					properties: []*ast.Node{},
				})
			}

			exitClassBody := func() {
				if len(propertiesInfoStack) == 0 {
					return
				}

				info := propertiesInfoStack[len(propertiesInfoStack)-1]
				propertiesInfoStack = propertiesInfoStack[:len(propertiesInfoStack)-1]

				for _, node := range info.properties {
					property := node.AsPropertyDeclaration()
					if property.Initializer == nil || !isSupportedLiteral(property.Initializer) {
						continue
					}

					name := getStaticMemberAccessValue(ctx, node)
					if name != "" && info.excludeSet[name] {
						continue
					}

					nameNode := property.Name()
					var nameText string
					if nameNode.Kind == ast.KindComputedPropertyName {

						nameText = strings.TrimSpace(ctx.SourceFile.Text()[nameNode.Pos():nameNode.End()])
					} else {

						nameText = nameNode.Text()
					}

					valueText := strings.TrimSpace(ctx.SourceFile.Text()[property.Initializer.Pos():property.Initializer.End()])

					var fixText string
					fixText += printNodeModifiers(node, "get")
					fixText += nameText
					fixText += fmt.Sprintf("() { return %s; }", valueText)

					reportNode := property.Name()
					if reportNode.Kind == ast.KindComputedPropertyName {
						computed := reportNode.AsComputedPropertyName()
						if computed.Expression != nil {
							reportNode = computed.Expression
						}
					}

					ctx.ReportNodeWithSuggestions(reportNode, buildPreferGetterStyleMessage(),
						rule.RuleSuggestion{
							Message: buildPreferGetterStyleSuggestionMessage(),
							FixesArr: []rule.RuleFix{
								rule.RuleFixReplace(ctx.SourceFile, node, fixText),
							},
						})
				}
			}

			listeners[ast.KindClassDeclaration] = func(node *ast.Node) {
				enterClassBody()
			}
			listeners[rule.ListenerOnExit(ast.KindClassDeclaration)] = func(node *ast.Node) {
				exitClassBody()
			}
			listeners[ast.KindClassExpression] = func(node *ast.Node) {
				enterClassBody()
			}
			listeners[rule.ListenerOnExit(ast.KindClassExpression)] = func(node *ast.Node) {
				exitClassBody()
			}

			listeners[ast.KindThisKeyword] = func(node *ast.Node) {

				if node.Parent == nil || (!ast.IsPropertyAccessExpression(node.Parent) && !ast.IsElementAccessExpression(node.Parent)) {
					return
				}

				memberExpr := node.Parent
				var propName string

				if ast.IsPropertyAccessExpression(memberExpr) {
					propAccess := memberExpr.AsPropertyAccessExpression()
					propName = extractPropertyName(ctx, propAccess.Name())
				} else if ast.IsElementAccessExpression(memberExpr) {
					elemAccess := memberExpr.AsElementAccessExpression()
					if ast.IsLiteralExpression(elemAccess.ArgumentExpression) {
						propName = extractPropertyName(ctx, elemAccess.ArgumentExpression)
					}
				}

				if propName == "" {
					return
				}

				parent := memberExpr.Parent
				for parent != nil && !isFunction(parent) {
					parent = parent.Parent
				}

				if parent != nil && parent.Parent != nil {
					if ast.IsMethodDeclaration(parent.Parent) {
						method := parent.Parent.AsMethodDeclaration()
						if method != nil && method.Kind == ast.KindConstructorKeyword {

							if len(propertiesInfoStack) > 0 {
								info := propertiesInfoStack[len(propertiesInfoStack)-1]
								info.excludeSet[propName] = true
							}
						}
					} else if ast.IsConstructorDeclaration(parent.Parent) {

						if len(propertiesInfoStack) > 0 {
							info := propertiesInfoStack[len(propertiesInfoStack)-1]
							info.excludeSet[propName] = true
						}
					}
				}
			}

			listeners[ast.KindBinaryExpression] = func(node *ast.Node) {
				binary := node.AsBinaryExpression()
				if binary.OperatorToken.Kind != ast.KindEqualsToken {
					return
				}

				left := binary.Left
				if !ast.IsPropertyAccessExpression(left) && !ast.IsElementAccessExpression(left) {
					return
				}

				var thisExpr *ast.Node
				var propName string

				if ast.IsPropertyAccessExpression(left) {
					propAccess := left.AsPropertyAccessExpression()
					if propAccess.Expression.Kind == ast.KindThisKeyword {
						thisExpr = propAccess.Expression
						propName = extractPropertyName(ctx, propAccess.Name())
					}
				} else if ast.IsElementAccessExpression(left) {
					elemAccess := left.AsElementAccessExpression()
					if elemAccess.Expression.Kind == ast.KindThisKeyword {
						thisExpr = elemAccess.Expression
						if ast.IsLiteralExpression(elemAccess.ArgumentExpression) {
							propName = extractPropertyName(ctx, elemAccess.ArgumentExpression)
						}
					}
				}

				if thisExpr == nil || propName == "" {
					return
				}

				current := node.Parent
				for current != nil && !ast.IsConstructorDeclaration(current) {

					if isFunction(current) && !ast.IsConstructorDeclaration(current) {
						return
					}
					current = current.Parent
				}

				if current != nil && len(propertiesInfoStack) > 0 {
					info := propertiesInfoStack[len(propertiesInfoStack)-1]
					info.excludeSet[propName] = true
				}
			}

			listeners[ast.KindPropertyDeclaration] = func(node *ast.Node) {
				if !ast.HasSyntacticModifier(node, ast.ModifierFlagsReadonly) {
					return
				}
				if ast.HasSyntacticModifier(node, ast.ModifierFlagsAmbient) {
					return
				}
				if ast.HasSyntacticModifier(node, ast.ModifierFlagsOverride) {
					return
				}

				if len(propertiesInfoStack) > 0 {
					info := propertiesInfoStack[len(propertiesInfoStack)-1]
					info.properties = append(info.properties, node)
				}
			}
		}

		return listeners
	},
})

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

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