@adecore/merge 0.23.1 → 0.24.1
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/dist/blocks.d.ts +0 -1
- package/dist/blocks.js +0 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/patch.js +5 -1
- package/dist/resolve.d.ts +0 -1
- package/dist/resolve.js +8 -15
- package/package.json +2 -1
- package/src/blocks.ts +0 -5
- package/src/index.ts +2 -2
- package/src/patch.ts +6 -1
- package/src/resolve.ts +8 -16
package/dist/blocks.d.ts
CHANGED
package/dist/blocks.js
CHANGED
|
@@ -76,7 +76,3 @@ export function splitBlocks(base, ours, theirs) {
|
|
|
76
76
|
push(base.length, ours.length, theirs.length);
|
|
77
77
|
return blocks;
|
|
78
78
|
}
|
|
79
|
-
/* The stretches a person still has to decide on. */
|
|
80
|
-
export function openBlocks(blocks) {
|
|
81
|
-
return blocks.filter((block) => block.kind === 'conflict').length;
|
|
82
|
-
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { diffLines, type Change } from './diff.ts';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { splitBlocks, type MergeBlock, type MergeBlockKind } from './blocks.ts';
|
|
3
|
+
export { bothLines, draftOf, fingerprint, sideLines, wandLines, type MergeDraft, type MergeSide, type MergeSpan } from './resolve.ts';
|
|
4
4
|
export { joinLines, shapeOf, splitLines, type TextShape } from './text.ts';
|
|
5
5
|
export { missingSides, patchFits } from './patch.ts';
|
|
6
6
|
export { parsePatch, parseHunkHeader, type HunkHeader, type Hunk, type ParsedPatch, type PatchLine } from './patch-parser.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { diffLines } from './diff.js';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { splitBlocks } from './blocks.js';
|
|
3
|
+
export { bothLines, draftOf, fingerprint, sideLines, wandLines } from './resolve.js';
|
|
4
4
|
export { joinLines, shapeOf, splitLines } from './text.js';
|
|
5
5
|
export { missingSides, patchFits } from './patch.js';
|
|
6
6
|
export { parsePatch, parseHunkHeader } from './patch-parser.js';
|
package/dist/patch.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parsePatch } from './patch-parser.js';
|
|
1
2
|
/* Which side a patch says the file is missing on, read from its header so no line of the file can pass for it. */
|
|
2
3
|
export function missingSides(patch) {
|
|
3
4
|
const start = patch.search(/^@@/m);
|
|
@@ -5,8 +6,11 @@ export function missingSides(patch) {
|
|
|
5
6
|
return { old: /^--- \/dev\/null$/m.test(header), new: /^\+\+\+ \/dev\/null$/m.test(header) };
|
|
6
7
|
}
|
|
7
8
|
const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
8
|
-
/* Git's --ignore-all-space may show either side's spacing on a context line. */
|
|
9
|
+
/* Git's --ignore-all-space may show either side's spacing on a context line. A patch cut off before its hunks end fits nothing. */
|
|
9
10
|
export function patchFits(patch, oldText, newText, ignoreWhitespace) {
|
|
11
|
+
if (parsePatch(patch).partial) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
10
14
|
const oldLines = oldText.split('\n');
|
|
11
15
|
const newLines = newText.split('\n');
|
|
12
16
|
const same = ignoreWhitespace
|
package/dist/resolve.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { MergeBlock } from './blocks.ts';
|
|
|
2
2
|
export type MergeSide = 'ours' | 'theirs';
|
|
3
3
|
export declare function sideLines(block: MergeBlock, side: MergeSide): string[];
|
|
4
4
|
export declare function bothLines(block: MergeBlock, first: MergeSide): string[];
|
|
5
|
-
export declare function autoLines(block: MergeBlock): string[] | null;
|
|
6
5
|
export declare function wandLines(block: MergeBlock): string[] | null;
|
|
7
6
|
export declare function fingerprint(block: MergeBlock): string;
|
|
8
7
|
export interface MergeSpan {
|
package/dist/resolve.js
CHANGED
|
@@ -6,7 +6,7 @@ export function bothLines(block, first) {
|
|
|
6
6
|
return first === 'ours' ? [...block.ours, ...block.theirs] : [...block.theirs, ...block.ours];
|
|
7
7
|
}
|
|
8
8
|
/* What a block is worth without anyone choosing: the side that changed, or the change both made. */
|
|
9
|
-
|
|
9
|
+
function autoLines(block) {
|
|
10
10
|
switch (block.kind) {
|
|
11
11
|
case 'stable':
|
|
12
12
|
case 'ours':
|
|
@@ -18,16 +18,6 @@ export function autoLines(block) {
|
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
function squashed(lines) {
|
|
22
|
-
return lines
|
|
23
|
-
.map((line) => {
|
|
24
|
-
const body = line.trim();
|
|
25
|
-
// Indentation is meaning in Python, YAML or a Makefile, so only a blank line loses its own.
|
|
26
|
-
const indent = body === '' ? '' : line.slice(0, line.length - line.trimStart().length);
|
|
27
|
-
return `${indent}${body.replace(/\s+/g, ' ')}`;
|
|
28
|
-
})
|
|
29
|
-
.join('\n');
|
|
30
|
-
}
|
|
31
21
|
/* Where `inner` starts in `outer` as one run of lines, or -1. */
|
|
32
22
|
function runIn(outer, inner) {
|
|
33
23
|
for (let start = 0; start + inner.length <= outer.length; start += 1) {
|
|
@@ -51,14 +41,14 @@ function covers(base, outer, inner) {
|
|
|
51
41
|
}
|
|
52
42
|
/*
|
|
53
43
|
* What the wand makes of a conflict, or null for one that needs a person after all. It closes only
|
|
54
|
-
* sides
|
|
55
|
-
*
|
|
44
|
+
* identical sides and a side that already holds every line of the other without putting back what
|
|
45
|
+
* the other deleted. Whitespace keeps its meaning because this function has no language context.
|
|
56
46
|
*/
|
|
57
47
|
export function wandLines(block) {
|
|
58
48
|
if (block.kind !== 'conflict') {
|
|
59
49
|
return autoLines(block);
|
|
60
50
|
}
|
|
61
|
-
if (
|
|
51
|
+
if (block.ours.length === block.theirs.length && block.ours.every((line, index) => line === block.theirs[index])) {
|
|
62
52
|
return [...block.ours];
|
|
63
53
|
}
|
|
64
54
|
if (covers(block.base, block.ours, block.theirs)) {
|
|
@@ -94,7 +84,10 @@ export function draftOf(blocks, answered = new Map()) {
|
|
|
94
84
|
const spans = [];
|
|
95
85
|
for (const [index, block] of blocks.entries()) {
|
|
96
86
|
const from = lines.length;
|
|
97
|
-
|
|
87
|
+
// One push per line: a block of a few hundred thousand lines is more arguments than V8 takes in one call.
|
|
88
|
+
for (const line of answered.get(index) ?? autoLines(block) ?? block.ours) {
|
|
89
|
+
lines.push(line);
|
|
90
|
+
}
|
|
98
91
|
spans.push({ block: index, kind: block.kind, from, to: lines.length });
|
|
99
92
|
}
|
|
100
93
|
return { lines, spans };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adecore/merge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Pure line diffs, three-way merge blocks and conflict resolution.",
|
|
5
5
|
"license": "FSL-1.1-MIT",
|
|
6
6
|
"author": "Bas Milius",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dist",
|
|
20
20
|
"src",
|
|
21
21
|
"!src/**/*.test.ts",
|
|
22
|
+
"!src/**/__snapshots__",
|
|
22
23
|
"!src/fixtures"
|
|
23
24
|
],
|
|
24
25
|
"exports": {
|
package/src/blocks.ts
CHANGED
|
@@ -97,8 +97,3 @@ export function splitBlocks(base: readonly string[], ours: readonly string[], th
|
|
|
97
97
|
push(base.length, ours.length, theirs.length);
|
|
98
98
|
return blocks;
|
|
99
99
|
}
|
|
100
|
-
|
|
101
|
-
/* The stretches a person still has to decide on. */
|
|
102
|
-
export function openBlocks(blocks: readonly MergeBlock[]): number {
|
|
103
|
-
return blocks.filter((block) => block.kind === 'conflict').length;
|
|
104
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { diffLines, type Change } from './diff.ts';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { splitBlocks, type MergeBlock, type MergeBlockKind } from './blocks.ts';
|
|
3
|
+
export { bothLines, draftOf, fingerprint, sideLines, wandLines, type MergeDraft, type MergeSide, type MergeSpan } from './resolve.ts';
|
|
4
4
|
export { joinLines, shapeOf, splitLines, type TextShape } from './text.ts';
|
|
5
5
|
export { missingSides, patchFits } from './patch.ts';
|
|
6
6
|
export { parsePatch, parseHunkHeader, type HunkHeader, type Hunk, type ParsedPatch, type PatchLine } from './patch-parser.ts';
|
package/src/patch.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parsePatch } from './patch-parser.ts';
|
|
2
|
+
|
|
1
3
|
/* Which side a patch says the file is missing on, read from its header so no line of the file can pass for it. */
|
|
2
4
|
export function missingSides(patch: string): { old: boolean; new: boolean } {
|
|
3
5
|
const start = patch.search(/^@@/m);
|
|
@@ -7,8 +9,11 @@ export function missingSides(patch: string): { old: boolean; new: boolean } {
|
|
|
7
9
|
|
|
8
10
|
const HUNK_HEADER = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
9
11
|
|
|
10
|
-
/* Git's --ignore-all-space may show either side's spacing on a context line. */
|
|
12
|
+
/* Git's --ignore-all-space may show either side's spacing on a context line. A patch cut off before its hunks end fits nothing. */
|
|
11
13
|
export function patchFits(patch: string, oldText: string, newText: string, ignoreWhitespace: boolean): boolean {
|
|
14
|
+
if (parsePatch(patch).partial) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
12
17
|
const oldLines = oldText.split('\n');
|
|
13
18
|
const newLines = newText.split('\n');
|
|
14
19
|
const same = ignoreWhitespace
|
package/src/resolve.ts
CHANGED
|
@@ -12,7 +12,7 @@ export function bothLines(block: MergeBlock, first: MergeSide): string[] {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/* What a block is worth without anyone choosing: the side that changed, or the change both made. */
|
|
15
|
-
|
|
15
|
+
function autoLines(block: MergeBlock): string[] | null {
|
|
16
16
|
switch (block.kind) {
|
|
17
17
|
case 'stable':
|
|
18
18
|
case 'ours':
|
|
@@ -25,17 +25,6 @@ export function autoLines(block: MergeBlock): string[] | null {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function squashed(lines: readonly string[]): string {
|
|
29
|
-
return lines
|
|
30
|
-
.map((line) => {
|
|
31
|
-
const body = line.trim();
|
|
32
|
-
// Indentation is meaning in Python, YAML or a Makefile, so only a blank line loses its own.
|
|
33
|
-
const indent = body === '' ? '' : line.slice(0, line.length - line.trimStart().length);
|
|
34
|
-
return `${indent}${body.replace(/\s+/g, ' ')}`;
|
|
35
|
-
})
|
|
36
|
-
.join('\n');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
28
|
/* Where `inner` starts in `outer` as one run of lines, or -1. */
|
|
40
29
|
function runIn(outer: readonly string[], inner: readonly string[]): number {
|
|
41
30
|
for (let start = 0; start + inner.length <= outer.length; start += 1) {
|
|
@@ -61,14 +50,14 @@ function covers(base: readonly string[], outer: readonly string[], inner: readon
|
|
|
61
50
|
|
|
62
51
|
/*
|
|
63
52
|
* What the wand makes of a conflict, or null for one that needs a person after all. It closes only
|
|
64
|
-
* sides
|
|
65
|
-
*
|
|
53
|
+
* identical sides and a side that already holds every line of the other without putting back what
|
|
54
|
+
* the other deleted. Whitespace keeps its meaning because this function has no language context.
|
|
66
55
|
*/
|
|
67
56
|
export function wandLines(block: MergeBlock): string[] | null {
|
|
68
57
|
if (block.kind !== 'conflict') {
|
|
69
58
|
return autoLines(block);
|
|
70
59
|
}
|
|
71
|
-
if (
|
|
60
|
+
if (block.ours.length === block.theirs.length && block.ours.every((line, index) => line === block.theirs[index])) {
|
|
72
61
|
return [...block.ours];
|
|
73
62
|
}
|
|
74
63
|
if (covers(block.base, block.ours, block.theirs)) {
|
|
@@ -119,7 +108,10 @@ export function draftOf(blocks: readonly MergeBlock[], answered: ReadonlyMap<num
|
|
|
119
108
|
const spans: MergeSpan[] = [];
|
|
120
109
|
for (const [index, block] of blocks.entries()) {
|
|
121
110
|
const from = lines.length;
|
|
122
|
-
|
|
111
|
+
// One push per line: a block of a few hundred thousand lines is more arguments than V8 takes in one call.
|
|
112
|
+
for (const line of answered.get(index) ?? autoLines(block) ?? block.ours) {
|
|
113
|
+
lines.push(line);
|
|
114
|
+
}
|
|
123
115
|
spans.push({ block: index, kind: block.kind, from, to: lines.length });
|
|
124
116
|
}
|
|
125
117
|
return { lines, spans };
|