odf.js 1.2.0 → 1.3.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 +367 -69
- package/dist/index.d.cts +58 -2
- package/dist/index.d.ts +58 -2
- package/dist/index.js +341 -72
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -449,6 +449,17 @@ function txt(value) {
|
|
|
449
449
|
function encodeXmlText(value) {
|
|
450
450
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
451
451
|
}
|
|
452
|
+
const XML_ENTITY_PATTERN = /&(?:amp|lt|gt|quot|apos);/g;
|
|
453
|
+
const XML_ENTITY_DECODE = {
|
|
454
|
+
"&": "&",
|
|
455
|
+
"<": "<",
|
|
456
|
+
">": ">",
|
|
457
|
+
""": "\"",
|
|
458
|
+
"'": "'"
|
|
459
|
+
};
|
|
460
|
+
function decodeXmlText(value) {
|
|
461
|
+
return value.replace(XML_ENTITY_PATTERN, (entity) => XML_ENTITY_DECODE[entity]);
|
|
462
|
+
}
|
|
452
463
|
//#endregion
|
|
453
464
|
//#region src/manifest.ts
|
|
454
465
|
const ManifestEntrySchema = zod.z.object({
|
|
@@ -472,26 +483,26 @@ const STANDARD_XML_PART_NAMES = /* @__PURE__ */ new Set([
|
|
|
472
483
|
"meta.xml",
|
|
473
484
|
"settings.xml"
|
|
474
485
|
]);
|
|
475
|
-
function findChildElement(nodes, tag) {
|
|
486
|
+
function findChildElement$1(nodes, tag) {
|
|
476
487
|
for (const node of nodes) if (node.type === "element" && node.tag === tag) return node;
|
|
477
488
|
}
|
|
478
|
-
function attrValue$
|
|
489
|
+
function attrValue$2(element, name) {
|
|
479
490
|
return element.attributes.find((attribute) => attribute.name === name)?.value;
|
|
480
491
|
}
|
|
481
492
|
function readManifest(pkg) {
|
|
482
493
|
const part = pkg.parts[MANIFEST_PART];
|
|
483
494
|
if (part?.kind !== "xml") throw new Error(`package has no ${MANIFEST_PART} XML part to read`);
|
|
484
|
-
const root = findChildElement(part.nodes, "manifest:manifest");
|
|
495
|
+
const root = findChildElement$1(part.nodes, "manifest:manifest");
|
|
485
496
|
if (root === void 0) throw new Error(`${MANIFEST_PART} has no manifest:manifest root element`);
|
|
486
|
-
const version = attrValue$
|
|
497
|
+
const version = attrValue$2(root, "manifest:version");
|
|
487
498
|
if (version === void 0) throw new Error(`${MANIFEST_PART}'s manifest:manifest root is missing the required manifest:version attribute`);
|
|
488
499
|
const entries = [];
|
|
489
500
|
for (const child of root.children) {
|
|
490
501
|
if (child.type !== "element" || child.tag !== "manifest:file-entry") continue;
|
|
491
|
-
const fullPath = attrValue$
|
|
492
|
-
const mediaType = attrValue$
|
|
502
|
+
const fullPath = attrValue$2(child, "manifest:full-path");
|
|
503
|
+
const mediaType = attrValue$2(child, "manifest:media-type");
|
|
493
504
|
if (fullPath === void 0 || mediaType === void 0) throw new Error(`${MANIFEST_PART} has a manifest:file-entry missing manifest:full-path or manifest:media-type`);
|
|
494
|
-
const entryVersion = attrValue$
|
|
505
|
+
const entryVersion = attrValue$2(child, "manifest:version");
|
|
495
506
|
entries.push(entryVersion === void 0 ? {
|
|
496
507
|
fullPath,
|
|
497
508
|
mediaType
|
|
@@ -601,7 +612,7 @@ function validateManifest(pkg) {
|
|
|
601
612
|
});
|
|
602
613
|
return problems;
|
|
603
614
|
}
|
|
604
|
-
const root = findChildElement(manifestPart.nodes, "manifest:manifest");
|
|
615
|
+
const root = findChildElement$1(manifestPart.nodes, "manifest:manifest");
|
|
605
616
|
if (root === void 0) {
|
|
606
617
|
problems.push({
|
|
607
618
|
severity: "error",
|
|
@@ -650,7 +661,7 @@ function validateManifest(pkg) {
|
|
|
650
661
|
for (const child of root.children) {
|
|
651
662
|
if (child.type !== "element" || child.tag !== "manifest:file-entry") continue;
|
|
652
663
|
if (!child.children.some((grandchild) => grandchild.type === "element" && grandchild.tag === "manifest:encryption-data")) continue;
|
|
653
|
-
const fullPath = attrValue$
|
|
664
|
+
const fullPath = attrValue$2(child, "manifest:full-path");
|
|
654
665
|
if (fullPath === void 0) continue;
|
|
655
666
|
problems.push({
|
|
656
667
|
severity: "warning",
|
|
@@ -682,6 +693,48 @@ function setDocumentMediaType(pkg, mediaType, version = DEFAULT_MANIFEST_VERSION
|
|
|
682
693
|
});
|
|
683
694
|
}
|
|
684
695
|
//#endregion
|
|
696
|
+
//#region src/typed/shared/units.ts
|
|
697
|
+
const LENGTH_PATTERN = /^(-?(?:\d+(?:\.\d+)?|\.\d+))(cm|mm|in|pt|pc|px)$/;
|
|
698
|
+
const POINTS_PER_INCH = 72;
|
|
699
|
+
const POINTS_PER_PICA = 12;
|
|
700
|
+
const CM_PER_INCH = 2.54;
|
|
701
|
+
const MM_PER_INCH = 25.4;
|
|
702
|
+
const CSS_REFERENCE_PIXELS_PER_INCH = 96;
|
|
703
|
+
function unitToPtFactor(unit) {
|
|
704
|
+
switch (unit) {
|
|
705
|
+
case "pt": return 1;
|
|
706
|
+
case "in": return POINTS_PER_INCH;
|
|
707
|
+
case "cm": return POINTS_PER_INCH / CM_PER_INCH;
|
|
708
|
+
case "mm": return POINTS_PER_INCH / MM_PER_INCH;
|
|
709
|
+
case "pc": return POINTS_PER_PICA;
|
|
710
|
+
case "px": return POINTS_PER_INCH / CSS_REFERENCE_PIXELS_PER_INCH;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
function isLengthUnit(value) {
|
|
714
|
+
return value === "cm" || value === "mm" || value === "in" || value === "pt" || value === "pc" || value === "px";
|
|
715
|
+
}
|
|
716
|
+
function parseOdfLength(value) {
|
|
717
|
+
const match = LENGTH_PATTERN.exec(value);
|
|
718
|
+
if (match === null) return;
|
|
719
|
+
const numeric = match[1];
|
|
720
|
+
const unit = match[2];
|
|
721
|
+
if (numeric === void 0 || unit === void 0 || !isLengthUnit(unit)) return;
|
|
722
|
+
return Number(numeric) * unitToPtFactor(unit);
|
|
723
|
+
}
|
|
724
|
+
function formatOdfLength(pt, unit = "pt") {
|
|
725
|
+
return `${pt / unitToPtFactor(unit)}${unit}`;
|
|
726
|
+
}
|
|
727
|
+
//#endregion
|
|
728
|
+
//#region src/typed/shared/color.ts
|
|
729
|
+
const ODF_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
730
|
+
function parseOdfColor(value) {
|
|
731
|
+
if (!ODF_COLOR_PATTERN.test(value)) return;
|
|
732
|
+
return (0, document_content_model.rgbHexToColor)(value);
|
|
733
|
+
}
|
|
734
|
+
function formatOdfColor(color) {
|
|
735
|
+
return `#${(0, document_content_model.colorToRgbHex)(color)}`;
|
|
736
|
+
}
|
|
737
|
+
//#endregion
|
|
685
738
|
//#region src/styles/properties.ts
|
|
686
739
|
const StylePropertiesSchema = zod.z.object({
|
|
687
740
|
bold: zod.z.boolean().optional(),
|
|
@@ -741,30 +794,9 @@ function attributeMap(element) {
|
|
|
741
794
|
for (const attribute of element.attributes) map.set(attribute.name, attribute.value);
|
|
742
795
|
return map;
|
|
743
796
|
}
|
|
744
|
-
const
|
|
745
|
-
function unitToPtFactor(unit) {
|
|
746
|
-
switch (unit) {
|
|
747
|
-
case "pt": return 1;
|
|
748
|
-
case "in": return 72;
|
|
749
|
-
case "cm": return 72 / 2.54;
|
|
750
|
-
case "mm": return 72 / 25.4;
|
|
751
|
-
case "pc": return 12;
|
|
752
|
-
case "px": return .75;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
function isLengthUnit(value) {
|
|
756
|
-
return value === "cm" || value === "mm" || value === "in" || value === "pt" || value === "pc" || value === "px";
|
|
757
|
-
}
|
|
758
|
-
function parseLength(value) {
|
|
759
|
-
const match = LENGTH_PATTERN.exec(value);
|
|
760
|
-
if (match === null) return;
|
|
761
|
-
const numeric = match[1];
|
|
762
|
-
const unit = match[2];
|
|
763
|
-
if (numeric === void 0 || unit === void 0 || !isLengthUnit(unit)) return;
|
|
764
|
-
return Number(numeric) * unitToPtFactor(unit);
|
|
765
|
-
}
|
|
797
|
+
const parseLength = parseOdfLength;
|
|
766
798
|
function formatPt(valuePt) {
|
|
767
|
-
return
|
|
799
|
+
return formatOdfLength(valuePt, "pt");
|
|
768
800
|
}
|
|
769
801
|
const PERCENTAGE_PATTERN = /^(-?(?:\d+(?:\.\d+)?|\.\d+))%$/;
|
|
770
802
|
function parsePercentageMultiplier(value) {
|
|
@@ -777,14 +809,8 @@ function parsePercentageMultiplier(value) {
|
|
|
777
809
|
function formatPercentageMultiplier(multiplier) {
|
|
778
810
|
return `${multiplier * 100}%`;
|
|
779
811
|
}
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
if (!COLOR_PATTERN.test(value)) return;
|
|
783
|
-
return (0, document_content_model.rgbHexToColor)(value);
|
|
784
|
-
}
|
|
785
|
-
function formatColor(color) {
|
|
786
|
-
return `#${(0, document_content_model.colorToRgbHex)(color)}`;
|
|
787
|
-
}
|
|
812
|
+
const parseColor = parseOdfColor;
|
|
813
|
+
const formatColor = formatOdfColor;
|
|
788
814
|
function parseLineDecoration(style, companionA, companionAOnValue, companionB, companionBOnValue) {
|
|
789
815
|
if (style === void 0 && companionA === void 0 && companionB === void 0) return;
|
|
790
816
|
if (style === "solid" && (companionA === void 0 || companionA === companionAOnValue) && (companionB === void 0 || companionB === companionBOnValue)) return true;
|
|
@@ -1049,7 +1075,7 @@ function emptyFamilySets() {
|
|
|
1049
1075
|
graphic: /* @__PURE__ */ new Set()
|
|
1050
1076
|
};
|
|
1051
1077
|
}
|
|
1052
|
-
function attrValue(element, name) {
|
|
1078
|
+
function attrValue$1(element, name) {
|
|
1053
1079
|
return element.attributes.find((attribute) => attribute.name === name)?.value;
|
|
1054
1080
|
}
|
|
1055
1081
|
function findDirectChild(nodes, tag) {
|
|
@@ -1077,8 +1103,8 @@ function ensureAutomaticStyles(root) {
|
|
|
1077
1103
|
function reserveStyleNames(container, reserved) {
|
|
1078
1104
|
for (const child of container.children) {
|
|
1079
1105
|
if (child.type !== "element" || child.tag !== "style:style") continue;
|
|
1080
|
-
const name = attrValue(child, "style:name");
|
|
1081
|
-
const family = attrValue(child, "style:family");
|
|
1106
|
+
const name = attrValue$1(child, "style:name");
|
|
1107
|
+
const family = attrValue$1(child, "style:family");
|
|
1082
1108
|
if (name === void 0 || family === void 0 || !isStyleFamily(family)) continue;
|
|
1083
1109
|
reserved[family].add(name);
|
|
1084
1110
|
}
|
|
@@ -1124,14 +1150,14 @@ var StyleRegistry = class StyleRegistry {
|
|
|
1124
1150
|
const registry = new StyleRegistry(automaticStyles, prefixes, reservedByFamily);
|
|
1125
1151
|
for (const child of automaticStyles.children) {
|
|
1126
1152
|
if (child.type !== "element" || child.tag !== "style:style") continue;
|
|
1127
|
-
const name = attrValue(child, "style:name");
|
|
1128
|
-
const family = attrValue(child, "style:family");
|
|
1153
|
+
const name = attrValue$1(child, "style:name");
|
|
1154
|
+
const family = attrValue$1(child, "style:family");
|
|
1129
1155
|
if (name === void 0 || family === void 0 || !isStyleFamily(family)) continue;
|
|
1130
1156
|
registry.knownStyles.set(name, child);
|
|
1131
1157
|
reservedByFamily[family].add(name);
|
|
1132
1158
|
const parsed = parseStyleElementProperties(child);
|
|
1133
1159
|
if (!parsed.hasUnknown) {
|
|
1134
|
-
const parentStyleName = attrValue(child, "style:parent-style-name");
|
|
1160
|
+
const parentStyleName = attrValue$1(child, "style:parent-style-name");
|
|
1135
1161
|
const fingerprint = computeFingerprint(family, parsed.properties, parentStyleName);
|
|
1136
1162
|
if (!registry.fingerprintToName.has(fingerprint)) {
|
|
1137
1163
|
registry.fingerprintToName.set(fingerprint, name);
|
|
@@ -1205,10 +1231,62 @@ var StyleRegistry = class StyleRegistry {
|
|
|
1205
1231
|
}
|
|
1206
1232
|
};
|
|
1207
1233
|
//#endregion
|
|
1234
|
+
//#region src/xml/query.ts
|
|
1235
|
+
function rootElement(nodes) {
|
|
1236
|
+
for (const node of nodes) if (node.type === "element") return node;
|
|
1237
|
+
}
|
|
1238
|
+
function findChildElement(nodes, tag) {
|
|
1239
|
+
for (const node of nodes) if (node.type === "element" && node.tag === tag) return node;
|
|
1240
|
+
}
|
|
1241
|
+
function childrenWithTag(element, tag) {
|
|
1242
|
+
const out = [];
|
|
1243
|
+
for (const child of element.children) if (child.type === "element" && child.tag === tag) out.push(child);
|
|
1244
|
+
return out;
|
|
1245
|
+
}
|
|
1246
|
+
function attrValue(element, name) {
|
|
1247
|
+
return element.attributes.find((attribute) => attribute.name === name)?.value;
|
|
1248
|
+
}
|
|
1249
|
+
//#endregion
|
|
1250
|
+
//#region src/typed/shared/text.ts
|
|
1251
|
+
function getOdfSpaceCount(element) {
|
|
1252
|
+
const raw = attrValue(element, "text:c");
|
|
1253
|
+
if (raw === void 0) return 1;
|
|
1254
|
+
const parsed = Number.parseInt(raw, 10);
|
|
1255
|
+
if (!Number.isInteger(parsed) || parsed < 0 || String(parsed) !== raw) throw new Error(`getOdfSpaceCount: text:s has a malformed text:c attribute: "${raw}"`);
|
|
1256
|
+
return parsed;
|
|
1257
|
+
}
|
|
1258
|
+
function measureOdfNodeLength(node) {
|
|
1259
|
+
if (node.type === "text") return node.value.length;
|
|
1260
|
+
if (node.type !== "element") return 0;
|
|
1261
|
+
if (node.tag === "text:s") return getOdfSpaceCount(node);
|
|
1262
|
+
if (node.tag === "text:tab" || node.tag === "text:line-break") return 1;
|
|
1263
|
+
if (node.tag === "text:span") return sumOdfNodeLength(node.children);
|
|
1264
|
+
return 0;
|
|
1265
|
+
}
|
|
1266
|
+
function sumOdfNodeLength(nodes) {
|
|
1267
|
+
let total = 0;
|
|
1268
|
+
for (const node of nodes) total += measureOdfNodeLength(node);
|
|
1269
|
+
return total;
|
|
1270
|
+
}
|
|
1271
|
+
function decodeOdfNode(node) {
|
|
1272
|
+
if (node.type === "text") return decodeXmlText(node.value);
|
|
1273
|
+
if (node.type !== "element") return "";
|
|
1274
|
+
if (node.tag === "text:s") return " ".repeat(getOdfSpaceCount(node));
|
|
1275
|
+
if (node.tag === "text:tab") return " ";
|
|
1276
|
+
if (node.tag === "text:line-break") return "\n";
|
|
1277
|
+
if (node.tag === "text:span") return decodeOdfText(node);
|
|
1278
|
+
return "";
|
|
1279
|
+
}
|
|
1280
|
+
function decodeOdfText(container) {
|
|
1281
|
+
let text = "";
|
|
1282
|
+
for (const child of container.children) text += decodeOdfNode(child);
|
|
1283
|
+
return text;
|
|
1284
|
+
}
|
|
1285
|
+
//#endregion
|
|
1208
1286
|
//#region src/styles/span.ts
|
|
1209
1287
|
function ensureSpan(paragraph, start, end, styleName) {
|
|
1210
1288
|
if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start) throw new Error(`ensureSpan: invalid range [${start}, ${end})`);
|
|
1211
|
-
const total =
|
|
1289
|
+
const total = sumOdfNodeLength(paragraph.children);
|
|
1212
1290
|
if (end > total) throw new Error(`ensureSpan: range end ${end} exceeds the container's total character length ${total}`);
|
|
1213
1291
|
const { before, after: rest } = splitChildrenAt(paragraph.children, start);
|
|
1214
1292
|
const { before: middle, after } = splitChildrenAt(rest, end - start);
|
|
@@ -1240,29 +1318,9 @@ function setStyleName(span, styleName) {
|
|
|
1240
1318
|
value: encoded
|
|
1241
1319
|
});
|
|
1242
1320
|
}
|
|
1243
|
-
function getSpaceCount(spaceElement) {
|
|
1244
|
-
const raw = spaceElement.attributes.find((attribute) => attribute.name === "text:c")?.value;
|
|
1245
|
-
if (raw === void 0) return 1;
|
|
1246
|
-
const parsed = Number.parseInt(raw, 10);
|
|
1247
|
-
if (!Number.isInteger(parsed) || parsed < 0 || String(parsed) !== raw) throw new Error(`ensureSpan: text:s has a malformed text:c attribute: "${raw}"`);
|
|
1248
|
-
return parsed;
|
|
1249
|
-
}
|
|
1250
1321
|
function buildSpaceRun(count) {
|
|
1251
1322
|
return count === 1 ? el("text:s") : el("text:s", { "text:c": String(count) });
|
|
1252
1323
|
}
|
|
1253
|
-
function measureLength(node) {
|
|
1254
|
-
if (node.type === "text") return node.value.length;
|
|
1255
|
-
if (node.type !== "element") return 0;
|
|
1256
|
-
if (node.tag === "text:s") return getSpaceCount(node);
|
|
1257
|
-
if (node.tag === "text:tab" || node.tag === "text:line-break") return 1;
|
|
1258
|
-
if (node.tag === "text:span") return sumLength(node.children);
|
|
1259
|
-
return 0;
|
|
1260
|
-
}
|
|
1261
|
-
function sumLength(nodes) {
|
|
1262
|
-
let total = 0;
|
|
1263
|
-
for (const node of nodes) total += measureLength(node);
|
|
1264
|
-
return total;
|
|
1265
|
-
}
|
|
1266
1324
|
function splitNode(node, offset) {
|
|
1267
1325
|
if (node.type === "text") return {
|
|
1268
1326
|
left: {
|
|
@@ -1275,7 +1333,7 @@ function splitNode(node, offset) {
|
|
|
1275
1333
|
}
|
|
1276
1334
|
};
|
|
1277
1335
|
if (node.type === "element" && node.tag === "text:s") {
|
|
1278
|
-
const count =
|
|
1336
|
+
const count = getOdfSpaceCount(node);
|
|
1279
1337
|
return {
|
|
1280
1338
|
left: buildSpaceRun(offset),
|
|
1281
1339
|
right: buildSpaceRun(count - offset)
|
|
@@ -1312,7 +1370,7 @@ function splitChildrenAt(children, offset) {
|
|
|
1312
1370
|
after: children.slice(index)
|
|
1313
1371
|
};
|
|
1314
1372
|
const node = children[index];
|
|
1315
|
-
const length =
|
|
1373
|
+
const length = measureOdfNodeLength(node);
|
|
1316
1374
|
if (remaining >= length) {
|
|
1317
1375
|
before.push(node);
|
|
1318
1376
|
remaining -= length;
|
|
@@ -1334,9 +1392,227 @@ function splitChildrenAt(children, offset) {
|
|
|
1334
1392
|
};
|
|
1335
1393
|
}
|
|
1336
1394
|
//#endregion
|
|
1395
|
+
//#region src/typed/shared/a1.ts
|
|
1396
|
+
const ALPHABET_SIZE = 26;
|
|
1397
|
+
const ALPHABET_START_CODE = "A".charCodeAt(0);
|
|
1398
|
+
function columnIndexToLetters(index) {
|
|
1399
|
+
if (!Number.isInteger(index) || index < 0) throw new Error(`columnIndexToLetters: index must be a non-negative integer, got ${index}`);
|
|
1400
|
+
let remaining = index + 1;
|
|
1401
|
+
let letters = "";
|
|
1402
|
+
while (remaining > 0) {
|
|
1403
|
+
const digit = (remaining - 1) % ALPHABET_SIZE;
|
|
1404
|
+
letters = String.fromCharCode(ALPHABET_START_CODE + digit) + letters;
|
|
1405
|
+
remaining = Math.floor((remaining - 1) / ALPHABET_SIZE);
|
|
1406
|
+
}
|
|
1407
|
+
return letters;
|
|
1408
|
+
}
|
|
1409
|
+
function cellReference(columnIndex, rowIndex) {
|
|
1410
|
+
if (!Number.isInteger(rowIndex) || rowIndex < 0) throw new Error(`cellReference: rowIndex must be a non-negative integer, got ${rowIndex}`);
|
|
1411
|
+
return `${columnIndexToLetters(columnIndex)}${rowIndex + 1}`;
|
|
1412
|
+
}
|
|
1413
|
+
function validateRepeatCount(repeatCount, caller) {
|
|
1414
|
+
if (!Number.isInteger(repeatCount) || repeatCount < 1) throw new Error(`${caller}: repeatCount must be a positive integer, got ${repeatCount}`);
|
|
1415
|
+
}
|
|
1416
|
+
var TableCursor = class {
|
|
1417
|
+
columnCursor = 0;
|
|
1418
|
+
rowCursor = 0;
|
|
1419
|
+
get columnIndex() {
|
|
1420
|
+
return this.columnCursor;
|
|
1421
|
+
}
|
|
1422
|
+
get rowIndex() {
|
|
1423
|
+
return this.rowCursor;
|
|
1424
|
+
}
|
|
1425
|
+
nextCell(repeatCount = 1) {
|
|
1426
|
+
validateRepeatCount(repeatCount, "TableCursor.nextCell");
|
|
1427
|
+
const reference = cellReference(this.columnCursor, this.rowCursor);
|
|
1428
|
+
this.columnCursor += repeatCount;
|
|
1429
|
+
return reference;
|
|
1430
|
+
}
|
|
1431
|
+
nextRow(repeatCount = 1) {
|
|
1432
|
+
validateRepeatCount(repeatCount, "TableCursor.nextRow");
|
|
1433
|
+
this.rowCursor += repeatCount;
|
|
1434
|
+
this.columnCursor = 0;
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
//#endregion
|
|
1438
|
+
//#region src/typed/shared/geometry.ts
|
|
1439
|
+
function parsePageSize(pageLayoutProperties) {
|
|
1440
|
+
const widthValue = attrValue(pageLayoutProperties, "fo:page-width");
|
|
1441
|
+
const heightValue = attrValue(pageLayoutProperties, "fo:page-height");
|
|
1442
|
+
if (widthValue === void 0 || heightValue === void 0) return;
|
|
1443
|
+
const widthPt = parseOdfLength(widthValue);
|
|
1444
|
+
const heightPt = parseOdfLength(heightValue);
|
|
1445
|
+
if (widthPt === void 0 || heightPt === void 0) return;
|
|
1446
|
+
return {
|
|
1447
|
+
widthPt,
|
|
1448
|
+
heightPt
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
function parseMargins(pageLayoutProperties) {
|
|
1452
|
+
const topValue = attrValue(pageLayoutProperties, "fo:margin-top");
|
|
1453
|
+
const rightValue = attrValue(pageLayoutProperties, "fo:margin-right");
|
|
1454
|
+
const bottomValue = attrValue(pageLayoutProperties, "fo:margin-bottom");
|
|
1455
|
+
const leftValue = attrValue(pageLayoutProperties, "fo:margin-left");
|
|
1456
|
+
if (topValue === void 0 || rightValue === void 0 || bottomValue === void 0 || leftValue === void 0) return;
|
|
1457
|
+
const topPt = parseOdfLength(topValue);
|
|
1458
|
+
const rightPt = parseOdfLength(rightValue);
|
|
1459
|
+
const bottomPt = parseOdfLength(bottomValue);
|
|
1460
|
+
const leftPt = parseOdfLength(leftValue);
|
|
1461
|
+
if (topPt === void 0 || rightPt === void 0 || bottomPt === void 0 || leftPt === void 0) return;
|
|
1462
|
+
return {
|
|
1463
|
+
topPt,
|
|
1464
|
+
rightPt,
|
|
1465
|
+
bottomPt,
|
|
1466
|
+
leftPt
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
function parseBox(element) {
|
|
1470
|
+
const xValue = attrValue(element, "svg:x");
|
|
1471
|
+
const yValue = attrValue(element, "svg:y");
|
|
1472
|
+
const widthValue = attrValue(element, "svg:width");
|
|
1473
|
+
const heightValue = attrValue(element, "svg:height");
|
|
1474
|
+
if (xValue === void 0 || yValue === void 0 || widthValue === void 0 || heightValue === void 0) return;
|
|
1475
|
+
const xPt = parseOdfLength(xValue);
|
|
1476
|
+
const yPt = parseOdfLength(yValue);
|
|
1477
|
+
const widthPt = parseOdfLength(widthValue);
|
|
1478
|
+
const heightPt = parseOdfLength(heightValue);
|
|
1479
|
+
if (xPt === void 0 || yPt === void 0 || widthPt === void 0 || heightPt === void 0) return;
|
|
1480
|
+
return {
|
|
1481
|
+
xPt,
|
|
1482
|
+
yPt,
|
|
1483
|
+
widthPt,
|
|
1484
|
+
heightPt
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
//#endregion
|
|
1488
|
+
//#region src/typed/shared/cascade.ts
|
|
1489
|
+
const STYLE_PARTS = ["content.xml", "styles.xml"];
|
|
1490
|
+
const NAME_KEY_SEPARATOR = "\0";
|
|
1491
|
+
function nameKey(family, name) {
|
|
1492
|
+
return `${family}${NAME_KEY_SEPARATOR}${name}`;
|
|
1493
|
+
}
|
|
1494
|
+
function collectStyles(pkg) {
|
|
1495
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1496
|
+
const defaultByFamily = /* @__PURE__ */ new Map();
|
|
1497
|
+
for (const partPath of STYLE_PARTS) {
|
|
1498
|
+
const part = pkg.parts[partPath];
|
|
1499
|
+
if (part?.kind !== "xml") continue;
|
|
1500
|
+
const root = rootElement(part.nodes);
|
|
1501
|
+
if (root === void 0) continue;
|
|
1502
|
+
for (const containerTag of ["office:automatic-styles", "office:styles"]) {
|
|
1503
|
+
const container = findChildElement(root.children, containerTag);
|
|
1504
|
+
if (container === void 0) continue;
|
|
1505
|
+
for (const child of container.children) {
|
|
1506
|
+
if (child.type !== "element") continue;
|
|
1507
|
+
if (child.tag === "style:style") {
|
|
1508
|
+
const name = attrValue(child, "style:name");
|
|
1509
|
+
const family = attrValue(child, "style:family");
|
|
1510
|
+
if (name === void 0 || family === void 0 || !isStyleFamily(family)) continue;
|
|
1511
|
+
byName.set(nameKey(family, name), child);
|
|
1512
|
+
} else if (child.tag === "style:default-style") {
|
|
1513
|
+
const family = attrValue(child, "style:family");
|
|
1514
|
+
if (family === void 0 || !isStyleFamily(family)) continue;
|
|
1515
|
+
if (!defaultByFamily.has(family)) defaultByFamily.set(family, child);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return {
|
|
1521
|
+
byName,
|
|
1522
|
+
defaultByFamily
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
function resolveStyle(styleName, family, pkg) {
|
|
1526
|
+
const { byName, defaultByFamily } = collectStyles(pkg);
|
|
1527
|
+
const diagnostics = [];
|
|
1528
|
+
const defaultElement = defaultByFamily.get(family);
|
|
1529
|
+
let properties = defaultElement === void 0 ? {} : parseStyleElementProperties(defaultElement).properties;
|
|
1530
|
+
if (styleName === void 0) return {
|
|
1531
|
+
properties,
|
|
1532
|
+
diagnostics
|
|
1533
|
+
};
|
|
1534
|
+
const chain = [];
|
|
1535
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1536
|
+
let currentName = styleName;
|
|
1537
|
+
while (currentName !== void 0) {
|
|
1538
|
+
const key = nameKey(family, currentName);
|
|
1539
|
+
if (visited.has(key)) {
|
|
1540
|
+
diagnostics.push({
|
|
1541
|
+
severity: "warning",
|
|
1542
|
+
message: `cyclic style:parent-style-name chain detected at style "${currentName}" (family "${family}") -- breaking the cycle and stopping cascade resolution at this point`
|
|
1543
|
+
});
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
1546
|
+
visited.add(key);
|
|
1547
|
+
const element = byName.get(key);
|
|
1548
|
+
if (element === void 0) {
|
|
1549
|
+
diagnostics.push({
|
|
1550
|
+
severity: "warning",
|
|
1551
|
+
message: `style "${currentName}" (family "${family}") was not found in content.xml or styles.xml -- stopping cascade resolution at this point`
|
|
1552
|
+
});
|
|
1553
|
+
break;
|
|
1554
|
+
}
|
|
1555
|
+
chain.push(element);
|
|
1556
|
+
currentName = attrValue(element, "style:parent-style-name");
|
|
1557
|
+
}
|
|
1558
|
+
chain.reverse();
|
|
1559
|
+
for (const element of chain) properties = {
|
|
1560
|
+
...properties,
|
|
1561
|
+
...parseStyleElementProperties(element).properties
|
|
1562
|
+
};
|
|
1563
|
+
return {
|
|
1564
|
+
properties,
|
|
1565
|
+
diagnostics
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
//#endregion
|
|
1569
|
+
//#region src/typed/shared/metadata.ts
|
|
1570
|
+
const META_PART = "meta.xml";
|
|
1571
|
+
function elementText(element) {
|
|
1572
|
+
let text = "";
|
|
1573
|
+
for (const child of element.children) if (child.type === "text") text += decodeXmlText(child.value);
|
|
1574
|
+
return text;
|
|
1575
|
+
}
|
|
1576
|
+
function firstElementText(container, tag) {
|
|
1577
|
+
const element = childrenWithTag(container, tag)[0];
|
|
1578
|
+
if (element === void 0) return;
|
|
1579
|
+
const text = elementText(element);
|
|
1580
|
+
return text.length > 0 ? text : void 0;
|
|
1581
|
+
}
|
|
1582
|
+
function readOdfMetadata(pkg) {
|
|
1583
|
+
const part = pkg.parts[META_PART];
|
|
1584
|
+
if (part?.kind !== "xml") return {};
|
|
1585
|
+
const root = rootElement(part.nodes);
|
|
1586
|
+
const meta = root === void 0 ? void 0 : findChildElement(root.children, "office:meta");
|
|
1587
|
+
if (meta === void 0) return {};
|
|
1588
|
+
const metadata = {};
|
|
1589
|
+
const title = firstElementText(meta, "dc:title");
|
|
1590
|
+
if (title !== void 0) metadata.title = title;
|
|
1591
|
+
const author = firstElementText(meta, "meta:initial-creator");
|
|
1592
|
+
if (author !== void 0) metadata.author = author;
|
|
1593
|
+
const subject = firstElementText(meta, "dc:subject");
|
|
1594
|
+
if (subject !== void 0) metadata.subject = subject;
|
|
1595
|
+
const keywords = childrenWithTag(meta, "meta:keyword").map(elementText).filter((keyword) => keyword.length > 0);
|
|
1596
|
+
if (keywords.length > 0) metadata.keywords = keywords;
|
|
1597
|
+
const creator = firstElementText(meta, "meta:generator");
|
|
1598
|
+
if (creator !== void 0) metadata.creator = creator;
|
|
1599
|
+
const createdIso = firstElementText(meta, "meta:creation-date");
|
|
1600
|
+
if (createdIso !== void 0) metadata.createdIso = createdIso;
|
|
1601
|
+
const modifiedIso = firstElementText(meta, "dc:date");
|
|
1602
|
+
if (modifiedIso !== void 0) metadata.modifiedIso = modifiedIso;
|
|
1603
|
+
return metadata;
|
|
1604
|
+
}
|
|
1605
|
+
//#endregion
|
|
1606
|
+
Object.defineProperty(exports, "AlignmentSchema", {
|
|
1607
|
+
enumerable: true,
|
|
1608
|
+
get: function() {
|
|
1609
|
+
return document_content_model.AlignmentSchema;
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1337
1612
|
exports.AttributeSchema = AttributeSchema;
|
|
1338
1613
|
exports.BinaryPartSchema = BinaryPartSchema;
|
|
1339
1614
|
exports.MANIFEST_PART = MANIFEST_PART;
|
|
1615
|
+
exports.META_PART = META_PART;
|
|
1340
1616
|
exports.MIMETYPE_PART = MIMETYPE_PART;
|
|
1341
1617
|
exports.ManifestEntrySchema = ManifestEntrySchema;
|
|
1342
1618
|
exports.ManifestProblemSchema = ManifestProblemSchema;
|
|
@@ -1348,6 +1624,7 @@ exports.PartSchema = PartSchema;
|
|
|
1348
1624
|
exports.STYLE_FAMILIES = STYLE_FAMILIES;
|
|
1349
1625
|
exports.StylePropertiesSchema = StylePropertiesSchema;
|
|
1350
1626
|
exports.StyleRegistry = StyleRegistry;
|
|
1627
|
+
exports.TableCursor = TableCursor;
|
|
1351
1628
|
exports.XmlCdataSchema = XmlCdataSchema;
|
|
1352
1629
|
exports.XmlCommentSchema = XmlCommentSchema;
|
|
1353
1630
|
exports.XmlDeclarationSchema = XmlDeclarationSchema;
|
|
@@ -1356,34 +1633,55 @@ exports.XmlNodeSchema = XmlNodeSchema;
|
|
|
1356
1633
|
exports.XmlPartSchema = XmlPartSchema;
|
|
1357
1634
|
exports.XmlPiSchema = XmlPiSchema;
|
|
1358
1635
|
exports.XmlTextSchema = XmlTextSchema;
|
|
1636
|
+
exports.attrValue = attrValue;
|
|
1359
1637
|
exports.base64ToBytes = base64ToBytes;
|
|
1360
1638
|
exports.buildManifest = buildManifest;
|
|
1361
1639
|
exports.buildStylePropertyElements = buildStylePropertyElements;
|
|
1362
1640
|
exports.buildXml = buildXml;
|
|
1363
1641
|
exports.bytesToBase64 = bytesToBase64;
|
|
1364
1642
|
exports.canonicalPropertiesString = canonicalPropertiesString;
|
|
1643
|
+
exports.cellReference = cellReference;
|
|
1644
|
+
exports.childrenWithTag = childrenWithTag;
|
|
1645
|
+
exports.columnIndexToLetters = columnIndexToLetters;
|
|
1646
|
+
exports.decodeOdfText = decodeOdfText;
|
|
1365
1647
|
exports.decodePackage = decodePackage;
|
|
1648
|
+
exports.decodeXmlText = decodeXmlText;
|
|
1366
1649
|
exports.el = el;
|
|
1367
1650
|
exports.encodePackage = encodePackage;
|
|
1368
1651
|
exports.encodeXmlText = encodeXmlText;
|
|
1369
1652
|
exports.ensureSpan = ensureSpan;
|
|
1653
|
+
exports.findChildElement = findChildElement;
|
|
1654
|
+
exports.formatOdfColor = formatOdfColor;
|
|
1655
|
+
exports.formatOdfLength = formatOdfLength;
|
|
1370
1656
|
exports.formatPercentageMultiplier = formatPercentageMultiplier;
|
|
1371
1657
|
exports.formatPt = formatPt;
|
|
1658
|
+
exports.getOdfSpaceCount = getOdfSpaceCount;
|
|
1659
|
+
exports.isStyleFamily = isStyleFamily;
|
|
1372
1660
|
exports.isXmlNode = isXmlNode;
|
|
1661
|
+
exports.measureOdfNodeLength = measureOdfNodeLength;
|
|
1373
1662
|
exports.mediaTypeForExtension = mediaTypeForExtension;
|
|
1374
1663
|
exports.packageCodec = packageCodec;
|
|
1375
1664
|
exports.paragraphPropertiesToAttributes = paragraphPropertiesToAttributes;
|
|
1665
|
+
exports.parseBox = parseBox;
|
|
1376
1666
|
exports.parseLength = parseLength;
|
|
1667
|
+
exports.parseMargins = parseMargins;
|
|
1668
|
+
exports.parseOdfColor = parseOdfColor;
|
|
1669
|
+
exports.parseOdfLength = parseOdfLength;
|
|
1377
1670
|
exports.parsePackage = parsePackage;
|
|
1671
|
+
exports.parsePageSize = parsePageSize;
|
|
1378
1672
|
exports.parseParagraphProperties = parseParagraphProperties;
|
|
1379
1673
|
exports.parseStyleElementProperties = parseStyleElementProperties;
|
|
1380
1674
|
exports.parseTextProperties = parseTextProperties;
|
|
1381
1675
|
exports.parseXml = parseXml;
|
|
1382
1676
|
exports.readManifest = readManifest;
|
|
1383
1677
|
exports.readMimetype = readMimetype;
|
|
1678
|
+
exports.readOdfMetadata = readOdfMetadata;
|
|
1679
|
+
exports.resolveStyle = resolveStyle;
|
|
1680
|
+
exports.rootElement = rootElement;
|
|
1384
1681
|
exports.serializePackage = serializePackage;
|
|
1385
1682
|
exports.setDocumentMediaType = setDocumentMediaType;
|
|
1386
1683
|
exports.sniffImageFormat = sniffImageFormat;
|
|
1684
|
+
exports.sumOdfNodeLength = sumOdfNodeLength;
|
|
1387
1685
|
exports.syncManifest = syncManifest;
|
|
1388
1686
|
exports.textPropertiesToAttributes = textPropertiesToAttributes;
|
|
1389
1687
|
exports.txt = txt;
|