Skip to content
This repository was archived by the owner on Jul 30, 2020. It is now read-only.

Commit efa4c07

Browse files
committed
Add section diff utility for VE
1 parent 5d11ddd commit efa4c07

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

33
module.exports = {
4-
sections: require('./lib/sections')
4+
sections: require('./lib/sections'),
5+
sectionDiff: require('./lib/section_diff'),
56
};

lib/section_diff.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use strict';
2+
var assert = require('assert');
3+
4+
/**
5+
* Simple utility for full-document editing with the section API introduced in
6+
* https://phabricator.wikimedia.org/T94890.
7+
*/
8+
9+
/**
10+
* Compute section changes from an array of original IDs & an array of
11+
* modified nodes.
12+
*
13+
* @param {Array<string>} oldIds, the array of original section ids.
14+
* @param {Array<object>} newNodes, objects with
15+
* - {string} id: The id of the node. Absent for new and copy/pasted
16+
* (including moved) content.
17+
* - {boolean} modified, indicating whether this node's content was
18+
* modified.
19+
* - {string} value, the outerHTML of this section. Should exclude ID
20+
* attributes for copy/pasted (duplicated) content, but can include the ids
21+
* for moved content.
22+
* @return {object} Object with changes to the document, ready to be sent to
23+
* the REST section to wikitext transform API.
24+
*/
25+
function sectionDiff(oldIds, newNodes) {
26+
var changes = {};
27+
var oldIdx = 0;
28+
var prevNode = {id: 'mw0', value: ''};
29+
for (var n = 0; n < newNodes.length; n++) {
30+
// New content
31+
while (n < newNodes.length && !newNodes[n].id) {
32+
prevNode.value += newNodes[n].value;
33+
changes[prevNode.id] = prevNode.value;
34+
n++;
35+
}
36+
37+
// Modified sections
38+
var newNode = newNodes[n];
39+
if (newNode.modified) { changes[newNode.id] = newNode.value; }
40+
41+
// Deletions
42+
while (oldIds[oldIdx] !== newNode.id && oldIdx < oldIds.length) {
43+
changes[oldIds[oldIdx]] = '';
44+
oldIdx++;
45+
}
46+
oldIdx++;
47+
prevNode = newNode;
48+
}
49+
for (;oldIdx < oldIds.length; oldIdx++) { changes[oldIds[oldIdx]] = ''; }
50+
return changes;
51+
}
52+
53+
module.exports = sectionDiff;

test/section_diff.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const sectionDiff = require('../').sectionDiff;
5+
6+
const origIds = ['a','b','c','d','e','f'];
7+
8+
// Basic tests
9+
module.exports = {
10+
'Section diff': {
11+
'No change': () => {
12+
assert.deepEqual(sectionDiff(origIds, [{id:'a',value:'a'},{id:'b',value:'b'},{id:'c',value:'c'},{id:'d',value:'d'},{id:'e',value:'e'},{id:'f',value:'f'}]), {});
13+
},
14+
'Single deleted section': () => {
15+
assert.deepEqual(sectionDiff(origIds, [{id:'b',value:'b'},{id:'c',value:'c'},{id:'d',value:'d'},{id:'e',value:'e'},{id:'f',value:'f'}]), {a:''});
16+
},
17+
'Single deleted section, middle': () => {
18+
assert.deepEqual(sectionDiff(origIds, [{id:'a',value:'a'},{id:'c',value:'c'},{id:'d',value:'d'},{id:'e',value:'e'},{id:'f',value:'f'}]), {'b':''});
19+
},
20+
'Delete everything': () => {
21+
assert.deepEqual(sectionDiff(origIds, []), {a:'',b:'',c:'',d:'',e:'',f:''});
22+
},
23+
'Replace first section': () => {
24+
assert.deepEqual(sectionDiff(origIds, [{value:'foo'},{id:'b',value:'b'},{id:'c',value:'c'},{id:'d',value:'d'},{id:'e',value:'e'},{id:'f',value:'f'}]), {mw0:'foo',a:''});
25+
},
26+
'Edit + section replacement': () => {
27+
assert.deepEqual(sectionDiff(origIds, [{id:'a',value:'a'},{id:'b', modified: true, value: 'bar'},{id:'d', modified: true, value: 'deee'},{id:'e',value:'e'},{id:'f',value:'f'}]), {b:'bar',c:'',d:'deee'});
28+
},
29+
'Delete last section': () => {
30+
assert.deepEqual(sectionDiff(origIds, [{id:'a',value:'a'},{id:'b',value:'b'},{id:'c',value:'c'},{id:'d',value:'d'},{id:'e',value:'e'}]), {f:''});
31+
},
32+
'Prepend & delete last section': () => {
33+
assert.deepEqual(sectionDiff(origIds,
34+
[{value: 'foo'},{id:'a',value:'a'},{id:'b',value:'b'},{id:'c',value:'c'},{id:'d',value:'d'},{id:'e'}]),
35+
{'mw0':'foo',f: ''});
36+
},
37+
'Reorder sections 1': () => {
38+
assert.deepEqual(sectionDiff(origIds, [{id:'a', value:'aa'}, {id: 'b',
39+
value:'b'}, {value: 'foo'}, {id:'e', value: 'e'}]), {'b':'bfoo',c:
40+
'', d:'', f:''});
41+
}
42+
}
43+
};

0 commit comments

Comments
 (0)