UNPKG

3.42 kBJavaScriptView Raw
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} obj The object owning the property.
51 * @param {ASTNode} prop The property of the object.
52 * @param {ASTNode} node The corresponding node of the token.
53 * @returns {void}
54 */
55 function checkDotLocation(obj, prop, node) {
56 const dot = sourceCode.getTokenBefore(prop);
57
58 // `obj` expression can be parenthesized, but those paren tokens are not a part of the `obj` node.
59 const tokenBeforeDot = sourceCode.getTokenBefore(dot);
60
61 const textBeforeDot = sourceCode.getText().slice(tokenBeforeDot.range[1], dot.range[0]);
62 const textAfterDot = sourceCode.getText().slice(dot.range[1], prop.range[0]);
63
64 if (onObject) {
65 if (!astUtils.isTokenOnSameLine(tokenBeforeDot, dot)) {
66 const neededTextAfterToken = astUtils.isDecimalIntegerNumericToken(tokenBeforeDot) ? " " : "";
67
68 context.report({
69 node,
70 loc: dot.loc.start,
71 messageId: "expectedDotAfterObject",
72 fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], prop.range[0]], `${neededTextAfterToken}.${textBeforeDot}${textAfterDot}`)
73 });
74 }
75 } else if (!astUtils.isTokenOnSameLine(dot, prop)) {
76 context.report({
77 node,
78 loc: dot.loc.start,
79 messageId: "expectedDotBeforeProperty",
80 fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], prop.range[0]], `${textBeforeDot}${textAfterDot}.`)
81 });
82 }
83 }
84
85 /**
86 * Checks the spacing of the dot within a member expression.
87 * @param {ASTNode} node The node to check.
88 * @returns {void}
89 */
90 function checkNode(node) {
91 if (!node.computed) {
92 checkDotLocation(node.object, node.property, node);
93 }
94 }
95
96 return {
97 MemberExpression: checkNode
98 };
99 }
100};