@preventive/compare 1.2.6 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/names/check.js +4 -2
- package/src/names/pairing.js +35 -20
- package/src/names/rename.js +7 -4
package/package.json
CHANGED
package/src/names/check.js
CHANGED
|
@@ -24,12 +24,14 @@ export function checkAnalysis(text, { scopes, variables, occurrences, globals })
|
|
|
24
24
|
for (const at of scopes) for (const [name, variable] of at.names) holds(known.has(variable) && variable.name === name, `a scope's ${name} no variable of its name`)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
// Renamable variables alone paired, each new one once
|
|
28
|
-
|
|
27
|
+
// Renamable variables alone paired, each new one once and by some line, the
|
|
28
|
+
// weak among them.
|
|
29
|
+
export function checkPairing(a, b, { map, support, weak }) {
|
|
29
30
|
const news = new Set(b.variables), taken = new Set()
|
|
30
31
|
for (const [variable, to] of map) {
|
|
31
32
|
holds(variable.aside && to.aside && news.has(to), `${variable.name} paired with ${to.name}, the two not both renamable`)
|
|
32
33
|
holds(!taken.has(to), `two variables paired with ${to.name}`)
|
|
34
|
+
holds(support.get(variable) > 0, `${variable.name} paired with ${to.name} by no line`)
|
|
33
35
|
taken.add(to)
|
|
34
36
|
}
|
|
35
37
|
for (const variable of weak) holds(map.has(variable), `${variable.name} weak, and paired with none`)
|
package/src/names/pairing.js
CHANGED
|
@@ -151,13 +151,13 @@ function moves(ka, kb, blocks, alike) {
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
// Pairs of lines counted, a long run of unchanged ones apart from the rest,
|
|
155
|
-
// apart from both the variables a change's tokens pair
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
154
|
+
// Pairs of lines counted, a long run of unchanged ones apart from the rest, as
|
|
155
|
+
// is code moved, and apart from both the variables a change's tokens pair
|
|
156
|
+
// (`tokened`). Lines reading variables one side has and the other not say
|
|
157
|
+
// nothing. In a change of unlike lengths, lines alike but for a final `;` or `,`
|
|
158
|
+
// pair (a declaration others now follow: `let t = ...;` -> `let t = ...,`).
|
|
159
159
|
function tallied(ka, kb) {
|
|
160
|
-
const changed = tallies(),
|
|
160
|
+
const changed = tallies(), tokened = tallies(), unchanged = tallies()
|
|
161
161
|
const counted = ({ backward, forward }, variable, other) => {
|
|
162
162
|
count(forward, variable, other)
|
|
163
163
|
count(backward, other, variable)
|
|
@@ -182,8 +182,19 @@ function tallied(ka, kb) {
|
|
|
182
182
|
i = block.a1
|
|
183
183
|
j = block.b1
|
|
184
184
|
}
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
// Code moved counts a pair once a line, so that a moved line reading a variable
|
|
186
|
+
// often outweighs no lines in place reading it once each.
|
|
187
|
+
const once = (olds, news) => {
|
|
188
|
+
if (olds.length !== news.length) return
|
|
189
|
+
const seen = new Map()
|
|
190
|
+
olds.forEach((variable, k) => {
|
|
191
|
+
const others = seen.get(variable) ?? seen.set(variable, new Set()).get(variable)
|
|
192
|
+
if (!others.has(news[k])) counted(unchanged, variable, news[k])
|
|
193
|
+
others.add(news[k])
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
moves(ka, kb, blocks, once)
|
|
197
|
+
return { changed, tokened, unchanged }
|
|
187
198
|
}
|
|
188
199
|
|
|
189
200
|
// The most counted of those not yet paired, none where two tie.
|
|
@@ -199,8 +210,9 @@ function best(counts, taken) {
|
|
|
199
210
|
return found
|
|
200
211
|
}
|
|
201
212
|
|
|
202
|
-
// Pairs each the other's best, into `map`, until none more pair
|
|
203
|
-
|
|
213
|
+
// Pairs each the other's best, into `map`, until none more pair: each pair's
|
|
214
|
+
// count its `support`.
|
|
215
|
+
function matched({ backward, forward }, { map, paired, support }, eligible = () => true) {
|
|
204
216
|
const chosen = []
|
|
205
217
|
for (let more = true; more;) {
|
|
206
218
|
more = false
|
|
@@ -209,6 +221,7 @@ function matched({ backward, forward }, { map, paired }, eligible = () => true)
|
|
|
209
221
|
const to = best(counts, (other) => paired.has(other))
|
|
210
222
|
if (!to || best(backward.get(to), (other) => map.has(other)) !== variable || !eligible(variable, to)) continue
|
|
211
223
|
map.set(variable, to)
|
|
224
|
+
support.set(variable, counts.get(to))
|
|
212
225
|
paired.add(to)
|
|
213
226
|
chosen.push(variable)
|
|
214
227
|
more = true
|
|
@@ -217,23 +230,25 @@ function matched({ backward, forward }, { map, paired }, eligible = () => true)
|
|
|
217
230
|
return chosen
|
|
218
231
|
}
|
|
219
232
|
|
|
220
|
-
// Unchanged lines pair first
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
//
|
|
233
|
+
// Unchanged lines pair first, and code moved counted with them: a function's
|
|
234
|
+
// code moved into a helper reads its variables as the helper's, the function's
|
|
235
|
+
// own lines as its own, and the most lines decide. Changed ones then pair only
|
|
236
|
+
// what those say nothing of, and a change's tokens only what no line says
|
|
237
|
+
// anything of: lines reordered, a change's tokens may line up across them. Both
|
|
238
|
+
// are `weak` pairs, the first to give way where names read wrongly. A second
|
|
239
|
+
// pass reads the pairs found as names, so lines alike with every name set aside
|
|
240
|
+
// and diffed against the wrong one line up by those.
|
|
226
241
|
export function pairing(before, after, a, b) {
|
|
227
|
-
const found = { map: new Map(), paired: new Set() }, said = new Set(), weak = new Set()
|
|
242
|
+
const found = { map: new Map(), paired: new Set(), support: new Map() }, said = new Set(), weak = new Set()
|
|
228
243
|
const passes = [[() => null, () => null], [(variable) => found.map.get(variable)?.name ?? null, (variable) => (found.paired.has(variable) ? variable.name : null)]]
|
|
229
244
|
for (const [old, now] of passes) {
|
|
230
245
|
// A pass pairs nothing where every variable of a side is paired already.
|
|
231
246
|
if (!a.variables.some((variable) => variable.aside && !found.map.has(variable)) || !b.variables.some((variable) => variable.aside && !found.paired.has(variable))) break
|
|
232
|
-
const { changed,
|
|
233
|
-
for (const [counts, tier] of [[unchanged, false], [changed, true], [tokened, true]
|
|
247
|
+
const { changed, tokened, unchanged } = tallied(keyed(before, a, old), keyed(after, b, now))
|
|
248
|
+
for (const [counts, tier] of [[unchanged, false], [changed, true], [tokened, true]]) {
|
|
234
249
|
for (const variable of matched(counts, found, (from, to) => !said.has(from) && !said.has(to))) if (tier) weak.add(variable)
|
|
235
250
|
for (const variable of [...counts.forward.keys(), ...counts.backward.keys()]) said.add(variable)
|
|
236
251
|
}
|
|
237
252
|
}
|
|
238
|
-
return { map: found.map, weak }
|
|
253
|
+
return { map: found.map, support: found.support, weak }
|
|
239
254
|
}
|
package/src/names/rename.js
CHANGED
|
@@ -11,9 +11,10 @@ import { pairing } from './pairing.js'
|
|
|
11
11
|
import { APART, Broken, holds } from './syntax.js'
|
|
12
12
|
|
|
13
13
|
// Each old variable's name: its counterpart's, else its own, or one apart where
|
|
14
|
-
// the new side has its own. Those misread yield, weak pairs first
|
|
15
|
-
//
|
|
16
|
-
|
|
14
|
+
// the new side has its own. Those misread yield, weak pairs first, else those
|
|
15
|
+
// fewest lines pair: a pair that a few lines alone say gives way to one most
|
|
16
|
+
// do. null where none can.
|
|
17
|
+
function givenNames(a, b, { map, support, weak }) {
|
|
17
18
|
const apart = (name) => {
|
|
18
19
|
let named = name + APART
|
|
19
20
|
for (let n = 2; a.names.has(named) || b.names.has(named); n++) named = `${name}${APART}${n}`
|
|
@@ -27,7 +28,9 @@ function givenNames(a, b, { map, weak }) {
|
|
|
27
28
|
}
|
|
28
29
|
const wrong = [...misread(a, given)]
|
|
29
30
|
if (wrong.length === 0) return given
|
|
30
|
-
const
|
|
31
|
+
const paired = wrong.filter((variable) => map.has(variable))
|
|
32
|
+
const least = paired.reduce((n, variable) => Math.min(n, support.get(variable)), Infinity)
|
|
33
|
+
const yielding = paired.some((variable) => weak.has(variable)) ? paired.filter((variable) => weak.has(variable)) : paired.filter((variable) => support.get(variable) === least)
|
|
31
34
|
if (yielding.filter((variable) => map.delete(variable)).length === 0) return null
|
|
32
35
|
}
|
|
33
36
|
}
|