@harbour-enterprises/superdoc 0.18.1-next.2 → 0.19.0-next.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/chunks/{PdfViewer-DPqO7muc.cjs → PdfViewer-C2T9YTtR.cjs} +1 -1
- package/dist/chunks/{PdfViewer-BM7Ea3yr.es.js → PdfViewer-DXueyp6G.es.js} +1 -1
- package/dist/chunks/{index-CyUWXfUG.es.js → index-DYPEIENP.es.js} +2 -2
- package/dist/chunks/{index-CPLP-MPz.cjs → index-Do3Yz9zO.cjs} +2 -2
- package/dist/chunks/{super-editor.es-CzgdqA6a.es.js → super-editor.es-BY32iqnX.es.js} +300 -1
- package/dist/chunks/{super-editor.es-BSOX4l_Z.cjs → super-editor.es-ehqZe3p-.cjs} +300 -1
- package/dist/core/SuperDoc.d.ts.map +1 -1
- package/dist/super-editor/ai-writer.es.js +1 -1
- package/dist/super-editor/chunks/{editor-BZitQIK-.js → editor-DJIu60o8.js} +300 -1
- package/dist/super-editor/chunks/{toolbar-D1SFDkxX.js → toolbar-DYCZq9kV.js} +1 -1
- package/dist/super-editor/editor.es.js +1 -1
- package/dist/super-editor/src/core/super-validator/validators/xml/index.d.ts +2 -0
- package/dist/super-editor/src/core/super-validator/validators/xml/relationships/relationships-validator.d.ts +31 -0
- package/dist/super-editor/super-editor.es.js +3 -3
- package/dist/super-editor/toolbar.es.js +2 -2
- package/dist/super-editor.cjs +1 -1
- package/dist/super-editor.es.js +1 -1
- package/dist/superdoc.cjs +2 -2
- package/dist/superdoc.es.js +2 -2
- package/dist/superdoc.umd.js +300 -1
- package/dist/superdoc.umd.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const vue = require("./vue-DWle4Cai.cjs");
|
|
4
|
-
const superdoc = require("./index-
|
|
4
|
+
const superdoc = require("./index-Do3Yz9zO.cjs");
|
|
5
5
|
function self(vars) {
|
|
6
6
|
const {
|
|
7
7
|
opacityDisabled,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { m as defineComponent, B as h, O as Transition, $ as process$1, I as watchEffect, d as computed, r as ref, j as onMounted, W as onUnmounted, c as createElementBlock, o as openBlock, a as createBaseVNode, f as createCommentVNode, v as createVNode, x as unref } from "./vue-CXxsqYcP.es.js";
|
|
2
|
-
import { d as derived, c, a as cB, f as fadeInTransition, b as cM, N as NBaseLoading, w as warnOnce, u as useConfig, e as useTheme, p as pxfy, g as createKey, h as useThemeClass, i as useCompitable, _ as _export_sfc, j as useSuperdocStore, s as storeToRefs, k as useSelection } from "./index-
|
|
2
|
+
import { d as derived, c, a as cB, f as fadeInTransition, b as cM, N as NBaseLoading, w as warnOnce, u as useConfig, e as useTheme, p as pxfy, g as createKey, h as useThemeClass, i as useCompitable, _ as _export_sfc, j as useSuperdocStore, s as storeToRefs, k as useSelection } from "./index-DYPEIENP.es.js";
|
|
3
3
|
function self(vars) {
|
|
4
4
|
const {
|
|
5
5
|
opacityDisabled,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { q as index$1, C as CommentsPluginKey, h as TrackChangesBasePluginKey, E as Editor, n as getRichTextExtensions, f as SuperInput, e as SuperEditor, A as AIWriter, g as SuperToolbar, i as createZip } from "./super-editor.es-
|
|
1
|
+
import { q as index$1, C as CommentsPluginKey, h as TrackChangesBasePluginKey, E as Editor, n as getRichTextExtensions, f as SuperInput, e as SuperEditor, A as AIWriter, g as SuperToolbar, i as createZip } from "./super-editor.es-BY32iqnX.es.js";
|
|
2
2
|
import { a0 as effectScope, r as ref, _ as markRaw, $ as process$1, a1 as toRaw, d as computed, a2 as isRef, a3 as isReactive, C as toRef, i as inject, p as getCurrentInstance, l as watch, x as unref, a4 as hasInjectionContext, M as reactive, s as nextTick, a5 as getCurrentScope, a6 as onScopeDispose, a7 as toRefs, g as global$1, J as shallowRef, N as readonly, j as onMounted, k as onBeforeUnmount, h as onBeforeMount, S as onActivated, q as onDeactivated, z as createTextVNode, F as Fragment, Q as Comment, m as defineComponent, D as provide, H as withDirectives, B as h, U as Teleport, R as renderSlot, V as isVNode, I as watchEffect, O as Transition, a8 as TransitionGroup, E as mergeProps, P as vShow, G as cloneVNode, T as Text, c as createElementBlock, o as openBlock, t as toDisplayString, v as createVNode, y as withCtx, a as createBaseVNode, A as normalizeStyle, f as createCommentVNode, u as createBlock, w as withModifiers, n as normalizeClass, a9 as resolveDirective, e as renderList, b as createApp, X as resolveDynamicComponent, aa as defineAsyncComponent } from "./vue-CXxsqYcP.es.js";
|
|
3
3
|
import { B as Buffer$2 } from "./jszip-B8KIZSNe.es.js";
|
|
4
4
|
import { B as BlankDOCX } from "./blank-docx-iwdyG9RH.es.js";
|
|
@@ -17262,7 +17262,7 @@ const _sfc_main = {
|
|
|
17262
17262
|
__name: "SuperDoc",
|
|
17263
17263
|
emits: ["selection-update"],
|
|
17264
17264
|
setup(__props, { emit: __emit }) {
|
|
17265
|
-
const PdfViewer = defineAsyncComponent(() => import("./PdfViewer-
|
|
17265
|
+
const PdfViewer = defineAsyncComponent(() => import("./PdfViewer-DXueyp6G.es.js"));
|
|
17266
17266
|
const superdocStore = useSuperdocStore();
|
|
17267
17267
|
const commentsStore = useCommentsStore();
|
|
17268
17268
|
const {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const superEditor_es = require("./super-editor.es-
|
|
2
|
+
const superEditor_es = require("./super-editor.es-ehqZe3p-.cjs");
|
|
3
3
|
const vue = require("./vue-DWle4Cai.cjs");
|
|
4
4
|
const jszip = require("./jszip-b7l8QkfH.cjs");
|
|
5
5
|
const blankDocx = require("./blank-docx-CPqX9RF5.cjs");
|
|
@@ -17279,7 +17279,7 @@ const _sfc_main = {
|
|
|
17279
17279
|
__name: "SuperDoc",
|
|
17280
17280
|
emits: ["selection-update"],
|
|
17281
17281
|
setup(__props, { emit: __emit }) {
|
|
17282
|
-
const PdfViewer = vue.defineAsyncComponent(() => Promise.resolve().then(() => require("./PdfViewer-
|
|
17282
|
+
const PdfViewer = vue.defineAsyncComponent(() => Promise.resolve().then(() => require("./PdfViewer-C2T9YTtR.cjs")));
|
|
17283
17283
|
const superdocStore = useSuperdocStore();
|
|
17284
17284
|
const commentsStore = useCommentsStore();
|
|
17285
17285
|
const {
|
|
@@ -47186,8 +47186,307 @@ function pruneInvalidNumNodes(node2, removed) {
|
|
|
47186
47186
|
}
|
|
47187
47187
|
node2.elements = next;
|
|
47188
47188
|
}
|
|
47189
|
+
function createRelationshipsValidator({ editor, logger }) {
|
|
47190
|
+
return () => {
|
|
47191
|
+
const results = [];
|
|
47192
|
+
let modified = false;
|
|
47193
|
+
const convertedXml = editor?.converter?.convertedXml;
|
|
47194
|
+
if (!convertedXml || typeof convertedXml !== "object") {
|
|
47195
|
+
return { results, modified };
|
|
47196
|
+
}
|
|
47197
|
+
const { relsKey, wasNormalized } = findAndNormalizeRelationshipsFile(convertedXml, results);
|
|
47198
|
+
if (!relsKey) {
|
|
47199
|
+
return { results, modified };
|
|
47200
|
+
}
|
|
47201
|
+
if (wasNormalized) modified = true;
|
|
47202
|
+
const { root: root2, wasFixed } = validateRelationshipsRoot(convertedXml[relsKey], relsKey, results);
|
|
47203
|
+
if (!root2) {
|
|
47204
|
+
return { results, modified };
|
|
47205
|
+
}
|
|
47206
|
+
if (wasFixed) modified = true;
|
|
47207
|
+
const wasCleaned = cleanupRootChildren(root2);
|
|
47208
|
+
if (wasCleaned) modified = true;
|
|
47209
|
+
const { filteredIds, binMediaTargets, wasProcessed } = processRelationships(root2, convertedXml, results);
|
|
47210
|
+
if (wasProcessed) modified = true;
|
|
47211
|
+
const wasDocumentFixed = fixMissingDocumentRefs(convertedXml, filteredIds, results, logger);
|
|
47212
|
+
if (wasDocumentFixed) modified = true;
|
|
47213
|
+
const contentTypesKey = "[Content_Types].xml";
|
|
47214
|
+
const contentTypesXml = convertedXml[contentTypesKey];
|
|
47215
|
+
if (binMediaTargets.size > 0 || contentTypesXml) {
|
|
47216
|
+
const wasContentTypesUpdated = updateContentTypes(convertedXml, binMediaTargets, results);
|
|
47217
|
+
if (wasContentTypesUpdated) modified = true;
|
|
47218
|
+
} else {
|
|
47219
|
+
results.push("[Content_Types].xml not found or not parseable. Skipped content types patch.");
|
|
47220
|
+
}
|
|
47221
|
+
return { results, modified };
|
|
47222
|
+
};
|
|
47223
|
+
}
|
|
47224
|
+
function findAndNormalizeRelationshipsFile(convertedXml, results) {
|
|
47225
|
+
const candidateKeys = [
|
|
47226
|
+
"word/_rels/document.xml.rels",
|
|
47227
|
+
"word/document.xml.rels",
|
|
47228
|
+
"_rels/document.xml.rels",
|
|
47229
|
+
"document.xml.rels"
|
|
47230
|
+
];
|
|
47231
|
+
const relsKey = candidateKeys.find((k) => convertedXml?.[k]?.elements);
|
|
47232
|
+
if (!relsKey) return { relsKey: null, wasNormalized: false };
|
|
47233
|
+
const canonicalKey = "word/_rels/document.xml.rels";
|
|
47234
|
+
if (relsKey !== canonicalKey) {
|
|
47235
|
+
convertedXml[canonicalKey] = convertedXml[relsKey];
|
|
47236
|
+
delete convertedXml[relsKey];
|
|
47237
|
+
results.push(`Normalized relationships location to ${canonicalKey} (was ${relsKey})`);
|
|
47238
|
+
return { relsKey: canonicalKey, wasNormalized: true };
|
|
47239
|
+
}
|
|
47240
|
+
return { relsKey, wasNormalized: false };
|
|
47241
|
+
}
|
|
47242
|
+
function validateRelationshipsRoot(relsTree, relsKey, results) {
|
|
47243
|
+
const root2 = relsTree?.elements?.[0];
|
|
47244
|
+
if (!root2 || root2.type !== "element") {
|
|
47245
|
+
results.push(`${relsKey} is not a valid xml`);
|
|
47246
|
+
return { root: null, wasFixed: false };
|
|
47247
|
+
}
|
|
47248
|
+
const RELS_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
47249
|
+
let wasFixed = false;
|
|
47250
|
+
if (root2.name !== "Relationships") {
|
|
47251
|
+
root2.name = "Relationships";
|
|
47252
|
+
results.push(`Fixed relationships root element name to "Relationships"`);
|
|
47253
|
+
wasFixed = true;
|
|
47254
|
+
}
|
|
47255
|
+
root2.attributes = root2.attributes || {};
|
|
47256
|
+
if (root2.attributes.xmlns !== RELS_NS) {
|
|
47257
|
+
root2.attributes.xmlns = RELS_NS;
|
|
47258
|
+
results.push(`Set relationships xmlns to ${RELS_NS}`);
|
|
47259
|
+
wasFixed = true;
|
|
47260
|
+
}
|
|
47261
|
+
return { root: root2, wasFixed };
|
|
47262
|
+
}
|
|
47263
|
+
function cleanupRootChildren(root2, results) {
|
|
47264
|
+
const validChildren = root2.elements?.filter((child) => child?.type === "element" && child.name === "Relationship") || [];
|
|
47265
|
+
if (root2.elements?.length !== validChildren.length) {
|
|
47266
|
+
root2.elements = validChildren;
|
|
47267
|
+
return true;
|
|
47268
|
+
}
|
|
47269
|
+
return false;
|
|
47270
|
+
}
|
|
47271
|
+
function processRelationships(root2, convertedXml, results) {
|
|
47272
|
+
const binMediaTargets = /* @__PURE__ */ new Set();
|
|
47273
|
+
const filteredIds = /* @__PURE__ */ new Set();
|
|
47274
|
+
let wasProcessed = false;
|
|
47275
|
+
const ridNum = (id) => {
|
|
47276
|
+
const m2 = /^rId(\d+)$/.exec(String(id || ""));
|
|
47277
|
+
return m2 ? parseInt(m2[1], 10) : null;
|
|
47278
|
+
};
|
|
47279
|
+
const isType2 = (type2, tail) => typeof type2 === "string" && new RegExp(`/relationships/${tail}$`, "i").test(type2);
|
|
47280
|
+
const isHyperlinkType = (type2) => isType2(type2, "hyperlink");
|
|
47281
|
+
const isImageType = (type2) => isType2(type2, "image");
|
|
47282
|
+
const looksExternal = (target) => /^https?:\/\//i.test(target || "") || /^mailto:/i.test(target || "");
|
|
47283
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
47284
|
+
let maxRid = 0;
|
|
47285
|
+
for (const el of root2.elements) {
|
|
47286
|
+
el.attributes = el.attributes || {};
|
|
47287
|
+
const id = el.attributes.Id;
|
|
47288
|
+
const n = ridNum(id);
|
|
47289
|
+
if (Number.isInteger(n)) maxRid = Math.max(maxRid, n);
|
|
47290
|
+
if (typeof id === "string" && id) {
|
|
47291
|
+
usedIds.add(id);
|
|
47292
|
+
}
|
|
47293
|
+
}
|
|
47294
|
+
let ridCounter = maxRid;
|
|
47295
|
+
const allocateId = (preferred) => {
|
|
47296
|
+
let newId;
|
|
47297
|
+
do {
|
|
47298
|
+
ridCounter += 1;
|
|
47299
|
+
newId = `rId${ridCounter}`;
|
|
47300
|
+
} while (usedIds.has(newId));
|
|
47301
|
+
usedIds.add(newId);
|
|
47302
|
+
return newId;
|
|
47303
|
+
};
|
|
47304
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
47305
|
+
const filtered = [];
|
|
47306
|
+
function extractStringAttr(attrs, key) {
|
|
47307
|
+
return typeof attrs[key] === "string" ? attrs[key].trim() : "";
|
|
47308
|
+
}
|
|
47309
|
+
for (const rel of root2.elements) {
|
|
47310
|
+
rel.attributes = rel.attributes || {};
|
|
47311
|
+
const attrs = rel.attributes;
|
|
47312
|
+
let id = extractStringAttr(attrs, "Id");
|
|
47313
|
+
const type2 = extractStringAttr(attrs, "Type");
|
|
47314
|
+
let target = extractStringAttr(attrs, "Target");
|
|
47315
|
+
let targetMode = extractStringAttr(attrs, "TargetMode");
|
|
47316
|
+
if (!target) {
|
|
47317
|
+
results.push(`Removed relationship "${id}" without Target`);
|
|
47318
|
+
wasProcessed = true;
|
|
47319
|
+
continue;
|
|
47320
|
+
}
|
|
47321
|
+
if (isHyperlinkType(type2) && looksExternal(target) && targetMode.toLowerCase() !== "external") {
|
|
47322
|
+
attrs.TargetMode = "External";
|
|
47323
|
+
targetMode = "External";
|
|
47324
|
+
results.push(`Set TargetMode="External" for hyperlink ${id}`);
|
|
47325
|
+
wasProcessed = true;
|
|
47326
|
+
}
|
|
47327
|
+
if (isImageType(type2)) {
|
|
47328
|
+
const relPath = `word/${target.replace(/^\.?\//, "")}`;
|
|
47329
|
+
if (/^media\/.+\.bin$/i.test(target) && relPath in convertedXml) {
|
|
47330
|
+
binMediaTargets.add(`/${relPath}`);
|
|
47331
|
+
}
|
|
47332
|
+
}
|
|
47333
|
+
if (targetMode.toLowerCase() !== "external" && !looksExternal(target)) {
|
|
47334
|
+
const likelyPath = `word/${target.replace(/^\.?\//, "")}`;
|
|
47335
|
+
if (!(likelyPath in convertedXml)) {
|
|
47336
|
+
if (!isImageType(type2)) {
|
|
47337
|
+
results.push(`Removed relationship ${id} with missing target: ${target}`);
|
|
47338
|
+
wasProcessed = true;
|
|
47339
|
+
continue;
|
|
47340
|
+
} else {
|
|
47341
|
+
results.push(`Warning: image relationship ${id} target not found: ${target}.`);
|
|
47342
|
+
}
|
|
47343
|
+
}
|
|
47344
|
+
}
|
|
47345
|
+
if (!id) {
|
|
47346
|
+
const newId = allocateId();
|
|
47347
|
+
attrs.Id = newId;
|
|
47348
|
+
results.push(`Assigned missing Id "${newId}"`);
|
|
47349
|
+
wasProcessed = true;
|
|
47350
|
+
id = newId;
|
|
47351
|
+
}
|
|
47352
|
+
if (seenIds.has(id)) {
|
|
47353
|
+
results.push(`Removed duplicate relationship with ID "${id}"`);
|
|
47354
|
+
wasProcessed = true;
|
|
47355
|
+
continue;
|
|
47356
|
+
}
|
|
47357
|
+
seenIds.add(id);
|
|
47358
|
+
filtered.push(rel);
|
|
47359
|
+
}
|
|
47360
|
+
if (root2.elements.length !== filtered.length) {
|
|
47361
|
+
root2.elements = filtered;
|
|
47362
|
+
wasProcessed = true;
|
|
47363
|
+
} else {
|
|
47364
|
+
const contentChanged = root2.elements.some((el, i) => el !== filtered[i]);
|
|
47365
|
+
if (contentChanged) {
|
|
47366
|
+
root2.elements = filtered;
|
|
47367
|
+
wasProcessed = true;
|
|
47368
|
+
}
|
|
47369
|
+
}
|
|
47370
|
+
for (const rel of root2.elements) {
|
|
47371
|
+
const id = rel.attributes?.Id;
|
|
47372
|
+
if (typeof id === "string" && id) {
|
|
47373
|
+
filteredIds.add(id);
|
|
47374
|
+
}
|
|
47375
|
+
}
|
|
47376
|
+
return { filteredIds, binMediaTargets, wasProcessed };
|
|
47377
|
+
}
|
|
47378
|
+
function fixMissingDocumentRefs(convertedXml, filteredIds, results, logger) {
|
|
47379
|
+
const documentPath = "word/document.xml";
|
|
47380
|
+
const document2 = convertedXml[documentPath];
|
|
47381
|
+
if (document2?.elements?.length) {
|
|
47382
|
+
const documentRoot = document2.elements[0];
|
|
47383
|
+
if (documentRoot?.type === "element") {
|
|
47384
|
+
const missingRefs = [];
|
|
47385
|
+
processDocumentForMissingRefs(documentRoot, filteredIds, missingRefs);
|
|
47386
|
+
if (missingRefs.length) {
|
|
47387
|
+
results.push(`Fixed ${missingRefs.length} missing relationship references`);
|
|
47388
|
+
logger?.debug?.(`Fixed ${missingRefs.length} missing relationship references in document`);
|
|
47389
|
+
return true;
|
|
47390
|
+
}
|
|
47391
|
+
}
|
|
47392
|
+
}
|
|
47393
|
+
return false;
|
|
47394
|
+
}
|
|
47395
|
+
function updateContentTypes(convertedXml, binMediaTargets, results) {
|
|
47396
|
+
const contentTypesKey = "[Content_Types].xml";
|
|
47397
|
+
const contentTypesXml = convertedXml[contentTypesKey];
|
|
47398
|
+
if (typeof contentTypesXml === "string") {
|
|
47399
|
+
return updateContentTypesString(contentTypesXml, binMediaTargets, results, convertedXml, contentTypesKey);
|
|
47400
|
+
} else if (contentTypesXml?.elements?.length) {
|
|
47401
|
+
return updateContentTypesElements(contentTypesXml, binMediaTargets, results);
|
|
47402
|
+
} else {
|
|
47403
|
+
return false;
|
|
47404
|
+
}
|
|
47405
|
+
}
|
|
47406
|
+
function updateContentTypesString(contentTypesXml, binMediaTargets, results, convertedXml, contentTypesKey) {
|
|
47407
|
+
const CONTENT_TYPES_NS = '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
|
|
47408
|
+
const ensureDefault = (xmlString, ext, contentType) => {
|
|
47409
|
+
const defRe = new RegExp(`<Default\\s+Extension="${ext}"\\b`, "i");
|
|
47410
|
+
if (defRe.test(xmlString)) return xmlString;
|
|
47411
|
+
return xmlString.replace(
|
|
47412
|
+
CONTENT_TYPES_NS,
|
|
47413
|
+
`${CONTENT_TYPES_NS}<Default Extension="${ext}" ContentType="${contentType}"/>`
|
|
47414
|
+
);
|
|
47415
|
+
};
|
|
47416
|
+
const ensureOverride = (xmlString, partName, contentType) => {
|
|
47417
|
+
const esc = partName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
47418
|
+
const ovRe = new RegExp(`<Override\\s+PartName="${esc}"\\b`, "i");
|
|
47419
|
+
if (ovRe.test(xmlString)) return xmlString;
|
|
47420
|
+
return xmlString.replace(
|
|
47421
|
+
CONTENT_TYPES_NS,
|
|
47422
|
+
`${CONTENT_TYPES_NS}<Override PartName="${partName}" ContentType="${contentType}" />`
|
|
47423
|
+
);
|
|
47424
|
+
};
|
|
47425
|
+
let updated = contentTypesXml;
|
|
47426
|
+
updated = ensureDefault(updated, "rels", "application/vnd.openxmlformats-package.relationships+xml");
|
|
47427
|
+
updated = ensureDefault(updated, "xml", "application/xml");
|
|
47428
|
+
for (const partName of binMediaTargets) {
|
|
47429
|
+
updated = ensureOverride(updated, partName, "image/png");
|
|
47430
|
+
results.push(`Added Content Types Override for "${partName}" as image/png`);
|
|
47431
|
+
}
|
|
47432
|
+
if (updated !== contentTypesXml) {
|
|
47433
|
+
convertedXml[contentTypesKey] = updated;
|
|
47434
|
+
return true;
|
|
47435
|
+
}
|
|
47436
|
+
return false;
|
|
47437
|
+
}
|
|
47438
|
+
function updateContentTypesElements(contentTypesXml, binMediaTargets, results) {
|
|
47439
|
+
const typesRoot = contentTypesXml.elements.find((el) => el.name === "Types") || contentTypesXml.elements[0];
|
|
47440
|
+
typesRoot.elements = typesRoot.elements || [];
|
|
47441
|
+
const hasDefault = (ext) => typesRoot.elements.some((el) => el.name === "Default" && el.attributes?.Extension === ext);
|
|
47442
|
+
const addDefault = (ext, ct) => {
|
|
47443
|
+
typesRoot.elements.unshift({
|
|
47444
|
+
type: "element",
|
|
47445
|
+
name: "Default",
|
|
47446
|
+
attributes: { Extension: ext, ContentType: ct }
|
|
47447
|
+
});
|
|
47448
|
+
};
|
|
47449
|
+
const hasOverride = (part) => typesRoot.elements.some((el) => el.name === "Override" && el.attributes?.PartName === part);
|
|
47450
|
+
const addOverride = (part, ct) => {
|
|
47451
|
+
typesRoot.elements.unshift({
|
|
47452
|
+
type: "element",
|
|
47453
|
+
name: "Override",
|
|
47454
|
+
attributes: { PartName: part, ContentType: ct }
|
|
47455
|
+
});
|
|
47456
|
+
};
|
|
47457
|
+
let wasUpdated = false;
|
|
47458
|
+
if (!hasDefault("rels")) {
|
|
47459
|
+
addDefault("rels", "application/vnd.openxmlformats-package.relationships+xml");
|
|
47460
|
+
wasUpdated = true;
|
|
47461
|
+
}
|
|
47462
|
+
if (!hasDefault("xml")) {
|
|
47463
|
+
addDefault("xml", "application/xml");
|
|
47464
|
+
wasUpdated = true;
|
|
47465
|
+
}
|
|
47466
|
+
for (const partName of binMediaTargets) {
|
|
47467
|
+
if (!hasOverride(partName)) {
|
|
47468
|
+
addOverride(partName, "image/png");
|
|
47469
|
+
results.push(`Added Content Types Override for "${partName}" as image/png`);
|
|
47470
|
+
wasUpdated = true;
|
|
47471
|
+
}
|
|
47472
|
+
}
|
|
47473
|
+
return wasUpdated;
|
|
47474
|
+
}
|
|
47475
|
+
function processDocumentForMissingRefs(node2, usedIds, fixed) {
|
|
47476
|
+
if (!node2?.elements?.length) return;
|
|
47477
|
+
for (const element of node2.elements) {
|
|
47478
|
+
if (element?.type !== "element") continue;
|
|
47479
|
+
const rIdValue = element.attributes?.["r:id"];
|
|
47480
|
+
if (typeof rIdValue === "string" && !usedIds.has(rIdValue)) {
|
|
47481
|
+
delete element.attributes["r:id"];
|
|
47482
|
+
fixed.push(`Removed invalid r:id="${rIdValue}"`);
|
|
47483
|
+
}
|
|
47484
|
+
processDocumentForMissingRefs(element, usedIds, fixed);
|
|
47485
|
+
}
|
|
47486
|
+
}
|
|
47189
47487
|
const XmlValidators = {
|
|
47190
|
-
numberingValidator: createNumberingValidator
|
|
47488
|
+
numberingValidator: createNumberingValidator,
|
|
47489
|
+
relationshipsValidator: createRelationshipsValidator
|
|
47191
47490
|
};
|
|
47192
47491
|
class SuperValidator {
|
|
47193
47492
|
/**
|
|
@@ -47203,8 +47203,307 @@ function pruneInvalidNumNodes(node2, removed) {
|
|
|
47203
47203
|
}
|
|
47204
47204
|
node2.elements = next;
|
|
47205
47205
|
}
|
|
47206
|
+
function createRelationshipsValidator({ editor, logger }) {
|
|
47207
|
+
return () => {
|
|
47208
|
+
const results = [];
|
|
47209
|
+
let modified = false;
|
|
47210
|
+
const convertedXml = editor?.converter?.convertedXml;
|
|
47211
|
+
if (!convertedXml || typeof convertedXml !== "object") {
|
|
47212
|
+
return { results, modified };
|
|
47213
|
+
}
|
|
47214
|
+
const { relsKey, wasNormalized } = findAndNormalizeRelationshipsFile(convertedXml, results);
|
|
47215
|
+
if (!relsKey) {
|
|
47216
|
+
return { results, modified };
|
|
47217
|
+
}
|
|
47218
|
+
if (wasNormalized) modified = true;
|
|
47219
|
+
const { root: root2, wasFixed } = validateRelationshipsRoot(convertedXml[relsKey], relsKey, results);
|
|
47220
|
+
if (!root2) {
|
|
47221
|
+
return { results, modified };
|
|
47222
|
+
}
|
|
47223
|
+
if (wasFixed) modified = true;
|
|
47224
|
+
const wasCleaned = cleanupRootChildren(root2);
|
|
47225
|
+
if (wasCleaned) modified = true;
|
|
47226
|
+
const { filteredIds, binMediaTargets, wasProcessed } = processRelationships(root2, convertedXml, results);
|
|
47227
|
+
if (wasProcessed) modified = true;
|
|
47228
|
+
const wasDocumentFixed = fixMissingDocumentRefs(convertedXml, filteredIds, results, logger);
|
|
47229
|
+
if (wasDocumentFixed) modified = true;
|
|
47230
|
+
const contentTypesKey = "[Content_Types].xml";
|
|
47231
|
+
const contentTypesXml = convertedXml[contentTypesKey];
|
|
47232
|
+
if (binMediaTargets.size > 0 || contentTypesXml) {
|
|
47233
|
+
const wasContentTypesUpdated = updateContentTypes(convertedXml, binMediaTargets, results);
|
|
47234
|
+
if (wasContentTypesUpdated) modified = true;
|
|
47235
|
+
} else {
|
|
47236
|
+
results.push("[Content_Types].xml not found or not parseable. Skipped content types patch.");
|
|
47237
|
+
}
|
|
47238
|
+
return { results, modified };
|
|
47239
|
+
};
|
|
47240
|
+
}
|
|
47241
|
+
function findAndNormalizeRelationshipsFile(convertedXml, results) {
|
|
47242
|
+
const candidateKeys = [
|
|
47243
|
+
"word/_rels/document.xml.rels",
|
|
47244
|
+
"word/document.xml.rels",
|
|
47245
|
+
"_rels/document.xml.rels",
|
|
47246
|
+
"document.xml.rels"
|
|
47247
|
+
];
|
|
47248
|
+
const relsKey = candidateKeys.find((k) => convertedXml?.[k]?.elements);
|
|
47249
|
+
if (!relsKey) return { relsKey: null, wasNormalized: false };
|
|
47250
|
+
const canonicalKey = "word/_rels/document.xml.rels";
|
|
47251
|
+
if (relsKey !== canonicalKey) {
|
|
47252
|
+
convertedXml[canonicalKey] = convertedXml[relsKey];
|
|
47253
|
+
delete convertedXml[relsKey];
|
|
47254
|
+
results.push(`Normalized relationships location to ${canonicalKey} (was ${relsKey})`);
|
|
47255
|
+
return { relsKey: canonicalKey, wasNormalized: true };
|
|
47256
|
+
}
|
|
47257
|
+
return { relsKey, wasNormalized: false };
|
|
47258
|
+
}
|
|
47259
|
+
function validateRelationshipsRoot(relsTree, relsKey, results) {
|
|
47260
|
+
const root2 = relsTree?.elements?.[0];
|
|
47261
|
+
if (!root2 || root2.type !== "element") {
|
|
47262
|
+
results.push(`${relsKey} is not a valid xml`);
|
|
47263
|
+
return { root: null, wasFixed: false };
|
|
47264
|
+
}
|
|
47265
|
+
const RELS_NS = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
47266
|
+
let wasFixed = false;
|
|
47267
|
+
if (root2.name !== "Relationships") {
|
|
47268
|
+
root2.name = "Relationships";
|
|
47269
|
+
results.push(`Fixed relationships root element name to "Relationships"`);
|
|
47270
|
+
wasFixed = true;
|
|
47271
|
+
}
|
|
47272
|
+
root2.attributes = root2.attributes || {};
|
|
47273
|
+
if (root2.attributes.xmlns !== RELS_NS) {
|
|
47274
|
+
root2.attributes.xmlns = RELS_NS;
|
|
47275
|
+
results.push(`Set relationships xmlns to ${RELS_NS}`);
|
|
47276
|
+
wasFixed = true;
|
|
47277
|
+
}
|
|
47278
|
+
return { root: root2, wasFixed };
|
|
47279
|
+
}
|
|
47280
|
+
function cleanupRootChildren(root2, results) {
|
|
47281
|
+
const validChildren = root2.elements?.filter((child) => child?.type === "element" && child.name === "Relationship") || [];
|
|
47282
|
+
if (root2.elements?.length !== validChildren.length) {
|
|
47283
|
+
root2.elements = validChildren;
|
|
47284
|
+
return true;
|
|
47285
|
+
}
|
|
47286
|
+
return false;
|
|
47287
|
+
}
|
|
47288
|
+
function processRelationships(root2, convertedXml, results) {
|
|
47289
|
+
const binMediaTargets = /* @__PURE__ */ new Set();
|
|
47290
|
+
const filteredIds = /* @__PURE__ */ new Set();
|
|
47291
|
+
let wasProcessed = false;
|
|
47292
|
+
const ridNum = (id) => {
|
|
47293
|
+
const m2 = /^rId(\d+)$/.exec(String(id || ""));
|
|
47294
|
+
return m2 ? parseInt(m2[1], 10) : null;
|
|
47295
|
+
};
|
|
47296
|
+
const isType2 = (type2, tail) => typeof type2 === "string" && new RegExp(`/relationships/${tail}$`, "i").test(type2);
|
|
47297
|
+
const isHyperlinkType = (type2) => isType2(type2, "hyperlink");
|
|
47298
|
+
const isImageType = (type2) => isType2(type2, "image");
|
|
47299
|
+
const looksExternal = (target) => /^https?:\/\//i.test(target || "") || /^mailto:/i.test(target || "");
|
|
47300
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
47301
|
+
let maxRid = 0;
|
|
47302
|
+
for (const el of root2.elements) {
|
|
47303
|
+
el.attributes = el.attributes || {};
|
|
47304
|
+
const id = el.attributes.Id;
|
|
47305
|
+
const n = ridNum(id);
|
|
47306
|
+
if (Number.isInteger(n)) maxRid = Math.max(maxRid, n);
|
|
47307
|
+
if (typeof id === "string" && id) {
|
|
47308
|
+
usedIds.add(id);
|
|
47309
|
+
}
|
|
47310
|
+
}
|
|
47311
|
+
let ridCounter = maxRid;
|
|
47312
|
+
const allocateId = (preferred) => {
|
|
47313
|
+
let newId;
|
|
47314
|
+
do {
|
|
47315
|
+
ridCounter += 1;
|
|
47316
|
+
newId = `rId${ridCounter}`;
|
|
47317
|
+
} while (usedIds.has(newId));
|
|
47318
|
+
usedIds.add(newId);
|
|
47319
|
+
return newId;
|
|
47320
|
+
};
|
|
47321
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
47322
|
+
const filtered = [];
|
|
47323
|
+
function extractStringAttr(attrs, key) {
|
|
47324
|
+
return typeof attrs[key] === "string" ? attrs[key].trim() : "";
|
|
47325
|
+
}
|
|
47326
|
+
for (const rel of root2.elements) {
|
|
47327
|
+
rel.attributes = rel.attributes || {};
|
|
47328
|
+
const attrs = rel.attributes;
|
|
47329
|
+
let id = extractStringAttr(attrs, "Id");
|
|
47330
|
+
const type2 = extractStringAttr(attrs, "Type");
|
|
47331
|
+
let target = extractStringAttr(attrs, "Target");
|
|
47332
|
+
let targetMode = extractStringAttr(attrs, "TargetMode");
|
|
47333
|
+
if (!target) {
|
|
47334
|
+
results.push(`Removed relationship "${id}" without Target`);
|
|
47335
|
+
wasProcessed = true;
|
|
47336
|
+
continue;
|
|
47337
|
+
}
|
|
47338
|
+
if (isHyperlinkType(type2) && looksExternal(target) && targetMode.toLowerCase() !== "external") {
|
|
47339
|
+
attrs.TargetMode = "External";
|
|
47340
|
+
targetMode = "External";
|
|
47341
|
+
results.push(`Set TargetMode="External" for hyperlink ${id}`);
|
|
47342
|
+
wasProcessed = true;
|
|
47343
|
+
}
|
|
47344
|
+
if (isImageType(type2)) {
|
|
47345
|
+
const relPath = `word/${target.replace(/^\.?\//, "")}`;
|
|
47346
|
+
if (/^media\/.+\.bin$/i.test(target) && relPath in convertedXml) {
|
|
47347
|
+
binMediaTargets.add(`/${relPath}`);
|
|
47348
|
+
}
|
|
47349
|
+
}
|
|
47350
|
+
if (targetMode.toLowerCase() !== "external" && !looksExternal(target)) {
|
|
47351
|
+
const likelyPath = `word/${target.replace(/^\.?\//, "")}`;
|
|
47352
|
+
if (!(likelyPath in convertedXml)) {
|
|
47353
|
+
if (!isImageType(type2)) {
|
|
47354
|
+
results.push(`Removed relationship ${id} with missing target: ${target}`);
|
|
47355
|
+
wasProcessed = true;
|
|
47356
|
+
continue;
|
|
47357
|
+
} else {
|
|
47358
|
+
results.push(`Warning: image relationship ${id} target not found: ${target}.`);
|
|
47359
|
+
}
|
|
47360
|
+
}
|
|
47361
|
+
}
|
|
47362
|
+
if (!id) {
|
|
47363
|
+
const newId = allocateId();
|
|
47364
|
+
attrs.Id = newId;
|
|
47365
|
+
results.push(`Assigned missing Id "${newId}"`);
|
|
47366
|
+
wasProcessed = true;
|
|
47367
|
+
id = newId;
|
|
47368
|
+
}
|
|
47369
|
+
if (seenIds.has(id)) {
|
|
47370
|
+
results.push(`Removed duplicate relationship with ID "${id}"`);
|
|
47371
|
+
wasProcessed = true;
|
|
47372
|
+
continue;
|
|
47373
|
+
}
|
|
47374
|
+
seenIds.add(id);
|
|
47375
|
+
filtered.push(rel);
|
|
47376
|
+
}
|
|
47377
|
+
if (root2.elements.length !== filtered.length) {
|
|
47378
|
+
root2.elements = filtered;
|
|
47379
|
+
wasProcessed = true;
|
|
47380
|
+
} else {
|
|
47381
|
+
const contentChanged = root2.elements.some((el, i) => el !== filtered[i]);
|
|
47382
|
+
if (contentChanged) {
|
|
47383
|
+
root2.elements = filtered;
|
|
47384
|
+
wasProcessed = true;
|
|
47385
|
+
}
|
|
47386
|
+
}
|
|
47387
|
+
for (const rel of root2.elements) {
|
|
47388
|
+
const id = rel.attributes?.Id;
|
|
47389
|
+
if (typeof id === "string" && id) {
|
|
47390
|
+
filteredIds.add(id);
|
|
47391
|
+
}
|
|
47392
|
+
}
|
|
47393
|
+
return { filteredIds, binMediaTargets, wasProcessed };
|
|
47394
|
+
}
|
|
47395
|
+
function fixMissingDocumentRefs(convertedXml, filteredIds, results, logger) {
|
|
47396
|
+
const documentPath = "word/document.xml";
|
|
47397
|
+
const document2 = convertedXml[documentPath];
|
|
47398
|
+
if (document2?.elements?.length) {
|
|
47399
|
+
const documentRoot = document2.elements[0];
|
|
47400
|
+
if (documentRoot?.type === "element") {
|
|
47401
|
+
const missingRefs = [];
|
|
47402
|
+
processDocumentForMissingRefs(documentRoot, filteredIds, missingRefs);
|
|
47403
|
+
if (missingRefs.length) {
|
|
47404
|
+
results.push(`Fixed ${missingRefs.length} missing relationship references`);
|
|
47405
|
+
logger?.debug?.(`Fixed ${missingRefs.length} missing relationship references in document`);
|
|
47406
|
+
return true;
|
|
47407
|
+
}
|
|
47408
|
+
}
|
|
47409
|
+
}
|
|
47410
|
+
return false;
|
|
47411
|
+
}
|
|
47412
|
+
function updateContentTypes(convertedXml, binMediaTargets, results) {
|
|
47413
|
+
const contentTypesKey = "[Content_Types].xml";
|
|
47414
|
+
const contentTypesXml = convertedXml[contentTypesKey];
|
|
47415
|
+
if (typeof contentTypesXml === "string") {
|
|
47416
|
+
return updateContentTypesString(contentTypesXml, binMediaTargets, results, convertedXml, contentTypesKey);
|
|
47417
|
+
} else if (contentTypesXml?.elements?.length) {
|
|
47418
|
+
return updateContentTypesElements(contentTypesXml, binMediaTargets, results);
|
|
47419
|
+
} else {
|
|
47420
|
+
return false;
|
|
47421
|
+
}
|
|
47422
|
+
}
|
|
47423
|
+
function updateContentTypesString(contentTypesXml, binMediaTargets, results, convertedXml, contentTypesKey) {
|
|
47424
|
+
const CONTENT_TYPES_NS = '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
|
|
47425
|
+
const ensureDefault = (xmlString, ext, contentType) => {
|
|
47426
|
+
const defRe = new RegExp(`<Default\\s+Extension="${ext}"\\b`, "i");
|
|
47427
|
+
if (defRe.test(xmlString)) return xmlString;
|
|
47428
|
+
return xmlString.replace(
|
|
47429
|
+
CONTENT_TYPES_NS,
|
|
47430
|
+
`${CONTENT_TYPES_NS}<Default Extension="${ext}" ContentType="${contentType}"/>`
|
|
47431
|
+
);
|
|
47432
|
+
};
|
|
47433
|
+
const ensureOverride = (xmlString, partName, contentType) => {
|
|
47434
|
+
const esc = partName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
47435
|
+
const ovRe = new RegExp(`<Override\\s+PartName="${esc}"\\b`, "i");
|
|
47436
|
+
if (ovRe.test(xmlString)) return xmlString;
|
|
47437
|
+
return xmlString.replace(
|
|
47438
|
+
CONTENT_TYPES_NS,
|
|
47439
|
+
`${CONTENT_TYPES_NS}<Override PartName="${partName}" ContentType="${contentType}" />`
|
|
47440
|
+
);
|
|
47441
|
+
};
|
|
47442
|
+
let updated = contentTypesXml;
|
|
47443
|
+
updated = ensureDefault(updated, "rels", "application/vnd.openxmlformats-package.relationships+xml");
|
|
47444
|
+
updated = ensureDefault(updated, "xml", "application/xml");
|
|
47445
|
+
for (const partName of binMediaTargets) {
|
|
47446
|
+
updated = ensureOverride(updated, partName, "image/png");
|
|
47447
|
+
results.push(`Added Content Types Override for "${partName}" as image/png`);
|
|
47448
|
+
}
|
|
47449
|
+
if (updated !== contentTypesXml) {
|
|
47450
|
+
convertedXml[contentTypesKey] = updated;
|
|
47451
|
+
return true;
|
|
47452
|
+
}
|
|
47453
|
+
return false;
|
|
47454
|
+
}
|
|
47455
|
+
function updateContentTypesElements(contentTypesXml, binMediaTargets, results) {
|
|
47456
|
+
const typesRoot = contentTypesXml.elements.find((el) => el.name === "Types") || contentTypesXml.elements[0];
|
|
47457
|
+
typesRoot.elements = typesRoot.elements || [];
|
|
47458
|
+
const hasDefault = (ext) => typesRoot.elements.some((el) => el.name === "Default" && el.attributes?.Extension === ext);
|
|
47459
|
+
const addDefault = (ext, ct) => {
|
|
47460
|
+
typesRoot.elements.unshift({
|
|
47461
|
+
type: "element",
|
|
47462
|
+
name: "Default",
|
|
47463
|
+
attributes: { Extension: ext, ContentType: ct }
|
|
47464
|
+
});
|
|
47465
|
+
};
|
|
47466
|
+
const hasOverride = (part) => typesRoot.elements.some((el) => el.name === "Override" && el.attributes?.PartName === part);
|
|
47467
|
+
const addOverride = (part, ct) => {
|
|
47468
|
+
typesRoot.elements.unshift({
|
|
47469
|
+
type: "element",
|
|
47470
|
+
name: "Override",
|
|
47471
|
+
attributes: { PartName: part, ContentType: ct }
|
|
47472
|
+
});
|
|
47473
|
+
};
|
|
47474
|
+
let wasUpdated = false;
|
|
47475
|
+
if (!hasDefault("rels")) {
|
|
47476
|
+
addDefault("rels", "application/vnd.openxmlformats-package.relationships+xml");
|
|
47477
|
+
wasUpdated = true;
|
|
47478
|
+
}
|
|
47479
|
+
if (!hasDefault("xml")) {
|
|
47480
|
+
addDefault("xml", "application/xml");
|
|
47481
|
+
wasUpdated = true;
|
|
47482
|
+
}
|
|
47483
|
+
for (const partName of binMediaTargets) {
|
|
47484
|
+
if (!hasOverride(partName)) {
|
|
47485
|
+
addOverride(partName, "image/png");
|
|
47486
|
+
results.push(`Added Content Types Override for "${partName}" as image/png`);
|
|
47487
|
+
wasUpdated = true;
|
|
47488
|
+
}
|
|
47489
|
+
}
|
|
47490
|
+
return wasUpdated;
|
|
47491
|
+
}
|
|
47492
|
+
function processDocumentForMissingRefs(node2, usedIds, fixed) {
|
|
47493
|
+
if (!node2?.elements?.length) return;
|
|
47494
|
+
for (const element of node2.elements) {
|
|
47495
|
+
if (element?.type !== "element") continue;
|
|
47496
|
+
const rIdValue = element.attributes?.["r:id"];
|
|
47497
|
+
if (typeof rIdValue === "string" && !usedIds.has(rIdValue)) {
|
|
47498
|
+
delete element.attributes["r:id"];
|
|
47499
|
+
fixed.push(`Removed invalid r:id="${rIdValue}"`);
|
|
47500
|
+
}
|
|
47501
|
+
processDocumentForMissingRefs(element, usedIds, fixed);
|
|
47502
|
+
}
|
|
47503
|
+
}
|
|
47206
47504
|
const XmlValidators = {
|
|
47207
|
-
numberingValidator: createNumberingValidator
|
|
47505
|
+
numberingValidator: createNumberingValidator,
|
|
47506
|
+
relationshipsValidator: createRelationshipsValidator
|
|
47208
47507
|
};
|
|
47209
47508
|
class SuperValidator {
|
|
47210
47509
|
/**
|