@adeu/core 1.23.0 → 1.25.0
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 +185 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +185 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/diff.ts +23 -8
- package/src/engine.ts +132 -39
- package/src/repro_qa_report_v6.test.ts +486 -0
- package/src/sanitize/core.ts +57 -1
- package/src/sanitize/report.ts +5 -3
- package/src/sanitize/sanitize.test.ts +5 -4
- package/src/sanitize/transforms.ts +94 -16
package/dist/index.cjs
CHANGED
|
@@ -2845,7 +2845,8 @@ function _row_ops_for_table(table_o, table_m, opcodes, warnings) {
|
|
|
2845
2845
|
type: "modify",
|
|
2846
2846
|
target_text: o_txt,
|
|
2847
2847
|
new_text: m_txt,
|
|
2848
|
-
comment: "Diff: Table row modified"
|
|
2848
|
+
comment: "Diff: Table row modified",
|
|
2849
|
+
_is_table_edit: true
|
|
2849
2850
|
});
|
|
2850
2851
|
}
|
|
2851
2852
|
}
|
|
@@ -2947,14 +2948,18 @@ function generate_structured_edits(text_orig, struct_orig, text_mod, struct_mod)
|
|
|
2947
2948
|
if (row_opcodes !== null) {
|
|
2948
2949
|
edits.push(..._row_ops_for_table(t_o, t_m, row_opcodes, warnings));
|
|
2949
2950
|
} else {
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2951
|
+
for (let k = 0; k < t_o.rows.length; k++) {
|
|
2952
|
+
const o_txt = t_o.rows[k].cells.join(" | ");
|
|
2953
|
+
const m_txt = t_m.rows[k].cells.join(" | ");
|
|
2954
|
+
if (o_txt === m_txt) continue;
|
|
2955
|
+
edits.push({
|
|
2956
|
+
type: "modify",
|
|
2957
|
+
target_text: o_txt,
|
|
2958
|
+
new_text: m_txt,
|
|
2959
|
+
comment: "Diff: Table row modified",
|
|
2960
|
+
_is_table_edit: true
|
|
2961
|
+
});
|
|
2956
2962
|
}
|
|
2957
|
-
edits.push(...tbl_edits);
|
|
2958
2963
|
}
|
|
2959
2964
|
}
|
|
2960
2965
|
}
|
|
@@ -2972,7 +2977,7 @@ function generate_structured_edits(text_orig, struct_orig, text_mod, struct_mod)
|
|
|
2972
2977
|
};
|
|
2973
2978
|
let ambiguous_anchor_warned = false;
|
|
2974
2979
|
for (const e of edits) {
|
|
2975
|
-
if ((e.type === "insert_row" || e.type === "delete_row") && !ambiguous_anchor_warned) {
|
|
2980
|
+
if ((e.type === "insert_row" || e.type === "delete_row" || e._is_table_edit) && !ambiguous_anchor_warned) {
|
|
2976
2981
|
if (e.target_text && countOccurrences(text_orig, e.target_text) > 1) {
|
|
2977
2982
|
warnings.push(
|
|
2978
2983
|
`The row anchor "${e.target_text.substring(0, 60)}" appears more than once in the document. Applying this diff from its JSON output may be rejected as ambiguous \u2014 make the anchor rows unique, or apply the row changes with explicit insert_row/delete_row edits.`
|
|
@@ -4724,7 +4729,7 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
4724
4729
|
*
|
|
4725
4730
|
* Does NOT attach comments; callers handle that.
|
|
4726
4731
|
*/
|
|
4727
|
-
_track_insert_multiline(text, anchor_run, anchor_paragraph, reuse_id) {
|
|
4732
|
+
_track_insert_multiline(text, anchor_run, anchor_paragraph, reuse_id, positional_anchor_el = null) {
|
|
4728
4733
|
if (!text) {
|
|
4729
4734
|
return {
|
|
4730
4735
|
first_node: null,
|
|
@@ -4745,7 +4750,29 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
4745
4750
|
}
|
|
4746
4751
|
current_p = walker;
|
|
4747
4752
|
}
|
|
4748
|
-
|
|
4753
|
+
const suffix_nodes = [];
|
|
4754
|
+
const pos_source = positional_anchor_el && positional_anchor_el.parentNode ? positional_anchor_el : anchor_run !== null && anchor_run._element.parentNode ? anchor_run._element : null;
|
|
4755
|
+
if (current_p !== null && pos_source !== null) {
|
|
4756
|
+
let pos_anchor = pos_source;
|
|
4757
|
+
while (pos_anchor && pos_anchor.parentNode !== current_p) {
|
|
4758
|
+
pos_anchor = pos_anchor.parentNode;
|
|
4759
|
+
if (pos_anchor === current_p) {
|
|
4760
|
+
pos_anchor = null;
|
|
4761
|
+
break;
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
if (pos_anchor) {
|
|
4765
|
+
const relocatable = /* @__PURE__ */ new Set(["w:r", "w:ins", "w:del"]);
|
|
4766
|
+
let nxt = pos_anchor.nextSibling;
|
|
4767
|
+
while (nxt) {
|
|
4768
|
+
if (nxt.nodeType === 1 && relocatable.has(nxt.tagName)) {
|
|
4769
|
+
suffix_nodes.push(nxt);
|
|
4770
|
+
}
|
|
4771
|
+
nxt = nxt.nextSibling;
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
while (lines.length > 1 && lines[lines.length - 1] === "" && suffix_nodes.length === 0) {
|
|
4749
4776
|
lines.pop();
|
|
4750
4777
|
}
|
|
4751
4778
|
if (lines.length === 0) {
|
|
@@ -4843,6 +4870,12 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
4843
4870
|
first_node = new_p;
|
|
4844
4871
|
}
|
|
4845
4872
|
}
|
|
4873
|
+
if (!block_mode && last_p && suffix_nodes.length > 0) {
|
|
4874
|
+
for (const node of suffix_nodes) {
|
|
4875
|
+
node.parentNode?.removeChild(node);
|
|
4876
|
+
last_p.appendChild(node);
|
|
4877
|
+
}
|
|
4878
|
+
}
|
|
4846
4879
|
return { first_node, last_p, last_ins, used_block_mode: block_mode };
|
|
4847
4880
|
}
|
|
4848
4881
|
/**
|
|
@@ -4900,7 +4933,7 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
4900
4933
|
if (stripped_text.startsWith("* ") || stripped_text.startsWith("- ")) {
|
|
4901
4934
|
return [stripped_text.substring(2).trim(), "List Paragraph"];
|
|
4902
4935
|
}
|
|
4903
|
-
const match = stripped_text.match(
|
|
4936
|
+
const match = stripped_text.match(/^1\.\s+/);
|
|
4904
4937
|
if (match) {
|
|
4905
4938
|
return [stripped_text.substring(match[0].length).trim(), "List Number"];
|
|
4906
4939
|
}
|
|
@@ -5782,14 +5815,17 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
5782
5815
|
resolved_edits.push([edit, edit.new_text || null]);
|
|
5783
5816
|
} else if (edit.type === "insert_row" || edit.type === "delete_row") {
|
|
5784
5817
|
let matches = this.mapper.find_all_match_indices(edit.target_text);
|
|
5818
|
+
let resolved_mapper = this.mapper;
|
|
5785
5819
|
if (matches.length === 0) {
|
|
5786
5820
|
if (!this.clean_mapper) {
|
|
5787
5821
|
this.clean_mapper = new DocumentMapper(this.doc, true);
|
|
5788
5822
|
}
|
|
5789
5823
|
matches = this.clean_mapper.find_all_match_indices(edit.target_text);
|
|
5824
|
+
resolved_mapper = this.clean_mapper;
|
|
5790
5825
|
}
|
|
5791
5826
|
if (matches.length > 0) {
|
|
5792
5827
|
edit._resolved_start_idx = matches[0][0];
|
|
5828
|
+
edit._active_mapper_ref = resolved_mapper;
|
|
5793
5829
|
resolved_edits.push([edit, null]);
|
|
5794
5830
|
} else {
|
|
5795
5831
|
skipped++;
|
|
@@ -6038,7 +6074,8 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
6038
6074
|
}
|
|
6039
6075
|
_apply_table_edit(edit, rebuild_map) {
|
|
6040
6076
|
const start_idx = edit._resolved_start_idx !== void 0 && edit._resolved_start_idx !== null ? edit._resolved_start_idx : edit._match_start_index || 0;
|
|
6041
|
-
const
|
|
6077
|
+
const active_mapper = edit._active_mapper_ref || this.mapper;
|
|
6078
|
+
const [anchor_run, anchor_para] = active_mapper.get_insertion_anchor(
|
|
6042
6079
|
start_idx,
|
|
6043
6080
|
rebuild_map
|
|
6044
6081
|
);
|
|
@@ -6219,9 +6256,14 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
6219
6256
|
if (overlaps_virtual_pipe) {
|
|
6220
6257
|
const actual_cells = actual_doc_text.split("|");
|
|
6221
6258
|
const new_cells = current_effective_new_text.split("|");
|
|
6222
|
-
if (actual_cells.length
|
|
6259
|
+
if (actual_cells.length !== new_cells.length) {
|
|
6260
|
+
throw new BatchValidationError([
|
|
6261
|
+
`Target text spans ${actual_cells.length} table cells, but replacement provides ${new_cells.length}. To modify text without altering table structure (rows or columns), ensure the replacement contains the exact same number of '|' separators (e.g., replace with 'CellC | ' to empty the second cell).`
|
|
6262
|
+
]);
|
|
6263
|
+
}
|
|
6264
|
+
if (actual_cells.length > 1) {
|
|
6223
6265
|
const sub_edits2 = [];
|
|
6224
|
-
let
|
|
6266
|
+
let cell_start_in_target = 0;
|
|
6225
6267
|
let target_comment_idx = 0;
|
|
6226
6268
|
for (let idx = 0; idx < actual_cells.length; idx++) {
|
|
6227
6269
|
if (actual_cells[idx].trim() !== new_cells[idx].trim()) {
|
|
@@ -6234,13 +6276,7 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
6234
6276
|
const n_cell = new_cells[cell_idx];
|
|
6235
6277
|
const a_clean = a_cell.trim();
|
|
6236
6278
|
const n_clean = n_cell.trim();
|
|
6237
|
-
|
|
6238
|
-
if (a_clean) {
|
|
6239
|
-
actual_start = this.mapper.full_text.indexOf(a_clean, search_offset);
|
|
6240
|
-
if (actual_start === -1 || actual_start > search_offset + 10) {
|
|
6241
|
-
actual_start = search_offset;
|
|
6242
|
-
}
|
|
6243
|
-
}
|
|
6279
|
+
const actual_start = start_idx + cell_start_in_target + (a_clean ? a_cell.indexOf(a_clean) : 0);
|
|
6244
6280
|
const should_attach_comment = edit.comment !== null && edit.comment !== void 0 && cell_idx === target_comment_idx;
|
|
6245
6281
|
if (a_clean !== n_clean || should_attach_comment) {
|
|
6246
6282
|
const cell_sub_edits = this._word_diff_sub_edits(
|
|
@@ -6257,24 +6293,12 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
6257
6293
|
sub_edits2.push(se);
|
|
6258
6294
|
}
|
|
6259
6295
|
}
|
|
6260
|
-
|
|
6261
|
-
search_offset = actual_start + a_clean.length;
|
|
6262
|
-
}
|
|
6263
|
-
const next_pipe = this.mapper.full_text.indexOf(" | ", search_offset);
|
|
6264
|
-
if (next_pipe !== -1 && next_pipe <= search_offset + 10) {
|
|
6265
|
-
search_offset = next_pipe + 3;
|
|
6266
|
-
} else {
|
|
6267
|
-
search_offset += a_cell.length + 1;
|
|
6268
|
-
}
|
|
6296
|
+
cell_start_in_target += a_cell.length + 1;
|
|
6269
6297
|
}
|
|
6270
6298
|
for (const sub of sub_edits2) {
|
|
6271
6299
|
all_sub_edits.push(sub);
|
|
6272
6300
|
}
|
|
6273
6301
|
continue;
|
|
6274
|
-
} else {
|
|
6275
|
-
throw new BatchValidationError([
|
|
6276
|
-
`Target text spans ${actual_cells.length} table cells, but replacement provides ${new_cells.length}. To modify text without altering table structure (rows or columns), ensure the replacement contains the exact same number of '|' separators (e.g., replace with 'CellC | ' to empty the second cell).`
|
|
6277
|
-
]);
|
|
6278
6302
|
}
|
|
6279
6303
|
}
|
|
6280
6304
|
let has_markdown = false;
|
|
@@ -6368,6 +6392,19 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
6368
6392
|
continue;
|
|
6369
6393
|
}
|
|
6370
6394
|
}
|
|
6395
|
+
if (!final_target && final_new) {
|
|
6396
|
+
all_sub_edits.push({
|
|
6397
|
+
type: "modify",
|
|
6398
|
+
target_text: "",
|
|
6399
|
+
new_text: final_new,
|
|
6400
|
+
comment: edit.comment,
|
|
6401
|
+
_resolved_start_idx: effective_start_idx,
|
|
6402
|
+
_match_start_index: effective_start_idx,
|
|
6403
|
+
_internal_op: "INSERTION",
|
|
6404
|
+
_active_mapper_ref: active_mapper
|
|
6405
|
+
});
|
|
6406
|
+
continue;
|
|
6407
|
+
}
|
|
6371
6408
|
const sub_edits = this._word_diff_sub_edits(
|
|
6372
6409
|
actual_doc_text,
|
|
6373
6410
|
current_effective_new_text,
|
|
@@ -6809,7 +6846,10 @@ var RedlineEngine = class _RedlineEngine {
|
|
|
6809
6846
|
edit.new_text,
|
|
6810
6847
|
style_source_run,
|
|
6811
6848
|
mod_anchor_para,
|
|
6812
|
-
ins_id
|
|
6849
|
+
ins_id,
|
|
6850
|
+
// The insertion physically follows the deletion block; the style
|
|
6851
|
+
// run was detached when the deletion cloned it into <w:del>.
|
|
6852
|
+
last_del
|
|
6813
6853
|
);
|
|
6814
6854
|
if (result.first_node) {
|
|
6815
6855
|
const is_inline_first = result.first_node.tagName === "w:ins";
|
|
@@ -7356,7 +7396,10 @@ function scrub_doc_properties(doc) {
|
|
|
7356
7396
|
["keywords", "Keywords"],
|
|
7357
7397
|
["subject", "Subject"],
|
|
7358
7398
|
["contentStatus", "Content status"],
|
|
7359
|
-
["description", "Description/comments"]
|
|
7399
|
+
["description", "Description/comments"],
|
|
7400
|
+
["identifier", "Identifier"],
|
|
7401
|
+
["language", "Language"],
|
|
7402
|
+
["version", "Version"]
|
|
7360
7403
|
];
|
|
7361
7404
|
for (const [local, label] of leakFields) {
|
|
7362
7405
|
findDescendantsByLocalName(corePart._element, local).forEach((c) => {
|
|
@@ -7414,27 +7457,73 @@ function scrub_timestamps(doc) {
|
|
|
7414
7457
|
}
|
|
7415
7458
|
return modified ? ["Timestamps normalized to epoch"] : [];
|
|
7416
7459
|
}
|
|
7417
|
-
function
|
|
7418
|
-
const
|
|
7419
|
-
|
|
7420
|
-
const
|
|
7421
|
-
|
|
7422
|
-
const removeRelationsTo = (relsPart) => {
|
|
7460
|
+
function ejectPackageMembers(doc, matcher, relTargetMatcher) {
|
|
7461
|
+
const pkg = doc.pkg;
|
|
7462
|
+
const normalized = (p) => p.startsWith("/") ? p.substring(1) : p;
|
|
7463
|
+
for (const part of pkg.parts) {
|
|
7464
|
+
if (!part.partname.endsWith(".rels")) continue;
|
|
7423
7465
|
const toRemove = [];
|
|
7424
|
-
for (const rel of findAllDescendants(
|
|
7425
|
-
const target = rel.getAttribute("Target");
|
|
7426
|
-
if (target
|
|
7466
|
+
for (const rel of findAllDescendants(part._element, "Relationship")) {
|
|
7467
|
+
const target = rel.getAttribute("Target") || "";
|
|
7468
|
+
if (relTargetMatcher(target)) {
|
|
7469
|
+
toRemove.push(rel);
|
|
7470
|
+
const sourcePath = part.partname.replace("/_rels/", "/").replace(".rels", "");
|
|
7471
|
+
const sourcePart = pkg.getPartByPath(sourcePath);
|
|
7472
|
+
if (sourcePart) {
|
|
7473
|
+
const relId = rel.getAttribute("Id");
|
|
7474
|
+
if (relId) sourcePart.rels.delete(relId);
|
|
7475
|
+
}
|
|
7476
|
+
}
|
|
7427
7477
|
}
|
|
7428
7478
|
toRemove.forEach((r) => r.parentNode?.removeChild(r));
|
|
7429
|
-
}
|
|
7430
|
-
const
|
|
7431
|
-
if (
|
|
7432
|
-
|
|
7433
|
-
|
|
7479
|
+
}
|
|
7480
|
+
const ctPart = pkg.getPartByPath("[Content_Types].xml");
|
|
7481
|
+
if (ctPart) {
|
|
7482
|
+
const toRemove = [];
|
|
7483
|
+
for (const override of findAllDescendants(ctPart._element, "Override")) {
|
|
7484
|
+
const partName = override.getAttribute("PartName") || "";
|
|
7485
|
+
if (matcher(normalized(partName))) toRemove.push(override);
|
|
7486
|
+
}
|
|
7487
|
+
toRemove.forEach((o) => o.parentNode?.removeChild(o));
|
|
7488
|
+
}
|
|
7489
|
+
pkg.parts = pkg.parts.filter((p) => !matcher(normalized(p.partname)));
|
|
7490
|
+
for (const key of Object.keys(pkg.unzipped)) {
|
|
7491
|
+
if (matcher(normalized(key))) delete pkg.unzipped[key];
|
|
7492
|
+
}
|
|
7493
|
+
}
|
|
7494
|
+
function strip_custom_xml(doc) {
|
|
7495
|
+
const isCustomXml = (path) => path.startsWith("customXml/");
|
|
7496
|
+
const customParts = doc.pkg.parts.filter(
|
|
7497
|
+
(p) => isCustomXml(p.partname.startsWith("/") ? p.partname.substring(1) : p.partname)
|
|
7498
|
+
);
|
|
7499
|
+
const leakedMembers = Object.keys(doc.pkg.unzipped).filter(isCustomXml);
|
|
7500
|
+
if (customParts.length === 0 && leakedMembers.length === 0) return [];
|
|
7501
|
+
ejectPackageMembers(doc, isCustomXml, (target) => target.includes("customXml"));
|
|
7434
7502
|
for (const sdtPr of findAllDescendants(doc.element, "w:sdtPr")) {
|
|
7435
7503
|
findChildren(sdtPr, "w:dataBinding").forEach((b) => sdtPr.removeChild(b));
|
|
7436
7504
|
}
|
|
7437
|
-
return [`Custom XML parts: ${customParts.length} removed`];
|
|
7505
|
+
return [`Custom XML parts: ${Math.max(customParts.length, leakedMembers.length)} removed`];
|
|
7506
|
+
}
|
|
7507
|
+
var CUSTOM_PROPS_PATH = "docProps/custom.xml";
|
|
7508
|
+
function strip_custom_properties(doc) {
|
|
7509
|
+
const part = doc.pkg.getPartByPath(CUSTOM_PROPS_PATH);
|
|
7510
|
+
const leaked = Object.keys(doc.pkg.unzipped).includes(CUSTOM_PROPS_PATH);
|
|
7511
|
+
if (!part && !leaked) return [];
|
|
7512
|
+
const lines = [];
|
|
7513
|
+
if (part) {
|
|
7514
|
+
for (const prop of findDescendantsByLocalName(part._element, "property")) {
|
|
7515
|
+
const name = prop.getAttribute("name") || "(unnamed)";
|
|
7516
|
+
const value = (prop.textContent || "").trim();
|
|
7517
|
+
lines.push(` Custom property removed: ${name} = "${_truncate(value, 60)}"`);
|
|
7518
|
+
}
|
|
7519
|
+
}
|
|
7520
|
+
ejectPackageMembers(
|
|
7521
|
+
doc,
|
|
7522
|
+
(path) => path === CUSTOM_PROPS_PATH,
|
|
7523
|
+
(target) => target.includes("docProps/custom.xml")
|
|
7524
|
+
);
|
|
7525
|
+
const count = Math.max(lines.length, 1);
|
|
7526
|
+
return [`Custom document properties: ${count} removed (docProps/custom.xml)`].concat(lines);
|
|
7438
7527
|
}
|
|
7439
7528
|
function strip_image_alt_text(doc) {
|
|
7440
7529
|
let count = 0;
|
|
@@ -8788,6 +8877,9 @@ function _collect_footnote_ids_fast(owned_items) {
|
|
|
8788
8877
|
return ordered;
|
|
8789
8878
|
}
|
|
8790
8879
|
|
|
8880
|
+
// src/sanitize/core.ts
|
|
8881
|
+
var import_fflate2 = require("fflate");
|
|
8882
|
+
|
|
8791
8883
|
// src/sanitize/report.ts
|
|
8792
8884
|
var SanitizeReport = class {
|
|
8793
8885
|
filename;
|
|
@@ -8822,7 +8914,7 @@ var SanitizeReport = class {
|
|
|
8822
8914
|
} else {
|
|
8823
8915
|
this.removed_comment_lines.push(line);
|
|
8824
8916
|
}
|
|
8825
|
-
} else if (lower.includes("author") || lower.includes("template") || lower.includes("company") || lower.includes("manager") || lower.includes("metadata") || lower.includes("timestamp") || lower.includes("custom xml") || lower.includes("last modified by") || lower.includes("revision count") || lower.includes("last printed")) {
|
|
8917
|
+
} else if (lower.includes("author") || lower.includes("template") || lower.includes("company") || lower.includes("manager") || lower.includes("metadata") || lower.includes("timestamp") || lower.includes("custom xml") || lower.includes("custom propert") || lower.includes("identifier") || lower.includes("language") || lower.includes("version") || lower.includes("last modified by") || lower.includes("revision count") || lower.includes("last printed")) {
|
|
8826
8918
|
this.metadata_lines.push(line);
|
|
8827
8919
|
} else if (lower.includes("hyperlink") || lower.includes("warning")) {
|
|
8828
8920
|
this.warnings.push(line);
|
|
@@ -8935,6 +9027,7 @@ async function finalize_document(doc, options) {
|
|
|
8935
9027
|
report.add_transform_lines(scrub_doc_properties(doc));
|
|
8936
9028
|
report.add_transform_lines(scrub_timestamps(doc));
|
|
8937
9029
|
report.add_transform_lines(strip_custom_xml(doc));
|
|
9030
|
+
report.add_transform_lines(strip_custom_properties(doc));
|
|
8938
9031
|
report.add_transform_lines(strip_image_alt_text(doc));
|
|
8939
9032
|
const warnings = audit_hyperlinks(doc);
|
|
8940
9033
|
for (const w of warnings) report.warnings.push(w);
|
|
@@ -8982,8 +9075,47 @@ async function finalize_document(doc, options) {
|
|
|
8982
9075
|
}
|
|
8983
9076
|
if (report.warnings.length > 0) report.status = "clean_with_warnings";
|
|
8984
9077
|
const outBuffer = await doc.save();
|
|
9078
|
+
verifySanitizedPackage(outBuffer);
|
|
8985
9079
|
return { reportText: report.render(), outBuffer };
|
|
8986
9080
|
}
|
|
9081
|
+
var VERIFIED_CORE_FIELDS = [
|
|
9082
|
+
["creator", "author (dc:creator)"],
|
|
9083
|
+
["lastModifiedBy", "last modified by (cp:lastModifiedBy)"],
|
|
9084
|
+
["identifier", "identifier (dc:identifier)"],
|
|
9085
|
+
["description", "description (dc:description)"],
|
|
9086
|
+
["keywords", "keywords (cp:keywords)"],
|
|
9087
|
+
["category", "category (cp:category)"],
|
|
9088
|
+
["subject", "subject (dc:subject)"],
|
|
9089
|
+
["contentStatus", "content status (cp:contentStatus)"],
|
|
9090
|
+
["language", "language (dc:language)"],
|
|
9091
|
+
["version", "version (cp:version)"]
|
|
9092
|
+
];
|
|
9093
|
+
function verifySanitizedPackage(outBuffer) {
|
|
9094
|
+
const unzipped = (0, import_fflate2.unzipSync)(new Uint8Array(outBuffer));
|
|
9095
|
+
const names = Object.keys(unzipped);
|
|
9096
|
+
const problems = [];
|
|
9097
|
+
if (names.includes("docProps/custom.xml")) {
|
|
9098
|
+
problems.push("docProps/custom.xml (custom document properties) is still in the package");
|
|
9099
|
+
}
|
|
9100
|
+
if (names.some((n) => n.startsWith("customXml/"))) {
|
|
9101
|
+
problems.push("customXml/* parts are still in the package");
|
|
9102
|
+
}
|
|
9103
|
+
if (names.includes("docProps/core.xml")) {
|
|
9104
|
+
const core = parseXml((0, import_fflate2.strFromU8)(unzipped["docProps/core.xml"]));
|
|
9105
|
+
for (const [local, label] of VERIFIED_CORE_FIELDS) {
|
|
9106
|
+
for (const el of findDescendantsByLocalName(core.documentElement, local)) {
|
|
9107
|
+
if ((el.textContent || "").trim()) {
|
|
9108
|
+
problems.push(`core property ${label} still contains a value`);
|
|
9109
|
+
}
|
|
9110
|
+
}
|
|
9111
|
+
}
|
|
9112
|
+
}
|
|
9113
|
+
if (problems.length > 0) {
|
|
9114
|
+
throw new Error(
|
|
9115
|
+
"Sanitize integrity check failed \u2014 the saved package still contains metadata this run claims to remove:\n - " + problems.join("\n - ") + "\nRefusing to report a clean document."
|
|
9116
|
+
);
|
|
9117
|
+
}
|
|
9118
|
+
}
|
|
8987
9119
|
|
|
8988
9120
|
// src/index.ts
|
|
8989
9121
|
function identifyEngine() {
|