source-code-fixer.js
3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
* @fileoverview An object that caches and applies source code fixes.
* @author Nicholas C. Zakas
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const debug = require("debug")("eslint:text-fixer");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const BOM = "\uFEFF";
/**
* Compares items in a messages array by range.
* @param {Message} a The first message.
* @param {Message} b The second message.
* @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
* @private
*/
function compareMessagesByFixRange(a, b) {
return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1];
}
/**
* Compares items in a messages array by line and column.
* @param {Message} a The first message.
* @param {Message} b The second message.
* @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
* @private
*/
function compareMessagesByLocation(a, b) {
return a.line - b.line || a.column - b.column;
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
/**
* Utility for apply fixes to source code.
* @constructor
*/
function SourceCodeFixer() {
Object.freeze(this);
}
/**
* Applies the fixes specified by the messages to the given text. Tries to be
* smart about the fixes and won't apply fixes over the same area in the text.
* @param {SourceCode} sourceCode The source code to apply the changes to.
* @param {Message[]} messages The array of messages reported by ESLint.
* @returns {Object} An object containing the fixed text and any unfixed messages.
*/
SourceCodeFixer.applyFixes = function(sourceCode, messages) {
debug("Applying fixes");
if (!sourceCode) {
debug("No source code to fix");
return {
fixed: false,
messages,
output: ""
};
}
// clone the array
const remainingMessages = [],
fixes = [],
bom = (sourceCode.hasBOM ? BOM : ""),
text = sourceCode.text;
let lastPos = Number.NEGATIVE_INFINITY,
output = bom;
messages.forEach(problem => {
if (problem.hasOwnProperty("fix")) {
fixes.push(problem);
} else {
remainingMessages.push(problem);
}
});
if (fixes.length) {
debug("Found fixes to apply");
for (const problem of fixes.sort(compareMessagesByFixRange)) {
const fix = problem.fix;
const start = fix.range[0];
const end = fix.range[1];
// Remain it as a problem if it's overlapped or it's a negative range
if (lastPos >= start || start > end) {
remainingMessages.push(problem);
continue;
}
// Remove BOM.
if ((start < 0 && end >= 0) || (start === 0 && fix.text.startsWith(BOM))) {
output = "";
}
// Make output to this fix.
output += text.slice(Math.max(0, lastPos), Math.max(0, start));
output += fix.text;
lastPos = end;
}
output += text.slice(Math.max(0, lastPos));
return {
fixed: true,
messages: remainingMessages.sort(compareMessagesByLocation),
output
};
}
debug("No fixes to apply");
return {
fixed: false,
messages,
output: bom + text
};
};
module.exports = SourceCodeFixer;