@usejunior/docx-core 0.1.2 → 0.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.
Files changed (79) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/baselines/atomizer/consumerCompatibility.d.ts +2 -0
  3. package/dist/baselines/atomizer/consumerCompatibility.d.ts.map +1 -0
  4. package/dist/baselines/atomizer/consumerCompatibility.js +188 -0
  5. package/dist/baselines/atomizer/consumerCompatibility.js.map +1 -0
  6. package/dist/baselines/atomizer/documentReconstructor.d.ts.map +1 -1
  7. package/dist/baselines/atomizer/documentReconstructor.js +82 -42
  8. package/dist/baselines/atomizer/documentReconstructor.js.map +1 -1
  9. package/dist/baselines/atomizer/inPlaceModifier.d.ts +15 -1
  10. package/dist/baselines/atomizer/inPlaceModifier.d.ts.map +1 -1
  11. package/dist/baselines/atomizer/inPlaceModifier.js +111 -16
  12. package/dist/baselines/atomizer/inPlaceModifier.js.map +1 -1
  13. package/dist/baselines/atomizer/pipeline.d.ts +4 -0
  14. package/dist/baselines/atomizer/pipeline.d.ts.map +1 -1
  15. package/dist/baselines/atomizer/pipeline.js +335 -4
  16. package/dist/baselines/atomizer/pipeline.js.map +1 -1
  17. package/dist/benchmark/gates.d.ts +17 -0
  18. package/dist/benchmark/gates.d.ts.map +1 -0
  19. package/dist/benchmark/gates.js +260 -0
  20. package/dist/benchmark/gates.js.map +1 -0
  21. package/dist/benchmark/metrics.d.ts +5 -62
  22. package/dist/benchmark/metrics.d.ts.map +1 -1
  23. package/dist/benchmark/metrics.js +7 -28
  24. package/dist/benchmark/metrics.js.map +1 -1
  25. package/dist/benchmark/reporter.d.ts +6 -19
  26. package/dist/benchmark/reporter.d.ts.map +1 -1
  27. package/dist/benchmark/reporter.js +63 -116
  28. package/dist/benchmark/reporter.js.map +1 -1
  29. package/dist/benchmark/runner.d.ts +11 -26
  30. package/dist/benchmark/runner.d.ts.map +1 -1
  31. package/dist/benchmark/runner.js +191 -183
  32. package/dist/benchmark/runner.js.map +1 -1
  33. package/dist/benchmark/scores.d.ts +24 -0
  34. package/dist/benchmark/scores.d.ts.map +1 -0
  35. package/dist/benchmark/scores.js +103 -0
  36. package/dist/benchmark/scores.js.map +1 -0
  37. package/dist/benchmark/types.d.ts +81 -0
  38. package/dist/benchmark/types.d.ts.map +1 -0
  39. package/dist/benchmark/types.js +7 -0
  40. package/dist/benchmark/types.js.map +1 -0
  41. package/dist/primitives/document.d.ts +12 -0
  42. package/dist/primitives/document.d.ts.map +1 -1
  43. package/dist/primitives/document.js +17 -2
  44. package/dist/primitives/document.js.map +1 -1
  45. package/dist/primitives/document_view.d.ts +5 -1
  46. package/dist/primitives/document_view.d.ts.map +1 -1
  47. package/dist/primitives/document_view.js +46 -19
  48. package/dist/primitives/document_view.js.map +1 -1
  49. package/dist/primitives/formatting_tags.d.ts +22 -9
  50. package/dist/primitives/formatting_tags.d.ts.map +1 -1
  51. package/dist/primitives/formatting_tags.js +166 -92
  52. package/dist/primitives/formatting_tags.js.map +1 -1
  53. package/dist/primitives/matching.d.ts +16 -2
  54. package/dist/primitives/matching.d.ts.map +1 -1
  55. package/dist/primitives/matching.js +93 -14
  56. package/dist/primitives/matching.js.map +1 -1
  57. package/dist/primitives/merge_runs.d.ts.map +1 -1
  58. package/dist/primitives/merge_runs.js +48 -0
  59. package/dist/primitives/merge_runs.js.map +1 -1
  60. package/dist/primitives/namespaces.d.ts +1 -0
  61. package/dist/primitives/namespaces.d.ts.map +1 -1
  62. package/dist/primitives/namespaces.js +1 -0
  63. package/dist/primitives/namespaces.js.map +1 -1
  64. package/dist/primitives/semantic_tags.d.ts +10 -25
  65. package/dist/primitives/semantic_tags.d.ts.map +1 -1
  66. package/dist/primitives/semantic_tags.js +34 -115
  67. package/dist/primitives/semantic_tags.js.map +1 -1
  68. package/dist/primitives/styles.d.ts.map +1 -1
  69. package/dist/primitives/styles.js +21 -6
  70. package/dist/primitives/styles.js.map +1 -1
  71. package/dist/primitives/text.d.ts +3 -0
  72. package/dist/primitives/text.d.ts.map +1 -1
  73. package/dist/primitives/text.js +65 -20
  74. package/dist/primitives/text.js.map +1 -1
  75. package/dist/shared/validators/structural.d.ts +31 -0
  76. package/dist/shared/validators/structural.d.ts.map +1 -0
  77. package/dist/shared/validators/structural.js +110 -0
  78. package/dist/shared/validators/structural.js.map +1 -0
  79. package/package.json +1 -1
@@ -1,4 +1,12 @@
1
1
  import type { RunFormatting } from './styles.js';
2
+ /**
3
+ * Controls formatting tag emission behaviour.
4
+ *
5
+ * - `compact` — 60% threshold suppression (default, current behavior)
6
+ * - `full` — all formatting emitted, no suppression (benchmark mode)
7
+ * - `plain_text` — no formatting tags at all (future: fast text-only views)
8
+ */
9
+ export type FormattingMode = 'compact' | 'full' | 'plain_text';
2
10
  export type AnnotatedRun = {
3
11
  text: string;
4
12
  formatting: RunFormatting;
@@ -12,19 +20,24 @@ export type FormattingBaseline = {
12
20
  underline: boolean;
13
21
  suppressed: boolean;
14
22
  };
15
- export declare function computeModalBaseline(runs: AnnotatedRun[]): FormattingBaseline;
16
- export type DefinitionSpan = {
17
- /** Plain-text offset of the opening quote (inclusive). */
18
- start: number;
19
- /** Plain-text offset one past the closing quote (exclusive). */
20
- end: number;
21
- /** The defined term text (excluding quotes). */
22
- term: string;
23
+ export type FontBaseline = {
24
+ modalColor: string | null;
25
+ colorSuppressed: boolean;
26
+ modalFontSizePt: number;
27
+ fontSizeSuppressed: boolean;
28
+ modalFontName: string;
29
+ fontNameSuppressed: boolean;
23
30
  };
31
+ export declare function computeModalBaseline(runs: AnnotatedRun[], options?: {
32
+ formattingMode?: FormattingMode;
33
+ }): FormattingBaseline;
34
+ export declare function computeParagraphFontBaseline(runs: AnnotatedRun[], options?: {
35
+ formattingMode?: FormattingMode;
36
+ }): FontBaseline;
24
37
  export declare function emitFormattingTags(params: {
25
38
  runs: AnnotatedRun[];
26
39
  baseline: FormattingBaseline;
27
- definitionSpans?: DefinitionSpan[];
40
+ fontBaseline?: FontBaseline | null;
28
41
  }): string;
29
42
  export declare function mergeAdjacentTags(tagged: string): string;
30
43
  //# sourceMappingURL=formatting_tags.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatting_tags.d.ts","sourceRoot":"","sources":["../../src/primitives/formatting_tags.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAYF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,kBAAkB,CAyC7E;AAyED,MAAM,MAAM,cAAc,GAAG;IAC3B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACpC,GAAG,MAAM,CA2ET;AA8BD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAaxD"}
1
+ {"version":3,"file":"formatting_tags.d.ts","sourceRoot":"","sources":["../../src/primitives/formatting_tags.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,YAAY,CAAC;AAI/D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAYF,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAAE,EACpB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,cAAc,CAAA;CAAE,GAC5C,kBAAkB,CA2CpB;AAgED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,YAAY,EAAE,EACpB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,cAAc,CAAA;CAAE,GAC5C,YAAY,CAcd;AA2ID,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACpC,GAAG,MAAM,CAwBT;AAOD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0BxD"}
@@ -1,17 +1,18 @@
1
1
  // Inline formatting tag emission for run-level formatting visibility in TOON output.
2
2
  //
3
- // Adds <b>, <i>, <u>, <highlighting>, and <a href="..."> tags around runs that
4
- // deviate from a char-weighted modal baseline. When >=60% of non-header body
5
- // chars share the same (bold, italic, underline) tuple, that tuple becomes the
6
- // suppressed baseline and only deviating runs get b/i/u tags. Below 60%, runs
7
- // emit absolute b/i/u tags.
3
+ // Adds <b>, <i>, <u>, <highlighting>, <font>, and <a href="..."> tags around runs that
4
+ // deviate from baselines. BIU uses a document-wide char-weighted modal baseline.
5
+ // Font properties (color, size, face) use paragraph-local baselines.
6
+ // When >=60% of non-header body chars share the same tuple/value, that becomes the
7
+ // suppressed baseline and only deviating runs get tags.
8
8
  import { HIGHLIGHT_TAG } from './semantic_tags.js';
9
9
  // ── Baseline computation ─────────────────────────────────────────────
10
10
  const SUPPRESSION_THRESHOLD = 0.60;
11
11
  function fmtKey(bold, italic, underline) {
12
12
  return `${bold}|${italic}|${underline}`;
13
13
  }
14
- export function computeModalBaseline(runs) {
14
+ export function computeModalBaseline(runs, options) {
15
+ const mode = options?.formattingMode ?? 'compact';
15
16
  // Only consider non-header body runs for baseline computation.
16
17
  const bodyRuns = runs.filter((r) => !r.isHeaderRun && r.charCount > 0);
17
18
  const totalChars = bodyRuns.reduce((sum, r) => sum + r.charCount, 0);
@@ -45,15 +46,92 @@ export function computeModalBaseline(runs) {
45
46
  const bold = boldStr === 'true';
46
47
  const italic = italicStr === 'true';
47
48
  const underline = underlineStr === 'true';
48
- const suppressed = bestChars / totalChars >= SUPPRESSION_THRESHOLD;
49
+ const suppressed = mode === 'compact' && bestChars / totalChars >= SUPPRESSION_THRESHOLD;
49
50
  return { bold, italic, underline, suppressed };
50
51
  }
52
+ // ── Paragraph-local font baseline ───────────────────────────────────
53
+ function computeModalString(runs, extract, mode = 'compact') {
54
+ const bodyRuns = runs.filter((r) => !r.isHeaderRun && r.charCount > 0);
55
+ const totalChars = bodyRuns.reduce((sum, r) => sum + r.charCount, 0);
56
+ if (totalChars === 0)
57
+ return { modal: null, suppressed: false };
58
+ const counts = new Map();
59
+ for (const r of bodyRuns) {
60
+ const val = extract(r) ?? '';
61
+ counts.set(val, (counts.get(val) ?? 0) + r.charCount);
62
+ }
63
+ let bestVal = '';
64
+ let bestChars = 0;
65
+ for (const [val, chars] of counts) {
66
+ if (chars > bestChars) {
67
+ bestVal = val;
68
+ bestChars = chars;
69
+ }
70
+ }
71
+ return {
72
+ modal: bestVal || null,
73
+ suppressed: mode === 'compact' && bestChars / totalChars >= SUPPRESSION_THRESHOLD,
74
+ };
75
+ }
76
+ function computeModalNumber(runs, extract, mode = 'compact') {
77
+ const bodyRuns = runs.filter((r) => !r.isHeaderRun && r.charCount > 0);
78
+ const totalChars = bodyRuns.reduce((sum, r) => sum + r.charCount, 0);
79
+ if (totalChars === 0)
80
+ return { modal: 0, suppressed: false };
81
+ const counts = new Map();
82
+ for (const r of bodyRuns) {
83
+ const val = extract(r);
84
+ counts.set(val, (counts.get(val) ?? 0) + r.charCount);
85
+ }
86
+ let bestVal = 0;
87
+ let bestChars = 0;
88
+ for (const [val, chars] of counts) {
89
+ if (chars > bestChars) {
90
+ bestVal = val;
91
+ bestChars = chars;
92
+ }
93
+ }
94
+ return {
95
+ modal: bestVal,
96
+ suppressed: mode === 'compact' && bestChars / totalChars >= SUPPRESSION_THRESHOLD,
97
+ };
98
+ }
99
+ export function computeParagraphFontBaseline(runs, options) {
100
+ const mode = options?.formattingMode ?? 'compact';
101
+ const color = computeModalString(runs, (r) => r.formatting.colorHex, mode);
102
+ const fontSize = computeModalNumber(runs, (r) => r.formatting.fontSizePt, mode);
103
+ const fontName = computeModalString(runs, (r) => r.formatting.fontName, mode);
104
+ return {
105
+ modalColor: color.modal,
106
+ colorSuppressed: color.suppressed,
107
+ modalFontSizePt: fontSize.modal,
108
+ fontSizeSuppressed: fontSize.suppressed,
109
+ modalFontName: fontName.modal ?? '',
110
+ fontNameSuppressed: fontName.suppressed,
111
+ };
112
+ }
51
113
  function tagsEqual(a, b) {
52
114
  return (a.hyperlinkUrl === b.hyperlinkUrl &&
53
115
  a.bold === b.bold &&
54
116
  a.italic === b.italic &&
55
117
  a.underline === b.underline &&
56
- a.highlighting === b.highlighting);
118
+ a.highlighting === b.highlighting &&
119
+ a.color === b.color &&
120
+ a.fontSize === b.fontSize &&
121
+ a.fontName === b.fontName);
122
+ }
123
+ function fontTagString(tags) {
124
+ const attrs = [];
125
+ if (tags.color !== null)
126
+ attrs.push(`color="${tags.color}"`);
127
+ if (tags.fontSize !== null)
128
+ attrs.push(`size="${tags.fontSize}"`);
129
+ if (tags.fontName !== null)
130
+ attrs.push(`face="${tags.fontName}"`);
131
+ return attrs.length > 0 ? `<font ${attrs.join(' ')}>` : null;
132
+ }
133
+ function hasFontAttrs(tags) {
134
+ return tags.color !== null || tags.fontSize !== null || tags.fontName !== null;
57
135
  }
58
136
  function closeTags(out, tags) {
59
137
  if (tags.highlighting)
@@ -64,6 +142,8 @@ function closeTags(out, tags) {
64
142
  out.push('</i>');
65
143
  if (tags.bold)
66
144
  out.push('</b>');
145
+ if (hasFontAttrs(tags))
146
+ out.push('</font>');
67
147
  if (tags.hyperlinkUrl !== null)
68
148
  out.push('</a>');
69
149
  }
@@ -78,6 +158,9 @@ function openTags(out, tags) {
78
158
  if (tags.hyperlinkUrl !== null) {
79
159
  out.push(`<a href="${escapeHtmlAttribute(tags.hyperlinkUrl)}">`);
80
160
  }
161
+ const ft = fontTagString(tags);
162
+ if (ft)
163
+ out.push(ft);
81
164
  if (tags.bold)
82
165
  out.push('<b>');
83
166
  if (tags.italic)
@@ -87,108 +170,82 @@ function openTags(out, tags) {
87
170
  if (tags.highlighting)
88
171
  out.push(`<${HIGHLIGHT_TAG}>`);
89
172
  }
90
- function desiredTagsForRun(run, baseline) {
173
+ function desiredTagsForRun(run, baseline, fontBaseline) {
91
174
  if (run.isHeaderRun) {
92
- return { hyperlinkUrl: null, bold: false, italic: false, underline: false, highlighting: false };
93
- }
94
- const highlighting = !!run.formatting.highlightVal;
95
- if (!baseline.suppressed) {
96
175
  return {
97
- hyperlinkUrl: run.hyperlinkUrl,
98
- bold: run.formatting.bold,
99
- italic: run.formatting.italic,
100
- underline: run.formatting.underline,
101
- highlighting,
176
+ hyperlinkUrl: null,
177
+ bold: false, italic: false, underline: false, highlighting: false,
178
+ color: null, fontSize: null, fontName: null,
102
179
  };
103
180
  }
104
- return {
105
- hyperlinkUrl: run.hyperlinkUrl,
106
- bold: run.formatting.bold !== baseline.bold ? run.formatting.bold : false,
107
- italic: run.formatting.italic !== baseline.italic ? run.formatting.italic : false,
108
- underline: run.formatting.underline !== baseline.underline ? run.formatting.underline : false,
109
- highlighting,
110
- };
111
- }
112
- export function emitFormattingTags(params) {
113
- const { runs, baseline, definitionSpans } = params;
114
- if (runs.length === 0)
115
- return '';
116
- // When there are no definition spans, use the fast per-run path.
117
- if (!definitionSpans || definitionSpans.length === 0) {
118
- return emitFormattingTagsSimple(runs, baseline);
181
+ const highlighting = !!run.formatting.highlightVal;
182
+ // BIU
183
+ let bold;
184
+ let italic;
185
+ let underline;
186
+ if (!baseline.suppressed) {
187
+ bold = run.formatting.bold;
188
+ italic = run.formatting.italic;
189
+ underline = run.formatting.underline;
119
190
  }
120
- // Build skip/insert maps from definition spans.
121
- // For each definition: skip the open-quote char, emit <definition>, skip close-quote char, emit </definition>.
122
- // Offsets relative to the plain-text character stream.
123
- const skipChars = new Set(); // chars to omit (quote chars)
124
- const insertBefore = new Map(); // tags to insert before a char
125
- const insertAfter = new Map(); // tags to insert after a char
126
- for (const ds of definitionSpans) {
127
- skipChars.add(ds.start); // open quote
128
- skipChars.add(ds.end - 1); // close quote
129
- insertBefore.set(ds.start + 1, '<definition>'); // before first term char
130
- insertAfter.set(ds.end - 2, '</definition>'); // after last term char
191
+ else {
192
+ bold = run.formatting.bold !== baseline.bold ? run.formatting.bold : false;
193
+ italic = run.formatting.italic !== baseline.italic ? run.formatting.italic : false;
194
+ underline = run.formatting.underline !== baseline.underline ? run.formatting.underline : false;
131
195
  }
132
- const out = [];
133
- const noTags = () => ({
134
- hyperlinkUrl: null,
135
- bold: false,
136
- italic: false,
137
- underline: false,
138
- highlighting: false,
139
- });
140
- let active = noTags();
141
- let plainOffset = 0;
142
- for (const run of runs) {
143
- if (!run.text)
144
- continue;
145
- const desired = desiredTagsForRun(run, baseline);
146
- for (let ci = 0; ci < run.text.length; ci++) {
147
- const gOffset = plainOffset + ci;
148
- // At a definition boundary, close formatting tags before emitting
149
- // semantic tags so we never interleave crossing tag structures.
150
- const insertB = insertBefore.get(gOffset);
151
- if (insertB) {
152
- closeTags(out, active);
153
- active = noTags();
154
- out.push(insertB);
196
+ // Font properties (paragraph-local baseline)
197
+ let color = null;
198
+ let fontSize = null;
199
+ let fontName = null;
200
+ if (fontBaseline) {
201
+ // Color: emit only when suppressed and differs from modal, or not suppressed and has a value
202
+ if (fontBaseline.colorSuppressed) {
203
+ if (run.formatting.colorHex !== fontBaseline.modalColor) {
204
+ color = run.formatting.colorHex;
155
205
  }
156
- // Skip quote characters that are absorbed into definition tags.
157
- if (!skipChars.has(gOffset)) {
158
- if (!tagsEqual(active, desired)) {
159
- closeTags(out, active);
160
- openTags(out, desired);
161
- active = desired;
162
- }
163
- out.push(run.text[ci]);
206
+ }
207
+ else if (run.formatting.colorHex) {
208
+ color = run.formatting.colorHex;
209
+ }
210
+ // Font size: emit only when suppressed and differs from modal, or not suppressed and > 0
211
+ if (fontBaseline.fontSizeSuppressed) {
212
+ if (run.formatting.fontSizePt !== fontBaseline.modalFontSizePt) {
213
+ fontSize = run.formatting.fontSizePt;
164
214
  }
165
- // Insert definition close tag after this char.
166
- const insertA = insertAfter.get(gOffset);
167
- if (insertA) {
168
- closeTags(out, active);
169
- active = noTags();
170
- out.push(insertA);
215
+ }
216
+ else if (run.formatting.fontSizePt > 0) {
217
+ fontSize = run.formatting.fontSizePt;
218
+ }
219
+ // Font name: emit only when suppressed and differs from modal, or not suppressed and has a value
220
+ if (fontBaseline.fontNameSuppressed) {
221
+ if (run.formatting.fontName !== fontBaseline.modalFontName) {
222
+ fontName = run.formatting.fontName || null;
171
223
  }
172
224
  }
173
- plainOffset += run.text.length;
225
+ else if (run.formatting.fontName) {
226
+ fontName = run.formatting.fontName;
227
+ }
174
228
  }
175
- closeTags(out, active);
176
- return out.join('');
229
+ return {
230
+ hyperlinkUrl: run.hyperlinkUrl,
231
+ bold, italic, underline, highlighting,
232
+ color, fontSize, fontName,
233
+ };
177
234
  }
178
- /** Fast path when no definition spans need interleaving. */
179
- function emitFormattingTagsSimple(runs, baseline) {
235
+ export function emitFormattingTags(params) {
236
+ const { runs, baseline, fontBaseline } = params;
237
+ if (runs.length === 0)
238
+ return '';
180
239
  const out = [];
181
240
  let active = {
182
241
  hyperlinkUrl: null,
183
- bold: false,
184
- italic: false,
185
- underline: false,
186
- highlighting: false,
242
+ bold: false, italic: false, underline: false, highlighting: false,
243
+ color: null, fontSize: null, fontName: null,
187
244
  };
188
245
  for (const run of runs) {
189
246
  if (!run.text)
190
247
  continue;
191
- const desired = desiredTagsForRun(run, baseline);
248
+ const desired = desiredTagsForRun(run, baseline, fontBaseline ?? null);
192
249
  if (!tagsEqual(active, desired)) {
193
250
  closeTags(out, active);
194
251
  openTags(out, desired);
@@ -200,8 +257,9 @@ function emitFormattingTagsSimple(runs, baseline) {
200
257
  return out.join('');
201
258
  }
202
259
  // ── Adjacent tag merging ─────────────────────────────────────────────
260
+ // Build a pattern matching </font><font ...> with identical attributes.
261
+ const FONT_ADJACENT_RE = /<\/font>(<font [^>]*>)/g;
203
262
  export function mergeAdjacentTags(tagged) {
204
- // Collapse </b><b>, </i><i>, </u><u>, </highlighting><highlighting>.
205
263
  let result = tagged;
206
264
  let prev;
207
265
  do {
@@ -211,6 +269,22 @@ export function mergeAdjacentTags(tagged) {
211
269
  .replace(/<\/i><i>/g, '')
212
270
  .replace(/<\/u><u>/g, '')
213
271
  .replace(new RegExp(`</${HIGHLIGHT_TAG}><${HIGHLIGHT_TAG}>`, 'g'), '');
272
+ // Collapse identical adjacent font tags: </font><font color="X" size="Y"> → remove if same
273
+ FONT_ADJACENT_RE.lastIndex = 0;
274
+ result = result.replace(FONT_ADJACENT_RE, (_match, nextOpen, offset) => {
275
+ // Find the preceding <font ...> opening tag for this </font>
276
+ const beforeClose = result.slice(0, offset);
277
+ const lastOpenIdx = beforeClose.lastIndexOf('<font ');
278
+ if (lastOpenIdx === -1)
279
+ return _match;
280
+ const lastOpenEnd = beforeClose.indexOf('>', lastOpenIdx);
281
+ if (lastOpenEnd === -1)
282
+ return _match;
283
+ const prevOpen = beforeClose.slice(lastOpenIdx, lastOpenEnd + 1);
284
+ if (prevOpen === nextOpen)
285
+ return ''; // identical — merge
286
+ return _match;
287
+ });
214
288
  } while (result !== prev);
215
289
  return result;
216
290
  }
@@ -1 +1 @@
1
- {"version":3,"file":"formatting_tags.js","sourceRoot":"","sources":["../../src/primitives/formatting_tags.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"formatting_tags.js","sourceRoot":"","sources":["../../src/primitives/formatting_tags.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type MatchMode = 'exact' | 'quote_normalized' | 'flexible_whitespace' | 'quote_optional';
1
+ export type MatchMode = 'exact' | 'quote_normalized' | 'flexible_whitespace' | 'quote_optional' | 'clean';
2
2
  export type UniqueSubstringMatchResult = {
3
3
  status: 'not_found';
4
4
  } | {
@@ -13,5 +13,19 @@ export type UniqueSubstringMatchResult = {
13
13
  end: number;
14
14
  matchedText: string;
15
15
  };
16
- export declare function findUniqueSubstringMatch(haystack: string, needle: string): UniqueSubstringMatchResult;
16
+ /**
17
+ * Transfer the document's smart-quote style to a target string.
18
+ *
19
+ * Scans `documentText` for the first left/right double and single smart-quote
20
+ * variants, then replaces straight quotes in `targetText` with those variants.
21
+ * Uses positional context (after whitespace/punctuation/start → opening, else closing)
22
+ * to choose the correct direction.
23
+ *
24
+ * Returns `targetText` unchanged when `documentText` contains no smart quotes.
25
+ * Angle quotes (« » ‹ ›) are explicitly non-goal for v1.
26
+ */
27
+ export declare function applyDocumentQuoteStyle(documentText: string, targetText: string): string;
28
+ export declare function findUniqueSubstringMatch(haystack: string, needle: string, options?: {
29
+ mode?: MatchMode | 'default';
30
+ }): UniqueSubstringMatchResult;
17
31
  //# sourceMappingURL=matching.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"matching.d.ts","sourceRoot":"","sources":["../../src/primitives/matching.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,kBAAkB,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAEhG,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3D;IACE,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,CAAC,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AA8GN,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,0BAA0B,CA4CrG"}
1
+ {"version":3,"file":"matching.d.ts","sourceRoot":"","sources":["../../src/primitives/matching.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,kBAAkB,GAAG,qBAAqB,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAE1G,MAAM,MAAM,0BAA0B,GAClC;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3D;IACE,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,CAAC,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AA4IN;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CA4CxF;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAO,GAC7C,0BAA0B,CA2C5B"}
@@ -85,6 +85,33 @@ function removeQuotes(input) {
85
85
  }
86
86
  return { text: outChars.join(''), spans: outSpans };
87
87
  }
88
+ function stripAllTags(input) {
89
+ if (!input.text)
90
+ return input;
91
+ const tags = [
92
+ /<\/?[biu]>/g,
93
+ /<a\s+href="[^"]*">/g,
94
+ /<\/a>/g,
95
+ /<highlight>/g,
96
+ /<\/highlight>/g,
97
+ /<highlighting>/g,
98
+ /<\/highlighting>/g,
99
+ ];
100
+ let text = input.text;
101
+ const spans = input.spans.slice();
102
+ for (const tag of tags) {
103
+ let match;
104
+ tag.lastIndex = 0;
105
+ while ((match = tag.exec(text)) !== null) {
106
+ const len = match[0].length;
107
+ const idx = match.index;
108
+ text = text.slice(0, idx) + text.slice(idx + len);
109
+ spans.splice(idx, len);
110
+ tag.lastIndex = idx;
111
+ }
112
+ }
113
+ return { text, spans };
114
+ }
88
115
  function findAllMatchIndices(haystack, needle) {
89
116
  if (!needle)
90
117
  return [];
@@ -99,18 +126,76 @@ function findAllMatchIndices(haystack, needle) {
99
126
  }
100
127
  return hits;
101
128
  }
102
- export function findUniqueSubstringMatch(haystack, needle) {
129
+ /**
130
+ * Transfer the document's smart-quote style to a target string.
131
+ *
132
+ * Scans `documentText` for the first left/right double and single smart-quote
133
+ * variants, then replaces straight quotes in `targetText` with those variants.
134
+ * Uses positional context (after whitespace/punctuation/start → opening, else closing)
135
+ * to choose the correct direction.
136
+ *
137
+ * Returns `targetText` unchanged when `documentText` contains no smart quotes.
138
+ * Angle quotes (« » ‹ ›) are explicitly non-goal for v1.
139
+ */
140
+ export function applyDocumentQuoteStyle(documentText, targetText) {
141
+ // Detect which smart-quote variants the document uses.
142
+ let leftDouble = null;
143
+ let rightDouble = null;
144
+ let leftSingle = null;
145
+ let rightSingle = null;
146
+ // Angle quotes are excluded from transfer (v1 non-goal).
147
+ const ANGLE_QUOTES = new Set(['\u00ab', '\u00bb', '\u2039', '\u203a']);
148
+ for (const ch of documentText) {
149
+ if (ANGLE_QUOTES.has(ch))
150
+ continue;
151
+ if (ch === '\u201c' && !leftDouble)
152
+ leftDouble = ch;
153
+ if (ch === '\u201d' && !rightDouble)
154
+ rightDouble = ch;
155
+ if (ch === '\u2018' && !leftSingle)
156
+ leftSingle = ch;
157
+ if (ch === '\u2019' && !rightSingle)
158
+ rightSingle = ch;
159
+ }
160
+ // No smart quotes in document → return unchanged.
161
+ if (!leftDouble && !rightDouble && !leftSingle && !rightSingle)
162
+ return targetText;
163
+ let result = '';
164
+ for (let i = 0; i < targetText.length; i++) {
165
+ const ch = targetText[i];
166
+ if (ch === '"' && (leftDouble || rightDouble)) {
167
+ // Determine opening vs closing by looking at the preceding character.
168
+ const prev = i > 0 ? targetText[i - 1] : '';
169
+ const isOpening = i === 0 || /[\s(\[{]/.test(prev);
170
+ result += isOpening ? (leftDouble ?? rightDouble) : (rightDouble ?? leftDouble);
171
+ continue;
172
+ }
173
+ if (ch === "'" && (leftSingle || rightSingle)) {
174
+ const prev = i > 0 ? targetText[i - 1] : '';
175
+ const isOpening = i === 0 || /[\s(\[{]/.test(prev);
176
+ result += isOpening ? (leftSingle ?? rightSingle) : (rightSingle ?? leftSingle);
177
+ continue;
178
+ }
179
+ result += ch;
180
+ }
181
+ return result;
182
+ }
183
+ export function findUniqueSubstringMatch(haystack, needle, options = {}) {
103
184
  if (!needle)
104
185
  return { status: 'not_found' };
105
186
  const hayBase = toMappedText(haystack);
106
187
  const needleBase = toMappedText(needle);
107
188
  const stages = [
108
189
  { mode: 'exact', transforms: [] },
109
- { mode: 'quote_normalized', transforms: [normalizeQuotes] },
110
- { mode: 'flexible_whitespace', transforms: [normalizeQuotes, collapseWhitespace] },
111
- { mode: 'quote_optional', transforms: [normalizeQuotes, collapseWhitespace, removeQuotes] },
190
+ { mode: 'clean', transforms: [stripAllTags] },
191
+ { mode: 'quote_normalized', transforms: [stripAllTags, normalizeQuotes] },
192
+ { mode: 'flexible_whitespace', transforms: [stripAllTags, normalizeQuotes, collapseWhitespace] },
193
+ { mode: 'quote_optional', transforms: [stripAllTags, normalizeQuotes, collapseWhitespace, removeQuotes] },
112
194
  ];
195
+ const targetMode = options.mode === 'default' ? undefined : options.mode;
113
196
  for (const stage of stages) {
197
+ if (targetMode !== undefined && stage.mode !== targetMode)
198
+ continue;
114
199
  const h = applyTransforms(hayBase, stage.transforms);
115
200
  const n = applyTransforms(needleBase, stage.transforms);
116
201
  if (!n.text)
@@ -119,24 +204,18 @@ export function findUniqueSubstringMatch(haystack, needle) {
119
204
  if (hits.length === 0)
120
205
  continue;
121
206
  if (hits.length > 1) {
122
- return {
123
- status: 'multiple',
124
- mode: stage.mode,
125
- matchCount: hits.length,
126
- };
207
+ return { status: 'multiple', mode: stage.mode, matchCount: hits.length };
127
208
  }
128
209
  const hit = hits[0];
129
210
  const startSpan = h.spans[hit];
130
211
  const endSpan = h.spans[hit + n.text.length - 1];
131
- const start = startSpan.start;
132
- const end = endSpan.end;
133
212
  return {
134
213
  status: 'unique',
135
214
  mode: stage.mode,
136
215
  matchCount: 1,
137
- start,
138
- end,
139
- matchedText: haystack.slice(start, end),
216
+ start: startSpan.start,
217
+ end: endSpan.end,
218
+ matchedText: haystack.slice(startSpan.start, endSpan.end),
140
219
  };
141
220
  }
142
221
  return { status: 'not_found' };