dot_notation

package
v0.1.13 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2025 License: MIT Imports: 6 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DotNotationRule = rule.CreateRule(rule.Rule{
	Name: "dot-notation",
	Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
		opts := parseOptions(options)
		var allowRE *regexp.Regexp
		if opts.AllowPattern != "" {
			if re, err := regexp.Compile(opts.AllowPattern); err == nil {
				allowRE = re
			}

		}

		if ctx.Program != nil {
			_ = ctx.Program.Options()
		}

		listeners := rule.RuleListeners{}

		listeners[ast.KindElementAccessExpression] = func(node *ast.Node) {
			elem := node.AsElementAccessExpression()
			if elem == nil || elem.ArgumentExpression == nil {
				return
			}

			propName, ok := getStringLiteralValue(ctx.SourceFile, elem.ArgumentExpression)
			if !ok {
				return
			}

			if allowRE != nil && allowRE.MatchString(propName) {
				return
			}

			if !opts.AllowKeywords && (propName == "null" || propName == "true" || propName == "false") {
				return
			}

			objType := ctx.TypeChecker.GetTypeAtLocation(elem.Expression)
			nnType := ctx.TypeChecker.GetNonNullableType(objType)
			appType := checker.Checker_getApparentType(ctx.TypeChecker, nnType)

			sym := checker.Checker_getPropertyOfType(ctx.TypeChecker, appType, propName)
			if sym == nil {
				for _, s := range checker.Checker_getPropertiesOfType(ctx.TypeChecker, appType) {
					if s != nil && s.Name == propName {
						sym = s
						break
					}
				}
			}

			if sym != nil {
				flags := checker.GetDeclarationModifierFlagsFromSymbol(sym)
				if (flags & ast.ModifierFlagsPrivate) != 0 {
					if opts.AllowPrivateClassPropertyAccess {
						return
					}

				} else if (flags & ast.ModifierFlagsProtected) != 0 {
					if opts.AllowProtectedClassPropertyAccess {
						return
					}

				}
			} else {

				allowIndexAccess := opts.AllowIndexSignaturePropertyAccess
				if ctx.Program != nil {
					if copts := ctx.Program.Options(); copts != nil && copts.NoPropertyAccessFromIndexSignature.IsTrue() {
						allowIndexAccess = true
					}
				}

				if hasAnyIndexSignature(appType) && allowIndexAccess {

					return
				}
			}

			if isValidIdentifier(propName) && (opts.AllowKeywords || (!isKeyword(propName))) {

				text := ctx.SourceFile.Text()
				nodeRange := utils.TrimNodeTextRange(ctx.SourceFile, node)
				exprRange := utils.TrimNodeTextRange(ctx.SourceFile, elem.Expression)

				bracketStart := exprRange.End()
				for bracketStart < nodeRange.End() && text[bracketStart] != '[' {
					bracketStart++
				}

				whitespace := ""
				if bracketStart > exprRange.End() {
					whitespace = text[exprRange.End():bracketStart]
				}

				objectText := text[exprRange.Pos():exprRange.End()]
				replacement := objectText + whitespace + "." + propName

				ctx.ReportNodeWithFixes(node, buildUseDotMessage(), rule.RuleFixReplace(ctx.SourceFile, node, replacement))
			}
		}

		listeners[ast.KindPropertyAccessExpression] = func(node *ast.Node) {
			if opts.AllowKeywords {
				return
			}
			pae := node.AsPropertyAccessExpression()
			if pae == nil || pae.Name() == nil || pae.Expression == nil {
				return
			}
			name := pae.Name().Text()
			if !isKeyword(name) && name != "true" && name != "false" && name != "null" {
				return
			}

			textRange := utils.TrimNodeTextRange(ctx.SourceFile, node)
			if !utils.HasCommentsInRange(ctx.SourceFile, textRange) {
				text := ctx.SourceFile.Text()
				objRange := utils.TrimNodeTextRange(ctx.SourceFile, pae.Expression)

				dotPos := objRange.End()
				for dotPos < textRange.End() && text[dotPos] != '.' {
					dotPos++
				}

				whitespace := ""
				if dotPos > objRange.End() {
					whitespace = text[objRange.End():dotPos]
				}

				objectText := text[objRange.Pos():objRange.End()]
				replacement := objectText + whitespace + "[\"" + name + "\"]"
				ctx.ReportNodeWithFixes(node, buildUseBracketsMessage(name), rule.RuleFixReplace(ctx.SourceFile, node, replacement))
				return
			}
			ctx.ReportNode(node, buildUseBracketsMessage(name))
		}

		return listeners
	},
})

DotNotationRule enforces dot-notation when safe and allowed by options.

KNOWN LIMITATION: The test infrastructure in /packages/rule-tester doesn't properly pass TypeScript compiler options from individual test cases. This means tests that rely on specific tsconfig settings (like noPropertyAccessFromIndexSignature) may not work correctly. The test runner always uses the same rslint.json config file for all test cases, which references a fixed tsconfig.json. Individual test cases can specify different tsconfig files via languageOptions.parserOptions.project, but these are ignored by the test runner. See: /packages/rule-tester/src/index.ts line 273 - the lint() call doesn't use per-test config.

Functions

This section is empty.

Types

type Options

type Options struct {
	AllowIndexSignaturePropertyAccess bool   `json:"allowIndexSignaturePropertyAccess"`
	AllowKeywords                     bool   `json:"allowKeywords"`
	AllowPattern                      string `json:"allowPattern"`
	AllowPrivateClassPropertyAccess   bool   `json:"allowPrivateClassPropertyAccess"`
	AllowProtectedClassPropertyAccess bool   `json:"allowProtectedClassPropertyAccess"`
}

Options mirrors @typescript-eslint/dot-notation options

Jump to

Keyboard shortcuts

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