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