/
fix-tracker.js
146 lines (124 loc) · 4.88 KB
/
fix-tracker.js
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @fileoverview Tests for FixTracker.
* @author Alan Pierce
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const assert = require("chai").assert,
espree = require("espree"),
FixTracker = require("../../../../lib/rules/utils/fix-tracker"),
ruleFixer = require("../../../../lib/linter/rule-fixer"),
{ SourceCode } = require("../../../../lib/source-code"),
Traverser = require("../../../../lib/shared/traverser");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const DEFAULT_CONFIG = {
ecmaVersion: 6,
comment: true,
tokens: true,
range: true,
loc: true
};
/**
* Create a SourceCode instance from the given code. Also add parent pointers in
* the AST so that parent traversals will work.
* @param {string} text The text of the code.
* @returns {SourceCode} The SourceCode.
*/
function createSourceCode(text) {
const ast = espree.parse(text, DEFAULT_CONFIG);
Traverser.traverse(ast, {
enter(node, parent) {
node.parent = parent;
}
});
return new SourceCode(text, ast);
}
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
describe("FixTracker", () => {
describe("replaceTextRange", () => {
it("should expand to include an explicitly retained range", () => {
const sourceCode = createSourceCode("var foo = +bar;");
const result = new FixTracker(ruleFixer, sourceCode)
.retainRange([4, 14])
.replaceTextRange([10, 11], "-");
assert.deepStrictEqual(result, {
range: [4, 14],
text: "foo = -bar"
});
});
it("ignores a retained range that's smaller than the replaced range", () => {
const sourceCode = createSourceCode("abcdefghij");
const result = new FixTracker(ruleFixer, sourceCode)
.retainRange([5, 7])
.replaceTextRange([4, 8], "123");
assert.deepStrictEqual(result, {
range: [4, 8],
text: "123"
});
});
it("allows an unspecified retained range", () => {
const sourceCode = createSourceCode("abcdefghij");
const result = new FixTracker(ruleFixer, sourceCode)
.replaceTextRange([4, 8], "123");
assert.deepStrictEqual(result, {
range: [4, 8],
text: "123"
});
});
});
describe("remove", () => {
it("should expand to include an explicitly retained range", () => {
const sourceCode = createSourceCode("a = b + +c");
const result = new FixTracker(ruleFixer, sourceCode)
.retainRange([4, 10])
.remove(sourceCode.ast.tokens[4]);
assert.deepStrictEqual(result, {
range: [4, 10],
text: "b + c"
});
});
});
describe("retainEnclosingFunction", () => {
it("handles a normal enclosing function", () => {
const sourceCode = createSourceCode("f = function() { return x; }");
const xNode = sourceCode.ast.body[0].expression.right.body.body[0].argument;
const result = new FixTracker(ruleFixer, sourceCode)
.retainEnclosingFunction(xNode)
.replaceTextRange(xNode.range, "y");
assert.deepStrictEqual(result, {
range: [4, 28],
text: "function() { return y; }"
});
});
it("handles the case when there is no enclosing function", () => {
const sourceCode = createSourceCode("const a = b;");
const bNode = sourceCode.ast.body[0].declarations[0].init;
const result = new FixTracker(ruleFixer, sourceCode)
.retainEnclosingFunction(bNode)
.replaceTextRange(bNode.range, "c");
assert.deepStrictEqual(result, {
range: [0, 12],
text: "const a = c;"
});
});
});
describe("retainSurroundingTokens", () => {
it("handles a change to a binary operator", () => {
const sourceCode = createSourceCode("const i = j + k;");
const plusToken = sourceCode.ast.tokens[4];
const result = new FixTracker(ruleFixer, sourceCode)
.retainSurroundingTokens(plusToken)
.replaceTextRange(plusToken.range, "*");
assert.deepStrictEqual(result, {
range: [10, 15],
text: "j * k"
});
});
});
});