documentation-hub 5.7.2
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/.eslintrc.json +43 -0
- package/.github/workflows/build.yml +64 -0
- package/.github/workflows/ci.yml +39 -0
- package/.vscode/extensions.json +3 -0
- package/Current.md +97 -0
- package/DocHub_Image.png +0 -0
- package/README.md +666 -0
- package/USER_GUIDE.md +1173 -0
- package/Updater.md +311 -0
- package/build/256x256.png +0 -0
- package/build/512x512.png +0 -0
- package/build/app-update.yml +4 -0
- package/build/create-icon.js +208 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon_1024x1024.png +0 -0
- package/dist/assets/Analytics-BpsG9895.js +1 -0
- package/dist/assets/Card-IAZin8kp.js +1 -0
- package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
- package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
- package/dist/assets/Documents-CqZ25axS.js +1 -0
- package/dist/assets/Input-l89xwXBi.js +1 -0
- package/dist/assets/Reporting-DqdHJY_a.js +1 -0
- package/dist/assets/Search-XNbu5z_3.js +1 -0
- package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
- package/dist/assets/Sessions-ClZOPYNc.js +1 -0
- package/dist/assets/Settings-DUEHGURa.js +11 -0
- package/dist/assets/index-8xUe8ptc.js +24 -0
- package/dist/assets/index-RYyJqF7O.css +1 -0
- package/dist/assets/path-BkOl0AGO.js +1 -0
- package/dist/assets/promises-ID_B9S-h.js +1 -0
- package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
- package/dist/assets/useToast-yRSO1dkm.js +1 -0
- package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
- package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
- package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
- package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
- package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
- package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
- package/dist/electron/main-CXkNtyv-.js +19789 -0
- package/dist/electron/main.js +5 -0
- package/dist/electron/preload.js +1 -0
- package/dist/icon.png +0 -0
- package/dist/index.html +27 -0
- package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
- package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
- package/docs/README.md +115 -0
- package/docs/TOC_WIRING_GUIDE.md +344 -0
- package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
- package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
- package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
- package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
- package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
- package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
- package/docs/analysis/List_Implementation.md +206 -0
- package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
- package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
- package/docs/analysis/RefactorStyles.md +852 -0
- package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
- package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
- package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
- package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
- package/docs/analysis/github-issues-to-create.md +237 -0
- package/docs/api/API_README.md +538 -0
- package/docs/api/API_REFERENCE.md +751 -0
- package/docs/api/TYPE_DEFINITIONS.md +869 -0
- package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
- package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
- package/docs/docxmlater-readme.md +1341 -0
- package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
- package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
- package/docs/fixes/README.md +37 -0
- package/docs/github-issues/issue-1-body.md +125 -0
- package/docs/github-issues/issue-10-body.md +850 -0
- package/docs/github-issues/issue-2-body.md +200 -0
- package/docs/github-issues/issue-3-body.md +270 -0
- package/docs/github-issues/issue-4-body.md +169 -0
- package/docs/github-issues/issue-5-body.md +173 -0
- package/docs/github-issues/issue-6-body.md +158 -0
- package/docs/github-issues/issue-7-body.md +171 -0
- package/docs/github-issues/issue-8-body.md +407 -0
- package/docs/github-issues/issue-9-body.md +515 -0
- package/docs/github-issues/issue-tracker.md +274 -0
- package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
- package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
- package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
- package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
- package/docs/implementation/RefactorStyles.md +588 -0
- package/docs/implementation/implement-plan.md +489 -0
- package/docs/implementation/missing-helpers-implementation.md +391 -0
- package/docs/implementation/refactor-plan.md +520 -0
- package/docs/implementation/session-implementation-complete.md +233 -0
- package/docs/implementation/session-management-plan.md +250 -0
- package/docs/setup-checklist.md +77 -0
- package/docs/versions/changelog.md +345 -0
- package/electron/customUpdater.ts +656 -0
- package/electron/main.ts +2441 -0
- package/electron/memoryConfig.ts +187 -0
- package/electron/preload.ts +394 -0
- package/electron/proxyConfig.ts +340 -0
- package/electron/services/BackupService.ts +452 -0
- package/electron/services/DictionaryService.ts +402 -0
- package/electron/services/LocalDictionaryLookupService.ts +147 -0
- package/electron/services/PowerAutomateApiService.ts +231 -0
- package/electron/services/SharePointSyncService.ts +474 -0
- package/electron/windowsCertStore.ts +427 -0
- package/electron/zscalerConfig.ts +381 -0
- package/eslint.config.js +92 -0
- package/jest.config.js +52 -0
- package/package.json +214 -0
- package/postcss.config.mjs +6 -0
- package/public/icon.png +0 -0
- package/publish-release.ps1 +5 -0
- package/renovate.json +30 -0
- package/src/App.tsx +216 -0
- package/src/__mocks__/p-limit.js +12 -0
- package/src/__mocks__/styleMock.js +1 -0
- package/src/components/common/BugReportButton.tsx +44 -0
- package/src/components/common/BugReportDialog.tsx +193 -0
- package/src/components/common/Button.tsx +153 -0
- package/src/components/common/Card.tsx +86 -0
- package/src/components/common/ColorPickerDialog.tsx +177 -0
- package/src/components/common/ConfirmDialog.tsx +96 -0
- package/src/components/common/DebugConsole.tsx +275 -0
- package/src/components/common/EmptyState.tsx +183 -0
- package/src/components/common/ErrorBoundary.tsx +98 -0
- package/src/components/common/ErrorDetailsDialog.tsx +153 -0
- package/src/components/common/ErrorFallback.tsx +218 -0
- package/src/components/common/Input.tsx +109 -0
- package/src/components/common/Skeleton.tsx +184 -0
- package/src/components/common/SplashScreen.tsx +81 -0
- package/src/components/common/Toast.tsx +155 -0
- package/src/components/common/Tooltip.tsx +79 -0
- package/src/components/common/UpdateNotification.tsx +320 -0
- package/src/components/comparison/ComparisonWindow.tsx +374 -0
- package/src/components/comparison/SideBySideDiff.tsx +486 -0
- package/src/components/comparison/index.ts +8 -0
- package/src/components/document/DocumentUploader.tsx +288 -0
- package/src/components/document/HyperlinkPreview.tsx +430 -0
- package/src/components/document/HyperlinkService.md +1484 -0
- package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
- package/src/components/document/InlineChangesView.tsx +707 -0
- package/src/components/document/ProcessingProgress.tsx +303 -0
- package/src/components/document/ProcessingResults.tsx +256 -0
- package/src/components/document/TrackedChangesDetail.tsx +530 -0
- package/src/components/document/TrackedChangesPanel.tsx +546 -0
- package/src/components/document/VirtualDocumentList.tsx +240 -0
- package/src/components/editor/DocumentEditor.tsx +723 -0
- package/src/components/editor/DocumentEditorModal.tsx +640 -0
- package/src/components/editor/EditorQuickActions.tsx +502 -0
- package/src/components/editor/EditorToolbar.tsx +312 -0
- package/src/components/editor/TableEditor.tsx +926 -0
- package/src/components/editor/index.ts +18 -0
- package/src/components/layout/Header.tsx +190 -0
- package/src/components/layout/Sidebar.tsx +313 -0
- package/src/components/layout/TitleBar.tsx +190 -0
- package/src/components/navigation/CommandPalette.tsx +233 -0
- package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
- package/src/components/sessions/ChangeItem.tsx +408 -0
- package/src/components/sessions/ChangeViewer.tsx +1155 -0
- package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
- package/src/components/sessions/ProcessingOptions.tsx +297 -0
- package/src/components/sessions/ReplacementsTab.tsx +438 -0
- package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
- package/src/components/sessions/SessionManager.tsx +188 -0
- package/src/components/sessions/StylesEditor.tsx +1335 -0
- package/src/components/sessions/TabContainer.tsx +151 -0
- package/src/components/sessions/VirtualSessionList.tsx +157 -0
- package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
- package/src/components/settings/CertificateManager.tsx +410 -0
- package/src/components/settings/SegmentedControl.tsx +88 -0
- package/src/components/settings/SettingRow.tsx +52 -0
- package/src/contexts/GlobalStatsContext.tsx +396 -0
- package/src/contexts/SessionContext.tsx +2129 -0
- package/src/contexts/ThemeContext.tsx +428 -0
- package/src/contexts/UserSettingsContext.tsx +290 -0
- package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
- package/src/global.d.ts +273 -0
- package/src/hooks/useDocumentQueue.tsx +210 -0
- package/src/hooks/useToast.tsx +55 -0
- package/src/main.tsx +10 -0
- package/src/pages/Analytics.tsx +386 -0
- package/src/pages/CurrentSession.tsx +1174 -0
- package/src/pages/Dashboard.tsx +319 -0
- package/src/pages/Documents.tsx +317 -0
- package/src/pages/Projects.tsx +250 -0
- package/src/pages/Reporting.tsx +386 -0
- package/src/pages/Search.tsx +349 -0
- package/src/pages/Sessions.tsx +285 -0
- package/src/pages/Settings.tsx +2662 -0
- package/src/services/HyperlinkService.ts +1085 -0
- package/src/services/document/DocXMLaterProcessor.ts +617 -0
- package/src/services/document/DocumentProcessingComparison.ts +856 -0
- package/src/services/document/DocumentSnapshotService.ts +575 -0
- package/src/services/document/WordDocumentProcessor.ts +10509 -0
- package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
- package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
- package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
- package/src/services/document/blanklines/BlankLineManager.ts +658 -0
- package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
- package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
- package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
- package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
- package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
- package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
- package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
- package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
- package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
- package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
- package/src/services/document/blanklines/index.ts +67 -0
- package/src/services/document/blanklines/rules/additionRules.ts +337 -0
- package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
- package/src/services/document/blanklines/rules/removalRules.ts +362 -0
- package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
- package/src/services/document/blanklines/types.ts +29 -0
- package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
- package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
- package/src/services/document/helpers/whitespace.ts +117 -0
- package/src/services/document/list/ListNormalizer.ts +947 -0
- package/src/services/document/list/index.ts +45 -0
- package/src/services/document/list/list-detection.ts +275 -0
- package/src/services/document/list/list-types.ts +162 -0
- package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
- package/src/services/document/processors/ListProcessor.ts +257 -0
- package/src/services/document/processors/StructureProcessor.ts +176 -0
- package/src/services/document/processors/StyleProcessor.ts +389 -0
- package/src/services/document/processors/TableProcessor.ts +2238 -0
- package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
- package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
- package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
- package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
- package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
- package/src/services/document/processors/index.ts +28 -0
- package/src/services/document/types/docx-processing.ts +310 -0
- package/src/services/editor/EditorActionHandlers.ts +901 -0
- package/src/services/editor/index.ts +13 -0
- package/src/setupTests.ts +47 -0
- package/src/styles/global.css +782 -0
- package/src/types/backup.ts +132 -0
- package/src/types/dictionary.ts +125 -0
- package/src/types/document-processing.ts +331 -0
- package/src/types/docxmlater-augments.d.ts +142 -0
- package/src/types/editor.ts +280 -0
- package/src/types/electron.ts +340 -0
- package/src/types/globalStats.ts +155 -0
- package/src/types/hyperlink.ts +471 -0
- package/src/types/operations.ts +354 -0
- package/src/types/session.ts +427 -0
- package/src/types/settings.ts +112 -0
- package/src/utils/MemoryMonitor.ts +248 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/colorConvert.ts +306 -0
- package/src/utils/diffUtils.ts +347 -0
- package/src/utils/documentUtils.ts +202 -0
- package/src/utils/electronGuard.ts +62 -0
- package/src/utils/indexedDB.ts +915 -0
- package/src/utils/logger.ts +717 -0
- package/src/utils/pathSecurity.ts +232 -0
- package/src/utils/pathValidator.ts +236 -0
- package/src/utils/processingTimeEstimator.ts +153 -0
- package/src/utils/safeJsonParse.ts +62 -0
- package/src/utils/textSanitizer.ts +162 -0
- package/src/utils/urlHelpers.ts +304 -0
- package/src/utils/urlPatterns.ts +198 -0
- package/src/utils/urlSanitizer.ts +152 -0
- package/src/vite-env.d.ts +11 -0
- package/tsconfig.electron.json +19 -0
- package/tsconfig.json +36 -0
- package/tsconfig.node.json +12 -0
- package/typedoc.json +45 -0
- package/vite.config.ts +152 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Suite for HLP Tips Column Bullet Preservation (v5.3.5)
|
|
3
|
+
*
|
|
4
|
+
* Verifies that bullet markers in two-column HLP table tips cells (FFF2CC)
|
|
5
|
+
* are preserved when paragraphs use ListParagraph with inherited numbering.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { vi, describe, it, expect, beforeEach, type Mocked } from 'vitest';
|
|
9
|
+
import { TableProcessor } from '../TableProcessor';
|
|
10
|
+
import { Document, Table, Paragraph, Run, Hyperlink, PreservedElement, TableCell, TableRow, NumberingLevel, WORD_NATIVE_BULLETS } from 'docxmlater';
|
|
11
|
+
|
|
12
|
+
vi.mock('docxmlater');
|
|
13
|
+
|
|
14
|
+
// ═══════════════════════════════════════════════════════════
|
|
15
|
+
// Mock Factories
|
|
16
|
+
// ═══════════════════════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
function createMockRun(bold: boolean, characterStyle?: string): Mocked<Run> {
|
|
19
|
+
return {
|
|
20
|
+
getText: vi.fn().mockReturnValue('Text'),
|
|
21
|
+
getFormatting: vi.fn().mockReturnValue({ bold, characterStyle }),
|
|
22
|
+
setFont: vi.fn(),
|
|
23
|
+
setSize: vi.fn(),
|
|
24
|
+
setBold: vi.fn(),
|
|
25
|
+
setColor: vi.fn(),
|
|
26
|
+
setUnderline: vi.fn(),
|
|
27
|
+
setCharacterStyle: vi.fn(),
|
|
28
|
+
} as unknown as Mocked<Run>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createMockParagraph(style: string): Mocked<Paragraph> {
|
|
32
|
+
return {
|
|
33
|
+
getStyle: vi.fn().mockReturnValue(style),
|
|
34
|
+
setStyle: vi.fn(),
|
|
35
|
+
getText: vi.fn().mockReturnValue('Sample text'),
|
|
36
|
+
getRuns: vi.fn().mockReturnValue([]),
|
|
37
|
+
getNumbering: vi.fn().mockReturnValue(null),
|
|
38
|
+
getContent: vi.fn().mockReturnValue([]),
|
|
39
|
+
setAlignment: vi.fn(),
|
|
40
|
+
setSpaceBefore: vi.fn(),
|
|
41
|
+
setSpaceAfter: vi.fn(),
|
|
42
|
+
setLineSpacing: vi.fn(),
|
|
43
|
+
setNumbering: vi.fn(),
|
|
44
|
+
getLeftIndent: vi.fn().mockReturnValue(undefined),
|
|
45
|
+
setLeftIndent: vi.fn(),
|
|
46
|
+
setFirstLineIndent: vi.fn(),
|
|
47
|
+
} as unknown as Mocked<Paragraph>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function createMockParagraphWithRuns(runs: any[], style = 'Normal'): Mocked<Paragraph> {
|
|
51
|
+
return {
|
|
52
|
+
getStyle: vi.fn().mockReturnValue(style),
|
|
53
|
+
setStyle: vi.fn(),
|
|
54
|
+
getText: vi.fn().mockReturnValue('Sample text'),
|
|
55
|
+
getRuns: vi.fn().mockReturnValue(runs),
|
|
56
|
+
getNumbering: vi.fn().mockReturnValue(null),
|
|
57
|
+
getContent: vi.fn().mockReturnValue(runs),
|
|
58
|
+
setAlignment: vi.fn(),
|
|
59
|
+
setSpaceBefore: vi.fn(),
|
|
60
|
+
setSpaceAfter: vi.fn(),
|
|
61
|
+
setLineSpacing: vi.fn(),
|
|
62
|
+
setNumbering: vi.fn(),
|
|
63
|
+
getLeftIndent: vi.fn().mockReturnValue(undefined),
|
|
64
|
+
setLeftIndent: vi.fn(),
|
|
65
|
+
setFirstLineIndent: vi.fn(),
|
|
66
|
+
} as unknown as Mocked<Paragraph>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function createMockRow(cells: any[]): Mocked<TableRow> {
|
|
70
|
+
return {
|
|
71
|
+
getCells: vi.fn().mockReturnValue(cells),
|
|
72
|
+
} as unknown as Mocked<TableRow>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function createHLPHeaderCell(text = 'High Level Process'): Mocked<TableCell> {
|
|
76
|
+
const mockParagraph = createMockParagraph('Heading2');
|
|
77
|
+
mockParagraph.getText.mockReturnValue(text);
|
|
78
|
+
return {
|
|
79
|
+
getShading: vi.fn().mockReturnValue('FFC000'),
|
|
80
|
+
setShading: vi.fn(),
|
|
81
|
+
setBorders: vi.fn(),
|
|
82
|
+
setMargins: vi.fn(),
|
|
83
|
+
getParagraphs: vi.fn().mockReturnValue([mockParagraph]),
|
|
84
|
+
getFormatting: vi.fn().mockReturnValue({ shading: { fill: 'FFC000' } }),
|
|
85
|
+
getColumnSpan: vi.fn().mockReturnValue(2),
|
|
86
|
+
setAllRunsFont: vi.fn(),
|
|
87
|
+
setAllRunsSize: vi.fn(),
|
|
88
|
+
getText: vi.fn().mockReturnValue(text),
|
|
89
|
+
hasNestedTables: vi.fn().mockReturnValue(false),
|
|
90
|
+
} as unknown as Mocked<TableCell>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a content (left) cell with a main action item (ListParagraph, no numbering)
|
|
95
|
+
* and a numbered sub-item (numId=33, level=1).
|
|
96
|
+
*/
|
|
97
|
+
function createContentCell(): Mocked<TableCell> {
|
|
98
|
+
const mainRun = createMockRun(true);
|
|
99
|
+
const mainPara = createMockParagraphWithRuns([mainRun], 'ListParagraph');
|
|
100
|
+
mainPara.getText.mockReturnValue('Verify the member request');
|
|
101
|
+
let mainNumbering: { numId: number; level: number } | null = null;
|
|
102
|
+
mainPara.getNumbering.mockImplementation(() => mainNumbering);
|
|
103
|
+
mainPara.setNumbering.mockImplementation((numId: number, level: number) => {
|
|
104
|
+
mainNumbering = { numId, level };
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const subRun = createMockRun(false);
|
|
108
|
+
const subPara = createMockParagraphWithRuns([subRun], 'ListParagraph');
|
|
109
|
+
subPara.getNumbering.mockReturnValue({ numId: 33, level: 1 });
|
|
110
|
+
subPara.getText.mockReturnValue('Check eligibility');
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
getShading: vi.fn().mockReturnValue('FFFFFF'),
|
|
114
|
+
setShading: vi.fn(),
|
|
115
|
+
setBorders: vi.fn(),
|
|
116
|
+
setMargins: vi.fn(),
|
|
117
|
+
getParagraphs: vi.fn().mockReturnValue([mainPara, subPara]),
|
|
118
|
+
getFormatting: vi.fn().mockReturnValue({ shading: undefined }),
|
|
119
|
+
getColumnSpan: vi.fn().mockReturnValue(1),
|
|
120
|
+
setAllRunsFont: vi.fn(),
|
|
121
|
+
setAllRunsSize: vi.fn(),
|
|
122
|
+
getText: vi.fn().mockReturnValue('Verify the member request\nCheck eligibility'),
|
|
123
|
+
hasNestedTables: vi.fn().mockReturnValue(false),
|
|
124
|
+
} as unknown as Mocked<TableCell>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a tips (right) cell with ListParagraph paragraphs that have
|
|
129
|
+
* inherited numbering (no explicit numPr) — the scenario that causes
|
|
130
|
+
* bullet stripping without the v5.3.5 fix.
|
|
131
|
+
*/
|
|
132
|
+
function createTipsCellWithInheritedBullets(texts: string[]): Mocked<TableCell> {
|
|
133
|
+
const paras = texts.map(text => {
|
|
134
|
+
const run = createMockRun(false);
|
|
135
|
+
run.getText.mockReturnValue(text);
|
|
136
|
+
const para = createMockParagraphWithRuns([run], 'ListParagraph');
|
|
137
|
+
para.getText.mockReturnValue(text);
|
|
138
|
+
para.getNumbering.mockReturnValue(null); // Inherited — no explicit numPr
|
|
139
|
+
return para;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
getShading: vi.fn().mockReturnValue('FFF2CC'),
|
|
144
|
+
setShading: vi.fn(),
|
|
145
|
+
setBorders: vi.fn(),
|
|
146
|
+
setMargins: vi.fn(),
|
|
147
|
+
getParagraphs: vi.fn().mockReturnValue(paras),
|
|
148
|
+
getFormatting: vi.fn().mockReturnValue({ shading: { fill: 'FFF2CC' } }),
|
|
149
|
+
getColumnSpan: vi.fn().mockReturnValue(1),
|
|
150
|
+
setAllRunsFont: vi.fn(),
|
|
151
|
+
setAllRunsSize: vi.fn(),
|
|
152
|
+
getText: vi.fn().mockReturnValue(texts.join('\n')),
|
|
153
|
+
hasNestedTables: vi.fn().mockReturnValue(false),
|
|
154
|
+
} as unknown as Mocked<TableCell>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Create a tips cell with already-explicit bullet numbering.
|
|
159
|
+
*/
|
|
160
|
+
function createTipsCellWithExplicitBullets(texts: string[]): Mocked<TableCell> {
|
|
161
|
+
const paras = texts.map(text => {
|
|
162
|
+
const run = createMockRun(false);
|
|
163
|
+
run.getText.mockReturnValue(text);
|
|
164
|
+
const para = createMockParagraphWithRuns([run], 'ListParagraph');
|
|
165
|
+
para.getText.mockReturnValue(text);
|
|
166
|
+
para.getNumbering.mockReturnValue({ numId: 5, level: 0 }); // Explicit numbering
|
|
167
|
+
return para;
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
getShading: vi.fn().mockReturnValue('FFF2CC'),
|
|
172
|
+
setShading: vi.fn(),
|
|
173
|
+
setBorders: vi.fn(),
|
|
174
|
+
setMargins: vi.fn(),
|
|
175
|
+
getParagraphs: vi.fn().mockReturnValue(paras),
|
|
176
|
+
getFormatting: vi.fn().mockReturnValue({ shading: { fill: 'FFF2CC' } }),
|
|
177
|
+
getColumnSpan: vi.fn().mockReturnValue(1),
|
|
178
|
+
setAllRunsFont: vi.fn(),
|
|
179
|
+
setAllRunsSize: vi.fn(),
|
|
180
|
+
getText: vi.fn().mockReturnValue(texts.join('\n')),
|
|
181
|
+
hasNestedTables: vi.fn().mockReturnValue(false),
|
|
182
|
+
} as unknown as Mocked<TableCell>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function createMockNumberingManager(nextNumId = 50) {
|
|
186
|
+
return {
|
|
187
|
+
createCustomList: vi.fn().mockReturnValue(nextNumId),
|
|
188
|
+
getInstance: vi.fn().mockReturnValue(null),
|
|
189
|
+
getAbstractNumbering: vi.fn().mockReturnValue(null),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ═══════════════════════════════════════════════════════════
|
|
194
|
+
// Tests
|
|
195
|
+
// ═══════════════════════════════════════════════════════════
|
|
196
|
+
|
|
197
|
+
describe('HLP Tips Column Bullet Preservation', () => {
|
|
198
|
+
let processor: TableProcessor;
|
|
199
|
+
let mockDoc: Mocked<Document>;
|
|
200
|
+
let mockManager: ReturnType<typeof createMockNumberingManager>;
|
|
201
|
+
|
|
202
|
+
beforeEach(() => {
|
|
203
|
+
vi.clearAllMocks();
|
|
204
|
+
processor = new TableProcessor();
|
|
205
|
+
mockManager = createMockNumberingManager(50);
|
|
206
|
+
|
|
207
|
+
mockDoc = {
|
|
208
|
+
getTables: vi.fn().mockReturnValue([]),
|
|
209
|
+
getBodyElements: vi.fn().mockReturnValue([]),
|
|
210
|
+
getNumberingManager: vi.fn().mockReturnValue(mockManager),
|
|
211
|
+
} as unknown as Mocked<Document>;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should assign bullet numbering to tips cell ListParagraph paragraphs with inherited numbering', async () => {
|
|
215
|
+
const tipsTexts = [
|
|
216
|
+
'Ask the member why an additional supply is required',
|
|
217
|
+
'Verify the date of the last order',
|
|
218
|
+
];
|
|
219
|
+
const contentCell = createContentCell();
|
|
220
|
+
const tipsCell = createTipsCellWithInheritedBullets(tipsTexts);
|
|
221
|
+
|
|
222
|
+
const headerCell = createHLPHeaderCell();
|
|
223
|
+
const headerRow = createMockRow([headerCell]);
|
|
224
|
+
const dataRow = createMockRow([contentCell, tipsCell]);
|
|
225
|
+
const table = {
|
|
226
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
227
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
228
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
229
|
+
setBorders: vi.fn(),
|
|
230
|
+
} as unknown as Mocked<Table>;
|
|
231
|
+
|
|
232
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
233
|
+
await processor.processHLPTables(mockDoc);
|
|
234
|
+
|
|
235
|
+
// createCustomList should have been called for the tips bullet list
|
|
236
|
+
expect(mockManager.createCustomList).toHaveBeenCalled();
|
|
237
|
+
|
|
238
|
+
// Each tips paragraph with text should get the tips bullet numId
|
|
239
|
+
const tipsParas = tipsCell.getParagraphs();
|
|
240
|
+
for (const tipPara of tipsParas) {
|
|
241
|
+
expect(tipPara.setStyle).toHaveBeenCalledWith('Normal');
|
|
242
|
+
expect(tipPara.setNumbering).toHaveBeenCalledWith(50, 0);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should NOT assign tips bullet numId to empty tips paragraphs', async () => {
|
|
247
|
+
const tipsTexts = [
|
|
248
|
+
'Ask the member why an additional supply is required',
|
|
249
|
+
'', // Empty paragraph — should not get numbering
|
|
250
|
+
];
|
|
251
|
+
const contentCell = createContentCell();
|
|
252
|
+
const tipsCell = createTipsCellWithInheritedBullets(tipsTexts);
|
|
253
|
+
|
|
254
|
+
const headerCell = createHLPHeaderCell();
|
|
255
|
+
const headerRow = createMockRow([headerCell]);
|
|
256
|
+
const dataRow = createMockRow([contentCell, tipsCell]);
|
|
257
|
+
const table = {
|
|
258
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
259
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
260
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
261
|
+
setBorders: vi.fn(),
|
|
262
|
+
} as unknown as Mocked<Table>;
|
|
263
|
+
|
|
264
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
265
|
+
await processor.processHLPTables(mockDoc);
|
|
266
|
+
|
|
267
|
+
const tipsParas = tipsCell.getParagraphs();
|
|
268
|
+
// First paragraph (has text) should get numbering
|
|
269
|
+
expect(tipsParas[0].setNumbering).toHaveBeenCalledWith(50, 0);
|
|
270
|
+
// Second paragraph (empty) should NOT get numbering
|
|
271
|
+
expect(tipsParas[1].setNumbering).not.toHaveBeenCalled();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should NOT assign tips bullet numId to content column paragraphs', async () => {
|
|
275
|
+
const tipsTexts = ['Tip text here'];
|
|
276
|
+
const contentCell = createContentCell();
|
|
277
|
+
const tipsCell = createTipsCellWithInheritedBullets(tipsTexts);
|
|
278
|
+
|
|
279
|
+
const headerCell = createHLPHeaderCell();
|
|
280
|
+
const headerRow = createMockRow([headerCell]);
|
|
281
|
+
const dataRow = createMockRow([contentCell, tipsCell]);
|
|
282
|
+
const table = {
|
|
283
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
284
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
285
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
286
|
+
setBorders: vi.fn(),
|
|
287
|
+
} as unknown as Mocked<Table>;
|
|
288
|
+
|
|
289
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
290
|
+
await processor.processHLPTables(mockDoc);
|
|
291
|
+
|
|
292
|
+
// Content cell main para (ListParagraph, no numbering) should get
|
|
293
|
+
// discoveredNumId=33 (from sub-item), NOT tipsBulletNumId=50
|
|
294
|
+
const contentParas = contentCell.getParagraphs();
|
|
295
|
+
const mainPara = contentParas[0];
|
|
296
|
+
expect(mainPara.setNumbering).toHaveBeenCalledWith(33, 0);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('should NOT create tips bullet list for single-column HLP tables', async () => {
|
|
300
|
+
const mainRun = createMockRun(true);
|
|
301
|
+
const mainPara = createMockParagraphWithRuns([mainRun], 'ListParagraph');
|
|
302
|
+
mainPara.getText.mockReturnValue('Action item');
|
|
303
|
+
mainPara.getNumbering.mockReturnValue(null);
|
|
304
|
+
|
|
305
|
+
const subRun = createMockRun(false);
|
|
306
|
+
const subPara = createMockParagraphWithRuns([subRun], 'ListParagraph');
|
|
307
|
+
subPara.getNumbering.mockReturnValue({ numId: 33, level: 1 });
|
|
308
|
+
subPara.getText.mockReturnValue('Sub-item');
|
|
309
|
+
|
|
310
|
+
const dataCell = {
|
|
311
|
+
getShading: vi.fn().mockReturnValue('FFFFFF'),
|
|
312
|
+
setShading: vi.fn(),
|
|
313
|
+
setBorders: vi.fn(),
|
|
314
|
+
setMargins: vi.fn(),
|
|
315
|
+
getParagraphs: vi.fn().mockReturnValue([mainPara, subPara]),
|
|
316
|
+
getFormatting: vi.fn().mockReturnValue({ shading: undefined }),
|
|
317
|
+
getColumnSpan: vi.fn().mockReturnValue(1),
|
|
318
|
+
setAllRunsFont: vi.fn(),
|
|
319
|
+
setAllRunsSize: vi.fn(),
|
|
320
|
+
getText: vi.fn().mockReturnValue('Action item\nSub-item'),
|
|
321
|
+
hasNestedTables: vi.fn().mockReturnValue(false),
|
|
322
|
+
} as unknown as Mocked<TableCell>;
|
|
323
|
+
|
|
324
|
+
const headerCell = createHLPHeaderCell();
|
|
325
|
+
headerCell.getColumnSpan.mockReturnValue(1);
|
|
326
|
+
const headerRow = createMockRow([headerCell]);
|
|
327
|
+
const dataRow = createMockRow([dataCell]);
|
|
328
|
+
const table = {
|
|
329
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
330
|
+
getColumnCount: vi.fn().mockReturnValue(1),
|
|
331
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
332
|
+
setBorders: vi.fn(),
|
|
333
|
+
} as unknown as Mocked<Table>;
|
|
334
|
+
|
|
335
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
336
|
+
await processor.processHLPTables(mockDoc);
|
|
337
|
+
|
|
338
|
+
// createCustomList should NOT be called for tips bullets in single-column tables.
|
|
339
|
+
// It may still be called for fallback or bullet conversion, but not with "HLP Tips Bullet" label.
|
|
340
|
+
const tipsBulletCalls = mockManager.createCustomList.mock.calls.filter(
|
|
341
|
+
(call: any[]) => call[1] === 'HLP Tips Bullet'
|
|
342
|
+
);
|
|
343
|
+
expect(tipsBulletCalls).toHaveLength(0);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should NOT reassign numbering to tips paragraphs that already have explicit numbering', async () => {
|
|
347
|
+
const tipsTexts = ['Tip with explicit bullets'];
|
|
348
|
+
const contentCell = createContentCell();
|
|
349
|
+
const tipsCell = createTipsCellWithExplicitBullets(tipsTexts);
|
|
350
|
+
|
|
351
|
+
const headerCell = createHLPHeaderCell();
|
|
352
|
+
const headerRow = createMockRow([headerCell]);
|
|
353
|
+
const dataRow = createMockRow([contentCell, tipsCell]);
|
|
354
|
+
const table = {
|
|
355
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
356
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
357
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
358
|
+
setBorders: vi.fn(),
|
|
359
|
+
} as unknown as Mocked<Table>;
|
|
360
|
+
|
|
361
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
362
|
+
await processor.processHLPTables(mockDoc);
|
|
363
|
+
|
|
364
|
+
// Paragraph already has explicit numbering (numId=5), so the
|
|
365
|
+
// ListParagraph→Normal fixup block is NOT entered — style stays,
|
|
366
|
+
// and setNumbering should NOT be called with tips bullet numId
|
|
367
|
+
const tipsParas = tipsCell.getParagraphs();
|
|
368
|
+
expect(tipsParas[0].setStyle).not.toHaveBeenCalledWith('Normal');
|
|
369
|
+
expect(tipsParas[0].setNumbering).not.toHaveBeenCalledWith(50, 0);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should handle multiple data rows with tips bullets', async () => {
|
|
373
|
+
const headerCell = createHLPHeaderCell();
|
|
374
|
+
const headerRow = createMockRow([headerCell]);
|
|
375
|
+
|
|
376
|
+
const rows = [headerRow];
|
|
377
|
+
for (let i = 0; i < 3; i++) {
|
|
378
|
+
const contentCell = createContentCell();
|
|
379
|
+
const tipsCell = createTipsCellWithInheritedBullets([
|
|
380
|
+
`Tip row ${i + 1} item A`,
|
|
381
|
+
`Tip row ${i + 1} item B`,
|
|
382
|
+
]);
|
|
383
|
+
rows.push(createMockRow([contentCell, tipsCell]));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const table = {
|
|
387
|
+
getRows: vi.fn().mockReturnValue(rows),
|
|
388
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
389
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
390
|
+
setBorders: vi.fn(),
|
|
391
|
+
} as unknown as Mocked<Table>;
|
|
392
|
+
|
|
393
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
394
|
+
await processor.processHLPTables(mockDoc);
|
|
395
|
+
|
|
396
|
+
// All 3 rows × 2 tips paragraphs = 6 tips paragraphs should get numbering
|
|
397
|
+
for (let ri = 1; ri <= 3; ri++) {
|
|
398
|
+
const dataRow = rows[ri];
|
|
399
|
+
const tipsCell = dataRow.getCells()[1];
|
|
400
|
+
const tipsParas = tipsCell.getParagraphs();
|
|
401
|
+
for (const tipPara of tipsParas) {
|
|
402
|
+
expect(tipPara.setNumbering).toHaveBeenCalledWith(50, 0);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('should gracefully handle null numbering manager', async () => {
|
|
408
|
+
mockDoc.getNumberingManager = vi.fn().mockReturnValue(null) as any;
|
|
409
|
+
|
|
410
|
+
const tipsTexts = ['Tip text'];
|
|
411
|
+
const contentCell = createContentCell();
|
|
412
|
+
const tipsCell = createTipsCellWithInheritedBullets(tipsTexts);
|
|
413
|
+
|
|
414
|
+
const headerCell = createHLPHeaderCell();
|
|
415
|
+
const headerRow = createMockRow([headerCell]);
|
|
416
|
+
const dataRow = createMockRow([contentCell, tipsCell]);
|
|
417
|
+
const table = {
|
|
418
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
419
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
420
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
421
|
+
setBorders: vi.fn(),
|
|
422
|
+
} as unknown as Mocked<Table>;
|
|
423
|
+
|
|
424
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
425
|
+
|
|
426
|
+
// Should not throw — tipsBulletNumId will be 0, so tips paragraphs
|
|
427
|
+
// get style changed to Normal but no numbering assigned
|
|
428
|
+
await expect(processor.processHLPTables(mockDoc)).resolves.not.toThrow();
|
|
429
|
+
|
|
430
|
+
const tipsParas = tipsCell.getParagraphs();
|
|
431
|
+
expect(tipsParas[0].setStyle).toHaveBeenCalledWith('Normal');
|
|
432
|
+
expect(tipsParas[0].setNumbering).not.toHaveBeenCalled();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('should call createCustomList with bullet format and Symbol font', async () => {
|
|
436
|
+
const tipsTexts = ['Bullet item'];
|
|
437
|
+
const contentCell = createContentCell();
|
|
438
|
+
const tipsCell = createTipsCellWithInheritedBullets(tipsTexts);
|
|
439
|
+
|
|
440
|
+
const headerCell = createHLPHeaderCell();
|
|
441
|
+
const headerRow = createMockRow([headerCell]);
|
|
442
|
+
const dataRow = createMockRow([contentCell, tipsCell]);
|
|
443
|
+
const table = {
|
|
444
|
+
getRows: vi.fn().mockReturnValue([headerRow, dataRow]),
|
|
445
|
+
getColumnCount: vi.fn().mockReturnValue(2),
|
|
446
|
+
isFloating: vi.fn().mockReturnValue(false),
|
|
447
|
+
setBorders: vi.fn(),
|
|
448
|
+
} as unknown as Mocked<Table>;
|
|
449
|
+
|
|
450
|
+
mockDoc.getTables.mockReturnValue([table]);
|
|
451
|
+
await processor.processHLPTables(mockDoc);
|
|
452
|
+
|
|
453
|
+
// Verify createCustomList was called with a NumberingLevel array and label
|
|
454
|
+
expect(mockManager.createCustomList).toHaveBeenCalledWith(
|
|
455
|
+
expect.arrayContaining([expect.any(Object)]),
|
|
456
|
+
'HLP Tips Bullet',
|
|
457
|
+
);
|
|
458
|
+
});
|
|
459
|
+
});
|