.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / linter / source-code-fixer.js
1 /**
2  * @fileoverview An object that caches and applies source code fixes.
3  * @author Nicholas C. Zakas
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const debug = require("debug")("eslint:source-code-fixer");
12
13 //------------------------------------------------------------------------------
14 // Helpers
15 //------------------------------------------------------------------------------
16
17 const BOM = "\uFEFF";
18
19 /**
20  * Compares items in a messages array by range.
21  * @param {Message} a The first message.
22  * @param {Message} b The second message.
23  * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
24  * @private
25  */
26 function compareMessagesByFixRange(a, b) {
27     return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1];
28 }
29
30 /**
31  * Compares items in a messages array by line and column.
32  * @param {Message} a The first message.
33  * @param {Message} b The second message.
34  * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
35  * @private
36  */
37 function compareMessagesByLocation(a, b) {
38     return a.line - b.line || a.column - b.column;
39 }
40
41 //------------------------------------------------------------------------------
42 // Public Interface
43 //------------------------------------------------------------------------------
44
45 /**
46  * Utility for apply fixes to source code.
47  * @constructor
48  */
49 function SourceCodeFixer() {
50     Object.freeze(this);
51 }
52
53 /**
54  * Applies the fixes specified by the messages to the given text. Tries to be
55  * smart about the fixes and won't apply fixes over the same area in the text.
56  * @param {string} sourceText The text to apply the changes to.
57  * @param {Message[]} messages The array of messages reported by ESLint.
58  * @param {boolean|Function} [shouldFix=true] Determines whether each message should be fixed
59  * @returns {Object} An object containing the fixed text and any unfixed messages.
60  */
61 SourceCodeFixer.applyFixes = function(sourceText, messages, shouldFix) {
62     debug("Applying fixes");
63
64     if (shouldFix === false) {
65         debug("shouldFix parameter was false, not attempting fixes");
66         return {
67             fixed: false,
68             messages,
69             output: sourceText
70         };
71     }
72
73     // clone the array
74     const remainingMessages = [],
75         fixes = [],
76         bom = sourceText.startsWith(BOM) ? BOM : "",
77         text = bom ? sourceText.slice(1) : sourceText;
78     let lastPos = Number.NEGATIVE_INFINITY,
79         output = bom;
80
81     /**
82      * Try to use the 'fix' from a problem.
83      * @param   {Message} problem The message object to apply fixes from
84      * @returns {boolean}         Whether fix was successfully applied
85      */
86     function attemptFix(problem) {
87         const fix = problem.fix;
88         const start = fix.range[0];
89         const end = fix.range[1];
90
91         // Remain it as a problem if it's overlapped or it's a negative range
92         if (lastPos >= start || start > end) {
93             remainingMessages.push(problem);
94             return false;
95         }
96
97         // Remove BOM.
98         if ((start < 0 && end >= 0) || (start === 0 && fix.text.startsWith(BOM))) {
99             output = "";
100         }
101
102         // Make output to this fix.
103         output += text.slice(Math.max(0, lastPos), Math.max(0, start));
104         output += fix.text;
105         lastPos = end;
106         return true;
107     }
108
109     messages.forEach(problem => {
110         if (Object.prototype.hasOwnProperty.call(problem, "fix")) {
111             fixes.push(problem);
112         } else {
113             remainingMessages.push(problem);
114         }
115     });
116
117     if (fixes.length) {
118         debug("Found fixes to apply");
119         let fixesWereApplied = false;
120
121         for (const problem of fixes.sort(compareMessagesByFixRange)) {
122             if (typeof shouldFix !== "function" || shouldFix(problem)) {
123                 attemptFix(problem);
124
125                 /*
126                  * The only time attemptFix will fail is if a previous fix was
127                  * applied which conflicts with it.  So we can mark this as true.
128                  */
129                 fixesWereApplied = true;
130             } else {
131                 remainingMessages.push(problem);
132             }
133         }
134         output += text.slice(Math.max(0, lastPos));
135
136         return {
137             fixed: fixesWereApplied,
138             messages: remainingMessages.sort(compareMessagesByLocation),
139             output
140         };
141     }
142
143     debug("No fixes to apply");
144     return {
145         fixed: false,
146         messages,
147         output: bom + text
148     };
149
150 };
151
152 module.exports = SourceCodeFixer;