1 | /**
|
2 | * @fileoverview An object that caches and applies source code fixes.
|
3 | * @author Nicholas C. Zakas
|
4 | * @copyright 2015 Nicholas C. Zakas. All rights reserved.
|
5 | * See LICENSE file in root directory for full license.
|
6 | */
|
7 | ;
|
8 |
|
9 | //------------------------------------------------------------------------------
|
10 | // Requirements
|
11 | //------------------------------------------------------------------------------
|
12 |
|
13 | var debug = require("debug")("eslint:text-fixer");
|
14 |
|
15 | //------------------------------------------------------------------------------
|
16 | // Helpers
|
17 | //------------------------------------------------------------------------------
|
18 |
|
19 | /**
|
20 | * Compares items in a messages array by line and column.
|
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 compareMessagesByLocation(a, b) {
|
27 | var lineDiff = a.line - b.line;
|
28 |
|
29 | if (lineDiff === 0) {
|
30 | return a.column - b.column;
|
31 | } else {
|
32 | return lineDiff;
|
33 | }
|
34 | }
|
35 |
|
36 | //------------------------------------------------------------------------------
|
37 | // Public Interface
|
38 | //------------------------------------------------------------------------------
|
39 |
|
40 | /**
|
41 | * Utility for apply fixes to source code.
|
42 | * @constructor
|
43 | */
|
44 | function SourceCodeFixer() {
|
45 | Object.freeze(this);
|
46 | }
|
47 |
|
48 | /**
|
49 | * Applies the fixes specified by the messages to the given text. Tries to be
|
50 | * smart about the fixes and won't apply fixes over the same area in the text.
|
51 | * @param {SourceCode} sourceCode The source code to apply the changes to.
|
52 | * @param {Message[]} messages The array of messages reported by ESLint.
|
53 | * @returns {Object} An object containing the fixed text and any unfixed messages.
|
54 | */
|
55 | SourceCodeFixer.applyFixes = function(sourceCode, messages) {
|
56 |
|
57 | debug("Applying fixes");
|
58 |
|
59 | // clone the array
|
60 | var remainingMessages = [],
|
61 | fixes = [],
|
62 | text = sourceCode.text,
|
63 | lastFixPos = text.length + 1;
|
64 |
|
65 | messages.forEach(function(problem) {
|
66 | if (problem.hasOwnProperty("fix")) {
|
67 | fixes.push(problem);
|
68 | } else {
|
69 | remainingMessages.push(problem);
|
70 | }
|
71 | });
|
72 |
|
73 | if (fixes.length) {
|
74 | debug("Found fixes to apply");
|
75 |
|
76 | // sort in reverse order of occurrence
|
77 | fixes.sort(function(a, b) {
|
78 | if (a.fix.range[1] <= b.fix.range[0]) {
|
79 | return 1;
|
80 | } else {
|
81 | return -1;
|
82 | }
|
83 | });
|
84 |
|
85 | // split into array of characters for easier manipulation
|
86 | var chars = text.split("");
|
87 |
|
88 | fixes.forEach(function(problem) {
|
89 | var fix = problem.fix;
|
90 |
|
91 | if (fix.range[1] <= lastFixPos) {
|
92 | chars.splice(fix.range[0], fix.range[1] - fix.range[0], fix.text);
|
93 | lastFixPos = fix.range[0];
|
94 | } else {
|
95 | remainingMessages.push(problem);
|
96 | }
|
97 | });
|
98 |
|
99 | return {
|
100 | fixed: true,
|
101 | messages: remainingMessages.sort(compareMessagesByLocation),
|
102 | output: chars.join("")
|
103 | };
|
104 | } else {
|
105 | debug("No fixes to apply");
|
106 | return {
|
107 | fixed: false,
|
108 | messages: messages,
|
109 | output: text
|
110 | };
|
111 | }
|
112 | };
|
113 |
|
114 | module.exports = SourceCodeFixer;
|