@a3s-lab/office 0.26.0 → 0.28.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 (87) hide show
  1. package/README.md +89 -2
  2. package/dist/0~4595.js +16 -2
  3. package/dist/0~5093.js +563 -201
  4. package/dist/0~6090.js +77 -77
  5. package/dist/{0~2805.js → 0~7043.js} +305 -2
  6. package/dist/0~document-editor.js +2633 -976
  7. package/dist/0~spreadsheet-editor.js +1324 -378
  8. package/dist/0~work-docx-export.js +737 -17
  9. package/dist/0~work-docx-import.js +173 -98
  10. package/dist/0~work-office-diagnostics.js +250 -5
  11. package/dist/{164.js → 1544.js} +1083 -785
  12. package/dist/4104.js +145 -29
  13. package/dist/5184.js +13 -0
  14. package/dist/6282.js +1898 -345
  15. package/dist/core.js +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/internal/features/work/editors/document-command-catalog.d.ts +102 -0
  18. package/dist/internal/features/work/editors/document-font-dialog-model.d.ts +111 -0
  19. package/dist/internal/features/work/editors/document-font-dialog-script-font-model.d.ts +18 -0
  20. package/dist/internal/features/work/editors/document-font-dialog.d.ts +9 -0
  21. package/dist/internal/features/work/editors/document-home-ribbon.d.ts +2 -1
  22. package/dist/internal/features/work/editors/document-page-chrome-editor.d.ts +6 -0
  23. package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +2 -1
  24. package/dist/internal/features/work/editors/document-strike-ribbon.d.ts +7 -0
  25. package/dist/internal/features/work/editors/document-text-case-ribbon.d.ts +4 -0
  26. package/dist/internal/features/work/editors/document-toolbar.d.ts +3 -1
  27. package/dist/internal/features/work/editors/document-underline-ribbon.d.ts +9 -0
  28. package/dist/internal/features/work/editors/document-wps-shortcuts.d.ts +1 -0
  29. package/dist/internal/features/work/editors/spreadsheet-cell-fill-format.d.ts +11 -0
  30. package/dist/internal/features/work/editors/spreadsheet-cell-format.d.ts +2 -1
  31. package/dist/internal/features/work/editors/spreadsheet-format-cells-dialog-model.d.ts +13 -2
  32. package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-panel.d.ts +13 -0
  33. package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-preview.d.ts +6 -0
  34. package/dist/internal/features/work/editors/spreadsheet-format-painter.d.ts +1 -1
  35. package/dist/internal/features/work/editors/work-office-chrome.d.ts +9 -1
  36. package/dist/internal/features/work/work-document-character-formatting.d.ts +16 -1
  37. package/dist/internal/features/work/work-document-character-position.d.ts +9 -0
  38. package/dist/internal/features/work/work-document-character-scale.d.ts +8 -0
  39. package/dist/internal/features/work/work-document-character-spacing.d.ts +8 -0
  40. package/dist/internal/features/work/work-document-emphasis.d.ts +7 -0
  41. package/dist/internal/features/work/work-document-equations.d.ts +2 -1
  42. package/dist/internal/features/work/work-document-format-changes.d.ts +20 -2
  43. package/dist/internal/features/work/work-document-hidden-text.d.ts +5 -0
  44. package/dist/internal/features/work/work-document-kerning.d.ts +10 -0
  45. package/dist/internal/features/work/work-document-legacy-text-effects.d.ts +27 -0
  46. package/dist/internal/features/work/work-document-script-font-extension.d.ts +2 -0
  47. package/dist/internal/features/work/work-document-script-fonts.d.ts +51 -0
  48. package/dist/internal/features/work/work-document-strike.d.ts +21 -0
  49. package/dist/internal/features/work/work-document-text-case.d.ts +10 -0
  50. package/dist/internal/features/work/work-document-underline.d.ts +37 -0
  51. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +16 -0
  52. package/dist/internal/features/work/work-docx-character-position.d.ts +2 -0
  53. package/dist/internal/features/work/work-docx-character-scale.d.ts +2 -0
  54. package/dist/internal/features/work/work-docx-character-spacing.d.ts +4 -0
  55. package/dist/internal/features/work/work-docx-emphasis-diagnostics.d.ts +3 -0
  56. package/dist/internal/features/work/work-docx-emphasis.d.ts +14 -0
  57. package/dist/internal/features/work/work-docx-hidden-text-diagnostics.d.ts +3 -0
  58. package/dist/internal/features/work/work-docx-hidden-text-export.d.ts +17 -0
  59. package/dist/internal/features/work/work-docx-hidden-text.d.ts +11 -0
  60. package/dist/internal/features/work/work-docx-kerning-diagnostics.d.ts +3 -0
  61. package/dist/internal/features/work/work-docx-kerning.d.ts +14 -0
  62. package/dist/internal/features/work/work-docx-legacy-text-effects-diagnostics.d.ts +3 -0
  63. package/dist/internal/features/work/work-docx-legacy-text-effects-export.d.ts +18 -0
  64. package/dist/internal/features/work/work-docx-legacy-text-effects.d.ts +12 -0
  65. package/dist/internal/features/work/work-docx-run-fonts-diagnostics.d.ts +3 -0
  66. package/dist/internal/features/work/work-docx-run-fonts-export.d.ts +14 -0
  67. package/dist/internal/features/work/work-docx-run-fonts.d.ts +13 -0
  68. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +27 -2
  69. package/dist/internal/features/work/work-docx-run-property-order.d.ts +2 -0
  70. package/dist/internal/features/work/work-docx-run-script-font-import.d.ts +9 -0
  71. package/dist/internal/features/work/work-docx-strike.d.ts +8 -0
  72. package/dist/internal/features/work/work-docx-theme-reference.d.ts +1 -1
  73. package/dist/internal/features/work/work-docx-twips.d.ts +6 -0
  74. package/dist/internal/features/work/work-docx-underline.d.ts +3 -0
  75. package/dist/internal/features/work/work-spreadsheet-gradient-fill-canvas.d.ts +10 -0
  76. package/dist/internal/features/work/work-spreadsheet-native-fill-canvas.d.ts +8 -0
  77. package/dist/internal/features/work/work-spreadsheet-pattern-fill-canvas.d.ts +8 -0
  78. package/dist/internal/features/work/work-xlsx-cell-style-origin.d.ts +2 -1
  79. package/dist/internal/features/work/work-xlsx-cell-style-writer.d.ts +3 -0
  80. package/dist/internal/features/work/work-xlsx-cell-styles.d.ts +4 -0
  81. package/dist/internal/features/work/work-xlsx-gradient-fill.d.ts +31 -0
  82. package/dist/internal/features/work/work-xlsx-native-fill.d.ts +17 -0
  83. package/dist/internal/features/work/work-xlsx-pattern-fill.d.ts +21 -0
  84. package/dist/office-kernel.wasm +0 -0
  85. package/dist/styles.css +809 -78
  86. package/docs/latest/en/browser-editor-architecture.md +24 -0
  87. package/package.json +35 -1
@@ -1,11 +1,11 @@
1
1
  import { __webpack_require__ } from "./0~rslib-runtime.js";
2
2
  import { contentTypeForPart, directChildren, OoxmlPackage, parseXml, firstDescendant, descendants, directChild, xmlContainsAnyElement, attribute } from "./5184.js";
3
- import { normalizeDocumentBookmarkName, docxBookmarkReferenceTarget, normalizeDocumentBookmarkNativeId, isDocumentParagraphArtBorderStyle, supportedDocxBookmarkReferenceInstruction, documentCitationTagsFromInstruction, docxDocumentFieldKind } from "./6282.js";
4
- import { markDocxParagraphShading, inspectDocxPageSize, docxCaptionBookmark, hasInvalidDocxFieldStructure, inspectDocxPageMargins, inspectDocxPaperSource, createDocxParagraphStyleResolver, createDocxTableStyleResolver, docxFieldOccurrences, inspectDocxEquation, inspectDocxPageMarginSettings, markDocxParagraphBorders, isSupportedDocxParagraphFormattingChange, docxFieldOccurrenceIsInlineEditable, docxCaptionSequenceKind, inspectDocxPageBorders, isSupportedDocxRunFormattingChange, docxFieldInstructions, isSupportedDocxEquationPlacement } from "./0~5093.js";
3
+ import { normalizeDocumentBookmarkName, docxBookmarkReferenceTarget, isDocumentParagraphArtBorderStyle, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, normalizeDocumentBookmarkNativeId, supportedDocxBookmarkReferenceInstruction, documentCitationTagsFromInstruction, docxDocumentFieldKind } from "./6282.js";
4
+ import { markDocxParagraphShading, inspectDocxPageSize, docxCaptionBookmark, hasInvalidDocxFieldStructure, inspectDocxLegacyTextEffects, inspectDocxPageMargins, inspectDocxPaperSource, createDocxParagraphStyleResolver, createDocxTableStyleResolver, docxFieldOccurrences, inspectDocxRunFonts, inspectDocxEquation, inspectDocxPageMarginSettings, markDocxParagraphBorders, isSupportedDocxParagraphFormattingChange, docxFieldOccurrenceIsInlineEditable, inspectDocxHiddenText, docxCaptionSequenceKind, inspectDocxPageBorders, isSupportedDocxRunFormattingChange, docxFieldInstructions, isSupportedDocxEquationPlacement } from "./0~5093.js";
5
5
  import { normalizeDocumentHref } from "./0~work-document-links.js";
6
- import { xmlAttributeLocalName, parseDocxParagraphDefaultCollapsed, readDocxBibliography, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace, createDocxThemeResolver } from "./0~2805.js";
6
+ import { xmlAttributeLocalName, readDocxBibliography, inspectDocxEmphasisMark, createDocxThemeResolver, parseDocxParagraphDefaultCollapsed, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace, inspectDocxKerningThresholdHalfPoints } from "./0~7043.js";
7
7
  import { updateSpreadsheetWorksheetCompatibilitySummary, inspectXlsxPivotTables, isSupportedXlsxChartLegend, isSupportedXlsxChartPlotLayout, xlsxChartNodeUsesStackedGrouping, isSupportedXlsxChartSeriesFormatting, readXlsxFormulaFeaturesFromPackage, inspectXlsxHeaderFooterText, emptySpreadsheetWorksheetCompatibilitySummary, isSupportedXlsxWorksheetImageContentType, MAX_XLSX_WORKSHEET_IMAGE_BYTES, xlsxChartSeriesFormattingShapeProperties, diagnoseXlsxProtection, isEditableXlsxPaperSizeCode, isSupportedXlsxCombinationChartNodes } from "./4104.js";
8
- import { spreadsheetConditionalComparisonNeedsUpperValue, isSpreadsheetConditionalIconSetName, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconSetCount, xlsxWorksheetCellEntries } from "./164.js";
8
+ import { spreadsheetConditionalComparisonNeedsUpperValue, isSpreadsheetConditionalIconSetName, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconSetCount, xlsxWorksheetCellEntries } from "./1544.js";
9
9
  import { formulaHasStructuredReference, formulaHasExternalReference, parseSpreadsheetPrintTitles, volatileSpreadsheetFormulaFunctions, stripSpreadsheetSheetQualifier } from "./8715.js";
10
10
  import { unsupportedSpreadsheetFormulaFunctions } from "./0~work-spreadsheet-formula-support.js";
11
11
  var work_office_diagnostics_namespaceObject = {};
@@ -269,6 +269,187 @@ function equationIssue(code, message, severity = 'warning') {
269
269
  severity
270
270
  };
271
271
  }
272
+ const EMPHASIS_DIAGNOSTIC_PART_PATTERN = /^word\/(?:document|styles|header\d*|footer\d*|footnotes|endnotes)\.xml$/i;
273
+ async function diagnoseDocxEmphasisMarks(archive, document) {
274
+ const parts = [
275
+ {
276
+ path: 'word/document.xml',
277
+ document
278
+ }
279
+ ];
280
+ for (const path of archive.paths('word/'))if ('word/document.xml' !== path.toLowerCase() && EMPHASIS_DIAGNOSTIC_PART_PATTERN.test(path)) parts.push({
281
+ path,
282
+ document: await archive.xml(path)
283
+ });
284
+ let validCount = 0;
285
+ let explicitNoneCount = 0;
286
+ let underDotCount = 0;
287
+ let invalidCount = 0;
288
+ for (const part of parts){
289
+ const propertySets = descendants(part.document, 'rPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? ''));
290
+ for (const properties of propertySets){
291
+ if (!directChildren(properties, 'em').length) continue;
292
+ const inspection = inspectDocxEmphasisMark(properties);
293
+ if ('valid' === inspection.status) {
294
+ validCount += 1;
295
+ if ('none' === inspection.value) explicitNoneCount += 1;
296
+ if ('underDot' === inspection.value) underDotCount += 1;
297
+ } else if ('invalid' === inspection.status) invalidCount += 1;
298
+ }
299
+ invalidCount += descendants(part.document, 'em').filter((element)=>{
300
+ const parent = element.parentElement;
301
+ return !parent || 'rPr' !== parent.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(parent.namespaceURI ?? '');
302
+ }).length;
303
+ }
304
+ const issues = [];
305
+ if (validCount) issues.push({
306
+ code: 'docx.emphasis-mark',
307
+ severity: 'info',
308
+ feature: 'East Asian emphasis marks',
309
+ message: `${validCount} native emphasis mark(s), including ${explicitNoneCount} explicit none reset(s) and ${underDotCount} below-text dot(s), preserve all five w:em values through style inheritance, body and page-chrome editing, formatting revisions, CSS projection, and DOCX export. Runs with visible marks use browser line measurement so their out-of-line glyph extents are not approximated by the Worker/WASM shaper.`
310
+ });
311
+ if (invalidCount) issues.push({
312
+ code: 'docx.emphasis-mark.invalid',
313
+ severity: 'warning',
314
+ feature: 'East Asian emphasis marks',
315
+ message: `${invalidCount} malformed, duplicated, misplaced, namespace-spoofed, text-bearing, or unknown emphasis property set(s) are ignored instead of enabling untrusted typography.`
316
+ });
317
+ return issues;
318
+ }
319
+ const HIDDEN_TEXT_DIAGNOSTIC_PART_PATTERN = /^word\/(?:document|styles|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
320
+ async function diagnoseDocxHiddenText(archive, document) {
321
+ const parts = [
322
+ document
323
+ ];
324
+ for (const path of archive.paths('word/'))if ('word/document.xml' !== path.toLowerCase() && HIDDEN_TEXT_DIAGNOSTIC_PART_PATTERN.test(path)) parts.push(await archive.xml(path));
325
+ let hiddenCount = 0;
326
+ let visibleResetCount = 0;
327
+ let invalidCount = 0;
328
+ for (const part of parts){
329
+ const propertySets = descendants(part, 'rPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? ''));
330
+ for (const properties of propertySets){
331
+ if (!directChildren(properties, 'vanish').length) continue;
332
+ const inspection = inspectDocxHiddenText(properties);
333
+ if ('valid' === inspection.status) if (inspection.value) hiddenCount += 1;
334
+ else visibleResetCount += 1;
335
+ else if ('invalid' === inspection.status) invalidCount += 1;
336
+ }
337
+ invalidCount += descendants(part, 'vanish').filter((element)=>{
338
+ const parent = element.parentElement;
339
+ return !parent || 'rPr' !== parent.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(parent.namespaceURI ?? '');
340
+ }).length;
341
+ }
342
+ const issues = [];
343
+ const validCount = hiddenCount + visibleResetCount;
344
+ if (validCount) issues.push({
345
+ code: 'docx.hidden-text',
346
+ severity: 'info',
347
+ feature: 'Hidden text',
348
+ message: `${validCount} native hidden-text value(s), including ${hiddenCount} hidden value(s) and ${visibleResetCount} explicit visible reset(s), were detected across document defaults, character and paragraph styles, body, headers, footers, notes, comments, and formatting revisions. Editable Writer stories preserve w:vanish through the Font dialog, the show-hidden-text editing view, and exact DOCX export; unchanged comment XML remains source-preserved rather than becoming a rich comment-editing claim. Preview and PDF output keep hidden text suppressed, while affected paragraphs use browser-authoritative line measurement.`
349
+ });
350
+ if (invalidCount) issues.push({
351
+ code: 'docx.hidden-text.invalid',
352
+ severity: 'warning',
353
+ feature: 'Hidden text',
354
+ message: `${invalidCount} malformed, duplicated, misplaced, namespace-spoofed, text-bearing, child-bearing, extra-attribute, or unknown hidden-text property set(s) are ignored instead of hiding untrusted content.`
355
+ });
356
+ return issues;
357
+ }
358
+ const KERNING_DIAGNOSTIC_PART_PATTERN = /^word\/(?:document|styles|header\d*|footer\d*|footnotes|endnotes)\.xml$/i;
359
+ async function diagnoseDocxKerning(archive, document) {
360
+ const parts = [
361
+ {
362
+ path: 'word/document.xml',
363
+ document
364
+ }
365
+ ];
366
+ for (const path of archive.paths('word/'))if ('word/document.xml' !== path.toLowerCase() && KERNING_DIAGNOSTIC_PART_PATTERN.test(path)) parts.push({
367
+ path,
368
+ document: await archive.xml(path)
369
+ });
370
+ let validCount = 0;
371
+ let explicitZeroCount = 0;
372
+ let invalidCount = 0;
373
+ for (const part of parts){
374
+ const propertySets = descendants(part.document, 'rPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? ''));
375
+ for (const properties of propertySets){
376
+ if (!directChildren(properties, 'kern').length) continue;
377
+ const inspection = inspectDocxKerningThresholdHalfPoints(properties);
378
+ if ('valid' === inspection.status) {
379
+ validCount += 1;
380
+ if (0 === inspection.value) explicitZeroCount += 1;
381
+ } else if ('invalid' === inspection.status) invalidCount += 1;
382
+ }
383
+ invalidCount += descendants(part.document, 'kern').filter((element)=>{
384
+ const parent = element.parentElement;
385
+ return !parent || 'rPr' !== parent.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(parent.namespaceURI ?? '');
386
+ }).length;
387
+ }
388
+ const issues = [];
389
+ if (validCount) issues.push({
390
+ code: 'docx.kerning',
391
+ severity: 'info',
392
+ feature: 'Character kerning',
393
+ message: `${validCount} native kerning threshold(s), including ${explicitZeroCount} explicit all-font-size value(s), preserve exact half-points through style inheritance, body and page-chrome editing, effective font-size rendering, formatting revisions, and DOCX export. Pair kerning applies when the effective w:sz value meets or exceeds w:kern; absence throughout the hierarchy keeps kerning disabled.`
394
+ });
395
+ if (invalidCount) issues.push({
396
+ code: 'docx.kerning.invalid',
397
+ severity: 'warning',
398
+ feature: 'Character kerning',
399
+ message: `${invalidCount} malformed, duplicated, misplaced, namespace-spoofed, text-bearing, or out-of-range kerning property set(s) are ignored instead of enabling untrusted typography.`
400
+ });
401
+ return issues;
402
+ }
403
+ const LEGACY_TEXT_EFFECTS_DIAGNOSTIC_PART_PATTERN = /^word\/(?:document|styles|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
404
+ async function diagnoseDocxLegacyTextEffects(archive, document) {
405
+ const parts = [
406
+ document
407
+ ];
408
+ for (const path of archive.paths('word/'))if ('word/document.xml' !== path.toLowerCase() && LEGACY_TEXT_EFFECTS_DIAGNOSTIC_PART_PATTERN.test(path)) parts.push(await archive.xml(path));
409
+ const enabled = {
410
+ outline: 0,
411
+ shadow: 0,
412
+ emboss: 0,
413
+ imprint: 0
414
+ };
415
+ let validCount = 0;
416
+ let explicitFalseCount = 0;
417
+ let invalidCount = 0;
418
+ for (const part of parts){
419
+ const propertySets = descendants(part, 'rPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? ''));
420
+ for (const properties of propertySets){
421
+ if (!DOCUMENT_LEGACY_TEXT_EFFECT_NAMES.some((name)=>directChildren(properties, name).length > 0)) continue;
422
+ const inspection = inspectDocxLegacyTextEffects(properties);
423
+ if ('valid' === inspection.status) for (const name of DOCUMENT_LEGACY_TEXT_EFFECT_NAMES){
424
+ const value = inspection.value[name];
425
+ if (void 0 !== value) {
426
+ validCount += 1;
427
+ if (value) enabled[name] += 1;
428
+ else explicitFalseCount += 1;
429
+ }
430
+ }
431
+ else if ('invalid' === inspection.status) invalidCount += 1;
432
+ }
433
+ for (const name of DOCUMENT_LEGACY_TEXT_EFFECT_NAMES)invalidCount += descendants(part, name).filter((element)=>{
434
+ const parent = element.parentElement;
435
+ return !parent || 'rPr' !== parent.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(parent.namespaceURI ?? '');
436
+ }).length;
437
+ }
438
+ const issues = [];
439
+ if (validCount) issues.push({
440
+ code: 'docx.legacy-text-effects',
441
+ severity: 'info',
442
+ feature: 'Legacy text effects',
443
+ message: `${validCount} native legacy text-effect value(s), including ${explicitFalseCount} explicit false reset(s), ${enabled.outline} enabled outline value(s), ${enabled.shadow} enabled shadow value(s), ${enabled.emboss} enabled emboss value(s), and ${enabled.imprint} enabled imprint value(s), were detected across document defaults, styles, body, page chrome, notes, comments, and formatting revisions. Editable Writer stories preserve w:outline, w:shadow, w:emboss, and w:imprint through independently mixed Font-dialog controls, conflict-aware one-step Undo, Format Painter, bounded CSS paint projections, and exact DOCX export. Outline plus shadow remains valid; emboss and imprint stay mutually exclusive with the other enabled legacy effects. The browser and PDF projections are bounded visual approximations rather than a claim of desktop-engine pixel identity, and no non-standard shortcut is invented.`
444
+ });
445
+ if (invalidCount) issues.push({
446
+ code: 'docx.legacy-text-effects.invalid',
447
+ severity: 'warning',
448
+ feature: 'Legacy text effects',
449
+ message: `${invalidCount} malformed, duplicated, misplaced, namespace-spoofed, text-bearing, child-bearing, extra-attribute, unknown, or conflicting legacy text-effect property set(s) are ignored instead of enabling contradictory or untrusted paint effects.`
450
+ });
451
+ return issues;
452
+ }
272
453
  const WORDPROCESSINGML_NAMESPACES = new Set([
273
454
  'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
274
455
  'http://purl.oclc.org/ooxml/wordprocessingml/main'
@@ -665,6 +846,63 @@ async function diagnoseDocxParagraphShading(archive, document) {
665
846
  });
666
847
  return issues;
667
848
  }
849
+ const RUN_FONT_DIAGNOSTIC_PART_PATTERN = /^word\/(?:document|styles|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
850
+ async function diagnoseDocxRunFonts(archive, document) {
851
+ const parts = [
852
+ {
853
+ path: 'word/document.xml',
854
+ document
855
+ }
856
+ ];
857
+ for (const path of archive.paths('word/'))if ('word/document.xml' !== path.toLowerCase() && RUN_FONT_DIAGNOSTIC_PART_PATTERN.test(path)) parts.push({
858
+ path,
859
+ document: await archive.xml(path)
860
+ });
861
+ let validCount = 0;
862
+ let directSlotCount = 0;
863
+ let themeSlotCount = 0;
864
+ let hintCount = 0;
865
+ let invalidCount = 0;
866
+ for (const part of parts){
867
+ const propertySets = descendants(part.document, 'rPr').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? ''));
868
+ for (const properties of propertySets){
869
+ if (!directChildren(properties, 'rFonts').length) continue;
870
+ const inspection = inspectDocxRunFonts(properties);
871
+ if ('valid' === inspection.status) {
872
+ validCount += 1;
873
+ if (!inspection.value) continue;
874
+ for (const slot of [
875
+ inspection.value.ascii,
876
+ inspection.value.highAnsi,
877
+ inspection.value.eastAsia,
878
+ inspection.value.complexScript
879
+ ]){
880
+ if (slot?.name) directSlotCount += 1;
881
+ if (slot?.theme) themeSlotCount += 1;
882
+ }
883
+ if (inspection.value.hint) hintCount += 1;
884
+ } else if ('invalid' === inspection.status) invalidCount += 1;
885
+ }
886
+ invalidCount += descendants(part.document, 'rFonts').filter((element)=>{
887
+ const parent = element.parentElement;
888
+ return !parent || 'rPr' !== parent.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(parent.namespaceURI ?? '');
889
+ }).length;
890
+ }
891
+ const issues = [];
892
+ if (validCount) issues.push({
893
+ code: "docx.script-fonts",
894
+ severity: 'info',
895
+ feature: 'Script-specific run fonts',
896
+ message: `${validCount} native run-font property set(s), containing ${directSlotCount} direct slot value(s), ${themeSlotCount} theme slot reference(s), and ${hintCount} script hint(s), preserve the independent ASCII, high ANSI, East Asian, and complex-script identities through style inheritance, mixed-script browser rendering, body and page-chrome editing, formatting revisions, and DOCX export. Browser-resolved families remain separate from native source identity so font substitution does not rewrite untouched theme references.`
897
+ });
898
+ if (invalidCount) issues.push({
899
+ code: "docx.script-fonts.invalid",
900
+ severity: 'warning',
901
+ feature: 'Script-specific run fonts',
902
+ message: `${invalidCount} malformed, duplicated, misplaced, namespace-spoofed, child-bearing, text-bearing, unknown, or oversized run-font property set(s) are ignored instead of applying untrusted font metadata.`
903
+ });
904
+ return issues;
905
+ }
668
906
  const SUPPORTED_CHART_ELEMENTS = new Set([
669
907
  'barChart',
670
908
  'lineChart',
@@ -1687,6 +1925,13 @@ async function analyzeDocxCompatibility(file, messages, sourcePackage) {
1687
1925
  }
1688
1926
  issues.push(...await diagnoseDocxNotes(archive, document));
1689
1927
  issues.push(...await diagnoseDocxEquations(archive, document));
1928
+ if (document) {
1929
+ issues.push(...await diagnoseDocxKerning(archive, document));
1930
+ issues.push(...await diagnoseDocxEmphasisMarks(archive, document));
1931
+ issues.push(...await diagnoseDocxHiddenText(archive, document));
1932
+ issues.push(...await diagnoseDocxLegacyTextEffects(archive, document));
1933
+ issues.push(...await diagnoseDocxRunFonts(archive, document));
1934
+ }
1690
1935
  issues.push(...await diagnoseDocxPageChrome(archive));
1691
1936
  if (archive.paths('word/embeddings/').length) issues.push(work_office_diagnostics_issue('docx.embedded', 'Embedded objects', 'Embedded Office and OLE payload parts plus safe relationships are retained in source-backed exports, but Work does not render or edit their object anchors; placement inside regenerated document XML may normalize.'));
1692
1937
  if (document) {
@@ -1716,7 +1961,7 @@ async function analyzeDocxCompatibility(file, messages, sourcePackage) {
1716
1961
  const supportedRunFormattingRevisionCount = runFormattingRevisions.filter(isSupportedDocxRunFormattingChange).length;
1717
1962
  const supportedParagraphFormattingRevisionCount = paragraphFormattingRevisions.filter(isSupportedDocxParagraphFormattingChange).length;
1718
1963
  if (textRevisions.some((revision)=>descendants(revision, 't').length || descendants(revision, 'delText').length)) issues.push(work_office_diagnostics_issue('docx.revisions', 'Tracked changes', 'Body-text insertions and deletions preserve their author and date, remain reviewable in Work, and round-trip as native DOCX revisions.', 'info'));
1719
- if (supportedRunFormattingRevisionCount) issues.push(work_office_diagnostics_issue('docx.revisions.formatting', 'Character-formatting revisions', `${supportedRunFormattingRevisionCount} bounded character-formatting revision(s) preserve author, date, current formatting, and prior bold, italic, underline, strike, subscript, superscript, font, size, color, highlight, and grid state. They remain reviewable in Work and round-trip as native w:rPrChange records.`, 'info'));
1964
+ if (supportedRunFormattingRevisionCount) issues.push(work_office_diagnostics_issue('docx.revisions.formatting', 'Character-formatting revisions', `${supportedRunFormattingRevisionCount} bounded character-formatting revision(s) preserve author, date, current formatting, and prior bold, italic, underline, strike, text case, hidden text, outline, shadow, emboss, imprint, subscript, superscript, font, size, color, highlight, character scale, spacing, kerning threshold, emphasis mark, baseline position, and grid state. They remain reviewable in Work and round-trip as native w:rPrChange records.`, 'info'));
1720
1965
  if (supportedParagraphFormattingRevisionCount) issues.push(work_office_diagnostics_issue('docx.revisions.paragraph-formatting', 'Paragraph-formatting revisions', `${supportedParagraphFormattingRevisionCount} bounded paragraph-formatting revision(s) preserve author, date, current formatting, and prior alignment, direction, indentation, spacing, pagination, outline, tab-stop, border, shading, and collapsed state. They remain reviewable in Work and round-trip as native w:pPrChange records.`, 'info'));
1721
1966
  if (textRevisions.some((revision)=>!descendants(revision, 't').length && !descendants(revision, 'delText').length) || supportedRunFormattingRevisionCount !== runFormattingRevisions.length || supportedParagraphFormattingRevisionCount !== paragraphFormattingRevisions.length || [
1722
1967
  'moveFrom',