UNPKG

3.67 kBJavaScriptView Raw
1/**
2 * @fileoverview Disallow mixed spaces and tabs for indentation
3 * @author Jary Niebur
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Rule Definition
9//------------------------------------------------------------------------------
10
11module.exports = {
12 meta: {
13 type: "layout",
14
15 docs: {
16 description: "disallow mixed spaces and tabs for indentation",
17 category: "Stylistic Issues",
18 recommended: true,
19 url: "https://eslint.org/docs/rules/no-mixed-spaces-and-tabs"
20 },
21
22 schema: [
23 {
24 enum: ["smart-tabs", true, false]
25 }
26 ],
27
28 messages: {
29 mixedSpacesAndTabs: "Mixed spaces and tabs."
30 }
31 },
32
33 create(context) {
34 const sourceCode = context.getSourceCode();
35
36 let smartTabs;
37
38 switch (context.options[0]) {
39 case true: // Support old syntax, maybe add deprecation warning here
40 case "smart-tabs":
41 smartTabs = true;
42 break;
43 default:
44 smartTabs = false;
45 }
46
47 //--------------------------------------------------------------------------
48 // Public
49 //--------------------------------------------------------------------------
50
51 return {
52
53 "Program:exit"(node) {
54 const lines = sourceCode.lines,
55 comments = sourceCode.getAllComments(),
56 ignoredCommentLines = new Set();
57
58 // Add all lines except the first ones.
59 comments.forEach(comment => {
60 for (let i = comment.loc.start.line + 1; i <= comment.loc.end.line; i++) {
61 ignoredCommentLines.add(i);
62 }
63 });
64
65 /*
66 * At least one space followed by a tab
67 * or the reverse before non-tab/-space
68 * characters begin.
69 */
70 let regex = /^(?=( +|\t+))\1(?:\t| )/u;
71
72 if (smartTabs) {
73
74 /*
75 * At least one space followed by a tab
76 * before non-tab/-space characters begin.
77 */
78 regex = /^(?=(\t*))\1(?=( +))\2\t/u;
79 }
80
81 lines.forEach((line, i) => {
82 const match = regex.exec(line);
83
84 if (match) {
85 const lineNumber = i + 1;
86 const loc = {
87 start: {
88 line: lineNumber,
89 column: match[0].length - 2
90 },
91 end: {
92 line: lineNumber,
93 column: match[0].length
94 }
95 };
96
97 if (!ignoredCommentLines.has(lineNumber)) {
98 const containingNode = sourceCode.getNodeByRangeIndex(sourceCode.getIndexFromLoc(loc.start));
99
100 if (!(containingNode && ["Literal", "TemplateElement"].includes(containingNode.type))) {
101 context.report({
102 node,
103 loc,
104 messageId: "mixedSpacesAndTabs"
105 });
106 }
107 }
108 }
109 });
110 }
111 };
112 }
113};