@mapples/textpatch 1.6.0-beta.20260929132641
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/README.md +23 -0
- package/dist/hash.d.ts +10 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +15 -0
- package/dist/hash.js.map +1 -0
- package/dist/hunks.d.ts +49 -0
- package/dist/hunks.d.ts.map +1 -0
- package/dist/hunks.js +315 -0
- package/dist/hunks.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lines.d.ts +16 -0
- package/dist/lines.d.ts.map +1 -0
- package/dist/lines.js +23 -0
- package/dist/lines.js.map +1 -0
- package/dist/merge.d.ts +20 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +142 -0
- package/dist/merge.js.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @mapples/textpatch
|
|
2
|
+
|
|
3
|
+
Unified-diff hunks for Mapples Source text (RFC-0001 A13). A page's or
|
|
4
|
+
component's TSX moves between the Creator, the `mapples` CLI and the server
|
|
5
|
+
as the hunk section of a unified diff — `+`/`-` lines against the text whose
|
|
6
|
+
hash is `base` — never as the whole file.
|
|
7
|
+
|
|
8
|
+
- `makeHunks(old, new)`: the hunks turning `old` into `new` (`''` when equal).
|
|
9
|
+
- `applyHunks(text, hunks)`: exact apply — no fuzz, no offset, no whitespace
|
|
10
|
+
normalization; throws `TextPatchError` (`SOURCE_PATCH_INVALID`).
|
|
11
|
+
- `merge3(base, ours, theirs)`: line-level 3-way merge (diff3 over jsdiff);
|
|
12
|
+
identical edits on both sides are not conflicts, touching hunks are (as in
|
|
13
|
+
git); never writes conflict markers.
|
|
14
|
+
- `textHash(text)`: the `b3:` content hash of the text (canonical JSON string).
|
|
15
|
+
- `parseHunks`, `countLines`, `mapAddedLines`, `splitLines`, `joinLines`.
|
|
16
|
+
|
|
17
|
+
The apply rules are normative and mirrored line for line by the server's
|
|
18
|
+
`api/canvas/textpatch.py`; `textpatch_vectors.json` pins both. Hunks are not
|
|
19
|
+
canonical (jsdiff and difflib may group an edit differently), so they are
|
|
20
|
+
only ever applied, never hashed or compared.
|
|
21
|
+
|
|
22
|
+
Line rule: split on `\n` only — `\r`, `\f` and `
` are content, so CRLF
|
|
23
|
+
files round-trip byte-exact.
|
package/dist/hash.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `b3:` content hash of a text: BLAKE3 over the canonical JSON of the
|
|
3
|
+
* string value, 20 hex chars — exactly what the JPATCH engines and the
|
|
4
|
+
* server compute for any JSON value (RFC-0001 §4). For a string the
|
|
5
|
+
* canonical form is `JSON.stringify(text)`; `json.dumps(ensure_ascii=False)`
|
|
6
|
+
* agrees byte for byte on every string the server accepts (lone surrogates
|
|
7
|
+
* are rejected as SOURCE_INVALID before any hash is taken).
|
|
8
|
+
*/
|
|
9
|
+
export declare const textHash: (text: string) => string;
|
|
10
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,KAAG,MAKrC,CAAC"}
|
package/dist/hash.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `b3:` content hash of a text: BLAKE3 over the canonical JSON of the
|
|
3
|
+
* string value, 20 hex chars — exactly what the JPATCH engines and the
|
|
4
|
+
* server compute for any JSON value (RFC-0001 §4). For a string the
|
|
5
|
+
* canonical form is `JSON.stringify(text)`; `json.dumps(ensure_ascii=False)`
|
|
6
|
+
* agrees byte for byte on every string the server accepts (lone surrogates
|
|
7
|
+
* are rejected as SOURCE_INVALID before any hash is taken).
|
|
8
|
+
*/
|
|
9
|
+
import { blake3 } from '@noble/hashes/blake3.js';
|
|
10
|
+
import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js';
|
|
11
|
+
const HASH_PREFIX = 'b3:';
|
|
12
|
+
const PREFIX_HEX = 20;
|
|
13
|
+
export const textHash = (text) => HASH_PREFIX +
|
|
14
|
+
bytesToHex(blake3(utf8ToBytes(JSON.stringify(text)))).slice(0, PREFIX_HEX);
|
|
15
|
+
//# sourceMappingURL=hash.js.map
|
package/dist/hash.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,UAAU,GAAG,EAAE,CAAC;AAEtB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAU,EAAE,CAC/C,WAAW;IACX,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CACzD,CAAC,EACD,UAAU,CACX,CAAC"}
|
package/dist/hunks.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified-diff hunks (RFC-0001 A13). Format, emitted by every generator and
|
|
3
|
+
* accepted by every parser:
|
|
4
|
+
*
|
|
5
|
+
* @@ -A,B +C,D @@
|
|
6
|
+
* context
|
|
7
|
+
* -removed
|
|
8
|
+
* +added
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* The marker follows the last line of a side that lacks a trailing newline;
|
|
12
|
+
* lines are joined with "\n" and the string ends with "\n"; hunks are
|
|
13
|
+
* ascending and non-overlapping. An empty file has zero lines:
|
|
14
|
+
* `@@ -0,0 +1,N @@` fills one, `@@ -1,N +0,0 @@` empties one. The parser also
|
|
15
|
+
* accepts the short `-A +C` header form (count 1).
|
|
16
|
+
*
|
|
17
|
+
* Apply is exact: every context and removed line must equal the old line at
|
|
18
|
+
* the cursor, header counts must match, and the no-newline markers must agree
|
|
19
|
+
* with the old text. Any violation is `SOURCE_PATCH_INVALID`. The rules are
|
|
20
|
+
* mirrored line for line by the server's `api/canvas/textpatch.py`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const NO_EOL = "\";
|
|
23
|
+
export declare class TextPatchError extends Error {
|
|
24
|
+
readonly code = "SOURCE_PATCH_INVALID";
|
|
25
|
+
constructor(message: string);
|
|
26
|
+
}
|
|
27
|
+
export interface Hunk {
|
|
28
|
+
oldStart: number;
|
|
29
|
+
oldLen: number;
|
|
30
|
+
newStart: number;
|
|
31
|
+
newLen: number;
|
|
32
|
+
/** Each with its prefix: " ", "-", "+" or the no-newline marker. */
|
|
33
|
+
lines: string[];
|
|
34
|
+
}
|
|
35
|
+
/** The hunks turning `oldText` into `newText`; `''` when they are equal. */
|
|
36
|
+
export declare const makeHunks: (oldText: string, newText: string, options?: {
|
|
37
|
+
context?: number;
|
|
38
|
+
}) => string;
|
|
39
|
+
export declare const parseHunks: (hunks: string) => Hunk[];
|
|
40
|
+
/** Apply `hunks` to `oldText` exactly; `TextPatchError` on any mismatch. */
|
|
41
|
+
export declare const applyHunks: (oldText: string, hunks: string) => string;
|
|
42
|
+
/** `{ added, removed }` line counts of a hunks string. */
|
|
43
|
+
export declare const countLines: (hunks: string) => {
|
|
44
|
+
added: number;
|
|
45
|
+
removed: number;
|
|
46
|
+
};
|
|
47
|
+
/** Rewrite the body of every `+` line (cid resolution lives there). */
|
|
48
|
+
export declare const mapAddedLines: (hunks: string, fn: (line: string) => string) => string;
|
|
49
|
+
//# sourceMappingURL=hunks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hunks.d.ts","sourceRoot":"","sources":["../src/hunks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,eAAO,MAAM,MAAM,iCAAiC,CAAC;AAGrD,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,0BAA0B;gBAE3B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAmFD,4EAA4E;AAC5E,eAAO,MAAM,SAAS,GACpB,SAAS,MAAM,EACf,SAAS,MAAM,EACf,UAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,KACjC,MAgCF,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,IAAI,EAiE9C,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,OAAO,MAAM,KAAG,MA8E3D,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,UAAU,GACrB,OAAO,MAAM,KACZ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAWlC,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,KAC3B,MAYF,CAAC"}
|
package/dist/hunks.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified-diff hunks (RFC-0001 A13). Format, emitted by every generator and
|
|
3
|
+
* accepted by every parser:
|
|
4
|
+
*
|
|
5
|
+
* @@ -A,B +C,D @@
|
|
6
|
+
* context
|
|
7
|
+
* -removed
|
|
8
|
+
* +added
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* The marker follows the last line of a side that lacks a trailing newline;
|
|
12
|
+
* lines are joined with "\n" and the string ends with "\n"; hunks are
|
|
13
|
+
* ascending and non-overlapping. An empty file has zero lines:
|
|
14
|
+
* `@@ -0,0 +1,N @@` fills one, `@@ -1,N +0,0 @@` empties one. The parser also
|
|
15
|
+
* accepts the short `-A +C` header form (count 1).
|
|
16
|
+
*
|
|
17
|
+
* Apply is exact: every context and removed line must equal the old line at
|
|
18
|
+
* the cursor, header counts must match, and the no-newline markers must agree
|
|
19
|
+
* with the old text. Any violation is `SOURCE_PATCH_INVALID`. The rules are
|
|
20
|
+
* mirrored line for line by the server's `api/canvas/textpatch.py`.
|
|
21
|
+
*/
|
|
22
|
+
import { diffLines } from 'diff';
|
|
23
|
+
import { joinLines, splitLines } from './lines.js';
|
|
24
|
+
export const NO_EOL = '\';
|
|
25
|
+
const HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@$/;
|
|
26
|
+
export class TextPatchError extends Error {
|
|
27
|
+
code = 'SOURCE_PATCH_INVALID';
|
|
28
|
+
constructor(message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = 'TextPatchError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const lineCount = (value) => splitLines(value).lines.length;
|
|
34
|
+
/** difflib-shaped opcodes over line indexes, computed by jsdiff's line diff. */
|
|
35
|
+
const opcodes = (oldText, newText) => {
|
|
36
|
+
const codes = [];
|
|
37
|
+
let i = 0;
|
|
38
|
+
let j = 0;
|
|
39
|
+
for (const part of diffLines(oldText, newText)) {
|
|
40
|
+
const n = lineCount(part.value);
|
|
41
|
+
if (n === 0)
|
|
42
|
+
continue;
|
|
43
|
+
if (part.added) {
|
|
44
|
+
codes.push({ tag: 'insert', i1: i, i2: i, j1: j, j2: j + n });
|
|
45
|
+
j += n;
|
|
46
|
+
}
|
|
47
|
+
else if (part.removed) {
|
|
48
|
+
codes.push({ tag: 'delete', i1: i, i2: i + n, j1: j, j2: j });
|
|
49
|
+
i += n;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
codes.push({ tag: 'equal', i1: i, i2: i + n, j1: j, j2: j + n });
|
|
53
|
+
i += n;
|
|
54
|
+
j += n;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return codes;
|
|
58
|
+
};
|
|
59
|
+
/** Port of difflib's `get_grouped_opcodes`: hunks with `n` lines of context. */
|
|
60
|
+
const groupOpcodes = (input, n) => {
|
|
61
|
+
const codes = input.map((code) => ({ ...code }));
|
|
62
|
+
const first = codes[0];
|
|
63
|
+
if (first.tag === 'equal') {
|
|
64
|
+
codes[0] = {
|
|
65
|
+
...first,
|
|
66
|
+
i1: Math.max(first.i1, first.i2 - n),
|
|
67
|
+
j1: Math.max(first.j1, first.j2 - n),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const last = codes[codes.length - 1];
|
|
71
|
+
if (last.tag === 'equal') {
|
|
72
|
+
codes[codes.length - 1] = {
|
|
73
|
+
...last,
|
|
74
|
+
i2: Math.min(last.i2, last.i1 + n),
|
|
75
|
+
j2: Math.min(last.j2, last.j1 + n),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const nn = n + n;
|
|
79
|
+
const groups = [];
|
|
80
|
+
let group = [];
|
|
81
|
+
for (const code of codes) {
|
|
82
|
+
let { i1, j1 } = code;
|
|
83
|
+
const { tag, i2, j2 } = code;
|
|
84
|
+
if (tag === 'equal' && i2 - i1 > nn) {
|
|
85
|
+
group.push({
|
|
86
|
+
tag,
|
|
87
|
+
i1,
|
|
88
|
+
i2: Math.min(i2, i1 + n),
|
|
89
|
+
j1,
|
|
90
|
+
j2: Math.min(j2, j1 + n),
|
|
91
|
+
});
|
|
92
|
+
groups.push(group);
|
|
93
|
+
group = [];
|
|
94
|
+
i1 = Math.max(i1, i2 - n);
|
|
95
|
+
j1 = Math.max(j1, j2 - n);
|
|
96
|
+
}
|
|
97
|
+
group.push({ tag, i1, i2, j1, j2 });
|
|
98
|
+
}
|
|
99
|
+
if (group.length > 0 && !(group.length === 1 && group[0].tag === 'equal')) {
|
|
100
|
+
groups.push(group);
|
|
101
|
+
}
|
|
102
|
+
return groups;
|
|
103
|
+
};
|
|
104
|
+
/** The hunks turning `oldText` into `newText`; `''` when they are equal. */
|
|
105
|
+
export const makeHunks = (oldText, newText, options = {}) => {
|
|
106
|
+
if (oldText === newText)
|
|
107
|
+
return '';
|
|
108
|
+
const context = options.context ?? 3;
|
|
109
|
+
const old = splitLines(oldText);
|
|
110
|
+
const next = splitLines(newText);
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const group of groupOpcodes(opcodes(oldText, newText), context)) {
|
|
113
|
+
const i1 = group[0].i1;
|
|
114
|
+
const i2 = group[group.length - 1].i2;
|
|
115
|
+
const j1 = group[0].j1;
|
|
116
|
+
const j2 = group[group.length - 1].j2;
|
|
117
|
+
const oldLen = i2 - i1;
|
|
118
|
+
const newLen = j2 - j1;
|
|
119
|
+
out.push(`@@ -${oldLen > 0 ? i1 + 1 : i1},${oldLen} +${newLen > 0 ? j1 + 1 : j1},${newLen} @@`);
|
|
120
|
+
for (const code of group) {
|
|
121
|
+
if (code.tag === 'equal' || code.tag === 'delete') {
|
|
122
|
+
const prefix = code.tag === 'equal' ? ' ' : '-';
|
|
123
|
+
for (let i = code.i1; i < code.i2; i += 1) {
|
|
124
|
+
out.push(prefix + old.lines[i]);
|
|
125
|
+
if (i === old.lines.length - 1 && !old.eol)
|
|
126
|
+
out.push(NO_EOL);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
for (let j = code.j1; j < code.j2; j += 1) {
|
|
131
|
+
out.push(`+${next.lines[j]}`);
|
|
132
|
+
if (j === next.lines.length - 1 && !next.eol)
|
|
133
|
+
out.push(NO_EOL);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return `${out.join('\n')}\n`;
|
|
139
|
+
};
|
|
140
|
+
export const parseHunks = (hunks) => {
|
|
141
|
+
if (hunks === '' || !hunks.endsWith('\n')) {
|
|
142
|
+
throw new TextPatchError('hunks must be a non-empty string ending with a newline');
|
|
143
|
+
}
|
|
144
|
+
const raw = hunks.split('\n');
|
|
145
|
+
raw.pop(); // the terminator
|
|
146
|
+
const parsed = [];
|
|
147
|
+
let i = 0;
|
|
148
|
+
while (i < raw.length) {
|
|
149
|
+
const match = HEADER_RE.exec(raw[i]);
|
|
150
|
+
if (match === null) {
|
|
151
|
+
throw new TextPatchError(`expected a hunk header at line ${i + 1}`);
|
|
152
|
+
}
|
|
153
|
+
const oldStart = Number(match[1]);
|
|
154
|
+
const oldLen = match[2] !== undefined ? Number(match[2]) : 1;
|
|
155
|
+
const newStart = Number(match[3]);
|
|
156
|
+
const newLen = match[4] !== undefined ? Number(match[4]) : 1;
|
|
157
|
+
if ((oldLen > 0 && oldStart === 0) || (newLen > 0 && newStart === 0)) {
|
|
158
|
+
throw new TextPatchError(`hunk header at line ${i + 1} starts at line 0`);
|
|
159
|
+
}
|
|
160
|
+
i += 1;
|
|
161
|
+
const lines = [];
|
|
162
|
+
let seenOld = 0;
|
|
163
|
+
let seenNew = 0;
|
|
164
|
+
while (i < raw.length) {
|
|
165
|
+
const line = raw[i];
|
|
166
|
+
if (line.startsWith('\\')) {
|
|
167
|
+
if (line !== NO_EOL) {
|
|
168
|
+
throw new TextPatchError(`unknown marker at line ${i + 1}`);
|
|
169
|
+
}
|
|
170
|
+
if (lines.length === 0 || lines[lines.length - 1] === NO_EOL) {
|
|
171
|
+
throw new TextPatchError(`marker without a line at line ${i + 1}`);
|
|
172
|
+
}
|
|
173
|
+
lines.push(line);
|
|
174
|
+
i += 1;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (seenOld === oldLen && seenNew === newLen)
|
|
178
|
+
break;
|
|
179
|
+
const prefix = line.slice(0, 1);
|
|
180
|
+
if (prefix === ' ') {
|
|
181
|
+
seenOld += 1;
|
|
182
|
+
seenNew += 1;
|
|
183
|
+
}
|
|
184
|
+
else if (prefix === '-') {
|
|
185
|
+
seenOld += 1;
|
|
186
|
+
}
|
|
187
|
+
else if (prefix === '+') {
|
|
188
|
+
seenNew += 1;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
throw new TextPatchError(`unknown line prefix at line ${i + 1}`);
|
|
192
|
+
}
|
|
193
|
+
if (seenOld > oldLen || seenNew > newLen) {
|
|
194
|
+
throw new TextPatchError(`hunk body exceeds its header counts at line ${i + 1}`);
|
|
195
|
+
}
|
|
196
|
+
lines.push(line);
|
|
197
|
+
i += 1;
|
|
198
|
+
}
|
|
199
|
+
if (seenOld !== oldLen || seenNew !== newLen) {
|
|
200
|
+
throw new TextPatchError('hunk body is shorter than its header counts');
|
|
201
|
+
}
|
|
202
|
+
parsed.push({ oldStart, oldLen, newStart, newLen, lines });
|
|
203
|
+
}
|
|
204
|
+
return parsed;
|
|
205
|
+
};
|
|
206
|
+
/** Apply `hunks` to `oldText` exactly; `TextPatchError` on any mismatch. */
|
|
207
|
+
export const applyHunks = (oldText, hunks) => {
|
|
208
|
+
const parsed = parseHunks(hunks);
|
|
209
|
+
const old = splitLines(oldText);
|
|
210
|
+
const out = [];
|
|
211
|
+
let cursor = 0;
|
|
212
|
+
/** `out.length` when a +/context line was marked no-EOL: nothing may follow. */
|
|
213
|
+
let markedLen = null;
|
|
214
|
+
for (const hunk of parsed) {
|
|
215
|
+
const start = hunk.oldLen > 0 ? hunk.oldStart - 1 : hunk.oldStart;
|
|
216
|
+
if (start < cursor || start > old.lines.length) {
|
|
217
|
+
throw new TextPatchError('hunk out of order or past the end of the text');
|
|
218
|
+
}
|
|
219
|
+
if (markedLen !== null) {
|
|
220
|
+
throw new TextPatchError('lines follow a no-newline marker');
|
|
221
|
+
}
|
|
222
|
+
out.push(...old.lines.slice(cursor, start));
|
|
223
|
+
cursor = start;
|
|
224
|
+
const expectedNew = hunk.newLen > 0 ? hunk.newStart - 1 : hunk.newStart;
|
|
225
|
+
if (out.length !== expectedNew) {
|
|
226
|
+
throw new TextPatchError('hunk new-side line number does not match');
|
|
227
|
+
}
|
|
228
|
+
let prev = null;
|
|
229
|
+
let needMarker = false;
|
|
230
|
+
for (const line of hunk.lines) {
|
|
231
|
+
if (line === NO_EOL) {
|
|
232
|
+
if (prev === null)
|
|
233
|
+
throw new TextPatchError('marker without a line');
|
|
234
|
+
if ((prev.kind === ' ' || prev.kind === '-') &&
|
|
235
|
+
(prev.oldIndex !== old.lines.length - 1 || old.eol)) {
|
|
236
|
+
throw new TextPatchError('no-newline marker does not match the old text');
|
|
237
|
+
}
|
|
238
|
+
if (prev.kind === ' ' || prev.kind === '+')
|
|
239
|
+
markedLen = out.length;
|
|
240
|
+
needMarker = false;
|
|
241
|
+
prev = null;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (needMarker) {
|
|
245
|
+
throw new TextPatchError('old text has no trailing newline but the hunk claims one');
|
|
246
|
+
}
|
|
247
|
+
if (markedLen !== null) {
|
|
248
|
+
throw new TextPatchError('lines follow a no-newline marker');
|
|
249
|
+
}
|
|
250
|
+
const prefix = line[0];
|
|
251
|
+
const body = line.slice(1);
|
|
252
|
+
if (prefix === ' ' || prefix === '-') {
|
|
253
|
+
if (cursor >= old.lines.length || old.lines[cursor] !== body) {
|
|
254
|
+
throw new TextPatchError(`hunk does not apply at line ${cursor + 1}`);
|
|
255
|
+
}
|
|
256
|
+
if (prefix === ' ')
|
|
257
|
+
out.push(body);
|
|
258
|
+
prev = { kind: prefix, oldIndex: cursor };
|
|
259
|
+
needMarker = cursor === old.lines.length - 1 && !old.eol;
|
|
260
|
+
cursor += 1;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
out.push(body);
|
|
264
|
+
prev = { kind: '+', oldIndex: null };
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (needMarker) {
|
|
268
|
+
throw new TextPatchError('old text has no trailing newline but the hunk claims one');
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const tail = old.lines.slice(cursor);
|
|
272
|
+
if (tail.length > 0 && markedLen !== null) {
|
|
273
|
+
throw new TextPatchError('lines follow a no-newline marker');
|
|
274
|
+
}
|
|
275
|
+
out.push(...tail);
|
|
276
|
+
let newEol;
|
|
277
|
+
if (markedLen !== null)
|
|
278
|
+
newEol = false;
|
|
279
|
+
else if (tail.length > 0)
|
|
280
|
+
newEol = old.eol;
|
|
281
|
+
else
|
|
282
|
+
newEol = true;
|
|
283
|
+
return joinLines(out, newEol);
|
|
284
|
+
};
|
|
285
|
+
/** `{ added, removed }` line counts of a hunks string. */
|
|
286
|
+
export const countLines = (hunks) => {
|
|
287
|
+
let added = 0;
|
|
288
|
+
let removed = 0;
|
|
289
|
+
for (const hunk of parseHunks(hunks)) {
|
|
290
|
+
for (const line of hunk.lines) {
|
|
291
|
+
if (line === NO_EOL)
|
|
292
|
+
continue;
|
|
293
|
+
if (line[0] === '+')
|
|
294
|
+
added += 1;
|
|
295
|
+
else if (line[0] === '-')
|
|
296
|
+
removed += 1;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return { added, removed };
|
|
300
|
+
};
|
|
301
|
+
/** Rewrite the body of every `+` line (cid resolution lives there). */
|
|
302
|
+
export const mapAddedLines = (hunks, fn) => {
|
|
303
|
+
const out = [];
|
|
304
|
+
for (const hunk of parseHunks(hunks)) {
|
|
305
|
+
out.push(`@@ -${hunk.oldStart},${hunk.oldLen} +${hunk.newStart},${hunk.newLen} @@`);
|
|
306
|
+
for (const line of hunk.lines) {
|
|
307
|
+
if (line !== NO_EOL && line[0] === '+')
|
|
308
|
+
out.push(`+${fn(line.slice(1))}`);
|
|
309
|
+
else
|
|
310
|
+
out.push(line);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return `${out.join('\n')}\n`;
|
|
314
|
+
};
|
|
315
|
+
//# sourceMappingURL=hunks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hunks.js","sourceRoot":"","sources":["../src/hunks.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** A Source update's `text` directive (RFC-0001 A13). */
|
|
2
|
+
export interface TextDirective {
|
|
3
|
+
/** `textHash` of the text the hunks were computed against. */
|
|
4
|
+
base: string;
|
|
5
|
+
/** Unified-diff hunk section turning that text into the new one. */
|
|
6
|
+
hunks: string;
|
|
7
|
+
}
|
|
8
|
+
export { joinLines, splitLines } from './lines.js';
|
|
9
|
+
export type { SplitText } from './lines.js';
|
|
10
|
+
export { applyHunks, countLines, makeHunks, mapAddedLines, NO_EOL, parseHunks, TextPatchError, } from './hunks.js';
|
|
11
|
+
export type { Hunk } from './hunks.js';
|
|
12
|
+
export { merge3 } from './merge.js';
|
|
13
|
+
export type { Merge3Result } from './merge.js';
|
|
14
|
+
export { textHash } from './hash.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,MAAM,EACN,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { joinLines, splitLines } from './lines.js';
|
|
2
|
+
export { applyHunks, countLines, makeHunks, mapAddedLines, NO_EOL, parseHunks, TextPatchError, } from './hunks.js';
|
|
3
|
+
export { merge3 } from './merge.js';
|
|
4
|
+
export { textHash } from './hash.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,MAAM,EACN,UAAU,EACV,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/lines.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line rule (RFC-0001 A13, normative): split on "\n" only. "\r", "\f" and
|
|
3
|
+
* "
|
|
4
|
+
" are content, so CRLF files round-trip byte-exact. The server's
|
|
5
|
+
* Python twin uses `text.split("\n")` for the same reason — never
|
|
6
|
+
* `splitlines()`.
|
|
7
|
+
*/
|
|
8
|
+
export interface SplitText {
|
|
9
|
+
/** Lines without their "\n". */
|
|
10
|
+
lines: string[];
|
|
11
|
+
/** Whether the text ends with a newline. Empty text is zero lines, `true`. */
|
|
12
|
+
eol: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare const splitLines: (text: string) => SplitText;
|
|
15
|
+
export declare const joinLines: (lines: string[], eol: boolean) => string;
|
|
16
|
+
//# sourceMappingURL=lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../src/lines.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,SAAS;IACxB,gCAAgC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8EAA8E;IAC9E,GAAG,EAAE,OAAO,CAAC;CACd;AAED,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,SAQzC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,EAAE,EAAE,KAAK,OAAO,KAAG,MAGzD,CAAC"}
|
package/dist/lines.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line rule (RFC-0001 A13, normative): split on "\n" only. "\r", "\f" and
|
|
3
|
+
* "
|
|
4
|
+
" are content, so CRLF files round-trip byte-exact. The server's
|
|
5
|
+
* Python twin uses `text.split("\n")` for the same reason — never
|
|
6
|
+
* `splitlines()`.
|
|
7
|
+
*/
|
|
8
|
+
export const splitLines = (text) => {
|
|
9
|
+
if (text === '')
|
|
10
|
+
return { lines: [], eol: true };
|
|
11
|
+
const lines = text.split('\n');
|
|
12
|
+
if (lines[lines.length - 1] === '') {
|
|
13
|
+
lines.pop();
|
|
14
|
+
return { lines, eol: true };
|
|
15
|
+
}
|
|
16
|
+
return { lines, eol: false };
|
|
17
|
+
};
|
|
18
|
+
export const joinLines = (lines, eol) => {
|
|
19
|
+
if (lines.length === 0)
|
|
20
|
+
return '';
|
|
21
|
+
return lines.join('\n') + (eol ? '\n' : '');
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.js","sourceRoot":"","sources":["../src/lines.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAa,EAAE;IACpD,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACnC,KAAK,CAAC,GAAG,EAAE,CAAC;QACZ,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAe,EAAE,GAAY,EAAU,EAAE;IACjE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC,CAAC"}
|
package/dist/merge.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-level 3-way merge for Source text: base (the text both sides started
|
|
3
|
+
* from), ours, theirs. Regions of the base that only one side changed take
|
|
4
|
+
* that side; a region both sides changed merges only when both made the
|
|
5
|
+
* same change, otherwise it is a conflict — reported, never written as
|
|
6
|
+
* markers (the callers decide what a conflict means for them). As in git,
|
|
7
|
+
* two changes that touch without an unchanged line between them conflict.
|
|
8
|
+
*
|
|
9
|
+
* Built on jsdiff's array diff (browser-safe under every bundler); the
|
|
10
|
+
* region walk is the classic diff3 algorithm.
|
|
11
|
+
*/
|
|
12
|
+
export type Merge3Result = {
|
|
13
|
+
ok: true;
|
|
14
|
+
text: string;
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
conflicts: number;
|
|
18
|
+
};
|
|
19
|
+
export declare const merge3: (base: string, ours: string, theirs: string) => Merge3Result;
|
|
20
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAsErC,eAAO,MAAM,MAAM,GACjB,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,QAAQ,MAAM,KACb,YAyEF,CAAC"}
|
package/dist/merge.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-level 3-way merge for Source text: base (the text both sides started
|
|
3
|
+
* from), ours, theirs. Regions of the base that only one side changed take
|
|
4
|
+
* that side; a region both sides changed merges only when both made the
|
|
5
|
+
* same change, otherwise it is a conflict — reported, never written as
|
|
6
|
+
* markers (the callers decide what a conflict means for them). As in git,
|
|
7
|
+
* two changes that touch without an unchanged line between them conflict.
|
|
8
|
+
*
|
|
9
|
+
* Built on jsdiff's array diff (browser-safe under every bundler); the
|
|
10
|
+
* region walk is the classic diff3 algorithm.
|
|
11
|
+
*/
|
|
12
|
+
import { diffArrays } from 'diff';
|
|
13
|
+
const hunksOf = (base, side) => {
|
|
14
|
+
const hunks = [];
|
|
15
|
+
let baseAt = 0;
|
|
16
|
+
let sideAt = 0;
|
|
17
|
+
let open = null;
|
|
18
|
+
for (const part of diffArrays(base, side)) {
|
|
19
|
+
const count = part.value.length;
|
|
20
|
+
if (part.added || part.removed) {
|
|
21
|
+
if (open === null) {
|
|
22
|
+
open = {
|
|
23
|
+
baseStart: baseAt,
|
|
24
|
+
baseEnd: baseAt,
|
|
25
|
+
sideStart: sideAt,
|
|
26
|
+
sideEnd: sideAt,
|
|
27
|
+
};
|
|
28
|
+
hunks.push(open);
|
|
29
|
+
}
|
|
30
|
+
if (part.removed) {
|
|
31
|
+
baseAt += count;
|
|
32
|
+
open.baseEnd = baseAt;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
sideAt += count;
|
|
36
|
+
open.sideEnd = sideAt;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
open = null;
|
|
41
|
+
baseAt += count;
|
|
42
|
+
sideAt += count;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return hunks;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The side's line index that corresponds to a base index at a region edge.
|
|
49
|
+
* A pure insert is a zero-length base hunk sitting exactly on an index: at a
|
|
50
|
+
* region's start it belongs to the region (not counted), at its end it does
|
|
51
|
+
* (counted) — that is what makes the side slice cover the insert.
|
|
52
|
+
*/
|
|
53
|
+
const sideIndexAt = (hunks, baseIndex, edge) => {
|
|
54
|
+
let shift = 0;
|
|
55
|
+
for (const hunk of hunks) {
|
|
56
|
+
const before = edge === 'end'
|
|
57
|
+
? hunk.baseEnd <= baseIndex
|
|
58
|
+
: hunk.baseEnd < baseIndex ||
|
|
59
|
+
(hunk.baseEnd === baseIndex && hunk.baseStart < baseIndex);
|
|
60
|
+
if (!before)
|
|
61
|
+
break;
|
|
62
|
+
shift += hunk.sideEnd - hunk.sideStart - (hunk.baseEnd - hunk.baseStart);
|
|
63
|
+
}
|
|
64
|
+
return baseIndex + shift;
|
|
65
|
+
};
|
|
66
|
+
const sameLines = (a, b) => a.length === b.length && a.every((line, at) => line === b[at]);
|
|
67
|
+
export const merge3 = (base, ours, theirs) => {
|
|
68
|
+
if (ours === theirs)
|
|
69
|
+
return { ok: true, text: ours };
|
|
70
|
+
if (ours === base)
|
|
71
|
+
return { ok: true, text: theirs };
|
|
72
|
+
if (theirs === base)
|
|
73
|
+
return { ok: true, text: ours };
|
|
74
|
+
// A trailing "\n" leaves a final '' element, so the newline state merges
|
|
75
|
+
// like any other line.
|
|
76
|
+
const baseLines = base.split('\n');
|
|
77
|
+
const oursLines = ours.split('\n');
|
|
78
|
+
const theirsLines = theirs.split('\n');
|
|
79
|
+
const oursHunks = hunksOf(baseLines, oursLines);
|
|
80
|
+
const theirsHunks = hunksOf(baseLines, theirsLines);
|
|
81
|
+
const out = [];
|
|
82
|
+
let conflicts = 0;
|
|
83
|
+
let baseAt = 0;
|
|
84
|
+
let oi = 0;
|
|
85
|
+
let ti = 0;
|
|
86
|
+
while (oi < oursHunks.length || ti < theirsHunks.length) {
|
|
87
|
+
const nextOurs = oursHunks[oi];
|
|
88
|
+
const nextTheirs = theirsHunks[ti];
|
|
89
|
+
const first = nextOurs === undefined
|
|
90
|
+
? nextTheirs
|
|
91
|
+
: nextTheirs === undefined
|
|
92
|
+
? nextOurs
|
|
93
|
+
: nextOurs.baseStart <= nextTheirs.baseStart
|
|
94
|
+
? nextOurs
|
|
95
|
+
: nextTheirs;
|
|
96
|
+
let start = first.baseStart;
|
|
97
|
+
let end = first.baseEnd;
|
|
98
|
+
let usedOurs = false;
|
|
99
|
+
let usedTheirs = false;
|
|
100
|
+
// Grow the region while a hunk of either side touches it.
|
|
101
|
+
for (;;) {
|
|
102
|
+
let grew = false;
|
|
103
|
+
while (oi < oursHunks.length && oursHunks[oi].baseStart <= end) {
|
|
104
|
+
end = Math.max(end, oursHunks[oi].baseEnd);
|
|
105
|
+
start = Math.min(start, oursHunks[oi].baseStart);
|
|
106
|
+
usedOurs = true;
|
|
107
|
+
oi += 1;
|
|
108
|
+
grew = true;
|
|
109
|
+
}
|
|
110
|
+
while (ti < theirsHunks.length && theirsHunks[ti].baseStart <= end) {
|
|
111
|
+
end = Math.max(end, theirsHunks[ti].baseEnd);
|
|
112
|
+
start = Math.min(start, theirsHunks[ti].baseStart);
|
|
113
|
+
usedTheirs = true;
|
|
114
|
+
ti += 1;
|
|
115
|
+
grew = true;
|
|
116
|
+
}
|
|
117
|
+
if (!grew)
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
out.push(...baseLines.slice(baseAt, start));
|
|
121
|
+
const oursRegion = oursLines.slice(sideIndexAt(oursHunks, start, 'start'), sideIndexAt(oursHunks, end, 'end'));
|
|
122
|
+
const theirsRegion = theirsLines.slice(sideIndexAt(theirsHunks, start, 'start'), sideIndexAt(theirsHunks, end, 'end'));
|
|
123
|
+
if (usedOurs && usedTheirs) {
|
|
124
|
+
if (sameLines(oursRegion, theirsRegion))
|
|
125
|
+
out.push(...oursRegion);
|
|
126
|
+
else
|
|
127
|
+
conflicts += 1;
|
|
128
|
+
}
|
|
129
|
+
else if (usedOurs) {
|
|
130
|
+
out.push(...oursRegion);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
out.push(...theirsRegion);
|
|
134
|
+
}
|
|
135
|
+
baseAt = end;
|
|
136
|
+
}
|
|
137
|
+
out.push(...baseLines.slice(baseAt));
|
|
138
|
+
if (conflicts > 0)
|
|
139
|
+
return { ok: false, conflicts };
|
|
140
|
+
return { ok: true, text: out.join('\n') };
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mapples/textpatch",
|
|
3
|
+
"version": "1.6.0-beta.20260929132641",
|
|
4
|
+
"description": "Unified-diff hunks for Mapples Source text (RFC-0001 A13): generate, apply exactly, 3-way merge, text hash. Shared by the Creator and the mapples CLI; mirrored by the server's Python applier.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc -b tsconfig.build.json",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"type-check": "tsc --noEmit",
|
|
12
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
13
|
+
},
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Oleksandr Soloviov",
|
|
16
|
+
"url": "https://mapples.org/people/olek_soloviov"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/mapplesorg/mapples-open-kit.git",
|
|
22
|
+
"directory": "packages/@mapples/textpatch"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@noble/hashes": "^1.5.0",
|
|
26
|
+
"diff": "^9.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"typescript": "~6.0.3"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18.18"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"package.json"
|
|
38
|
+
]
|
|
39
|
+
}
|