overleaf-review 0.6.1 → 0.6.2
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
CHANGED
|
@@ -339,6 +339,17 @@ project, verifies consolidation and protected review state, and checks that exis
|
|
|
339
339
|
were unchanged. It does not require or spoof another account. Foreign-author preservation is also
|
|
340
340
|
covered by the upstream model check. Never run this probe against a manuscript project.
|
|
341
341
|
|
|
342
|
+
From v0.6.2, rejection and underlying-text reconstruction account for insertions and deletions
|
|
343
|
+
at the same position, including multiple co-located deletions. The undo first restores selected
|
|
344
|
+
deletions, then removes insertions at their adjusted positions; exact-text and range verification
|
|
345
|
+
remain mandatory. Recreate unsubmitted plans from a fresh snapshot after upgrading, since the
|
|
346
|
+
operation ordering has changed. Do not re-plan to bypass an uncertain earlier submission.
|
|
347
|
+
|
|
348
|
+
`npm run probe:rejection-model` checks this ordering against pinned upstream range logic in both
|
|
349
|
+
tracking modes, including consolidation and reviewed paragraph rewrites. Add `-- --backup <file>`
|
|
350
|
+
to check a saved full snapshot (or a plan containing `backup`) offline. The backup stays local;
|
|
351
|
+
the probe fetches only public upstream code and never connects to an Overleaf project.
|
|
352
|
+
|
|
342
353
|
### Push overrides and submission
|
|
343
354
|
|
|
344
355
|
Use `--allow-overlap` only after inspecting those tracked changes. `--unsafe-no-base` is a deliberate
|
|
@@ -1285,17 +1285,26 @@ function applyUndo(text, op, changeId) {
|
|
|
1285
1285
|
}
|
|
1286
1286
|
function buildRejectionPlan(currentText, ranges, requestedIds) {
|
|
1287
1287
|
const requested = new Set(uniqueChangeIds(requestedIds));
|
|
1288
|
-
const fragments = ranges.filter((range) => requested.has(range.id));
|
|
1289
|
-
fragments.sort((a, b) => b.op.p - a.op.p);
|
|
1288
|
+
const fragments = ranges.map((range, index) => ({ range, index })).filter(({ range }) => requested.has(range.id)).map((fragment) => ({ ...fragment, inverse: inverseOf(fragment.range) }));
|
|
1289
|
+
fragments.sort((a, b) => Number(b.range.op.d !== void 0) - Number(a.range.op.d !== void 0) || b.range.op.p - a.range.op.p || a.index - b.index);
|
|
1290
|
+
const restorations = fragments.filter((fragment) => "i" in fragment.inverse);
|
|
1290
1291
|
const operations = [];
|
|
1291
1292
|
let expectedText = currentText;
|
|
1292
|
-
|
|
1293
|
-
|
|
1293
|
+
let restorePosition = -1;
|
|
1294
|
+
let restoredAtPosition = 0;
|
|
1295
|
+
for (const { range, inverse: originalInverse } of fragments) {
|
|
1296
|
+
if ("i" in originalInverse && originalInverse.p !== restorePosition) {
|
|
1297
|
+
restorePosition = originalInverse.p;
|
|
1298
|
+
restoredAtPosition = 0;
|
|
1299
|
+
}
|
|
1300
|
+
const shift = "d" in originalInverse ? restorations.reduce((sum, restored) => sum + (restored.range.op.p <= range.op.p ? restored.range.op.d.length : 0), 0) : restoredAtPosition;
|
|
1301
|
+
const inverse = { ...originalInverse, p: originalInverse.p + shift };
|
|
1294
1302
|
expectedText = applyUndo(expectedText, inverse, range.id);
|
|
1295
1303
|
operations.push(inverse);
|
|
1304
|
+
if ("i" in inverse) restoredAtPosition += inverse.i.length;
|
|
1296
1305
|
}
|
|
1297
1306
|
return {
|
|
1298
|
-
changeIds: changeIdsInRanges(fragments),
|
|
1307
|
+
changeIds: changeIdsInRanges(fragments.map((fragment) => fragment.range)),
|
|
1299
1308
|
fragmentCount: fragments.length,
|
|
1300
1309
|
operations,
|
|
1301
1310
|
expectedText
|
|
@@ -2299,7 +2308,7 @@ ${doc.localPath} \u2192 ${doc.docPath} (v${doc.liveVersion}): ${doc.ops.length}
|
|
|
2299
2308
|
}
|
|
2300
2309
|
async function push(opts) {
|
|
2301
2310
|
validatePushOptions(opts);
|
|
2302
|
-
const { isReviewedManifest, createReviewedFilePlan, applyReviewedFilePlan, REVIEWED_FILE_KIND } = await import("./reviewed-replace-
|
|
2311
|
+
const { isReviewedManifest, createReviewedFilePlan, applyReviewedFilePlan, REVIEWED_FILE_KIND } = await import("./reviewed-replace-CW447HNG.js");
|
|
2303
2312
|
if (opts.edits && isReviewedManifest(JSON.parse(readFileSync6(workspaceReadPath(opts.edits), "utf8")))) {
|
|
2304
2313
|
await createReviewedFilePlan(opts);
|
|
2305
2314
|
return;
|
package/dist/cli.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overleaf-review",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "The missing review layer for Overleaf's Git bridge — sync comments and tracked changes between Overleaf and your local repo.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"probe:review-live": "tsx src/probes/05-review-live.ts",
|
|
45
45
|
"probe:reviewed-model": "tsx src/probes/06-reviewed-model.ts",
|
|
46
46
|
"probe:reviewed-live": "tsx src/probes/07-reviewed-live.ts",
|
|
47
|
+
"probe:rejection-model": "tsx src/probes/08-rejection-model.ts",
|
|
47
48
|
"typecheck": "tsc --noEmit",
|
|
48
49
|
"test": "tsx --test test/*.test.ts",
|
|
49
50
|
"check": "npm run typecheck && npm test && npm run build"
|