diff --git a/data/presets.yaml b/data/presets.yaml index 61a0437b1..241a13702 100644 --- a/data/presets.yaml +++ b/data/presets.yaml @@ -450,6 +450,11 @@ en: description: # description=* label: Description + devices: + # devices=* + label: Number of Devices + # devices field placeholder + placeholder: '1, 2, 3...' diaper: # diaper=* label: Diaper Changing Available @@ -546,6 +551,9 @@ en: label: Type # ford field placeholder placeholder: Default + frequency: + # frequency=* + label: Operating Frequency fuel: # fuel=* label: Fuel @@ -977,6 +985,11 @@ en: payment_multi: # 'payment:=*' label: Payment Types + phases: + # phases=* + label: Number of Phases + # phases field placeholder + placeholder: '1, 2, 3...' phone: # phone=* label: Phone @@ -1078,6 +1091,9 @@ en: railway: # railway=* label: Type + rating: + # rating=* + label: Power Rating recycling_accepts: # 'recycling:=*' label: Accepts @@ -1443,6 +1459,26 @@ en: 'no': 'No: pathless, excellent orientation skills required' # trail_visibility field placeholder placeholder: 'Excellent, Good, Bad...' + transformer: + # transformer=* + label: Type of Transformer + options: + # transformer=auto + auto: Autotransformer + # transformer=auxiliary + auxiliary: Auxiliarty + # transformer=converter + converter: Converter + # transformer=distribution + distribution: Distribution + # transformer=generator + generator: Generator + # transformer=phase_angle_regulator + phase_angle_regulator: Phase Angle Regulator + # transformer=traction + traction: Traction + # transformer=yes + 'yes': Unknown trees: # trees=* label: Trees @@ -1484,6 +1520,15 @@ en: shield: Shield # 'volcano:type=stratovolcano' stratovolcano: Stratovolcano + voltage/primary: + # 'voltage:primary=*' + label: Primary Voltage + voltage/secondary: + # 'voltage:secondary=*' + label: Secondary Voltage + voltage/tertiary: + # 'voltage:tertiary=*' + label: Tertiary Voltage wall: # wall=* label: Type @@ -1513,6 +1558,29 @@ en: wikipedia: # 'wikipedia=*, wikidata=*' label: Wikipedia + windings: + # windings=* + label: Number of Windings + # windings field placeholder + placeholder: '1, 2, 3...' + windings/configuration: + # 'windings:configuration=*' + label: Windings Configuration + options: + # 'windings:configuration=delta' + delta: Delta + # 'windings:configuration=leblanc' + leblanc: Leblanc + # 'windings:configuration=open' + open: Open + # 'windings:configuration=open-delta' + open-delta: Open Delta + # 'windings:configuration=scott' + scott: Scott + # 'windings:configuration=star' + star: Star / Wye + # 'windings:configuration=zigzag' + zigzag: Zig Zag presets: address: # 'addr:*=*' diff --git a/data/presets/fields.json b/data/presets/fields.json index 5ed5f7172..a71ff70ef 100644 --- a/data/presets/fields.json +++ b/data/presets/fields.json @@ -594,6 +594,12 @@ "label": "Description", "universal": true }, + "devices": { + "key": "devices", + "type": "number", + "label": "Number of Devices", + "placeholder": "1, 2, 3..." + }, "diaper": { "key": "diaper", "type": "combo", @@ -740,6 +746,11 @@ "label": "Type", "placeholder": "Default" }, + "frequency": { + "key": "frequency", + "type": "combo", + "label": "Operating Frequency" + }, "fuel_multi": { "key": "fuel:", "type": "multiCombo", @@ -1316,6 +1327,12 @@ "type": "multiCombo", "label": "Payment Types" }, + "phases": { + "key": "phases", + "type": "number", + "label": "Number of Phases", + "placeholder": "1, 2, 3..." + }, "phone": { "key": "phone", "type": "tel", @@ -1435,6 +1452,12 @@ "type": "typeCombo", "label": "Type" }, + "rating": { + "key": "rating", + "type": "combo", + "label": "Power Rating", + "snake_case": false + }, "recycling_accepts": { "key": "recycling:", "type": "multiCombo", @@ -1964,6 +1987,23 @@ } } }, + "transformer": { + "key": "transformer", + "type": "combo", + "label": "Type of Transformer", + "strings": { + "options": { + "distribution": "Distribution", + "generator": "Generator", + "converter": "Converter", + "traction": "Traction", + "auto": "Autotransformer", + "phase_angle_regulator": "Phase Angle Regulator", + "auxiliary": "Auxiliarty", + "yes": "Unknown" + } + } + }, "trees": { "key": "trees", "type": "semiCombo", @@ -2016,6 +2056,21 @@ } } }, + "voltage/primary": { + "key": "voltage:primary", + "type": "combo", + "label": "Primary Voltage" + }, + "voltage/secondary": { + "key": "voltage:secondary", + "type": "combo", + "label": "Secondary Voltage" + }, + "voltage/tertiary": { + "key": "voltage:tertiary", + "type": "combo", + "label": "Tertiary Voltage" + }, "wall": { "key": "wall", "type": "combo", @@ -2076,6 +2131,28 @@ "icon": "wikipedia", "universal": true, "label": "Wikipedia" + }, + "windings": { + "key": "windings", + "type": "number", + "label": "Number of Windings", + "placeholder": "1, 2, 3..." + }, + "windings/configuration": { + "key": "windings:configuration", + "type": "combo", + "label": "Windings Configuration", + "strings": { + "options": { + "star": "Star / Wye", + "delta": "Delta", + "open-delta": "Open Delta", + "zigzag": "Zig Zag", + "open": "Open", + "scott": "Scott", + "leblanc": "Leblanc" + } + } } } } \ No newline at end of file diff --git a/data/presets/fields/devices.json b/data/presets/fields/devices.json new file mode 100644 index 000000000..d2f35f22e --- /dev/null +++ b/data/presets/fields/devices.json @@ -0,0 +1,6 @@ +{ + "key": "devices", + "type": "number", + "label": "Number of Devices", + "placeholder": "1, 2, 3..." +} diff --git a/data/presets/fields/frequency.json b/data/presets/fields/frequency.json new file mode 100644 index 000000000..97246994d --- /dev/null +++ b/data/presets/fields/frequency.json @@ -0,0 +1,5 @@ +{ + "key": "frequency", + "type": "combo", + "label": "Operating Frequency" +} diff --git a/data/presets/fields/phases.json b/data/presets/fields/phases.json new file mode 100644 index 000000000..5b32604d5 --- /dev/null +++ b/data/presets/fields/phases.json @@ -0,0 +1,6 @@ +{ + "key": "phases", + "type": "number", + "label": "Number of Phases", + "placeholder": "1, 2, 3..." +} diff --git a/data/presets/fields/rating.json b/data/presets/fields/rating.json new file mode 100644 index 000000000..334552d14 --- /dev/null +++ b/data/presets/fields/rating.json @@ -0,0 +1,6 @@ +{ + "key": "rating", + "type": "combo", + "label": "Power Rating", + "snake_case": false +} diff --git a/data/presets/fields/transformer.json b/data/presets/fields/transformer.json new file mode 100644 index 000000000..b4f877ffc --- /dev/null +++ b/data/presets/fields/transformer.json @@ -0,0 +1,17 @@ +{ + "key": "transformer", + "type": "combo", + "label": "Type of Transformer", + "strings": { + "options": { + "distribution": "Distribution", + "generator": "Generator", + "converter": "Converter", + "traction": "Traction", + "auto": "Autotransformer", + "phase_angle_regulator": "Phase Angle Regulator", + "auxiliary": "Auxiliarty", + "yes": "Unknown" + } + } +} diff --git a/data/presets/fields/voltage/primary.json b/data/presets/fields/voltage/primary.json new file mode 100644 index 000000000..b8f7af86f --- /dev/null +++ b/data/presets/fields/voltage/primary.json @@ -0,0 +1,5 @@ +{ + "key": "voltage:primary", + "type": "combo", + "label": "Primary Voltage" +} diff --git a/data/presets/fields/voltage/secondary.json b/data/presets/fields/voltage/secondary.json new file mode 100644 index 000000000..676c2cf0f --- /dev/null +++ b/data/presets/fields/voltage/secondary.json @@ -0,0 +1,5 @@ +{ + "key": "voltage:secondary", + "type": "combo", + "label": "Secondary Voltage" +} diff --git a/data/presets/fields/voltage/tertiary.json b/data/presets/fields/voltage/tertiary.json new file mode 100644 index 000000000..f3a516e0d --- /dev/null +++ b/data/presets/fields/voltage/tertiary.json @@ -0,0 +1,5 @@ +{ + "key": "voltage:tertiary", + "type": "combo", + "label": "Tertiary Voltage" +} diff --git a/data/presets/fields/windings.json b/data/presets/fields/windings.json new file mode 100644 index 000000000..2c123b0a7 --- /dev/null +++ b/data/presets/fields/windings.json @@ -0,0 +1,6 @@ +{ + "key": "windings", + "type": "number", + "label": "Number of Windings", + "placeholder": "1, 2, 3..." +} diff --git a/data/presets/fields/windings/configuration.json b/data/presets/fields/windings/configuration.json new file mode 100644 index 000000000..defe3ec2c --- /dev/null +++ b/data/presets/fields/windings/configuration.json @@ -0,0 +1,16 @@ +{ + "key": "windings:configuration", + "type": "combo", + "label": "Windings Configuration", + "strings": { + "options": { + "star": "Star / Wye", + "delta": "Delta", + "open-delta": "Open Delta", + "zigzag": "Zig Zag", + "open": "Open", + "scott": "Scott", + "leblanc": "Leblanc" + } + } +} diff --git a/data/presets/presets.json b/data/presets/presets.json index 1a8772944..35c2a1046 100644 --- a/data/presets/presets.json +++ b/data/presets/presets.json @@ -12026,6 +12026,19 @@ }, "power/transformer": { "icon": "poi-power", + "fields": [ + "transformer", + "location", + "rating", + "devices", + "phases", + "frequency", + "voltage/primary", + "voltage/secondary", + "voltage/tertiary", + "windings", + "windings/configuration" + ], "geometry": [ "point", "vertex", diff --git a/data/presets/presets/power/transformer.json b/data/presets/presets/power/transformer.json index aa1bb5104..f1af8a2ec 100644 --- a/data/presets/presets/power/transformer.json +++ b/data/presets/presets/power/transformer.json @@ -1,5 +1,18 @@ { "icon": "poi-power", + "fields": [ + "transformer", + "location", + "rating", + "devices", + "phases", + "frequency", + "voltage/primary", + "voltage/secondary", + "voltage/tertiary", + "windings", + "windings/configuration" + ], "geometry": [ "point", "vertex", diff --git a/dist/locales/en.json b/dist/locales/en.json index c4eef77bd..86ef1b37e 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -1472,6 +1472,10 @@ "description": { "label": "Description" }, + "devices": { + "label": "Number of Devices", + "placeholder": "1, 2, 3..." + }, "diaper": { "label": "Diaper Changing Available" }, @@ -1553,6 +1557,9 @@ "label": "Type", "placeholder": "Default" }, + "frequency": { + "label": "Operating Frequency" + }, "fuel_multi": { "label": "Fuel Types" }, @@ -1911,6 +1918,10 @@ "payment_multi": { "label": "Payment Types" }, + "phases": { + "label": "Number of Phases", + "placeholder": "1, 2, 3..." + }, "phone": { "label": "Phone", "placeholder": "+31 42 123 4567" @@ -1990,6 +2001,9 @@ "railway": { "label": "Type" }, + "rating": { + "label": "Power Rating" + }, "recycling_accepts": { "label": "Accepts" }, @@ -2299,6 +2313,19 @@ "no": "No: pathless, excellent orientation skills required" } }, + "transformer": { + "label": "Type of Transformer", + "options": { + "distribution": "Distribution", + "generator": "Generator", + "converter": "Converter", + "traction": "Traction", + "auto": "Autotransformer", + "phase_angle_regulator": "Phase Angle Regulator", + "auxiliary": "Auxiliarty", + "yes": "Unknown" + } + }, "trees": { "label": "Trees" }, @@ -2333,6 +2360,15 @@ "scoria": "Scoria" } }, + "voltage/primary": { + "label": "Primary Voltage" + }, + "voltage/secondary": { + "label": "Secondary Voltage" + }, + "voltage/tertiary": { + "label": "Tertiary Voltage" + }, "wall": { "label": "Type" }, @@ -2360,6 +2396,22 @@ }, "wikipedia": { "label": "Wikipedia" + }, + "windings": { + "label": "Number of Windings", + "placeholder": "1, 2, 3..." + }, + "windings/configuration": { + "label": "Windings Configuration", + "options": { + "star": "Star / Wye", + "delta": "Delta", + "open-delta": "Open Delta", + "zigzag": "Zig Zag", + "open": "Open", + "scott": "Scott", + "leblanc": "Leblanc" + } } }, "presets": { diff --git a/modules/actions/merge_remote_changes.js b/modules/actions/merge_remote_changes.js index b842f3322..71412bf00 100644 --- a/modules/actions/merge_remote_changes.js +++ b/modules/actions/merge_remote_changes.js @@ -9,10 +9,10 @@ import _union from 'lodash-es/union'; import _uniq from 'lodash-es/uniq'; import _without from 'lodash-es/without'; +import { diff3Merge } from 'node-diff3'; import { t } from '../util/locale'; import { actionDeleteMultiple } from './delete_multiple'; import { osmEntity } from '../osm'; -import { diff3_merge } from '../util/diff3'; import { dataDiscarded } from '../../data'; @@ -57,7 +57,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser a = target.nodes || [], b = remote.nodes || [], nodes = [], - hunks = diff3_merge(a, o, b, true); + hunks = diff3Merge(a, o, b, true); for (var i = 0; i < hunks.length; i++) { var hunk = hunks[i]; @@ -65,7 +65,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser nodes.push.apply(nodes, hunk.ok); } else { // for all conflicts, we can assume c.a !== c.b - // because `diff3_merge` called with `true` option to exclude false conflicts.. + // because `diff3Merge` called with `true` option to exclude false conflicts.. var c = hunk.conflict; if (_isEqual(c.o, c.a)) { // only changed remotely nodes.push.apply(nodes, c.b); diff --git a/modules/services/taginfo.js b/modules/services/taginfo.js index 50b4e2c34..2149b37a3 100644 --- a/modules/services/taginfo.js +++ b/modules/services/taginfo.js @@ -264,7 +264,7 @@ export default { // A few OSM keys expect values to contain uppercase values (see #3377). // This is not an exhaustive list (e.g. `name` also has uppercase values) // but these are the fields where taginfo value lookup is most useful. - var re = /network|taxon|genus|species|brand|grape_variety|_hours|_times/; + var re = /network|taxon|genus|species|brand|grape_variety|rating|:output|_hours|_times/; var allowUpperCase = (params.key.match(re) !== null); var f = filterValues(allowUpperCase); diff --git a/modules/util/diff3.js b/modules/util/diff3.js deleted file mode 100644 index d36371a14..000000000 --- a/modules/util/diff3.js +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright (c) 2006, 2008 Tony Garnock-Jones -// Copyright (c) 2006, 2008 LShift Ltd. -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation files -// (the "Software"), to deal in the Software without restriction, -// including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, -// and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -// source: https://bitbucket.org/lshift/synchrotron/src -export function longest_common_subsequence(file1, file2) { - /* Text diff algorithm following Hunt and McIlroy 1976. - * J. W. Hunt and M. D. McIlroy, An algorithm for differential file - * comparison, Bell Telephone Laboratories CSTR #41 (1976) - * http://www.cs.dartmouth.edu/~doug/ - * - * Expects two arrays of strings. - */ - var equivalenceClasses; - var file2indices; - var newCandidate; - var candidates; - var line; - var c, i, j, jX, r, s; - - equivalenceClasses = {}; - for (j = 0; j < file2.length; j++) { - line = file2[j]; - if (equivalenceClasses[line]) { - equivalenceClasses[line].push(j); - } else { - equivalenceClasses[line] = [j]; - } - } - - candidates = [{file1index: -1, - file2index: -1, - chain: null}]; - - for (i = 0; i < file1.length; i++) { - line = file1[i]; - file2indices = equivalenceClasses[line] || []; - - r = 0; - c = candidates[0]; - - for (jX = 0; jX < file2indices.length; jX++) { - j = file2indices[jX]; - - for (s = 0; s < candidates.length; s++) { - if ((candidates[s].file2index < j) && - ((s === candidates.length - 1) || - (candidates[s + 1].file2index > j))) - break; - } - - if (s < candidates.length) { - newCandidate = {file1index: i, - file2index: j, - chain: candidates[s]}; - if (r === candidates.length) { - candidates.push(c); - } else { - candidates[r] = c; - } - r = s + 1; - c = newCandidate; - if (r === candidates.length) { - break; // no point in examining further (j)s - } - } - } - - candidates[r] = c; - } - - // At this point, we know the LCS: it's in the reverse of the - // linked-list through .chain of - // candidates[candidates.length - 1]. - - return candidates[candidates.length - 1]; -} - -export function diff_comm(file1, file2) { - // We apply the LCS to build a "comm"-style picture of the - // differences between file1 and file2. - - var result = []; - var tail1 = file1.length; - var tail2 = file2.length; - var common = {common: []}; - - function processCommon() { - if (common.common.length) { - common.common.reverse(); - result.push(common); - common = {common: []}; - } - } - - for (var candidate = longest_common_subsequence(file1, file2); - candidate !== null; - candidate = candidate.chain) - { - var different = {file1: [], file2: []}; - - while (--tail1 > candidate.file1index) { - different.file1.push(file1[tail1]); - } - - while (--tail2 > candidate.file2index) { - different.file2.push(file2[tail2]); - } - - if (different.file1.length || different.file2.length) { - processCommon(); - different.file1.reverse(); - different.file2.reverse(); - result.push(different); - } - - if (tail1 >= 0) { - common.common.push(file1[tail1]); - } - } - - processCommon(); - - result.reverse(); - return result; -} - -export function diff_patch(file1, file2) { - // We apply the LCD to build a JSON representation of a - // diff(1)-style patch. - - var result = []; - var tail1 = file1.length; - var tail2 = file2.length; - - function chunkDescription(file, offset, length) { - var chunk = []; - for (var i = 0; i < length; i++) { - chunk.push(file[offset + i]); - } - return {offset: offset, - length: length, - chunk: chunk}; - } - - for (var candidate = longest_common_subsequence(file1, file2); - candidate !== null; - candidate = candidate.chain) - { - var mismatchLength1 = tail1 - candidate.file1index - 1; - var mismatchLength2 = tail2 - candidate.file2index - 1; - tail1 = candidate.file1index; - tail2 = candidate.file2index; - - if (mismatchLength1 || mismatchLength2) { - result.push({file1: chunkDescription(file1, - candidate.file1index + 1, - mismatchLength1), - file2: chunkDescription(file2, - candidate.file2index + 1, - mismatchLength2)}); - } - } - - result.reverse(); - return result; -} - -export function strip_patch(patch) { - // Takes the output of Diff3.diff_patch(), and removes - // information from it. It can still be used by patch(), - // below, but can no longer be inverted. - var newpatch = []; - for (var i = 0; i < patch.length; i++) { - var chunk = patch[i]; - newpatch.push({file1: {offset: chunk.file1.offset, - length: chunk.file1.length}, - file2: {chunk: chunk.file2.chunk}}); - } - return newpatch; -} - -export function invert_patch (patch) { - // Takes the output of Diff3.diff_patch(), and inverts the - // sense of it, so that it can be applied to file2 to give - // file1 rather than the other way around. - - for (var i = 0; i < patch.length; i++) { - var chunk = patch[i]; - var tmp = chunk.file1; - chunk.file1 = chunk.file2; - chunk.file2 = tmp; - } -} - -export function patch (file, patch) { - // Applies a patch to a file. - // - // Given file1 and file2, Diff3.patch(file1, - // Diff3.diff_patch(file1, file2)) should give file2. - - var result = []; - var commonOffset = 0; - - function copyCommon(targetOffset) { - while (commonOffset < targetOffset) { - result.push(file[commonOffset]); - commonOffset++; - } - } - - for (var chunkIndex = 0; chunkIndex < patch.length; chunkIndex++) { - var chunk = patch[chunkIndex]; - copyCommon(chunk.file1.offset); - for (var lineIndex = 0; lineIndex < chunk.file2.chunk.length; lineIndex++) { - result.push(chunk.file2.chunk[lineIndex]); - } - commonOffset += chunk.file1.length; - } - - copyCommon(file.length); - return result; -} - -export function diff_indices(file1, file2) { - // We apply the LCS to give a simple representation of the - // offsets and lengths of mismatched chunks in the input - // files. This is used by diff3_merge_indices below. - - var result = []; - var tail1 = file1.length; - var tail2 = file2.length; - - for (var candidate = longest_common_subsequence(file1, file2); - candidate !== null; - candidate = candidate.chain) - { - var mismatchLength1 = tail1 - candidate.file1index - 1; - var mismatchLength2 = tail2 - candidate.file2index - 1; - tail1 = candidate.file1index; - tail2 = candidate.file2index; - - if (mismatchLength1 || mismatchLength2) { - result.push({file1: [tail1 + 1, mismatchLength1], - file2: [tail2 + 1, mismatchLength2]}); - } - } - - result.reverse(); - return result; -} - -export function diff3_merge_indices (a, o, b) { - // Given three files, A, O, and B, where both A and B are - // independently derived from O, returns a fairly complicated - // internal representation of merge decisions it's taken. The - // interested reader may wish to consult - // - // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A - // Formal Investigation of Diff3." In Arvind and Prasad, - // editors, Foundations of Software Technology and Theoretical - // Computer Science (FSTTCS), December 2007. - // - // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf) - var i; - - var m1 = diff_indices(o, a); - var m2 = diff_indices(o, b); - - var hunks = []; - function addHunk(h, side) { - hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]); - } - for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); } - for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); } - hunks.sort(); - - var result = []; - var commonOffset = 0; - function copyCommon(targetOffset) { - if (targetOffset > commonOffset) { - result.push([1, commonOffset, targetOffset - commonOffset]); - commonOffset = targetOffset; - } - } - - for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) { - var firstHunkIndex = hunkIndex; - var hunk = hunks[hunkIndex]; - var regionLhs = hunk[0]; - var regionRhs = regionLhs + hunk[2]; - while (hunkIndex < hunks.length - 1) { - var maybeOverlapping = hunks[hunkIndex + 1]; - var maybeLhs = maybeOverlapping[0]; - if (maybeLhs > regionRhs) break; - regionRhs = maybeLhs + maybeOverlapping[2]; - hunkIndex++; - } - - copyCommon(regionLhs); - if (firstHunkIndex === hunkIndex) { - // The "overlap" was only one hunk long, meaning that - // there's no conflict here. Either a and o were the - // same, or b and o were the same. - if (hunk[4] > 0) { - result.push([hunk[1], hunk[3], hunk[4]]); - } - } else { - // A proper conflict. Determine the extents of the - // regions involved from a, o and b. Effectively merge - // all the hunks on the left into one giant hunk, and - // do the same for the right; then, correct for skew - // in the regions of o that each side changed, and - // report appropriate spans for the three sides. - var regions = { - 0: [a.length, -1, o.length, -1], - 2: [b.length, -1, o.length, -1] - }; - for (i = firstHunkIndex; i <= hunkIndex; i++) { - hunk = hunks[i]; - var side = hunk[1]; - var r = regions[side]; - var oLhs = hunk[0]; - var oRhs = oLhs + hunk[2]; - var abLhs = hunk[3]; - var abRhs = abLhs + hunk[4]; - r[0] = Math.min(abLhs, r[0]); - r[1] = Math.max(abRhs, r[1]); - r[2] = Math.min(oLhs, r[2]); - r[3] = Math.max(oRhs, r[3]); - } - var aLhs = regions[0][0] + (regionLhs - regions[0][2]); - var aRhs = regions[0][1] + (regionRhs - regions[0][3]); - var bLhs = regions[2][0] + (regionLhs - regions[2][2]); - var bRhs = regions[2][1] + (regionRhs - regions[2][3]); - result.push([-1, - aLhs, aRhs - aLhs, - regionLhs, regionRhs - regionLhs, - bLhs, bRhs - bLhs]); - } - commonOffset = regionRhs; - } - - copyCommon(o.length); - return result; -} - -export function diff3_merge (a, o, b, excludeFalseConflicts) { - // Applies the output of Diff3.diff3_merge_indices to actually - // construct the merged file; the returned result alternates - // between "ok" and "conflict" blocks. - - var result = []; - var files = [a, o, b]; - var indices = diff3_merge_indices(a, o, b); - - var okLines = []; - function flushOk() { - if (okLines.length) { - result.push({ok: okLines}); - } - okLines = []; - } - function pushOk(xs) { - for (var j = 0; j < xs.length; j++) { - okLines.push(xs[j]); - } - } - - function isTrueConflict(rec) { - if (rec[2] !== rec[6]) return true; - var aoff = rec[1]; - var boff = rec[5]; - for (var j = 0; j < rec[2]; j++) { - if (a[j + aoff] !== b[j + boff]) return true; - } - return false; - } - - for (var i = 0; i < indices.length; i++) { - var x = indices[i]; - var side = x[0]; - if (side === -1) { - if (excludeFalseConflicts && !isTrueConflict(x)) { - pushOk(files[0].slice(x[1], x[1] + x[2])); - } else { - flushOk(); - result.push({conflict: {a: a.slice(x[1], x[1] + x[2]), - aIndex: x[1], - o: o.slice(x[3], x[3] + x[4]), - oIndex: x[3], - b: b.slice(x[5], x[5] + x[6]), - bIndex: x[5]}}); - } - } else { - pushOk(files[side].slice(x[1], x[1] + x[2])); - } - } - - flushOk(); - return result; -} diff --git a/package.json b/package.json index 57b4e1727..0803814e9 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "diacritics": "1.3.0", "lodash-es": "4.17.4", "marked": "0.3.6", + "node-diff3": "bhousel/node-diff3.git#v0.1.0", "osm-auth": "1.0.2", "rbush": "2.0.1", "wmf-sitematrix": "0.1.4" diff --git a/test/index.html b/test/index.html index 4d4ca1b70..c391ca88e 100644 --- a/test/index.html +++ b/test/index.html @@ -77,7 +77,6 @@ - diff --git a/test/spec/lib/diff3.js b/test/spec/lib/diff3.js deleted file mode 100644 index 588b5bbdf..000000000 --- a/test/spec/lib/diff3.js +++ /dev/null @@ -1,90 +0,0 @@ -/* global Diff3:false */ -describe('diff3', function() { - function split(s) { - return s ? s.split(/ /) : []; - } - - it('performs diff3 merge', function() { - var o = split('AA ZZ 00 M 99'), - a = split('AA a b c ZZ new 00 a a M 99'), - b = split('AA a d c ZZ 11 M z z 99'), - res = Diff3.diff3_merge(a, o, b); - - /* - AA - <<<<<<< a - a - b - c - ||||||| o - ======= - a - d - c - >>>>>>> b - ZZ - <<<<<<< a - new - 00 - a - a - ||||||| o - 00 - ======= - 11 - >>>>>>> b - M - z - z - 99 - */ - - expect(res[0].ok).to.eql(['AA']); - expect(res[0].conflict).to.be.undefined; - - expect(res[1].ok).to.be.undefined; - expect(res[1].conflict.o).to.eql([]); - expect(res[1].conflict.a).to.eql(['a', 'b', 'c']); - expect(res[1].conflict.b).to.eql(['a', 'd', 'c']); - - expect(res[2].ok).to.eql(['ZZ']); - expect(res[2].conflict).to.be.undefined; - - expect(res[3].ok).to.be.undefined; - expect(res[3].conflict.o).to.eql(['00']); - expect(res[3].conflict.a).to.eql(['new', '00', 'a', 'a']); - expect(res[3].conflict.b).to.eql(['11']); - - expect(res[4].ok).to.eql(['M', 'z', 'z', '99']); - expect(res[4].conflict).to.be.undefined; - }); - - it('can include false conflicts', function() { - var o = split('AA ZZ'), - a = split('AA a b c ZZ'), - b = split('AA a b c ZZ'), - res = Diff3.diff3_merge(a, o, b, false); - - expect(res[0].ok).to.eql(['AA']); - expect(res[0].conflict).to.be.undefined; - - expect(res[1].ok).to.be.undefined; - expect(res[1].conflict.o).to.eql([]); - expect(res[1].conflict.a).to.eql(['a', 'b', 'c']); - expect(res[1].conflict.b).to.eql(['a', 'b', 'c']); - - expect(res[2].ok).to.eql(['ZZ']); - expect(res[2].conflict).to.be.undefined; - }); - - it('can exclude false conflicts', function() { - var o = split('AA ZZ'), - a = split('AA a b c ZZ'), - b = split('AA a b c ZZ'), - res = Diff3.diff3_merge(a, o, b, true); - - expect(res[0].ok).to.eql(['AA', 'a', 'b', 'c', 'ZZ']); - expect(res[0].conflict).to.be.undefined; - }); - -});