@adeu/core 1.18.0 → 1.18.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/dist/index.cjs +68 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +68 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/engine.comment-preservation.test.ts +174 -0
- package/src/engine.feedback.test.ts +34 -2
- package/src/engine.ts +106 -30
package/dist/index.d.cts
CHANGED
|
@@ -185,6 +185,16 @@ declare class RedlineEngine {
|
|
|
185
185
|
original_mapper: DocumentMapper | null;
|
|
186
186
|
skipped_details: string[];
|
|
187
187
|
constructor(doc: DocumentObject, author?: string);
|
|
188
|
+
/**
|
|
189
|
+
* Return a hint when a short, single-token anchor contains punctuation that
|
|
190
|
+
* can split awkwardly, else null.
|
|
191
|
+
*
|
|
192
|
+
* Surface this ONLY for edits that actually failed to match/apply. On a
|
|
193
|
+
* successful edit the batch report already carries the redline preview, so
|
|
194
|
+
* emitting this would be a false positive: the punctuation (dates,
|
|
195
|
+
* `[_name_]` placeholders, `____` blanks) is frequently the literal target
|
|
196
|
+
* and the edit succeeds despite it. Mirrors the Python engine.
|
|
197
|
+
*/
|
|
188
198
|
private _check_punctuation_warning;
|
|
189
199
|
/**
|
|
190
200
|
* Best-effort "did you mean" hint for a failed target. The common loop trap
|
|
@@ -305,6 +315,15 @@ declare class RedlineEngine {
|
|
|
305
315
|
*/
|
|
306
316
|
private _set_paragraph_style;
|
|
307
317
|
private _anchor_reply_comment;
|
|
318
|
+
/**
|
|
319
|
+
* Read a comment's author directly from the comments part. Used by
|
|
320
|
+
* _clean_wrapping_comments to decide whether a wrapping comment belongs to
|
|
321
|
+
* another author (and must be preserved when its anchored change is
|
|
322
|
+
* accepted/rejected) or to us (safe to delete). Reads the part rather than
|
|
323
|
+
* the mapper because the mapper's comments_map is not rebuilt between review
|
|
324
|
+
* actions, so it can be stale mid-batch. Returns null if not found.
|
|
325
|
+
*/
|
|
326
|
+
private _get_comment_author;
|
|
308
327
|
private _clean_wrapping_comments;
|
|
309
328
|
private _delete_comments_in_element;
|
|
310
329
|
validate_edits(edits: any[], index_offset?: number): string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -185,6 +185,16 @@ declare class RedlineEngine {
|
|
|
185
185
|
original_mapper: DocumentMapper | null;
|
|
186
186
|
skipped_details: string[];
|
|
187
187
|
constructor(doc: DocumentObject, author?: string);
|
|
188
|
+
/**
|
|
189
|
+
* Return a hint when a short, single-token anchor contains punctuation that
|
|
190
|
+
* can split awkwardly, else null.
|
|
191
|
+
*
|
|
192
|
+
* Surface this ONLY for edits that actually failed to match/apply. On a
|
|
193
|
+
* successful edit the batch report already carries the redline preview, so
|
|
194
|
+
* emitting this would be a false positive: the punctuation (dates,
|
|
195
|
+
* `[_name_]` placeholders, `____` blanks) is frequently the literal target
|
|
196
|
+
* and the edit succeeds despite it. Mirrors the Python engine.
|
|
197
|
+
*/
|
|
188
198
|
private _check_punctuation_warning;
|
|
189
199
|
/**
|
|
190
200
|
* Best-effort "did you mean" hint for a failed target. The common loop trap
|
|
@@ -305,6 +315,15 @@ declare class RedlineEngine {
|
|
|
305
315
|
*/
|
|
306
316
|
private _set_paragraph_style;
|
|
307
317
|
private _anchor_reply_comment;
|
|
318
|
+
/**
|
|
319
|
+
* Read a comment's author directly from the comments part. Used by
|
|
320
|
+
* _clean_wrapping_comments to decide whether a wrapping comment belongs to
|
|
321
|
+
* another author (and must be preserved when its anchored change is
|
|
322
|
+
* accepted/rejected) or to us (safe to delete). Reads the part rather than
|
|
323
|
+
* the mapper because the mapper's comments_map is not rebuilt between review
|
|
324
|
+
* actions, so it can be stale mid-batch. Returns null if not found.
|
|
325
|
+
*/
|
|
326
|
+
private _get_comment_author;
|
|
308
327
|
private _clean_wrapping_comments;
|
|
309
328
|
private _delete_comments_in_element;
|
|
310
329
|
validate_edits(edits: any[], index_offset?: number): string[];
|
package/dist/index.js
CHANGED
|
@@ -3012,8 +3012,19 @@ var RedlineEngine = class {
|
|
|
3012
3012
|
this.mapper = new DocumentMapper(this.doc);
|
|
3013
3013
|
this.comments_manager = new CommentsManager(this.doc);
|
|
3014
3014
|
}
|
|
3015
|
+
/**
|
|
3016
|
+
* Return a hint when a short, single-token anchor contains punctuation that
|
|
3017
|
+
* can split awkwardly, else null.
|
|
3018
|
+
*
|
|
3019
|
+
* Surface this ONLY for edits that actually failed to match/apply. On a
|
|
3020
|
+
* successful edit the batch report already carries the redline preview, so
|
|
3021
|
+
* emitting this would be a false positive: the punctuation (dates,
|
|
3022
|
+
* `[_name_]` placeholders, `____` blanks) is frequently the literal target
|
|
3023
|
+
* and the edit succeeds despite it. Mirrors the Python engine.
|
|
3024
|
+
*/
|
|
3015
3025
|
_check_punctuation_warning(target_text) {
|
|
3016
3026
|
if (!target_text) return null;
|
|
3027
|
+
if (target_text.length > 20 || target_text.includes(" ")) return null;
|
|
3017
3028
|
if (target_text.includes("_") || target_text.includes("-")) {
|
|
3018
3029
|
return `Warning: target_text '${target_text}' contains tokenization-splitting punctuation ('_' or '-'). This can trigger mid-word splits in the diff engine. Consider using a longer plain-prose anchor.`;
|
|
3019
3030
|
}
|
|
@@ -3811,6 +3822,27 @@ var RedlineEngine = class {
|
|
|
3811
3822
|
ref_run.appendChild(ref);
|
|
3812
3823
|
insertAfter(ref_run, new_end);
|
|
3813
3824
|
}
|
|
3825
|
+
/**
|
|
3826
|
+
* Read a comment's author directly from the comments part. Used by
|
|
3827
|
+
* _clean_wrapping_comments to decide whether a wrapping comment belongs to
|
|
3828
|
+
* another author (and must be preserved when its anchored change is
|
|
3829
|
+
* accepted/rejected) or to us (safe to delete). Reads the part rather than
|
|
3830
|
+
* the mapper because the mapper's comments_map is not rebuilt between review
|
|
3831
|
+
* actions, so it can be stale mid-batch. Returns null if not found.
|
|
3832
|
+
*/
|
|
3833
|
+
_get_comment_author(c_id) {
|
|
3834
|
+
const part = this.doc.pkg.parts.find(
|
|
3835
|
+
(p) => p.contentType === "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"
|
|
3836
|
+
);
|
|
3837
|
+
if (!part) return null;
|
|
3838
|
+
const comments = findAllDescendants(part._element, "w:comment");
|
|
3839
|
+
for (const c of comments) {
|
|
3840
|
+
if (c.getAttribute("w:id") === c_id) {
|
|
3841
|
+
return c.getAttribute("w:author");
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
return null;
|
|
3845
|
+
}
|
|
3814
3846
|
_clean_wrapping_comments(element) {
|
|
3815
3847
|
let first_node = element;
|
|
3816
3848
|
while (true) {
|
|
@@ -3875,7 +3907,11 @@ var RedlineEngine = class {
|
|
|
3875
3907
|
for (const s of starts_to_remove) {
|
|
3876
3908
|
const c_id = s.getAttribute("w:id");
|
|
3877
3909
|
if (c_id && end_ids.has(c_id)) {
|
|
3878
|
-
this.
|
|
3910
|
+
const author = this._get_comment_author(c_id);
|
|
3911
|
+
const is_own = author !== null && author === this.author;
|
|
3912
|
+
if (is_own) {
|
|
3913
|
+
this.comments_manager.deleteComment(c_id);
|
|
3914
|
+
}
|
|
3879
3915
|
if (s.parentNode) s.parentNode.removeChild(s);
|
|
3880
3916
|
for (const e of ends_to_remove) {
|
|
3881
3917
|
let e_id = null;
|
|
@@ -4004,10 +4040,9 @@ var RedlineEngine = class {
|
|
|
4004
4040
|
if (edit.target_text.includes("|")) {
|
|
4005
4041
|
matches = matches.slice(0, 1);
|
|
4006
4042
|
} else {
|
|
4007
|
-
const positions = matches.map(
|
|
4008
|
-
start,
|
|
4009
|
-
|
|
4010
|
-
]);
|
|
4043
|
+
const positions = matches.map(
|
|
4044
|
+
([start, length]) => [start, start + length]
|
|
4045
|
+
);
|
|
4011
4046
|
errors.push(
|
|
4012
4047
|
format_ambiguity_error(
|
|
4013
4048
|
i + 1 + index_offset,
|
|
@@ -4174,7 +4209,10 @@ var RedlineEngine = class {
|
|
|
4174
4209
|
_process_batch_internal(changes, dry_run_mode = false) {
|
|
4175
4210
|
for (const c of changes) {
|
|
4176
4211
|
if (c && typeof c === "object" && c.type === "modify" && c.target_text && c.new_text) {
|
|
4177
|
-
const [strippedTarget, strippedNew] = stripMatchingHeadingHashes(
|
|
4212
|
+
const [strippedTarget, strippedNew] = stripMatchingHeadingHashes(
|
|
4213
|
+
c.target_text,
|
|
4214
|
+
c.new_text
|
|
4215
|
+
);
|
|
4178
4216
|
c.target_text = strippedTarget;
|
|
4179
4217
|
c.new_text = strippedNew;
|
|
4180
4218
|
}
|
|
@@ -4190,10 +4228,7 @@ var RedlineEngine = class {
|
|
|
4190
4228
|
const action_errors = actions.length > 0 ? this.validate_review_actions(actions) : [];
|
|
4191
4229
|
const validate_edits_now = edits.length > 0 && action_errors.length > 0;
|
|
4192
4230
|
const edit_errors = validate_edits_now ? this.validate_edits(edits) : [];
|
|
4193
|
-
const all_errors = [
|
|
4194
|
-
...action_errors,
|
|
4195
|
-
...edit_errors
|
|
4196
|
-
];
|
|
4231
|
+
const all_errors = [...action_errors, ...edit_errors];
|
|
4197
4232
|
if (all_errors.length > 0) {
|
|
4198
4233
|
throw new BatchValidationError(all_errors);
|
|
4199
4234
|
}
|
|
@@ -4230,11 +4265,11 @@ var RedlineEngine = class {
|
|
|
4230
4265
|
for (let i = 0; i < edits.length; i++) {
|
|
4231
4266
|
const edit = edits[i];
|
|
4232
4267
|
const single_errors = this.validate_edits([edit], i);
|
|
4233
|
-
const warning = this._check_punctuation_warning(
|
|
4234
|
-
edit.target_text || ""
|
|
4235
|
-
);
|
|
4236
4268
|
if (single_errors.length > 0) {
|
|
4237
4269
|
skipped_edits++;
|
|
4270
|
+
const warning = this._check_punctuation_warning(
|
|
4271
|
+
edit.target_text || ""
|
|
4272
|
+
);
|
|
4238
4273
|
edits_reports.push({
|
|
4239
4274
|
status: "failed",
|
|
4240
4275
|
target_text: edit.target_text || "",
|
|
@@ -4254,7 +4289,7 @@ var RedlineEngine = class {
|
|
|
4254
4289
|
status: "applied",
|
|
4255
4290
|
target_text: edit.target_text || "",
|
|
4256
4291
|
new_text: edit.new_text || "",
|
|
4257
|
-
warning,
|
|
4292
|
+
warning: null,
|
|
4258
4293
|
error: null,
|
|
4259
4294
|
critic_markup: previews[0],
|
|
4260
4295
|
clean_text: previews[1],
|
|
@@ -4268,6 +4303,9 @@ var RedlineEngine = class {
|
|
|
4268
4303
|
} else {
|
|
4269
4304
|
skipped_edits++;
|
|
4270
4305
|
const error_msg = this.skipped_details.length > 0 ? this.skipped_details[this.skipped_details.length - 1] : "Failed to apply edit";
|
|
4306
|
+
const warning = this._check_punctuation_warning(
|
|
4307
|
+
edit.target_text || ""
|
|
4308
|
+
);
|
|
4271
4309
|
edits_reports.push({
|
|
4272
4310
|
status: "failed",
|
|
4273
4311
|
target_text: edit.target_text || "",
|
|
@@ -4306,22 +4344,22 @@ var RedlineEngine = class {
|
|
|
4306
4344
|
this.clean_mapper = null;
|
|
4307
4345
|
throw err;
|
|
4308
4346
|
}
|
|
4309
|
-
applied_edits = edits.filter(
|
|
4310
|
-
(e) => e._applied_status
|
|
4311
|
-
).length;
|
|
4347
|
+
applied_edits = edits.filter((e) => e._applied_status).length;
|
|
4312
4348
|
skipped_edits = edits.length - applied_edits;
|
|
4313
4349
|
for (const edit of edits) {
|
|
4314
4350
|
const success = edit._applied_status || false;
|
|
4315
4351
|
const error_msg = edit._error_msg || null;
|
|
4316
|
-
const warning = this._check_punctuation_warning(
|
|
4317
|
-
edit.target_text || ""
|
|
4318
|
-
);
|
|
4319
4352
|
let critic_markup = null;
|
|
4320
4353
|
let clean_text = null;
|
|
4354
|
+
let warning = null;
|
|
4321
4355
|
if (success) {
|
|
4322
4356
|
const previews = this._build_edit_context_previews(edit);
|
|
4323
4357
|
critic_markup = previews[0];
|
|
4324
4358
|
clean_text = previews[1];
|
|
4359
|
+
} else {
|
|
4360
|
+
warning = this._check_punctuation_warning(
|
|
4361
|
+
edit.target_text || ""
|
|
4362
|
+
);
|
|
4325
4363
|
}
|
|
4326
4364
|
edits_reports.push({
|
|
4327
4365
|
status: success ? "applied" : "failed",
|
|
@@ -4347,7 +4385,7 @@ var RedlineEngine = class {
|
|
|
4347
4385
|
skipped_details: this.skipped_details,
|
|
4348
4386
|
edits: edits_reports,
|
|
4349
4387
|
engine: "node",
|
|
4350
|
-
version: "1.
|
|
4388
|
+
version: "1.18.2"
|
|
4351
4389
|
};
|
|
4352
4390
|
}
|
|
4353
4391
|
apply_edits(edits, page_offsets = []) {
|
|
@@ -4791,7 +4829,10 @@ var RedlineEngine = class {
|
|
|
4791
4829
|
const t_seg = target_segs[k];
|
|
4792
4830
|
const n_seg = new_segs[k];
|
|
4793
4831
|
if (t_seg !== n_seg) {
|
|
4794
|
-
const [seg_prefix, seg_suffix] = trim_common_context(
|
|
4832
|
+
const [seg_prefix, seg_suffix] = trim_common_context(
|
|
4833
|
+
t_seg,
|
|
4834
|
+
n_seg
|
|
4835
|
+
);
|
|
4795
4836
|
const seg_target = t_seg.substring(
|
|
4796
4837
|
seg_prefix,
|
|
4797
4838
|
t_seg.length - seg_suffix
|
|
@@ -5202,7 +5243,11 @@ var RedlineEngine = class {
|
|
|
5202
5243
|
if (is_inline_first) {
|
|
5203
5244
|
const del_parent = last_del.parentNode;
|
|
5204
5245
|
if (del_parent && del_parent.tagName === "w:ins") {
|
|
5205
|
-
this._insert_and_split_ins(
|
|
5246
|
+
this._insert_and_split_ins(
|
|
5247
|
+
del_parent,
|
|
5248
|
+
last_del,
|
|
5249
|
+
result.first_node
|
|
5250
|
+
);
|
|
5206
5251
|
} else {
|
|
5207
5252
|
insertAfter(result.first_node, last_del);
|
|
5208
5253
|
}
|