• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * @fileoverview Validates newlines before and after dots
3 * @author Greg Cochard
4 */
5
6"use strict";
7
8const astUtils = require("./utils/ast-utils");
9
10//------------------------------------------------------------------------------
11// Rule Definition
12//------------------------------------------------------------------------------
13
14module.exports = {
15    meta: {
16        type: "layout",
17
18        docs: {
19            description: "enforce consistent newlines before and after dots",
20            category: "Best Practices",
21            recommended: false,
22            url: "https://eslint.org/docs/rules/dot-location"
23        },
24
25        schema: [
26            {
27                enum: ["object", "property"]
28            }
29        ],
30
31        fixable: "code",
32
33        messages: {
34            expectedDotAfterObject: "Expected dot to be on same line as object.",
35            expectedDotBeforeProperty: "Expected dot to be on same line as property."
36        }
37    },
38
39    create(context) {
40
41        const config = context.options[0];
42
43        // default to onObject if no preference is passed
44        const onObject = config === "object" || !config;
45
46        const sourceCode = context.getSourceCode();
47
48        /**
49         * Reports if the dot between object and property is on the correct loccation.
50         * @param {ASTNode} node The `MemberExpression` node.
51         * @returns {void}
52         */
53        function checkDotLocation(node) {
54            const property = node.property;
55            const dotToken = sourceCode.getTokenBefore(property);
56
57            if (onObject) {
58
59                // `obj` expression can be parenthesized, but those paren tokens are not a part of the `obj` node.
60                const tokenBeforeDot = sourceCode.getTokenBefore(dotToken);
61
62                if (!astUtils.isTokenOnSameLine(tokenBeforeDot, dotToken)) {
63                    context.report({
64                        node,
65                        loc: dotToken.loc,
66                        messageId: "expectedDotAfterObject",
67                        *fix(fixer) {
68                            if (dotToken.value.startsWith(".") && astUtils.isDecimalIntegerNumericToken(tokenBeforeDot)) {
69                                yield fixer.insertTextAfter(tokenBeforeDot, ` ${dotToken.value}`);
70                            } else {
71                                yield fixer.insertTextAfter(tokenBeforeDot, dotToken.value);
72                            }
73                            yield fixer.remove(dotToken);
74                        }
75                    });
76                }
77            } else if (!astUtils.isTokenOnSameLine(dotToken, property)) {
78                context.report({
79                    node,
80                    loc: dotToken.loc,
81                    messageId: "expectedDotBeforeProperty",
82                    *fix(fixer) {
83                        yield fixer.remove(dotToken);
84                        yield fixer.insertTextBefore(property, dotToken.value);
85                    }
86                });
87            }
88        }
89
90        /**
91         * Checks the spacing of the dot within a member expression.
92         * @param {ASTNode} node The node to check.
93         * @returns {void}
94         */
95        function checkNode(node) {
96            if (!node.computed) {
97                checkDotLocation(node);
98            }
99        }
100
101        return {
102            MemberExpression: checkNode
103        };
104    }
105};
106