reamkit 1.32.0 → 1.33.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/README.md +5 -4
- package/dist/esm/core/bidi/algorithm.js +2 -2
- package/dist/esm/core/bidi/char-types.js +1 -1
- package/dist/esm/core/bidi/index.js +3 -3
- package/dist/esm/core/bytes.js +1 -1
- package/dist/esm/core/converter/facade.js +3 -2
- package/dist/esm/core/converter/ream.js +12 -5
- package/dist/esm/core/crypto/asn1.js +2 -2
- package/dist/esm/core/crypto/cms.js +5 -3
- package/dist/esm/core/crypto/index.js +2 -1
- package/dist/esm/core/crypto/offcrypto.js +64 -19
- package/dist/esm/core/crypto/primitives.js +16 -16
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +174 -2
- package/dist/esm/core/drawingml/chart-geometry.d.ts +45 -17
- package/dist/esm/core/drawingml/chart-geometry.js +1090 -257
- package/dist/esm/core/drawingml/chart-parser.d.ts +24 -1
- package/dist/esm/core/drawingml/chart-parser.js +334 -41
- package/dist/esm/core/drawingml/chart-text.d.ts +41 -0
- package/dist/esm/core/drawingml/chart-text.js +93 -0
- package/dist/esm/core/drawingml/colors.js +5 -5
- package/dist/esm/core/drawingml/diagram/layout-engine.js +1 -4
- package/dist/esm/core/drawingml/diagram/run.js +2 -1
- package/dist/esm/core/drawingml/preset-geometry.js +4 -6
- package/dist/esm/core/drawingml/shape-render.js +1 -1
- package/dist/esm/core/drawingml/text-warp.js +4 -16
- package/dist/esm/core/drawingml/theme-parser.js +14 -8
- package/dist/esm/core/font/arabic-joining.js +2 -2
- package/dist/esm/core/font/binary-reader.js +2 -0
- package/dist/esm/core/font/font-registry.js +1 -0
- package/dist/esm/core/font/ligatures.js +1 -1
- package/dist/esm/core/font/opentype-layout.js +11 -5
- package/dist/esm/core/font/ttf-build.js +6 -10
- package/dist/esm/core/font/ttf-parser.js +2 -1
- package/dist/esm/core/font/ttf-subset.js +8 -8
- package/dist/esm/core/fonts/families.js +1 -1
- package/dist/esm/core/fonts/remote-fonts.js +4 -4
- package/dist/esm/core/hyphenation/index.js +1 -1
- package/dist/esm/core/images.js +8 -8
- package/dist/esm/core/ir/loss.js +1 -0
- package/dist/esm/core/line-breaker/cjk.js +1 -1
- package/dist/esm/core/line-breaker/index.js +4 -3
- package/dist/esm/core/links.js +1 -1
- package/dist/esm/core/lzw.js +1 -1
- package/dist/esm/core/metafile/blit.js +1 -1
- package/dist/esm/core/metafile/emf.js +5 -7
- package/dist/esm/core/metafile/picture.js +1 -1
- package/dist/esm/core/metafile/symbol-fonts.js +7 -7
- package/dist/esm/core/metafile/wmf.js +5 -7
- package/dist/esm/core/number-format.d.ts +40 -15
- package/dist/esm/core/number-format.js +284 -79
- package/dist/esm/core/numbering/index.js +3 -2
- package/dist/esm/core/ole/cfb.js +4 -4
- package/dist/esm/core/ole/escher-blip.js +1 -1
- package/dist/esm/core/opc/index.js +5 -4
- package/dist/esm/core/opc/package.js +3 -1
- package/dist/esm/core/opc/tag-scan.d.ts +15 -0
- package/dist/esm/core/opc/tag-scan.js +41 -0
- package/dist/esm/core/opc/xml-entities.js +40 -3
- package/dist/esm/core/outline.js +1 -1
- package/dist/esm/core/png-encode.js +3 -3
- package/dist/esm/core/po-helpers.js +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +6 -0
- package/dist/esm/core/style-cascade/index.js +4 -3
- package/dist/esm/core/tiff.js +3 -1
- package/dist/esm/excel/activex-parser.js +1 -1
- package/dist/esm/excel/conditional-format.js +7 -7
- package/dist/esm/excel/formula/functions.js +45 -18
- package/dist/esm/excel/formula/index.js +3 -3
- package/dist/esm/excel/formula/lexer.js +2 -2
- package/dist/esm/excel/formula/parser.js +4 -3
- package/dist/esm/excel/formula/value.js +1 -1
- package/dist/esm/excel/index.js +7 -6
- package/dist/esm/excel/print-model.js +18 -7
- package/dist/esm/excel/printer-settings.js +6 -7
- package/dist/esm/excel/rich-value.js +1 -1
- package/dist/esm/excel/sheet-shape-parser.js +4 -2
- package/dist/esm/excel/sheet-to-flow.js +13 -11
- package/dist/esm/excel/styles-parser.js +5 -3
- package/dist/esm/excel/tint.js +5 -5
- package/dist/esm/excel/vml-drawing.js +3 -3
- package/dist/esm/excel/worksheet-parser.js +5 -5
- package/dist/esm/excel/xls/biff-chart.js +1 -3
- package/dist/esm/excel/xls/biff-reader.js +10 -11
- package/dist/esm/excel/xls/xls-reader.js +1 -1
- package/dist/esm/excel/xlsx-reader.js +56 -9
- package/dist/esm/excel/xlsx-to-pdf.js +1 -1
- package/dist/esm/excel/xlsx-writer.js +2 -2
- package/dist/esm/html/html-writer.js +18 -10
- package/dist/esm/layout/line-paint.js +1 -1
- package/dist/esm/layout/math-layout.js +5 -8
- package/dist/esm/layout/styled-layout.js +104 -32
- package/dist/esm/layout/turned-section.js +2 -2
- package/dist/esm/markdown/markdown-writer.js +59 -8
- package/dist/esm/pdf/encryption.js +9 -9
- package/dist/esm/pdf/icc-profile.js +2 -2
- package/dist/esm/pdf/index.js +3 -2
- package/dist/esm/pdf/objects.js +7 -0
- package/dist/esm/pdf/serialize.js +1 -1
- package/dist/esm/pdf/struct-tree.js +3 -1
- package/dist/esm/pdf/styled-page-emitter.js +23 -15
- package/dist/esm/pdf/styled-page-renderer.js +9 -5
- package/dist/esm/pdf-reader/annot-draw.js +5 -5
- package/dist/esm/pdf-reader/annots.js +3 -1
- package/dist/esm/pdf-reader/ccitt.js +2 -1
- package/dist/esm/pdf-reader/cff-outline.js +1 -4
- package/dist/esm/pdf-reader/content.js +13 -15
- package/dist/esm/pdf-reader/decrypt.js +5 -4
- package/dist/esm/pdf-reader/document.js +6 -2
- package/dist/esm/pdf-reader/encodings.js +1 -1
- package/dist/esm/pdf-reader/flow-build.js +4 -6
- package/dist/esm/pdf-reader/font.js +4 -4
- package/dist/esm/pdf-reader/function.js +8 -7
- package/dist/esm/pdf-reader/icc.js +1 -1
- package/dist/esm/pdf-reader/images.js +1 -1
- package/dist/esm/pdf-reader/jbig2.js +36 -38
- package/dist/esm/pdf-reader/jpeg.js +14 -13
- package/dist/esm/pdf-reader/layout.js +13 -10
- package/dist/esm/pdf-reader/lexer.js +2 -1
- package/dist/esm/pdf-reader/math-rows.js +2 -2
- package/dist/esm/pdf-reader/optional-content.js +1 -1
- package/dist/esm/pdf-reader/page-numbers.js +1 -1
- package/dist/esm/pdf-reader/pattern-tint.js +1 -2
- package/dist/esm/pdf-reader/reader.js +2 -2
- package/dist/esm/pdf-reader/struct-tree.js +1 -1
- package/dist/esm/pdf-reader/tagged.js +3 -2
- package/dist/esm/pdf-reader/text.js +2 -2
- package/dist/esm/pdf-reader/type1-outline.js +1 -3
- package/dist/esm/pptx/embedded-fonts.js +3 -5
- package/dist/esm/pptx/placeholder-cascade.js +1 -1
- package/dist/esm/pptx/ppt/ppt-reader.js +5 -4
- package/dist/esm/pptx/ppt/ppt-text.js +9 -10
- package/dist/esm/pptx/pptx-reader.js +6 -5
- package/dist/esm/pptx/preset-table-styles.js +1 -1
- package/dist/esm/pptx/slide-parser.js +6 -4
- package/dist/esm/pptx/sp-helpers.js +1 -1
- package/dist/esm/pptx/table-style.js +2 -1
- package/dist/esm/svg/svg-writer.js +1 -1
- package/dist/esm/word/doc/doc-reader.js +2 -2
- package/dist/esm/word/doc/doc-text.js +20 -22
- package/dist/esm/word/document-parser.js +27 -22
- package/dist/esm/word/docx-reader.js +15 -10
- package/dist/esm/word/docx-to-pdf.js +6 -6
- package/dist/esm/word/docx-writer.js +10 -6
- package/dist/esm/word/drawing-parser.js +18 -18
- package/dist/esm/word/font-table.js +90 -11
- package/dist/esm/word/index.js +6 -5
- package/dist/esm/word/numbering-parser.js +5 -4
- package/dist/esm/word/omml-parser.js +1 -1
- package/dist/esm/word/paragraph-properties.js +11 -10
- package/dist/esm/word/run-properties.js +4 -4
- package/dist/esm/word/settings-parser.js +2 -1
- package/dist/esm/word/shading.js +1 -1
- package/dist/esm/word/styles-parser.js +5 -4
- package/dist/esm/word/table-parser.js +4 -4
- package/dist/esm/word/theme-fonts.js +1 -1
- package/package.json +10 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INDEXED_COLORS } from "./indexed-colors.js";
|
|
2
2
|
//#region src/core/number-format.ts
|
|
3
|
-
var BUILTIN = new Map([
|
|
3
|
+
var BUILTIN = /* @__PURE__ */ new Map([
|
|
4
4
|
[0, "General"],
|
|
5
5
|
[1, "0"],
|
|
6
6
|
[2, "0.00"],
|
|
@@ -22,7 +22,7 @@ var BUILTIN = new Map([
|
|
|
22
22
|
[48, "##0.0E+0"],
|
|
23
23
|
[49, "@"]
|
|
24
24
|
]);
|
|
25
|
-
var BUILTIN_DATE_FORMATS = new Map([
|
|
25
|
+
var BUILTIN_DATE_FORMATS = /* @__PURE__ */ new Map([
|
|
26
26
|
[14, "m/d/yyyy"],
|
|
27
27
|
[15, "d-mmm-yy"],
|
|
28
28
|
[16, "d-mmm"],
|
|
@@ -85,7 +85,7 @@ function numberFormatColorHex(rawValue, numFmtId, customFormats) {
|
|
|
85
85
|
if (idx < 0) return void 0;
|
|
86
86
|
return colorOfSection(sections[idx] ?? sections[0]);
|
|
87
87
|
}
|
|
88
|
-
var FORMAT_COLORS = new Map([
|
|
88
|
+
var FORMAT_COLORS = /* @__PURE__ */ new Map([
|
|
89
89
|
["black", "000000"],
|
|
90
90
|
["blue", "0000FF"],
|
|
91
91
|
["cyan", "00FFFF"],
|
|
@@ -95,8 +95,17 @@ var FORMAT_COLORS = new Map([
|
|
|
95
95
|
["white", "FFFFFF"],
|
|
96
96
|
["yellow", "FFFF00"]
|
|
97
97
|
]);
|
|
98
|
+
var BRACKET_CODE = /\[([^\]]*)\]/g;
|
|
99
|
+
function bracketCodes(format) {
|
|
100
|
+
return format.slice(0, format.lastIndexOf("]") + 1).matchAll(BRACKET_CODE);
|
|
101
|
+
}
|
|
102
|
+
/** The format with each `[…]` code replaced by what `fn` makes of its inside. */
|
|
103
|
+
function replaceBracketCodes(format, fn) {
|
|
104
|
+
const end = format.lastIndexOf("]") + 1;
|
|
105
|
+
return format.slice(0, end).replace(BRACKET_CODE, (_, body) => fn(body)) + format.slice(end);
|
|
106
|
+
}
|
|
98
107
|
function colorOfSection(section) {
|
|
99
|
-
for (const m of section
|
|
108
|
+
for (const m of bracketCodes(section)) {
|
|
100
109
|
const body = m[1].trim().toLowerCase();
|
|
101
110
|
const named = FORMAT_COLORS.get(body);
|
|
102
111
|
if (named !== void 0) return named;
|
|
@@ -251,7 +260,7 @@ function hasElapsedToken(code) {
|
|
|
251
260
|
return /\[(?:h+|m+|s+)\]/i.test(code.replace(/"[^"]*"/g, ""));
|
|
252
261
|
}
|
|
253
262
|
function isDateFormat(code) {
|
|
254
|
-
const cleaned = code.replace(/"[^"]*"/g, "")
|
|
263
|
+
const cleaned = replaceBracketCodes(code.replace(/"[^"]*"/g, ""), () => "");
|
|
255
264
|
return /[dyhs]|m+/i.test(cleaned) && /[dyhs]/i.test(cleaned);
|
|
256
265
|
}
|
|
257
266
|
function tokenizeDateFormat(format) {
|
|
@@ -442,18 +451,19 @@ function formatExcelDate(rawValue, format, date1904) {
|
|
|
442
451
|
case "elapsed-s":
|
|
443
452
|
out += elapsed(totalSeconds, t.text.length);
|
|
444
453
|
break;
|
|
445
|
-
case "subsec":
|
|
446
|
-
|
|
454
|
+
case "subsec": {
|
|
455
|
+
const places = Math.min(subsecDigits, 100);
|
|
456
|
+
const fraction = (totalSeconds - Math.floor(totalSeconds)).toFixed(places);
|
|
457
|
+
out += fraction.substring(1) + "0".repeat(subsecDigits - places);
|
|
447
458
|
break;
|
|
459
|
+
}
|
|
448
460
|
case "m":
|
|
449
461
|
out += t.text.length >= 2 ? pad2(minute) : String(minute);
|
|
450
462
|
break;
|
|
451
463
|
case "s":
|
|
452
464
|
out += t.text.length >= 2 ? pad2(second) : String(second);
|
|
453
465
|
break;
|
|
454
|
-
case "ampm":
|
|
455
|
-
out += ampmLabel(t.text);
|
|
456
|
-
break;
|
|
466
|
+
case "ampm": out += ampmLabel(t.text);
|
|
457
467
|
}
|
|
458
468
|
return out;
|
|
459
469
|
}
|
|
@@ -469,23 +479,28 @@ function excelExponent(rendered) {
|
|
|
469
479
|
return `${m[1]}E${m[2] === "-" ? "-" : "+"}${m[3].padStart(2, "0")}`;
|
|
470
480
|
}
|
|
471
481
|
/**
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
*
|
|
482
|
+
* The most characters General writes in a cell, its sign apart: however wide
|
|
483
|
+
* the column, 123456789012345 is 1.23457E+14 and 0.123456789012345 is
|
|
484
|
+
* 0.123456789 — Excel's own PDF (2026-10-02).
|
|
485
|
+
*/
|
|
486
|
+
var GENERAL_CELL_CHARS = 11;
|
|
487
|
+
/**
|
|
488
|
+
* A General number in its column: the most precise of the ways General may
|
|
489
|
+
* write it ({@link generalRenderings}) that `fits`.
|
|
479
490
|
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
491
|
+
* General is not a fixed format: a spreadsheet shows as many places as the
|
|
492
|
+
* column has room for and ROUNDS to that, so 4.3900875881221957 in a column
|
|
493
|
+
* eight characters wide reads 4.390088. We rendered every stored digit and let
|
|
494
|
+
* the cell clip it, which turns the same value into 4.390087 — off by one in
|
|
495
|
+
* the last place shown, with nothing to say a digit was cut. A number too wide
|
|
496
|
+
* for every way of writing it comes back in its finest, and the cell fills
|
|
497
|
+
* with `#` (CellProperties.hashOnOverflow); one under 1 always fits as `0` or
|
|
498
|
+
* `-0`, which is what Excel prints in a column too narrow for anything else.
|
|
482
499
|
*
|
|
483
|
-
* `fits` decides
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
* truncation this exists to prevent. Fewer digits than the reference shows is a
|
|
488
|
-
* coarser number; a clipped one is a different number.
|
|
500
|
+
* `fits` decides whether a rendering has room. The print model asks it in the
|
|
501
|
+
* document's own terms — the column's width less the padding it carries, in
|
|
502
|
+
* the font's widest digits — because that is the room Excel gives up places
|
|
503
|
+
* against, whatever face the page is drawn in.
|
|
489
504
|
*
|
|
490
505
|
* @param rawValue The cell's stored value.
|
|
491
506
|
* @param fits Whether a rendering will fit the cell.
|
|
@@ -493,36 +508,100 @@ function excelExponent(rendered) {
|
|
|
493
508
|
function generalToWidth(rawValue, fits) {
|
|
494
509
|
const n = Number(rawValue);
|
|
495
510
|
if (!Number.isFinite(n)) return defaultNumberRender(rawValue);
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
let shortened = full;
|
|
501
|
-
for (let decimals = full.length - dot - 2; decimals >= 0; decimals--) {
|
|
502
|
-
const shifted = Number(`${Number(n.toPrecision(15))}e${decimals}`);
|
|
503
|
-
const rounded = shifted < 0 ? -Math.round(-shifted) : Math.round(shifted);
|
|
504
|
-
const back = Number(`${rounded}e${-decimals}`);
|
|
505
|
-
if (!Number.isFinite(back)) break;
|
|
506
|
-
shortened = defaultNumberRender(String(back));
|
|
507
|
-
if (fits(shortened)) return shortened;
|
|
511
|
+
let widest;
|
|
512
|
+
for (const text of generalRenderings(n, GENERAL_CELL_CHARS)) {
|
|
513
|
+
if (fits(text)) return text;
|
|
514
|
+
widest ??= text;
|
|
508
515
|
}
|
|
509
|
-
return
|
|
516
|
+
return widest ?? defaultNumberRender(rawValue);
|
|
510
517
|
}
|
|
511
518
|
/**
|
|
512
|
-
* `value` in
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
519
|
+
* Every way General may write `value` in `chars` characters, the most precise
|
|
520
|
+
* first. One rule, measured in Excel's own PDF on chart axes, which give it
|
|
521
|
+
* nine characters with the sign among them, and in cells, eleven with the
|
|
522
|
+
* sign apart (2026-10-01/02):
|
|
523
|
+
*
|
|
524
|
+
* - the number as it is, its first 15 significant digits, where that fits:
|
|
525
|
+
* 0.000012345, 0.0000003, 12345678901;
|
|
526
|
+
* - else rounded to fewer places or written in scientific notation, whichever
|
|
527
|
+
* keeps the finer last digit — 0.123456789, not 1.23457E-01; 1.23457E-10,
|
|
528
|
+
* not 0; 4E-04, not 0, in a column five characters wide — and of two as
|
|
529
|
+
* fine, the plain one down to 0.0001 and the scientific one below it: 0.0001
|
|
530
|
+
* for 0.000123456 but 1E-05 for 1.00049E-05;
|
|
531
|
+
* - a whole part longer than the room only in scientific notation, and never
|
|
532
|
+
* with the zeros a mantissa or a fraction ends in: 1E+10, 2.5E+12.
|
|
533
|
+
*
|
|
534
|
+
* The digits are the 15 of {@link decimalOf}, rounded half away from zero, so
|
|
535
|
+
* 1.2345E-05 is 1.235E-05, where `toExponential` rounded the binary double
|
|
536
|
+
* down to 1.234E-05.
|
|
537
|
+
*
|
|
538
|
+
* @param value The number.
|
|
539
|
+
* @param chars How many characters General has.
|
|
540
|
+
* @param signCounts Whether a minus sign takes one of them.
|
|
541
|
+
* @returns The renderings, sign included, finest first.
|
|
516
542
|
*/
|
|
517
|
-
function
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
543
|
+
function* generalRenderings(value, chars, signCounts = false) {
|
|
544
|
+
if (value === 0 || !Number.isFinite(value)) {
|
|
545
|
+
yield value === 0 ? "0" : String(value);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const sign = value < 0 ? "-" : "";
|
|
549
|
+
const room = chars - (signCounts ? sign.length : 0);
|
|
550
|
+
const { digits, exponent } = decimalOf(value);
|
|
551
|
+
let shown = digits.length;
|
|
552
|
+
while (shown > 1 && digits[shown - 1] === "0") shown--;
|
|
553
|
+
const exactPlaces = Math.max(0, shown - 1 - exponent);
|
|
554
|
+
const exact = placeDigits(digits, exponent, exactPlaces);
|
|
555
|
+
if (exact.length <= room) yield sign + exact;
|
|
556
|
+
const forms = [];
|
|
557
|
+
if (exponent < room) {
|
|
558
|
+
const most = Math.min(exactPlaces, room - Math.max(exponent, 0) - 2);
|
|
559
|
+
for (let places = Math.max(0, most); places >= 0; places--) {
|
|
560
|
+
const text = withoutTrailingZeros(placeDigits(digits, exponent, places));
|
|
561
|
+
if (text.length <= room) forms.push({
|
|
562
|
+
text,
|
|
563
|
+
place: -decimalsIn(text),
|
|
564
|
+
plain: true
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const tail = (e) => `E${e < 0 ? "-" : "+"}${String(Math.abs(e)).padStart(2, "0")}`;
|
|
569
|
+
for (let places = Math.max(0, room - tail(exponent).length - 2); places >= 0; places--) {
|
|
570
|
+
let e = exponent;
|
|
571
|
+
let mantissa = placeDigits(digits, 0, places);
|
|
572
|
+
if (mantissa.length > 1 && mantissa[1] !== ".") {
|
|
573
|
+
e += 1;
|
|
574
|
+
mantissa = placeDigits("1", 0, places);
|
|
575
|
+
}
|
|
576
|
+
const stripped = withoutTrailingZeros(mantissa);
|
|
577
|
+
const text = stripped + tail(e);
|
|
578
|
+
if (text.length <= room) forms.push({
|
|
579
|
+
text,
|
|
580
|
+
place: e - decimalsIn(stripped),
|
|
581
|
+
plain: false
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
const plainFirst = exponent >= -4;
|
|
585
|
+
forms.sort((a, b) => a.place - b.place || (a.plain === b.plain ? 0 : a.plain === plainFirst ? -1 : 1));
|
|
586
|
+
const seen = new Set(exact.length <= room ? [exact] : []);
|
|
587
|
+
for (const form of forms) {
|
|
588
|
+
if (seen.has(form.text)) continue;
|
|
589
|
+
seen.add(form.text);
|
|
590
|
+
yield sign + form.text;
|
|
522
591
|
}
|
|
523
592
|
}
|
|
524
|
-
/**
|
|
525
|
-
|
|
593
|
+
/** A decimal without the zeros that end its fraction, nor a point left bare. */
|
|
594
|
+
function withoutTrailingZeros(fixed) {
|
|
595
|
+
if (!fixed.includes(".")) return fixed;
|
|
596
|
+
let end = fixed.length;
|
|
597
|
+
while (fixed[end - 1] === "0") end--;
|
|
598
|
+
return fixed.slice(0, fixed[end - 1] === "." ? end - 1 : end);
|
|
599
|
+
}
|
|
600
|
+
/** How many places a plain decimal shows after its point. */
|
|
601
|
+
var decimalsIn = (fixed) => {
|
|
602
|
+
const dot = fixed.indexOf(".");
|
|
603
|
+
return dot < 0 ? 0 : fixed.length - dot - 1;
|
|
604
|
+
};
|
|
526
605
|
function applyFormatString(rawValue, format) {
|
|
527
606
|
const n = Number(rawValue);
|
|
528
607
|
const sections = splitSections(format);
|
|
@@ -571,6 +650,43 @@ function countDigitPlaceholders(s) {
|
|
|
571
650
|
return n;
|
|
572
651
|
}
|
|
573
652
|
/**
|
|
653
|
+
* The decimal a spreadsheet takes a double for: its first 15 significant
|
|
654
|
+
* digits, and the power of ten the first of them stands at.
|
|
655
|
+
*
|
|
656
|
+
* Excel shows a number as those 15 digits and zeros after them, however many
|
|
657
|
+
* places its format asks for: 0.1 under thirty places is 0.1 and twenty-nine
|
|
658
|
+
* zeros, 1/3 is fifteen threes and zeros, 1E+21 under `0.00` is a 1, twenty-one
|
|
659
|
+
* zeros and `.00` — its own PDF of each (2026-10-01).
|
|
660
|
+
*/
|
|
661
|
+
function decimalOf(value) {
|
|
662
|
+
const [mantissa, exponent] = Math.abs(value).toExponential(14).split("e");
|
|
663
|
+
return {
|
|
664
|
+
digits: mantissa.replace(".", ""),
|
|
665
|
+
exponent: Number(exponent)
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Those digits at `decimals` places — the first standing at `exponent` —
|
|
670
|
+
* rounded half away from zero, as plain digits with a point and no sign.
|
|
671
|
+
*/
|
|
672
|
+
function placeDigits(digits, exponent, decimals) {
|
|
673
|
+
const kept = exponent + 1 + decimals;
|
|
674
|
+
let units;
|
|
675
|
+
if (kept >= digits.length) units = digits + "0".repeat(kept - digits.length);
|
|
676
|
+
else if (kept < 0) units = "";
|
|
677
|
+
else units = digits[kept] >= "5" ? incremented(digits.slice(0, kept)) : digits.slice(0, kept);
|
|
678
|
+
const padded = units.replace(/^0+/, "").padStart(decimals + 1, "0");
|
|
679
|
+
const whole = padded.slice(0, padded.length - decimals);
|
|
680
|
+
return decimals > 0 ? `${whole}.${padded.slice(whole.length)}` : whole;
|
|
681
|
+
}
|
|
682
|
+
/** A string of decimal digits plus one. */
|
|
683
|
+
function incremented(digits) {
|
|
684
|
+
let at = digits.length - 1;
|
|
685
|
+
while (at >= 0 && digits[at] === "9") at--;
|
|
686
|
+
if (at < 0) return `1${"0".repeat(digits.length)}`;
|
|
687
|
+
return `${digits.slice(0, at)}${String(Number(digits[at]) + 1)}${"0".repeat(digits.length - at - 1)}`;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
574
690
|
* `value` rounded to `decimals` places the way a spreadsheet rounds: on the
|
|
575
691
|
* DECIMAL number, half away from zero.
|
|
576
692
|
*
|
|
@@ -580,21 +696,19 @@ function countDigitPlaceholders(s) {
|
|
|
580
696
|
* every other reader show 1.0%. AverageTaxRates.xlsx had eleven of its
|
|
581
697
|
* percentages a tenth low for exactly this reason.
|
|
582
698
|
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
699
|
+
* The digits are the 15 of {@link decimalOf} and zeros after them, placed by
|
|
700
|
+
* hand: past seventeen significant digits `toFixed` printed the binary
|
|
701
|
+
* expansion (0.1 under twenty places as 0.10000000000000000555), from 1E+21 on
|
|
702
|
+
* it wrote the exponent (`1e+21.00`), and past a hundred places it threw.
|
|
586
703
|
*/
|
|
587
704
|
function toFixedDecimal(value, decimals) {
|
|
588
|
-
if (!Number.isFinite(value)) return value
|
|
589
|
-
const
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
const rounded = shifted < 0 ? -Math.round(-shifted) : Math.round(shifted);
|
|
593
|
-
const back = Number(`${rounded}e${-decimals}`);
|
|
594
|
-
return Number.isFinite(back) ? back.toFixed(decimals) : value.toFixed(decimals);
|
|
705
|
+
if (!Number.isFinite(value)) return String(value);
|
|
706
|
+
const { digits, exponent } = decimalOf(value);
|
|
707
|
+
const placed = placeDigits(digits, exponent, decimals);
|
|
708
|
+
return value < 0 && /[1-9]/.test(placed) ? `-${placed}` : placed;
|
|
595
709
|
}
|
|
596
710
|
function formatScientific(value, cleaned, negativeSection) {
|
|
597
|
-
const m = /^(.*?)([eE])([+-])(.*)$/.exec(cleaned);
|
|
711
|
+
const m = hasLineEnd(cleaned) ? null : /^(.*?)([eE])([+-])(.*)$/.exec(cleaned);
|
|
598
712
|
if (!m) return cleaned;
|
|
599
713
|
const mantissaFmt = m[1];
|
|
600
714
|
const eChar = m[2];
|
|
@@ -604,17 +718,16 @@ function formatScientific(value, cleaned, negativeSection) {
|
|
|
604
718
|
const intDigits = Math.max(1, countDigitPlaceholders(dot >= 0 ? mantissaFmt.slice(0, dot) : mantissaFmt));
|
|
605
719
|
const decimals = dot >= 0 ? countDigitPlaceholders(mantissaFmt.slice(dot + 1)) : 0;
|
|
606
720
|
let exp = 0;
|
|
607
|
-
let
|
|
608
|
-
if (
|
|
609
|
-
|
|
610
|
-
exp
|
|
611
|
-
|
|
612
|
-
if (
|
|
721
|
+
let mantStr = placeDigits("0", 0, decimals);
|
|
722
|
+
if (value !== 0) {
|
|
723
|
+
const { digits, exponent } = decimalOf(value);
|
|
724
|
+
exp = exponent - (exponent % intDigits + intDigits) % intDigits;
|
|
725
|
+
mantStr = placeDigits(digits, exponent - exp, decimals);
|
|
726
|
+
if (mantStr.split(".")[0].length > intDigits) {
|
|
613
727
|
exp += intDigits;
|
|
614
|
-
|
|
728
|
+
mantStr = placeDigits(digits, exponent - exp, decimals);
|
|
615
729
|
}
|
|
616
730
|
}
|
|
617
|
-
const mantStr = mant.toFixed(decimals);
|
|
618
731
|
const expDigits = countDigitPlaceholders(expFmt) || 2;
|
|
619
732
|
const expStr = String(Math.abs(exp)).padStart(expDigits, "0");
|
|
620
733
|
return `${value < 0 && !negativeSection ? "-" : ""}${mantStr}${eChar}${exp < 0 ? "-" : expSignFmt === "+" ? "+" : ""}${expStr}`;
|
|
@@ -629,11 +742,77 @@ function formatScientific(value, cleaned, negativeSection) {
|
|
|
629
742
|
* conditions) is decoration here and goes.
|
|
630
743
|
*/
|
|
631
744
|
function resolveBracketCodes(format) {
|
|
632
|
-
return format
|
|
745
|
+
return replaceBracketCodes(format, (body) => {
|
|
633
746
|
const symbol = /^\$([^-]*)(?:-.*)?$/.exec(body)?.[1]?.replace(/"/g, "") ?? "";
|
|
634
747
|
return symbol.length > 0 ? `"${symbol}"` : "";
|
|
635
748
|
});
|
|
636
749
|
}
|
|
750
|
+
var isPlaceholder = (c) => c === "0" || c === "#" || c === "?";
|
|
751
|
+
var isAsciiDigit = (c) => c !== void 0 && c >= "0" && c <= "9";
|
|
752
|
+
var isSpace = (c) => c !== void 0 && /\s/.test(c);
|
|
753
|
+
var isLineEnd = (c) => c === 10 || c === 13 || c === 8232 || c === 8233;
|
|
754
|
+
function hasLineEnd(s) {
|
|
755
|
+
for (let i = 0; i < s.length; i++) if (isLineEnd(s.charCodeAt(i))) return true;
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* A fraction section cut into head, numerator, denominator and tail — what
|
|
760
|
+
* `/^(.*?)([0#?]+)\s*\/\s*([0#?]+|\d+)(.*)$/` makes of it, in one pass. The
|
|
761
|
+
* expression, lazy at the front, took every position of a run of placeholders
|
|
762
|
+
* in turn as the start of the numerator and read the rest of the run from
|
|
763
|
+
* each: quadratic in a long run no slash follows. A start inside a run sees
|
|
764
|
+
* the same rest as the run's first, so only the first is tried. The head
|
|
765
|
+
* cannot cross a line end, nor the tail hold one.
|
|
766
|
+
*/
|
|
767
|
+
function fractionParts(s) {
|
|
768
|
+
let firstEnd = s.length;
|
|
769
|
+
let lastEnd = -1;
|
|
770
|
+
for (let i = 0; i < s.length; i++) {
|
|
771
|
+
if (!isLineEnd(s.charCodeAt(i))) continue;
|
|
772
|
+
firstEnd = Math.min(firstEnd, i);
|
|
773
|
+
lastEnd = i;
|
|
774
|
+
}
|
|
775
|
+
for (let start = 0; start < firstEnd;) {
|
|
776
|
+
if (!isPlaceholder(s[start])) {
|
|
777
|
+
start++;
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
let numEnd = start;
|
|
781
|
+
while (isPlaceholder(s[numEnd])) numEnd++;
|
|
782
|
+
let slash = numEnd;
|
|
783
|
+
while (isSpace(s[slash])) slash++;
|
|
784
|
+
if (s[slash] === "/") {
|
|
785
|
+
let den = slash + 1;
|
|
786
|
+
while (isSpace(s[den])) den++;
|
|
787
|
+
let denEnd = den;
|
|
788
|
+
const inDen = isPlaceholder(s[den]) ? isPlaceholder : isAsciiDigit;
|
|
789
|
+
while (inDen(s[denEnd])) denEnd++;
|
|
790
|
+
if (denEnd > den && lastEnd < denEnd) return {
|
|
791
|
+
head: s.slice(0, start),
|
|
792
|
+
num: s.slice(start, numEnd),
|
|
793
|
+
den: s.slice(den, denEnd),
|
|
794
|
+
tail: s.slice(denEnd)
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
start = numEnd;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* The last run of placeholders in the head and what follows it — what
|
|
802
|
+
* `/([0#?]+)([^0#?]*)$/` matches, read back from the end: that expression
|
|
803
|
+
* retried every placeholder of an earlier run, and is quadratic in a long one.
|
|
804
|
+
*/
|
|
805
|
+
function lastPlaceholderRun(head) {
|
|
806
|
+
let end = head.length;
|
|
807
|
+
while (end > 0 && !isPlaceholder(head[end - 1])) end--;
|
|
808
|
+
if (end === 0) return void 0;
|
|
809
|
+
let at = end - 1;
|
|
810
|
+
while (at > 0 && isPlaceholder(head[at - 1])) at--;
|
|
811
|
+
return {
|
|
812
|
+
at,
|
|
813
|
+
after: head.slice(end)
|
|
814
|
+
};
|
|
815
|
+
}
|
|
637
816
|
/**
|
|
638
817
|
* §18.8.31 fraction formats — `# ?/?`, `# ??/??`, `?/?`, `# ?/16`.
|
|
639
818
|
*
|
|
@@ -644,15 +823,13 @@ function resolveBracketCodes(format) {
|
|
|
644
823
|
* section is not a fraction, leaving the ordinary grammar to run.
|
|
645
824
|
*/
|
|
646
825
|
function formatFraction(value, cleaned, negativeSection) {
|
|
647
|
-
const m =
|
|
826
|
+
const m = fractionParts(cleaned);
|
|
648
827
|
if (!m) return void 0;
|
|
649
|
-
const head = m
|
|
650
|
-
const
|
|
651
|
-
const
|
|
652
|
-
const
|
|
653
|
-
const
|
|
654
|
-
const literalPrefix = unquoteLiteral(head.substring(0, intMatch ? intMatch.index : head.length));
|
|
655
|
-
const separator = intMatch ? unquoteLiteral(intMatch[2]) : " ";
|
|
828
|
+
const { head, den: denFmt, tail } = m;
|
|
829
|
+
const intMatch = lastPlaceholderRun(head);
|
|
830
|
+
const hasInteger = intMatch !== void 0;
|
|
831
|
+
const literalPrefix = unquoteLiteral(head.substring(0, intMatch ? intMatch.at : head.length));
|
|
832
|
+
const separator = intMatch ? unquoteLiteral(intMatch.after) : " ";
|
|
656
833
|
const magnitude = Math.abs(value);
|
|
657
834
|
const whole = hasInteger ? Math.floor(magnitude) : 0;
|
|
658
835
|
const rest = magnitude - whole;
|
|
@@ -724,7 +901,7 @@ function applyNumericSection(value, format, negativeSection) {
|
|
|
724
901
|
for (let i = 0; i < intPlaceholders.length - significant.length; i++) if (intPlaceholders[i] === "0") zeros += "0";
|
|
725
902
|
else if (intPlaceholders[i] === "?") spaces += " ";
|
|
726
903
|
const intDigits = zeros + significant;
|
|
727
|
-
let numberPart = spaces + (useThousands ? intDigits
|
|
904
|
+
let numberPart = spaces + (useThousands ? groupThousands(intDigits) : intDigits);
|
|
728
905
|
if (decimals > 0) {
|
|
729
906
|
let dec = decRaw ?? "".padEnd(decimals, "0");
|
|
730
907
|
if (dec.length < decimals) dec = dec.padEnd(decimals, "0");
|
|
@@ -739,6 +916,34 @@ function applyNumericSection(value, format, negativeSection) {
|
|
|
739
916
|
if (value < 0 && !negativeSection) signPrefix = "-";
|
|
740
917
|
return `${literalPrefix}${signPrefix}${numberPart}${isPercent ? "%" : ""}${literalSuffix}`;
|
|
741
918
|
}
|
|
919
|
+
/**
|
|
920
|
+
* The digits with a comma before every third from the right of each run — what
|
|
921
|
+
* `/\B(?=(\d{3})+(?!\d))/g` puts one at — in one pass. That expression read
|
|
922
|
+
* ahead over the rest of the run from every position, and the run is as long
|
|
923
|
+
* as the format has zeros, applied in every cell the format shows. A comma
|
|
924
|
+
* goes where the rest of the run is a whole number of threes and the character
|
|
925
|
+
* before is a word character, as `\B` asks: a digit inside the run, a letter
|
|
926
|
+
* at its start.
|
|
927
|
+
*/
|
|
928
|
+
function groupThousands(s) {
|
|
929
|
+
const isWord = (i) => i >= 0 && /\w/.test(s[i]);
|
|
930
|
+
let out = "";
|
|
931
|
+
let from = 0;
|
|
932
|
+
for (let start = 0; start < s.length;) {
|
|
933
|
+
if (!isAsciiDigit(s[start])) {
|
|
934
|
+
start++;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
let end = start;
|
|
938
|
+
while (isAsciiDigit(s[end])) end++;
|
|
939
|
+
for (let at = start; at < end; at++) if ((end - at) % 3 === 0 && isWord(at - 1)) {
|
|
940
|
+
out += `${s.slice(from, at)},`;
|
|
941
|
+
from = at;
|
|
942
|
+
}
|
|
943
|
+
start = end;
|
|
944
|
+
}
|
|
945
|
+
return out + s.slice(from);
|
|
946
|
+
}
|
|
742
947
|
function splitNumberFormat(cleaned) {
|
|
743
948
|
let firstDigit = -1;
|
|
744
949
|
let lastDigit = -1;
|
|
@@ -802,4 +1007,4 @@ function unquoteLiteral(s) {
|
|
|
802
1007
|
return out;
|
|
803
1008
|
}
|
|
804
1009
|
//#endregion
|
|
805
|
-
export { applyNumberFormat, excelSerialFromUtcParts, excelSerialToDate, generalToWidth, numberFormatColorHex };
|
|
1010
|
+
export { applyNumberFormat, excelSerialFromUtcParts, excelSerialToDate, generalRenderings, generalToWidth, numberFormatColorHex };
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import "./state.js";
|
|
2
|
-
import "./apply.js";
|
|
1
|
+
import { formatCounter } from "./state.js";
|
|
2
|
+
import { applyNumbering, applyNumberingToHeadersFooters } from "./apply.js";
|
|
3
|
+
export { applyNumbering, applyNumberingToHeadersFooters, formatCounter };
|
package/dist/esm/core/ole/cfb.js
CHANGED
|
@@ -13,7 +13,7 @@ var ENDOFCHAIN = 4294967294;
|
|
|
13
13
|
var FREESECT = 4294967295;
|
|
14
14
|
var HEADER_SIZE = 512;
|
|
15
15
|
var DIR_ENTRY_SIZE = 128;
|
|
16
|
-
var MAX_TOTAL_BYTES =
|
|
16
|
+
var MAX_TOTAL_BYTES = 536870912;
|
|
17
17
|
/** Error thrown for a malformed or unsupported compound file. */
|
|
18
18
|
var CfbError = class extends Error {};
|
|
19
19
|
/**
|
|
@@ -134,7 +134,7 @@ function openCfb(bytes) {
|
|
|
134
134
|
const ensureMini = () => {
|
|
135
135
|
if (miniStream && miniFat) return;
|
|
136
136
|
miniStream = readChainBytes(root.startSector, MAX_TOTAL_BYTES).subarray(0, root.size);
|
|
137
|
-
const mfBytes = firstMiniFatSector === ENDOFCHAIN ? new Uint8Array(0) : readChainBytes(firstMiniFatSector, MAX_TOTAL_BYTES);
|
|
137
|
+
const mfBytes = firstMiniFatSector === ENDOFCHAIN ? /* @__PURE__ */ new Uint8Array(0) : readChainBytes(firstMiniFatSector, MAX_TOTAL_BYTES);
|
|
138
138
|
const mfView = new DataView(mfBytes.buffer, mfBytes.byteOffset, mfBytes.byteLength);
|
|
139
139
|
miniFat = new Uint32Array(Math.floor(mfBytes.length / 4));
|
|
140
140
|
for (let i = 0; i < miniFat.length; i++) miniFat[i] = mfView.getUint32(i * 4, true);
|
|
@@ -159,7 +159,7 @@ function openCfb(bytes) {
|
|
|
159
159
|
return out;
|
|
160
160
|
};
|
|
161
161
|
const readEntry = (entry) => {
|
|
162
|
-
if (entry.size === 0) return new Uint8Array(0);
|
|
162
|
+
if (entry.size === 0) return /* @__PURE__ */ new Uint8Array(0);
|
|
163
163
|
if (entry.size > MAX_TOTAL_BYTES) throw new CfbError("stream exceeds size limit");
|
|
164
164
|
if (entry.size >= miniCutoff) return readChainBytes(entry.startSector, MAX_TOTAL_BYTES).subarray(0, entry.size);
|
|
165
165
|
return readMiniStream(entry);
|
|
@@ -201,4 +201,4 @@ function decodeName(dir, base, nameLen) {
|
|
|
201
201
|
return out;
|
|
202
202
|
}
|
|
203
203
|
//#endregion
|
|
204
|
-
export { isCfb, openCfb };
|
|
204
|
+
export { CfbError, isCfb, openCfb };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import "./relationship-types.js";
|
|
2
|
-
import "./package.js";
|
|
3
|
-
import "./core-properties.js";
|
|
4
|
-
import "./opc-writer.js";
|
|
1
|
+
import { isOoxmlRel } from "./relationship-types.js";
|
|
2
|
+
import { OpcPackage } from "./package.js";
|
|
3
|
+
import { parseCoreProperties } from "./core-properties.js";
|
|
4
|
+
import { buildOpcPackage } from "./opc-writer.js";
|
|
5
|
+
export { OpcPackage, buildOpcPackage, isOoxmlRel, parseCoreProperties };
|
|
@@ -3,13 +3,15 @@ import { isOoxmlRel } from "./relationship-types.js";
|
|
|
3
3
|
import { unzipSync } from "fflate";
|
|
4
4
|
//#region src/core/opc/package.ts
|
|
5
5
|
var ROOT_RELS_PATH = "_rels/.rels";
|
|
6
|
-
var MIB =
|
|
6
|
+
var MIB = 1048576;
|
|
7
7
|
/**
|
|
8
8
|
* An opened OPC package (ECMA-376 Part 2): a ZIP archive's parts plus its
|
|
9
9
|
* package-level relationships, with helpers to look up parts, resolve part
|
|
10
10
|
* relationships, and find the main document part.
|
|
11
11
|
*/
|
|
12
12
|
var OpcPackage = class OpcPackage {
|
|
13
|
+
parts;
|
|
14
|
+
rootRelationships;
|
|
13
15
|
/**
|
|
14
16
|
* @param parts The package parts keyed by ZIP-convention path (no leading slash).
|
|
15
17
|
* @param rootRelationships The package-level relationships from `_rels/.rels`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Whether the code unit is one `\w` matches. NaN, past the end, is not. */
|
|
2
|
+
export declare function isWordChar(c: number): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* The matches a global search with `re` finds in `xml` from `from`, in order.
|
|
5
|
+
*
|
|
6
|
+
* @param xml The part's text.
|
|
7
|
+
* @param open The tag's opening, `<w:font`, which `re` begins with.
|
|
8
|
+
* @param boundary Whether `re` puts `\b` right after `open`.
|
|
9
|
+
* @param re The expression, sticky (`y`): `open`, the `\b` if any, then
|
|
10
|
+
* `[^>]*` (greedy or lazy) before what it looks for in the tag.
|
|
11
|
+
* @param from Where the search starts.
|
|
12
|
+
*/
|
|
13
|
+
export declare function tagMatches(xml: string, open: string, boundary: boolean, re: RegExp, from?: number): Generator<RegExpExecArray>;
|
|
14
|
+
/** The first of {@link tagMatches}, or undefined when there is none. */
|
|
15
|
+
export declare function firstTagMatch(xml: string, open: string, boundary: boolean, re: RegExp, from?: number): RegExpExecArray | undefined;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/core/opc/tag-scan.ts
|
|
2
|
+
/** Whether the code unit is one `\w` matches. NaN, past the end, is not. */
|
|
3
|
+
function isWordChar(c) {
|
|
4
|
+
return c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The matches a global search with `re` finds in `xml` from `from`, in order.
|
|
8
|
+
*
|
|
9
|
+
* @param xml The part's text.
|
|
10
|
+
* @param open The tag's opening, `<w:font`, which `re` begins with.
|
|
11
|
+
* @param boundary Whether `re` puts `\b` right after `open`.
|
|
12
|
+
* @param re The expression, sticky (`y`): `open`, the `\b` if any, then
|
|
13
|
+
* `[^>]*` (greedy or lazy) before what it looks for in the tag.
|
|
14
|
+
* @param from Where the search starts.
|
|
15
|
+
*/
|
|
16
|
+
function* tagMatches(xml, open, boundary, re, from = 0) {
|
|
17
|
+
let at = xml.indexOf(open, from);
|
|
18
|
+
while (at >= 0) {
|
|
19
|
+
if (boundary && isWordChar(xml.charCodeAt(at + open.length))) {
|
|
20
|
+
at = xml.indexOf(open, at + 1);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
re.lastIndex = at;
|
|
24
|
+
const found = re.exec(xml);
|
|
25
|
+
if (found) {
|
|
26
|
+
const next = Math.max(re.lastIndex, at + 1);
|
|
27
|
+
yield found;
|
|
28
|
+
at = xml.indexOf(open, next);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const end = xml.indexOf(">", at + open.length);
|
|
32
|
+
if (end < 0) return;
|
|
33
|
+
at = xml.indexOf(open, end + 1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** The first of {@link tagMatches}, or undefined when there is none. */
|
|
37
|
+
function firstTagMatch(xml, open, boundary, re, from = 0) {
|
|
38
|
+
for (const found of tagMatches(xml, open, boundary, re, from)) return found;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { firstTagMatch, isWordChar, tagMatches };
|