-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmutation.js
108 lines (82 loc) · 2.84 KB
/
mutation.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
const chalk = require('chalk')
const jsdiff = require('diff')
const fs = require('fs')
const sha1 = require('sha1')
const config = require('./config')
const baselineDir = config.baselineDir
const contractsDir = config.contractsDir
function splice(str, start, length, replacement) {
return str.substring(0, start) + replacement + str.substring(start + length)
}
function Mutation(file, start, end, replace) {
this.file = file
this.start = start
this.end = end
this.replace = replace
}
Mutation.prototype.hash = function() {
const input = [this.file, this.start, this.end, this.replace].join(':')
return sha1(input).slice(0, 8)
}
Mutation.prototype.apply = function() {
const original = fs.readFileSync(this.file, 'utf8')
const mutated = this.applyToString(original)
fs.writeFileSync(this.file, mutated, 'utf8')
}
Mutation.prototype.applyToString = function(original) {
return splice(original, this.start, this.end - this.start, this.replace)
}
Mutation.prototype.restore = function() {
const baseline = this.baseline()
console.log('Restoring ' + this.file)
const original = fs.readFileSync(baseline, 'utf8')
fs.writeFileSync(this.file, original, 'utf8')
}
Mutation.prototype.baseline = function() {
return baselineDir + this.file.substr(contractsDir.length)
}
Mutation.prototype.diff = function() {
const original = fs.readFileSync(this.baseline(), 'utf8')
const mutated = this.applyToString(original)
let diff = jsdiff.diffLines(original, mutated)
const lineNumber = this.getLineNumber()
const context = 2
diff = diff
.filter(part => part.added || part.removed)
.map(function(part) {
// green for additions, red for deletions
// grey for common parts
const color = part.added ? 'green' : part.removed ? 'red' : 'grey'
let num
if (part.removed) {
num = lineNumber.toString().padStart(4)
num = chalk.gray(num + ' | ')
} else {
num = chalk.gray(' | ')
}
return num + chalk[color](part.value.replace(/\n$/, ''))
})
let lines = mutated.split('\n').map((line, i) => {
const num = (i + 1).toString().padStart(4)
return chalk.gray(num + ' | ' + line)
})
lines.splice(lineNumber - 1, 1, diff[0], diff[1])
lines = lines.slice(Math.max(0, lineNumber - context - 1), lineNumber + context + 1)
return lines.join('\n') + '\n'
}
Mutation.prototype.getLineNumber = function() {
const source = fs.readFileSync(this.baseline(), 'utf8')
const indexes = []
for (let i = 0; i < source.length; i++) {
if (source[i] == '\n') {
indexes.push(i)
}
}
return indexes.findIndex(idx => idx > this.start) + 1
}
Mutation.prototype.patch = function() {
const original = fs.readFileSync(this.baseline(), 'utf8')
const mutated = this.applyToString(original)
return jsdiff.createPatch(this.file, original, mutated)
}
module.exports = Mutation