Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var NoEmptyInterfaceRule = rule.CreateRule(rule.Rule{ Name: "no-empty-interface", Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { opts := NoEmptyInterfaceOptions{ AllowSingleExtends: false, } if options != nil { var optsMap map[string]interface{} var ok bool if optArray, isArray := options.([]interface{}); isArray && len(optArray) > 0 { optsMap, ok = optArray[0].(map[string]interface{}) } else { optsMap, ok = options.(map[string]interface{}) } if ok { if allowSingleExtends, ok := optsMap["allowSingleExtends"].(bool); ok { opts.AllowSingleExtends = allowSingleExtends } } } return rule.RuleListeners{ ast.KindInterfaceDeclaration: func(node *ast.Node) { interfaceDecl := node.AsInterfaceDeclaration() if interfaceDecl == nil { return } if interfaceDecl.Members != nil && len(interfaceDecl.Members.Nodes) > 0 { return } extendCount := 0 var extendClause *ast.HeritageClause if interfaceDecl.HeritageClauses != nil { for _, clause := range interfaceDecl.HeritageClauses.Nodes { heritageClause := clause.AsHeritageClause() if heritageClause == nil { continue } if heritageClause.Token == ast.KindExtendsKeyword { extendClause = heritageClause extendCount = len(heritageClause.Types.Nodes) break } } } if extendCount == 0 { ctx.ReportNode(interfaceDecl.Name(), rule.RuleMessage{ Id: "noEmpty", Description: "An empty interface is equivalent to `{}`.", }) return } if extendCount == 1 && !opts.AllowSingleExtends { mergedWithClassDeclaration := false if ctx.TypeChecker != nil { symbol := ctx.TypeChecker.GetSymbolAtLocation(interfaceDecl.Name()) if symbol != nil { for _, decl := range symbol.Declarations { if decl.Kind == ast.KindClassDeclaration { mergedWithClassDeclaration = true break } } } } isInAmbientDeclaration := false if strings.HasSuffix(ctx.SourceFile.FileName(), ".d.ts") { parent := node.Parent for parent != nil { if parent.Kind == ast.KindModuleDeclaration { moduleDecl := parent.AsModuleDeclaration() if moduleDecl == nil { parent = parent.Parent continue } modifiers := moduleDecl.Modifiers() if modifiers != nil { for _, modifier := range modifiers.Nodes { if modifier.Kind == ast.KindDeclareKeyword { isInAmbientDeclaration = true break } } } } if isInAmbientDeclaration { break } parent = parent.Parent } } // Build the replacement text // Check for export modifier var exportText string if interfaceDecl.Modifiers() != nil { for _, modifier := range interfaceDecl.Modifiers().Nodes { if modifier.Kind == ast.KindExportKeyword { exportText = "export " break } } } nameRange := utils.TrimNodeTextRange(ctx.SourceFile, interfaceDecl.Name()) nameText := ctx.SourceFile.Text()[nameRange.Pos():nameRange.End()] // Extract type parameters if present var typeParamsText string if interfaceDecl.TypeParameters != nil && len(interfaceDecl.TypeParameters.Nodes) > 0 { firstParam := interfaceDecl.TypeParameters.Nodes[0] lastParam := interfaceDecl.TypeParameters.Nodes[len(interfaceDecl.TypeParameters.Nodes)-1] firstRange := utils.TrimNodeTextRange(ctx.SourceFile, firstParam) lastRange := utils.TrimNodeTextRange(ctx.SourceFile, lastParam) typeParamsRange := firstRange.WithEnd(lastRange.End()) typeParamsRange = typeParamsRange.WithPos(typeParamsRange.Pos() - 1).WithEnd(typeParamsRange.End() + 1) typeParamsText = ctx.SourceFile.Text()[typeParamsRange.Pos():typeParamsRange.End()] } extendedTypeRange := utils.TrimNodeTextRange(ctx.SourceFile, extendClause.Types.Nodes[0]) extendedTypeText := ctx.SourceFile.Text()[extendedTypeRange.Pos():extendedTypeRange.End()] replacement := fmt.Sprintf("%stype %s%s = %s", exportText, nameText, typeParamsText, extendedTypeText) message := rule.RuleMessage{ Id: "noEmptyWithSuper", Description: "An interface declaring no members is equivalent to its supertype.", } if isInAmbientDeclaration || mergedWithClassDeclaration { ctx.ReportNode(interfaceDecl.Name(), message) } else { ctx.ReportNodeWithFixes(interfaceDecl.Name(), message, rule.RuleFixReplace(ctx.SourceFile, node, replacement)) } } }, } }, })
Functions ¶
This section is empty.
Types ¶
type NoEmptyInterfaceOptions ¶
type NoEmptyInterfaceOptions struct {
AllowSingleExtends bool `json:"allowSingleExtends"`
}
Click to show internal directories.
Click to hide internal directories.