@pixerate/editor 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -2
- package/THIRD_PARTY_NOTICES.md +80 -0
- package/dist/agent/index.cjs +10 -8
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +4 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +4437 -411
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +934 -4
- package/dist/canvas/index.d.ts +934 -4
- package/dist/canvas/index.js +4309 -283
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4BVP64JJ.cjs +1406 -0
- package/dist/chunk-4BVP64JJ.cjs.map +1 -0
- package/dist/chunk-664LQYFJ.js +115 -0
- package/dist/chunk-664LQYFJ.js.map +1 -0
- package/dist/chunk-7WISYZFO.cjs +740 -0
- package/dist/chunk-7WISYZFO.cjs.map +1 -0
- package/dist/chunk-AL6JMGWW.cjs +783 -0
- package/dist/chunk-AL6JMGWW.cjs.map +1 -0
- package/dist/chunk-BVP3TSLH.cjs +69 -0
- package/dist/chunk-BVP3TSLH.cjs.map +1 -0
- package/dist/{chunk-RIKBJLS2.cjs → chunk-C7P22VIP.cjs} +2001 -279
- package/dist/chunk-C7P22VIP.cjs.map +1 -0
- package/dist/chunk-D6FH2YAX.cjs +131 -0
- package/dist/chunk-D6FH2YAX.cjs.map +1 -0
- package/dist/chunk-ECCCYKGL.js +740 -0
- package/dist/chunk-ECCCYKGL.js.map +1 -0
- package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
- package/dist/chunk-FD4LPFAE.cjs.map +1 -0
- package/dist/{chunk-QBJ22YZR.js → chunk-FH6F67DN.js} +1999 -277
- package/dist/chunk-FH6F67DN.js.map +1 -0
- package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
- package/dist/chunk-FPENXAEJ.js.map +1 -0
- package/dist/chunk-HLIMTC6N.js +1 -0
- package/dist/chunk-HLIMTC6N.js.map +1 -0
- package/dist/chunk-HRMEDT2L.js +1406 -0
- package/dist/chunk-HRMEDT2L.js.map +1 -0
- package/dist/{chunk-QGHGJ56O.js → chunk-IXHSYOVY.js} +2518 -122
- package/dist/chunk-IXHSYOVY.js.map +1 -0
- package/dist/chunk-MKA3AHLV.cjs +256 -0
- package/dist/chunk-MKA3AHLV.cjs.map +1 -0
- package/dist/chunk-NAXVVS5I.js +783 -0
- package/dist/chunk-NAXVVS5I.js.map +1 -0
- package/dist/chunk-O5RYH2PG.js +69 -0
- package/dist/chunk-O5RYH2PG.js.map +1 -0
- package/dist/chunk-OXSV64JX.js +689 -0
- package/dist/chunk-OXSV64JX.js.map +1 -0
- package/dist/chunk-P3RQ5UJE.cjs +689 -0
- package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
- package/dist/chunk-P6ODPZ4W.js +256 -0
- package/dist/chunk-P6ODPZ4W.js.map +1 -0
- package/dist/chunk-PL4JB3BF.cjs +1 -0
- package/dist/chunk-PL4JB3BF.cjs.map +1 -0
- package/dist/{chunk-GVSMRPHB.cjs → chunk-PO6A6QQH.cjs} +2607 -211
- package/dist/chunk-PO6A6QQH.cjs.map +1 -0
- package/dist/{chunk-JJDLPEWL.js → chunk-QGYDWPRM.js} +2 -2
- package/dist/chunk-RR7F5GUM.js +5726 -0
- package/dist/chunk-RR7F5GUM.js.map +1 -0
- package/dist/chunk-TNNJXF46.cjs +115 -0
- package/dist/chunk-TNNJXF46.cjs.map +1 -0
- package/dist/chunk-U5HZSFCS.js +131 -0
- package/dist/chunk-U5HZSFCS.js.map +1 -0
- package/dist/{chunk-MJZBNWG7.js → chunk-UAKDG62Z.js} +309 -581
- package/dist/chunk-UAKDG62Z.js.map +1 -0
- package/dist/{chunk-CL37JGFW.cjs → chunk-V3CHHWOE.cjs} +4 -4
- package/dist/{chunk-CL37JGFW.cjs.map → chunk-V3CHHWOE.cjs.map} +1 -1
- package/dist/chunk-WSQKHXW7.cjs +5726 -0
- package/dist/chunk-WSQKHXW7.cjs.map +1 -0
- package/dist/{chunk-AA4ZEVCC.cjs → chunk-X4N4WUKB.cjs} +336 -608
- package/dist/chunk-X4N4WUKB.cjs.map +1 -0
- package/dist/commands/index.cjs +74 -1
- package/dist/commands/index.cjs.map +1 -1
- package/dist/commands/index.d.cts +38 -353
- package/dist/commands/index.d.ts +38 -353
- package/dist/commands/index.js +73 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/comment-store-BEMgVlAA.d.cts +135 -0
- package/dist/comment-store-BEMgVlAA.d.ts +135 -0
- package/dist/compare/index.cjs +15 -0
- package/dist/compare/index.cjs.map +1 -0
- package/dist/compare/index.d.cts +58 -0
- package/dist/compare/index.d.ts +58 -0
- package/dist/compare/index.js +15 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/controller-BIJiNoVs.d.cts +1842 -0
- package/dist/controller-BIJiNoVs.d.ts +1842 -0
- package/dist/documents-CHT1U5Vs.d.ts +86 -0
- package/dist/documents-Gp7wb0Me.d.cts +86 -0
- package/dist/extensions/index.cjs +100 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +16 -4
- package/dist/extensions/index.d.ts +16 -4
- package/dist/extensions/index.js +100 -5
- package/dist/generation/index.cjs +2317 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +1015 -0
- package/dist/generation/index.d.ts +1015 -0
- package/dist/generation/index.js +2317 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/grammar/index.cjs +48 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +322 -100
- package/dist/grammar/index.d.ts +322 -100
- package/dist/grammar/index.js +54 -9
- package/dist/image-editor/index.cjs +4392 -481
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +1249 -97
- package/dist/image-editor/index.d.ts +1249 -97
- package/dist/image-editor/index.js +4281 -370
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index-7a6bHTLy.d.ts +1754 -0
- package/dist/index-Csd5qI8u.d.cts +1754 -0
- package/dist/index.cjs +1682 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -21
- package/dist/index.d.ts +118 -21
- package/dist/index.js +1630 -47
- package/dist/index.js.map +1 -1
- package/dist/mention-text-CDnCFd3c.d.cts +53 -0
- package/dist/mention-text-CDnCFd3c.d.ts +53 -0
- package/dist/migrate-iTlm3a8h.d.cts +112 -0
- package/dist/migrate-iTlm3a8h.d.ts +112 -0
- package/dist/model-C1zApQM8.d.cts +219 -0
- package/dist/model-C1zApQM8.d.ts +219 -0
- package/dist/persistence/index.cjs +676 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +230 -0
- package/dist/persistence/index.d.ts +230 -0
- package/dist/persistence/index.js +676 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
- package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.cts} +12 -1
- package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.ts} +12 -1
- package/dist/registry-D32LpIc4.d.cts +354 -0
- package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
- package/dist/registry-evKTP4ls.d.ts +354 -0
- package/dist/schema-DYDGdYL9.d.cts +41 -0
- package/dist/schema-DYDGdYL9.d.ts +41 -0
- package/dist/serializers/index.cjs +12 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +40 -12
- package/dist/serializers/index.d.ts +40 -12
- package/dist/serializers/index.js +12 -3
- package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
- package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
- package/dist/spreadsheet/index.cjs +161 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +611 -20
- package/dist/spreadsheet/index.d.ts +611 -20
- package/dist/spreadsheet/index.js +168 -10
- package/dist/storage-BpFfspHm.d.cts +120 -0
- package/dist/storage-BpFfspHm.d.ts +120 -0
- package/dist/tokens/index.cjs +115 -0
- package/dist/tokens/index.cjs.map +1 -0
- package/dist/tokens/index.d.cts +212 -0
- package/dist/tokens/index.d.ts +212 -0
- package/dist/tokens/index.js +115 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
- package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
- package/dist/{track-changes-BSF58RK0.d.cts → track-changes-D_VAPELi.d.cts} +110 -144
- package/dist/{track-changes-BSF58RK0.d.ts → track-changes-Db_fGEvx.d.ts} +110 -144
- package/package.json +21 -1
- package/dist/chunk-4SUNJZWB.cjs.map +0 -1
- package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
- package/dist/chunk-AXV2ZW34.cjs +0 -118
- package/dist/chunk-AXV2ZW34.cjs.map +0 -1
- package/dist/chunk-B2ZRLN4S.js +0 -118
- package/dist/chunk-B2ZRLN4S.js.map +0 -1
- package/dist/chunk-GVSMRPHB.cjs.map +0 -1
- package/dist/chunk-K3R5NG2D.js +0 -3100
- package/dist/chunk-K3R5NG2D.js.map +0 -1
- package/dist/chunk-MJZBNWG7.js.map +0 -1
- package/dist/chunk-OYXSKQFR.js.map +0 -1
- package/dist/chunk-QBJ22YZR.js.map +0 -1
- package/dist/chunk-QGHGJ56O.js.map +0 -1
- package/dist/chunk-RIKBJLS2.cjs.map +0 -1
- package/dist/chunk-XDMXXC4Z.cjs +0 -3100
- package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
- package/dist/controller-pePCJLT1.d.cts +0 -959
- package/dist/controller-pePCJLT1.d.ts +0 -959
- package/dist/index-CCr_z9kF.d.cts +0 -899
- package/dist/index-Ck6ajwXh.d.ts +0 -899
- /package/dist/{chunk-JJDLPEWL.js.map → chunk-QGYDWPRM.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,39 +1,64 @@
|
|
|
1
|
+
import "./chunk-HLIMTC6N.js";
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
FIELD_ALIASES,
|
|
4
|
+
MAX_DATA_SOURCE_FIELDS,
|
|
5
|
+
MAX_DATA_SOURCE_RECORDS,
|
|
6
|
+
MAX_MERGE_LENGTH,
|
|
7
|
+
MAX_MERGE_OUTPUTS,
|
|
4
8
|
compactVariableValues,
|
|
5
|
-
|
|
9
|
+
detectDelimiter,
|
|
6
10
|
extractInstructionNames,
|
|
7
11
|
extractTemplateNames,
|
|
8
12
|
extractVariableNames,
|
|
9
13
|
extractVariables,
|
|
10
|
-
getLatestVersion,
|
|
11
|
-
getPromptDiagnostics,
|
|
12
|
-
getTemplateBody,
|
|
13
14
|
getVariableFormFields,
|
|
14
15
|
mapRawOffsetToResolved,
|
|
15
16
|
mapResolvedOffsetToRaw,
|
|
16
|
-
|
|
17
|
+
matchFields,
|
|
18
|
+
mergeRecords,
|
|
19
|
+
normalizeFieldKey,
|
|
20
|
+
normalizeFieldNames,
|
|
21
|
+
parseDataSource,
|
|
22
|
+
recordToValues,
|
|
17
23
|
resolveTemplates,
|
|
18
24
|
resolveTemplatesWithMapping,
|
|
19
25
|
resolveVariables,
|
|
26
|
+
serializeMergeOutputs
|
|
27
|
+
} from "./chunk-OXSV64JX.js";
|
|
28
|
+
import {
|
|
29
|
+
TEMPLATE_DEPTH_ERROR,
|
|
30
|
+
TEMPLATE_LOOP_ERROR,
|
|
31
|
+
evaluatePromptTokens,
|
|
32
|
+
getLatestVersion,
|
|
33
|
+
getPromptDiagnostics,
|
|
34
|
+
getTemplateBody,
|
|
35
|
+
resolvePrompt,
|
|
20
36
|
tokenizePrompt,
|
|
21
37
|
tokenizePromptWithDiagnostics
|
|
22
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-FPENXAEJ.js";
|
|
23
39
|
import {
|
|
24
40
|
Autocorrect,
|
|
25
41
|
BUILT_IN_IMPORT_ADAPTERS,
|
|
26
42
|
Bookmark,
|
|
43
|
+
CHARACTER_STYLE_MARK_NAME,
|
|
27
44
|
COMMENT_MARK_NAME,
|
|
45
|
+
CharacterStyle,
|
|
28
46
|
ColorHighlighter,
|
|
29
47
|
Comments,
|
|
30
48
|
CrossReference,
|
|
31
49
|
DEFAULT_AUTOCORRECT_EXCEPTIONS,
|
|
32
50
|
DEFAULT_DOCX_MAX_IMAGE_SIZE,
|
|
51
|
+
DEFAULT_STYLES,
|
|
33
52
|
DEFAULT_ZIP_MAX_ENTRIES,
|
|
34
53
|
DEFAULT_ZIP_MAX_TOTAL_SIZE,
|
|
35
54
|
DOCX_MIME_TYPES,
|
|
55
|
+
DocumentCompare,
|
|
56
|
+
EMPTY_FIND_REPLACE_SNAPSHOT,
|
|
57
|
+
FIND_OPTION_TOGGLES,
|
|
58
|
+
FIND_PARAGRAPH_MARK,
|
|
36
59
|
FileImport,
|
|
60
|
+
FindReplace,
|
|
61
|
+
FindReplaceStore,
|
|
37
62
|
FontSize,
|
|
38
63
|
Footnote,
|
|
39
64
|
FootnoteReference,
|
|
@@ -43,41 +68,60 @@ import {
|
|
|
43
68
|
ImportAdapterRegistry,
|
|
44
69
|
ImportError,
|
|
45
70
|
LoadingNode,
|
|
71
|
+
MAX_FIND_PATTERN_LENGTH,
|
|
46
72
|
Markdown,
|
|
47
73
|
Mention,
|
|
74
|
+
NORMAL_STYLE_ID,
|
|
48
75
|
Outline,
|
|
76
|
+
ParagraphStyles,
|
|
49
77
|
RichClipboard,
|
|
50
78
|
SMILIE_REPLACEMENTS,
|
|
79
|
+
STYLE_ID_ATTRIBUTE,
|
|
51
80
|
SlashCommands,
|
|
52
81
|
SmilieReplacer,
|
|
82
|
+
StyleRegistry,
|
|
53
83
|
TableOfContents,
|
|
54
84
|
TemplateSuggestions,
|
|
55
85
|
ZipArchive,
|
|
56
86
|
ZipError,
|
|
87
|
+
applyDocumentComparison,
|
|
88
|
+
applyReplacements,
|
|
57
89
|
autocorrectPluginKey,
|
|
58
90
|
buildOutlineTree,
|
|
59
91
|
capitalizeSentenceRules,
|
|
92
|
+
captureSelectionFormat,
|
|
60
93
|
commentsPluginKey,
|
|
94
|
+
compareInEditor,
|
|
95
|
+
compileFindPattern,
|
|
61
96
|
computeOutline,
|
|
62
97
|
createDocxImportAdapter,
|
|
98
|
+
createFindReplaceCommands,
|
|
63
99
|
createImportAdapterRegistry,
|
|
64
100
|
createImportContext,
|
|
65
101
|
createMentionExtension,
|
|
66
102
|
createOutlineStore,
|
|
103
|
+
createParagraphStylesStore,
|
|
67
104
|
createRichTextPreset,
|
|
105
|
+
createSearchBudget,
|
|
106
|
+
createStyleRegistry,
|
|
68
107
|
crossReferencePluginKey,
|
|
69
108
|
defaultAutocorrectRules,
|
|
70
109
|
defaultImportRegistry,
|
|
71
110
|
documentStructureCommandItems,
|
|
72
111
|
docxImportAdapter,
|
|
73
112
|
docxToDocumentImport,
|
|
113
|
+
expandReplacement,
|
|
74
114
|
fileImportPluginKey,
|
|
115
|
+
findAllMatches,
|
|
75
116
|
findAutocorrection,
|
|
76
117
|
findCommentRanges,
|
|
77
118
|
findHexColors,
|
|
78
119
|
findImportAdapter,
|
|
120
|
+
findReplacePluginKey,
|
|
121
|
+
foldCodePoint,
|
|
79
122
|
footnotesMarkdownIt,
|
|
80
123
|
footnotesPluginKey,
|
|
124
|
+
formatFindStatus,
|
|
81
125
|
fractionRules,
|
|
82
126
|
getActiveHeading,
|
|
83
127
|
getBookmarks,
|
|
@@ -87,9 +131,14 @@ import {
|
|
|
87
131
|
getCommentStore,
|
|
88
132
|
getCrossReferenceTargets,
|
|
89
133
|
getDocumentStructureCommandItems,
|
|
134
|
+
getFindReplaceState,
|
|
135
|
+
getFindReplaceStore,
|
|
90
136
|
getFootnotes,
|
|
91
137
|
getImportAccept,
|
|
138
|
+
getMentionNodes,
|
|
92
139
|
getOutline,
|
|
140
|
+
getParagraphStyleAt,
|
|
141
|
+
getStyleRegistry,
|
|
93
142
|
getTableOfContentsEntries,
|
|
94
143
|
handleImageInsertion,
|
|
95
144
|
htmlImportAdapter,
|
|
@@ -100,16 +149,23 @@ import {
|
|
|
100
149
|
insertImageNode,
|
|
101
150
|
insertImportedDocument,
|
|
102
151
|
isInsidePromptToken,
|
|
152
|
+
isParagraphStyleAvailable,
|
|
103
153
|
isUnsafeZipPath,
|
|
154
|
+
isValidStyleId,
|
|
104
155
|
markdownImportAdapter,
|
|
105
156
|
navigateToHeading,
|
|
106
157
|
outlinePluginKey,
|
|
158
|
+
paragraphStylesPluginKey,
|
|
159
|
+
parseReplacement,
|
|
107
160
|
plainTextImportAdapter,
|
|
108
161
|
readZip,
|
|
109
162
|
registerImportAdapter,
|
|
110
163
|
removeImageNode,
|
|
111
164
|
richClipboardPluginKey,
|
|
112
165
|
rtfImportAdapter,
|
|
166
|
+
safeCSSValue,
|
|
167
|
+
searchDocument,
|
|
168
|
+
setMentionRoleAt,
|
|
113
169
|
smartQuoteRules,
|
|
114
170
|
smilieAutocorrectRules,
|
|
115
171
|
symbolRules,
|
|
@@ -119,24 +175,39 @@ import {
|
|
|
119
175
|
twoInitialCapitalsRules,
|
|
120
176
|
unregisterImportAdapter,
|
|
121
177
|
updateImageSrc,
|
|
178
|
+
validateFindPattern,
|
|
122
179
|
writeRichClipboard,
|
|
123
180
|
zipCrc32
|
|
124
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-IXHSYOVY.js";
|
|
182
|
+
import {
|
|
183
|
+
compareDocuments,
|
|
184
|
+
compareHtml,
|
|
185
|
+
diffChanges,
|
|
186
|
+
diffSequences
|
|
187
|
+
} from "./chunk-NAXVVS5I.js";
|
|
125
188
|
import {
|
|
126
189
|
INSTRUCTION_REGEX,
|
|
127
190
|
TEMPLATE_REGEX,
|
|
128
191
|
VARIABLE_REGEX,
|
|
192
|
+
compareConditionValues,
|
|
193
|
+
conditionSubject,
|
|
194
|
+
describeConditionalTag,
|
|
129
195
|
escapeVariableText,
|
|
130
196
|
evaluateCondition,
|
|
197
|
+
evaluateConditionExpression,
|
|
198
|
+
formatComparisonOperand,
|
|
199
|
+
formatConditionalTag,
|
|
131
200
|
getSuppliedValue,
|
|
132
201
|
instructionRegex,
|
|
133
202
|
isPromptValueSet,
|
|
134
203
|
matchConditionalTags,
|
|
204
|
+
parseComparison,
|
|
205
|
+
parseConditionExpression,
|
|
135
206
|
parseVariableBody,
|
|
136
207
|
templateRegex,
|
|
137
208
|
unescapeVariableText,
|
|
138
209
|
variableRegex
|
|
139
|
-
} from "./chunk-
|
|
210
|
+
} from "./chunk-P6ODPZ4W.js";
|
|
140
211
|
import "./chunk-N7FG6CBO.js";
|
|
141
212
|
import {
|
|
142
213
|
PIXERATE_DOCUMENT_MIME,
|
|
@@ -148,62 +219,131 @@ import {
|
|
|
148
219
|
rtfToPlainText,
|
|
149
220
|
sanitizeImportedHtml,
|
|
150
221
|
serializeRichClipboardPayload
|
|
151
|
-
} from "./chunk-
|
|
222
|
+
} from "./chunk-QGYDWPRM.js";
|
|
152
223
|
import {
|
|
224
|
+
CONDITIONAL_FORMAT_ICON_SETS,
|
|
225
|
+
CONDITIONAL_FORMAT_PRESETS,
|
|
226
|
+
CONDITIONAL_FORMAT_STYLE_PRESETS,
|
|
227
|
+
CONDITIONAL_FORMAT_TIME_PERIODS,
|
|
228
|
+
ConditionalFormatEngine,
|
|
229
|
+
DATA_VALIDATION_ERROR_STYLE_OPTIONS,
|
|
230
|
+
DATA_VALIDATION_OPERATOR_OPTIONS,
|
|
231
|
+
DATA_VALIDATION_TYPE_OPTIONS,
|
|
153
232
|
DEFAULT_COLUMN_WIDTH,
|
|
233
|
+
DEFAULT_CONDITIONAL_FORMAT_STYLE,
|
|
234
|
+
DEFAULT_DATA_VALIDATION_MESSAGE,
|
|
235
|
+
DEFAULT_DATA_VALIDATION_TITLE,
|
|
154
236
|
DEFAULT_ROW_HEIGHT,
|
|
155
237
|
DataSourceBinder,
|
|
156
238
|
DependencyGraph,
|
|
239
|
+
EMPTY_CONDITIONAL_FORMAT_OVERLAY,
|
|
240
|
+
MAX_DEFINED_NAME_LENGTH,
|
|
241
|
+
MAX_SHEET_NAME_LENGTH,
|
|
242
|
+
NUMBER_FORMAT_PRESETS,
|
|
157
243
|
SPREADSHEET_CLIPBOARD_MIME,
|
|
158
244
|
SPREADSHEET_IMPORT_ADAPTERS,
|
|
159
245
|
SPREADSHEET_TABLE_ACTIONS,
|
|
160
246
|
SpreadsheetController,
|
|
247
|
+
adjustRangeForStructuralChange,
|
|
248
|
+
adjustRangesForStructuralChange,
|
|
161
249
|
aggregateValues,
|
|
162
250
|
applyFormulaSuggestion,
|
|
163
251
|
bindSpreadsheetTableActions,
|
|
252
|
+
blendConditionalFormatColors,
|
|
164
253
|
buildSpreadsheetView,
|
|
254
|
+
cellFormatForNumberFormat,
|
|
165
255
|
clampMenuPosition,
|
|
166
256
|
columnDependencyKey,
|
|
167
257
|
compareCellValues,
|
|
168
258
|
computeFillTarget,
|
|
169
259
|
computeRowGroups,
|
|
260
|
+
conditionalFormatContrastColor,
|
|
261
|
+
conditionalFormatIconCount,
|
|
262
|
+
conditionalFormatNumber,
|
|
263
|
+
conditionalFormatStyleString,
|
|
264
|
+
copySheetName,
|
|
265
|
+
createConditionalFormatRule,
|
|
170
266
|
createSpreadsheetClipboardData,
|
|
171
267
|
csvImportAdapter,
|
|
172
|
-
|
|
268
|
+
defaultIconThresholds,
|
|
269
|
+
deleteSheetInFormula,
|
|
270
|
+
describeConditionalFormat,
|
|
271
|
+
describeDataValidation,
|
|
272
|
+
evaluateConditionalFormats,
|
|
173
273
|
extractCellDependencies,
|
|
274
|
+
extractNameDependencies,
|
|
174
275
|
fillSeries,
|
|
276
|
+
findDataValidation,
|
|
277
|
+
findInvalidCells,
|
|
278
|
+
forEachRangeCell,
|
|
279
|
+
formatCellDisplay,
|
|
280
|
+
formatCellForDisplay,
|
|
281
|
+
formatRuleRanges,
|
|
282
|
+
formatSheetPrefix,
|
|
283
|
+
formatValueWithCode,
|
|
284
|
+
formulaIdentifiers,
|
|
285
|
+
getConditionalFormatCss,
|
|
286
|
+
getConditionalFormatIcon,
|
|
287
|
+
getDataBarCss,
|
|
175
288
|
getFillDirection,
|
|
176
289
|
getFormulaCaretContext,
|
|
177
290
|
getFormulaHints,
|
|
291
|
+
getNameManagerRows,
|
|
178
292
|
getRowSection,
|
|
293
|
+
getSheetTabMenuItems,
|
|
179
294
|
getSpreadsheetMenuItems,
|
|
180
295
|
getTableSections,
|
|
296
|
+
getValidationListValues,
|
|
181
297
|
importFileIntoSpreadsheet,
|
|
182
298
|
isBlankValue,
|
|
299
|
+
isGeneralNumberFormat,
|
|
300
|
+
isLambdaDefinition,
|
|
183
301
|
isSingleCellRange,
|
|
184
302
|
mapFormulaReferences,
|
|
185
303
|
matchesFilterRule,
|
|
304
|
+
matchesTimePeriod,
|
|
305
|
+
nextSheetName,
|
|
186
306
|
normalizeRange,
|
|
307
|
+
numberFormatForCellFormat,
|
|
187
308
|
offsetFormulaReferences,
|
|
188
|
-
parseCsv,
|
|
189
309
|
parseHtmlTable,
|
|
190
|
-
|
|
310
|
+
parseRuleRanges,
|
|
311
|
+
quoteSheetName,
|
|
191
312
|
rangeContains,
|
|
192
313
|
rangeContainsRange,
|
|
314
|
+
rangesContain,
|
|
193
315
|
rangesIntersect,
|
|
194
316
|
readSpreadsheetClipboard,
|
|
195
317
|
rebaseClipboardRows,
|
|
196
318
|
registerSpreadsheetImportAdapters,
|
|
197
319
|
remapFormulaReferences,
|
|
320
|
+
renameNameInFormula,
|
|
321
|
+
renameSheetInFormula,
|
|
198
322
|
roundFloat,
|
|
199
323
|
rowPassesFilters,
|
|
200
|
-
|
|
324
|
+
ruleAnchor,
|
|
325
|
+
ruleFormulaAt,
|
|
326
|
+
runSpreadsheetMenuItem,
|
|
201
327
|
serializeHtmlTable,
|
|
202
|
-
|
|
328
|
+
sheetDropIndex,
|
|
329
|
+
sheetNameNeedsQuotes,
|
|
203
330
|
shiftFormulaReferences,
|
|
331
|
+
shiftRuleFormula,
|
|
332
|
+
subtractRange,
|
|
333
|
+
subtractRangeFromRanges,
|
|
204
334
|
toNumber,
|
|
205
|
-
tsvImportAdapter
|
|
206
|
-
|
|
335
|
+
tsvImportAdapter,
|
|
336
|
+
validateCellInput,
|
|
337
|
+
validateDefinedName,
|
|
338
|
+
validateSheetName
|
|
339
|
+
} from "./chunk-RR7F5GUM.js";
|
|
340
|
+
import {
|
|
341
|
+
escapeCsvField,
|
|
342
|
+
parseCsv,
|
|
343
|
+
parseTsv,
|
|
344
|
+
serializeCsv,
|
|
345
|
+
serializeTsv
|
|
346
|
+
} from "./chunk-664LQYFJ.js";
|
|
207
347
|
import {
|
|
208
348
|
DirtyTracker,
|
|
209
349
|
HistoryManager,
|
|
@@ -213,14 +353,38 @@ import {
|
|
|
213
353
|
defaultIsEqual,
|
|
214
354
|
withoutDirty
|
|
215
355
|
} from "./chunk-2H7ZHPEJ.js";
|
|
356
|
+
import {
|
|
357
|
+
MARKDOWN_MENTION_SPLIT_REGEX,
|
|
358
|
+
escapeHtml,
|
|
359
|
+
extractMentions,
|
|
360
|
+
extractMentionsFromDoc,
|
|
361
|
+
getEditorMarkdown,
|
|
362
|
+
getEditorText,
|
|
363
|
+
htmlToPlainText,
|
|
364
|
+
markdownToTipTapHtml,
|
|
365
|
+
parseMentionSegments,
|
|
366
|
+
plainTextToSlice,
|
|
367
|
+
plainTextToTipTapHtml,
|
|
368
|
+
preprocessMarkdownFileLinks,
|
|
369
|
+
preprocessMarkdownMentions,
|
|
370
|
+
sanitizeHtml,
|
|
371
|
+
stripMarkdownCode
|
|
372
|
+
} from "./chunk-ECCCYKGL.js";
|
|
373
|
+
import {
|
|
374
|
+
MENTION_REGEX,
|
|
375
|
+
findTextMentions,
|
|
376
|
+
formatMentionText,
|
|
377
|
+
setMentionRoleInText
|
|
378
|
+
} from "./chunk-O5RYH2PG.js";
|
|
216
379
|
import {
|
|
217
380
|
BLOCK_CHANGE_ATTRIBUTE,
|
|
218
381
|
CommentStore,
|
|
219
382
|
DELETION_MARK_NAME,
|
|
220
383
|
FORMAT_CHANGE_MARK_NAME,
|
|
221
384
|
INSERTION_MARK_NAME,
|
|
222
|
-
|
|
223
|
-
|
|
385
|
+
MOVE_FROM_CLASS,
|
|
386
|
+
MOVE_ID_ATTRIBUTE,
|
|
387
|
+
MOVE_TO_CLASS,
|
|
224
388
|
TRACK_CHANGES_SKIP_META,
|
|
225
389
|
TrackChanges,
|
|
226
390
|
TrackChangesStore,
|
|
@@ -231,48 +395,47 @@ import {
|
|
|
231
395
|
createReviewId,
|
|
232
396
|
describeBlockChange,
|
|
233
397
|
describeFormatChange,
|
|
234
|
-
escapeHtml,
|
|
235
|
-
extractMentions,
|
|
236
|
-
extractMentionsFromDoc,
|
|
237
398
|
formatReviewTime,
|
|
238
|
-
getEditorMarkdown,
|
|
239
|
-
getEditorText,
|
|
240
399
|
getTrackChangesStore,
|
|
241
400
|
getTrackedChangeAt,
|
|
242
401
|
getTrackedChanges,
|
|
243
|
-
|
|
402
|
+
isMoveSized,
|
|
244
403
|
isTrackChangesEnabled,
|
|
245
|
-
markdownToTipTapHtml,
|
|
246
|
-
parseMentionSegments,
|
|
247
|
-
plainTextToSlice,
|
|
248
|
-
plainTextToTipTapHtml,
|
|
249
|
-
preprocessMarkdownFileLinks,
|
|
250
|
-
preprocessMarkdownMentions,
|
|
251
404
|
resolveTrackedChanges,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
} from "./chunk-MJZBNWG7.js";
|
|
405
|
+
trackChangesPluginKey,
|
|
406
|
+
trackedChangeLabel
|
|
407
|
+
} from "./chunk-UAKDG62Z.js";
|
|
256
408
|
import {
|
|
257
409
|
FORMULA_ERRORS,
|
|
258
410
|
FormulaEvaluator,
|
|
411
|
+
FormulaLambda,
|
|
259
412
|
FormulaParser,
|
|
260
413
|
MAX_FORMULA_ARRAY_SIZE,
|
|
414
|
+
MAX_LAMBDA_DEPTH,
|
|
415
|
+
MAX_NUMBER_FORMAT_CODE_CHARS,
|
|
416
|
+
NumberFormat,
|
|
261
417
|
WHOLE_COLUMN_END_ROW,
|
|
418
|
+
builtinNumberFormat,
|
|
419
|
+
builtinNumberFormatId,
|
|
262
420
|
checkFormulaArgumentCount,
|
|
421
|
+
clearNumberFormatCache,
|
|
263
422
|
colNameToIndex,
|
|
264
423
|
compareNumbers,
|
|
265
424
|
compareValues,
|
|
425
|
+
dateValueToSerial,
|
|
266
426
|
describeFormulaError,
|
|
267
|
-
|
|
268
|
-
|
|
427
|
+
formatGeneralFit,
|
|
428
|
+
formatNumberFormatValue,
|
|
429
|
+
formatTextFunction,
|
|
269
430
|
getFormulaArgumentSpecIndex,
|
|
270
431
|
getFormulaFunction,
|
|
271
432
|
getFormulaSignature,
|
|
272
433
|
getFormulaSignatureParts,
|
|
273
434
|
indexToColName,
|
|
274
435
|
isFormulaError,
|
|
436
|
+
isFormulaLambda,
|
|
275
437
|
listFormulaFunctions,
|
|
438
|
+
numberFormatColorToCss,
|
|
276
439
|
numberToText,
|
|
277
440
|
parseCellInput,
|
|
278
441
|
parseCellReference,
|
|
@@ -287,7 +450,7 @@ import {
|
|
|
287
450
|
tokenizeFormula,
|
|
288
451
|
unregisterFormulaFunction,
|
|
289
452
|
wildcardToRegExp
|
|
290
|
-
} from "./chunk-
|
|
453
|
+
} from "./chunk-FH6F67DN.js";
|
|
291
454
|
|
|
292
455
|
// src/controller.ts
|
|
293
456
|
import { Editor } from "@tiptap/core";
|
|
@@ -527,10 +690,1026 @@ var FileImportController = class {
|
|
|
527
690
|
function createFileImportController(getTarget, options) {
|
|
528
691
|
return new FileImportController(getTarget, options);
|
|
529
692
|
}
|
|
693
|
+
function summarizeImportStructure(outcomes) {
|
|
694
|
+
const reports = outcomes.map((outcome) => outcome.result?.structure).filter((report) => !!report);
|
|
695
|
+
if (!reports.length) return null;
|
|
696
|
+
const modes = new Set(reports.map((report) => report.mode));
|
|
697
|
+
const sum = (pick) => reports.reduce((total, report) => total + pick(report), 0);
|
|
698
|
+
return {
|
|
699
|
+
files: reports.length,
|
|
700
|
+
mode: modes.size > 1 ? "mixed" : reports[0].mode,
|
|
701
|
+
headings: sum((r) => r.counts.headings),
|
|
702
|
+
lists: sum((r) => r.counts.lists),
|
|
703
|
+
tables: sum((r) => r.counts.tables),
|
|
704
|
+
paragraphs: sum((r) => r.counts.paragraphs),
|
|
705
|
+
multiColumnPages: sum((r) => r.multiColumnPages),
|
|
706
|
+
confidence: Math.round(sum((r) => r.confidence) / reports.length * 100) / 100
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/import/pdf-layout.ts
|
|
711
|
+
var MAX_COLS = 63;
|
|
712
|
+
var MAX_TABLE_ROWS = 2e3;
|
|
713
|
+
var MAX_RULES = 2e3;
|
|
714
|
+
var MAX_DEPTH = 4;
|
|
715
|
+
var BULLET_GLYPH_RE = /^[•◦▪▫●○■□‣⁃∙·➢►▶✓✔❖]\s*/;
|
|
716
|
+
var BULLET_DASH_RE = /^[-–—*]\s+/;
|
|
717
|
+
var ORDERED_RE = /^(?:\((\d{1,3}|[a-zA-Z]|[ivxlcIVXLC]{1,6})\)|(\d{1,3}|[a-zA-Z]|[ivxlcIVXLC]{1,6})[.)])\s+/;
|
|
718
|
+
var MARKER_ONLY_RE = /^(?:[•◦▪▫●○■□‣⁃∙·➢►▶✓✔❖]|\(?(?:\d{1,3}|[a-zA-Z]|[ivxlcIVXLC]{1,6})[.)])$/;
|
|
719
|
+
var PAGE_NUMBER_RE = /^(?:page\s+)?(?:\d{1,4}|[ivxlcdm]{1,7})(?:\s*(?:of|\/)\s*\d{1,4})?$/i;
|
|
720
|
+
var DASHED_PAGE_NUMBER_RE = /^[-–—]\s*\d{1,4}\s*[-–—]$/;
|
|
721
|
+
var SENTENCE_END_RE = /[.!?:;]["'”’)\]]?$/;
|
|
722
|
+
var BOLD_FONT_RE = /bold|black|heavy|semibold|demi/i;
|
|
723
|
+
var ITALIC_FONT_RE = /italic|oblique/i;
|
|
724
|
+
function minOf(list, fn) {
|
|
725
|
+
let min = Infinity;
|
|
726
|
+
for (const item of list) min = Math.min(min, fn(item));
|
|
727
|
+
return min;
|
|
728
|
+
}
|
|
729
|
+
function maxOf(list, fn) {
|
|
730
|
+
let max = -Infinity;
|
|
731
|
+
for (const item of list) max = Math.max(max, fn(item));
|
|
732
|
+
return max;
|
|
733
|
+
}
|
|
734
|
+
function lowerBound(values, target) {
|
|
735
|
+
let lo = 0;
|
|
736
|
+
let hi = values.length;
|
|
737
|
+
while (lo < hi) {
|
|
738
|
+
const mid = lo + hi >> 1;
|
|
739
|
+
if (values[mid] < target) lo = mid + 1;
|
|
740
|
+
else hi = mid;
|
|
741
|
+
}
|
|
742
|
+
return lo;
|
|
743
|
+
}
|
|
744
|
+
function median(values) {
|
|
745
|
+
if (!values.length) return 0;
|
|
746
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
747
|
+
const mid = sorted.length >> 1;
|
|
748
|
+
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
749
|
+
}
|
|
750
|
+
var countWords = (text) => {
|
|
751
|
+
let words = 0;
|
|
752
|
+
let inWord = false;
|
|
753
|
+
for (let i = 0; i < text.length; i++) {
|
|
754
|
+
const space = text.charCodeAt(i) <= 32;
|
|
755
|
+
if (!space && !inWord) words++;
|
|
756
|
+
inWord = !space;
|
|
757
|
+
}
|
|
758
|
+
return words;
|
|
759
|
+
};
|
|
760
|
+
var collapse = (text) => text.replace(/\s+/g, " ").trim();
|
|
761
|
+
function runSize(run) {
|
|
762
|
+
if (run.fontSize && run.fontSize > 0) return run.fontSize;
|
|
763
|
+
if (run.height && run.height > 0) return run.height;
|
|
764
|
+
return 10;
|
|
765
|
+
}
|
|
766
|
+
function buildFragments(runs) {
|
|
767
|
+
const items = runs.filter((run) => typeof run.text === "string" && run.text.trim() !== "" && Number.isFinite(run.x) && Number.isFinite(run.y)).map((run) => {
|
|
768
|
+
const size = runSize(run);
|
|
769
|
+
const width = run.width !== void 0 && run.width >= 0 ? run.width : run.text.length * size * 0.5;
|
|
770
|
+
return {
|
|
771
|
+
text: run.text,
|
|
772
|
+
x0: run.x,
|
|
773
|
+
x1: run.x + width,
|
|
774
|
+
y: run.y,
|
|
775
|
+
size,
|
|
776
|
+
bold: run.bold ?? BOLD_FONT_RE.test(run.fontName ?? ""),
|
|
777
|
+
italic: run.italic ?? ITALIC_FONT_RE.test(run.fontName ?? "")
|
|
778
|
+
};
|
|
779
|
+
});
|
|
780
|
+
items.sort((a, b) => b.y - a.y || a.x0 - b.x0);
|
|
781
|
+
const frags = [];
|
|
782
|
+
let i = 0;
|
|
783
|
+
while (i < items.length) {
|
|
784
|
+
const anchor = items[i];
|
|
785
|
+
let j = i + 1;
|
|
786
|
+
while (j < items.length && anchor.y - items[j].y <= Math.max(1, Math.min(anchor.size, items[j].size) * 0.5)) j++;
|
|
787
|
+
const row = items.slice(i, j).sort((a, b) => a.x0 - b.x0);
|
|
788
|
+
i = j;
|
|
789
|
+
let current = null;
|
|
790
|
+
const finish = () => {
|
|
791
|
+
if (!current) return;
|
|
792
|
+
let best = "";
|
|
793
|
+
let bestChars = -1;
|
|
794
|
+
current.styleChars.forEach((chars, key) => {
|
|
795
|
+
if (chars > bestChars) {
|
|
796
|
+
best = key;
|
|
797
|
+
bestChars = chars;
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
const [size, bold, italic] = best.split("|");
|
|
801
|
+
current.size = Number(size);
|
|
802
|
+
current.bold = bold === "1";
|
|
803
|
+
current.italic = italic === "1";
|
|
804
|
+
current.text = collapse(current.text);
|
|
805
|
+
current.words = countWords(current.text);
|
|
806
|
+
current.top = current.y + current.size * 0.8;
|
|
807
|
+
current.bottom = current.y - current.size * 0.2;
|
|
808
|
+
if (current.text) frags.push(current);
|
|
809
|
+
current = null;
|
|
810
|
+
};
|
|
811
|
+
for (const item of row) {
|
|
812
|
+
if (current) {
|
|
813
|
+
const gap = item.x0 - current.x1;
|
|
814
|
+
const em = Math.max(current.size, item.size);
|
|
815
|
+
const markerOnly = MARKER_ONLY_RE.test(collapse(current.text));
|
|
816
|
+
if (gap > em * (markerOnly ? 6 : 1)) finish();
|
|
817
|
+
}
|
|
818
|
+
if (!current) {
|
|
819
|
+
current = {
|
|
820
|
+
text: item.text,
|
|
821
|
+
x0: item.x0,
|
|
822
|
+
x1: item.x1,
|
|
823
|
+
y: item.y,
|
|
824
|
+
top: 0,
|
|
825
|
+
bottom: 0,
|
|
826
|
+
size: item.size,
|
|
827
|
+
bold: item.bold,
|
|
828
|
+
italic: item.italic,
|
|
829
|
+
words: 0,
|
|
830
|
+
styleChars: /* @__PURE__ */ new Map()
|
|
831
|
+
};
|
|
832
|
+
} else {
|
|
833
|
+
const gap = item.x0 - current.x1;
|
|
834
|
+
if (gap > Math.max(current.size, item.size) * 0.15 && !/\s$/.test(current.text) && !/^\s/.test(item.text)) {
|
|
835
|
+
current.text += " ";
|
|
836
|
+
}
|
|
837
|
+
current.text += item.text;
|
|
838
|
+
current.x1 = Math.max(current.x1, item.x1);
|
|
839
|
+
}
|
|
840
|
+
const key = `${Math.round(item.size * 2) / 2}|${item.bold ? 1 : 0}|${item.italic ? 1 : 0}`;
|
|
841
|
+
current.styleChars.set(key, (current.styleChars.get(key) ?? 0) + item.text.trim().length);
|
|
842
|
+
}
|
|
843
|
+
finish();
|
|
844
|
+
}
|
|
845
|
+
return frags;
|
|
846
|
+
}
|
|
847
|
+
function baselineRows(frags) {
|
|
848
|
+
const rows = [];
|
|
849
|
+
for (const frag of frags) {
|
|
850
|
+
const row = rows[rows.length - 1];
|
|
851
|
+
if (row && Math.abs(row[0].y - frag.y) <= Math.max(1, Math.min(row[0].size, frag.size) * 0.5)) row.push(frag);
|
|
852
|
+
else rows.push([frag]);
|
|
853
|
+
}
|
|
854
|
+
return rows;
|
|
855
|
+
}
|
|
856
|
+
var edgeKey = (row) => collapse(row.map((f) => f.text).join(" ")).toLowerCase().replace(/\d+/g, "#");
|
|
857
|
+
function removeHeadersAndFooters(pages) {
|
|
858
|
+
const removed = { headers: 0, footers: 0, pageNumbers: 0 };
|
|
859
|
+
const pageRows = pages.map((frags) => baselineRows([...frags].sort((a, b) => b.y - a.y || a.x0 - b.x0)));
|
|
860
|
+
const counts = /* @__PURE__ */ new Map();
|
|
861
|
+
const candidates = [];
|
|
862
|
+
pageRows.forEach((rows, page) => {
|
|
863
|
+
const n = rows.length;
|
|
864
|
+
const picks = [];
|
|
865
|
+
for (let k = 0; k < Math.min(2, n); k++) picks.push([k, "top"]);
|
|
866
|
+
for (let k = Math.max(Math.min(2, n), n - 2); k < n; k++) picks.push([k, "bottom"]);
|
|
867
|
+
for (const [index, edge] of picks) {
|
|
868
|
+
const row = rows[index];
|
|
869
|
+
const extreme = edge === "top" ? index === 0 : index === n - 1;
|
|
870
|
+
const neighbour = edge === "top" ? rows[index + 1] : rows[index - 1];
|
|
871
|
+
const gap = neighbour ? Math.abs(row[0].y - neighbour[0].y) / row[0].size : Infinity;
|
|
872
|
+
candidates.push({ page, row, edge, extreme, gap });
|
|
873
|
+
const key = `${edge}:${edgeKey(row)}`;
|
|
874
|
+
if (!counts.has(key)) counts.set(key, /* @__PURE__ */ new Set());
|
|
875
|
+
counts.get(key).add(page);
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
const minPages = Math.max(2, Math.ceil(pages.length * 0.5));
|
|
879
|
+
const drop = /* @__PURE__ */ new Set();
|
|
880
|
+
for (const candidate of candidates) {
|
|
881
|
+
const text = collapse(candidate.row.map((f) => f.text).join(" "));
|
|
882
|
+
const isPageNumber = candidate.extreme && (PAGE_NUMBER_RE.test(text) || DASHED_PAGE_NUMBER_RE.test(text));
|
|
883
|
+
const repeated = (counts.get(`${candidate.edge}:${edgeKey(candidate.row)}`)?.size ?? 0) >= minPages;
|
|
884
|
+
let kind = null;
|
|
885
|
+
if (isPageNumber && (pages.length > 1 || candidate.gap > 2.5)) kind = "pageNumbers";
|
|
886
|
+
else if (repeated && pages.length > 1) kind = candidate.edge === "top" ? "headers" : "footers";
|
|
887
|
+
if (!kind || candidate.row.some((f) => drop.has(f))) continue;
|
|
888
|
+
candidate.row.forEach((f) => drop.add(f));
|
|
889
|
+
removed[kind]++;
|
|
890
|
+
}
|
|
891
|
+
if (drop.size) {
|
|
892
|
+
pages.forEach((frags, index) => {
|
|
893
|
+
pages[index] = frags.filter((f) => !drop.has(f));
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
return removed;
|
|
897
|
+
}
|
|
898
|
+
function splitRules(rules) {
|
|
899
|
+
const h = [];
|
|
900
|
+
const v = [];
|
|
901
|
+
for (const rule of rules.slice(0, MAX_RULES)) {
|
|
902
|
+
const { x1, y1, x2, y2 } = rule;
|
|
903
|
+
if (![x1, y1, x2, y2].every(Number.isFinite)) continue;
|
|
904
|
+
const dx = Math.abs(x2 - x1);
|
|
905
|
+
const dy = Math.abs(y2 - y1);
|
|
906
|
+
if (dy <= 1.5 && dx >= 6) h.push({ y: (y1 + y2) / 2, x0: Math.min(x1, x2), x1: Math.max(x1, x2) });
|
|
907
|
+
else if (dx <= 1.5 && dy >= 6) v.push({ x: (x1 + x2) / 2, y0: Math.min(y1, y2), y1: Math.max(y1, y2) });
|
|
908
|
+
}
|
|
909
|
+
return { h, v };
|
|
910
|
+
}
|
|
911
|
+
function clusterValues(values, tol) {
|
|
912
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
913
|
+
const out = [];
|
|
914
|
+
for (const value of sorted) {
|
|
915
|
+
const cluster = out[out.length - 1];
|
|
916
|
+
if (cluster && value - cluster.last <= tol) {
|
|
917
|
+
cluster.sum += value;
|
|
918
|
+
cluster.n++;
|
|
919
|
+
cluster.last = value;
|
|
920
|
+
} else out.push({ sum: value, n: 1, last: value });
|
|
921
|
+
}
|
|
922
|
+
return out.map((c) => c.sum / c.n);
|
|
923
|
+
}
|
|
924
|
+
function find(parent, i) {
|
|
925
|
+
while (parent[i] !== i) {
|
|
926
|
+
parent[i] = parent[parent[i]];
|
|
927
|
+
i = parent[i];
|
|
928
|
+
}
|
|
929
|
+
return i;
|
|
930
|
+
}
|
|
931
|
+
var cellText = (frags, dehyphenate, stats) => {
|
|
932
|
+
const sorted = [...frags].sort((a, b) => b.y - a.y || a.x0 - b.x0);
|
|
933
|
+
let text = "";
|
|
934
|
+
let lastY = Infinity;
|
|
935
|
+
for (const frag of sorted) {
|
|
936
|
+
if (!text) text = frag.text;
|
|
937
|
+
else if (Math.abs(lastY - frag.y) > frag.size * 0.5) text = joinLines(text, frag.text, dehyphenate, stats);
|
|
938
|
+
else text += ` ${frag.text}`;
|
|
939
|
+
lastY = frag.y;
|
|
940
|
+
}
|
|
941
|
+
return collapse(text);
|
|
942
|
+
};
|
|
943
|
+
var NUMERIC_RE = /^[-+−(]?[$€£¥]?\s?\d[\d,.\s]*%?\)?$/;
|
|
944
|
+
function headerRowCount(rowFrags) {
|
|
945
|
+
if (rowFrags.length < 2) return 0;
|
|
946
|
+
const cells = (row) => row.filter((cell) => cell.length > 0);
|
|
947
|
+
const first = cells(rowFrags[0]);
|
|
948
|
+
if (!first.length) return 0;
|
|
949
|
+
const rest = rowFrags.slice(1).flatMap(cells);
|
|
950
|
+
const allBold = (list) => list.length > 0 && list.every((cell) => cell.every((f) => f.bold));
|
|
951
|
+
if (allBold(first) && !allBold(rest)) return 1;
|
|
952
|
+
const numeric = (cell) => NUMERIC_RE.test(collapse(cell.map((f) => f.text).join(" ")));
|
|
953
|
+
if (first.every((cell) => !numeric(cell))) {
|
|
954
|
+
const columns = rowFrags[0].length;
|
|
955
|
+
for (let c = 0; c < columns; c++) {
|
|
956
|
+
const body = rowFrags.slice(1).map((row) => row[c]).filter((cell) => cell && cell.length > 0);
|
|
957
|
+
if (rowFrags[0][c].length && body.length >= 2 && body.every(numeric)) return 1;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
const firstSize = maxOf(first.flat(), (f) => f.size);
|
|
961
|
+
const restSize = median(rest.flat().map((f) => f.size));
|
|
962
|
+
if (restSize > 0 && firstSize >= restSize * 1.1) return 1;
|
|
963
|
+
return 0;
|
|
964
|
+
}
|
|
965
|
+
function ruledTables(frags, rules, page, dehyphenate, stats) {
|
|
966
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
967
|
+
const atoms = [];
|
|
968
|
+
const { h, v } = splitRules(rules);
|
|
969
|
+
if (h.length < 2) return { atoms, consumed };
|
|
970
|
+
const n = h.length + v.length;
|
|
971
|
+
const parent = Array.from({ length: n }, (_, i) => i);
|
|
972
|
+
const union = (a, b) => {
|
|
973
|
+
const ra = find(parent, a);
|
|
974
|
+
const rb = find(parent, b);
|
|
975
|
+
if (ra !== rb) parent[ra] = rb;
|
|
976
|
+
};
|
|
977
|
+
const tol = 2;
|
|
978
|
+
const vOrder = v.map((_, i) => i).sort((a, b) => v[a].x - v[b].x);
|
|
979
|
+
const vxs = vOrder.map((i) => v[i].x);
|
|
980
|
+
h.forEach((seg, hi) => {
|
|
981
|
+
let lo = 0;
|
|
982
|
+
let hiIdx = vxs.length;
|
|
983
|
+
while (lo < hiIdx) {
|
|
984
|
+
const mid = lo + hiIdx >> 1;
|
|
985
|
+
if (vxs[mid] < seg.x0 - tol) lo = mid + 1;
|
|
986
|
+
else hiIdx = mid;
|
|
987
|
+
}
|
|
988
|
+
for (let k = lo; k < vxs.length && vxs[k] <= seg.x1 + tol; k++) {
|
|
989
|
+
const vs = v[vOrder[k]];
|
|
990
|
+
if (seg.y >= vs.y0 - tol && seg.y <= vs.y1 + tol) union(hi, h.length + vOrder[k]);
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
const hOrder = h.map((_, i) => i).sort((a, b) => h[a].x0 - h[b].x0 || h[a].x1 - h[b].x1 || h[b].y - h[a].y);
|
|
994
|
+
for (let k = 1; k < hOrder.length; k++) {
|
|
995
|
+
const a = h[hOrder[k - 1]];
|
|
996
|
+
const b = h[hOrder[k]];
|
|
997
|
+
if (Math.abs(a.x0 - b.x0) <= 4 && Math.abs(a.x1 - b.x1) <= 4) union(hOrder[k - 1], hOrder[k]);
|
|
998
|
+
}
|
|
999
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1000
|
+
h.forEach((seg, i) => {
|
|
1001
|
+
const root = find(parent, i);
|
|
1002
|
+
if (!groups.has(root)) groups.set(root, { h: [], v: [] });
|
|
1003
|
+
groups.get(root).h.push(seg);
|
|
1004
|
+
});
|
|
1005
|
+
v.forEach((seg, i) => {
|
|
1006
|
+
const root = find(parent, h.length + i);
|
|
1007
|
+
groups.get(root)?.v.push(seg);
|
|
1008
|
+
});
|
|
1009
|
+
const byY = [...frags].sort((a, b) => a.y - b.y);
|
|
1010
|
+
const ys = byY.map((f) => f.y);
|
|
1011
|
+
const inRange = (y0, y1) => {
|
|
1012
|
+
let lo = 0;
|
|
1013
|
+
let hi = ys.length;
|
|
1014
|
+
while (lo < hi) {
|
|
1015
|
+
const mid = lo + hi >> 1;
|
|
1016
|
+
if (ys[mid] < y0) lo = mid + 1;
|
|
1017
|
+
else hi = mid;
|
|
1018
|
+
}
|
|
1019
|
+
const out = [];
|
|
1020
|
+
for (let k = lo; k < ys.length && ys[k] <= y1; k++) out.push(byY[k]);
|
|
1021
|
+
return out;
|
|
1022
|
+
};
|
|
1023
|
+
groups.forEach((group) => {
|
|
1024
|
+
const hys = clusterValues(group.h.map((s) => s.y), 1.5).sort((a, b) => b - a);
|
|
1025
|
+
if (hys.length < 2) return;
|
|
1026
|
+
const x0 = Math.min(...group.h.map((s) => s.x0), ...group.v.map((s) => s.x));
|
|
1027
|
+
const x1 = Math.max(...group.h.map((s) => s.x1), ...group.v.map((s) => s.x));
|
|
1028
|
+
const top = Math.max(hys[0], ...group.v.map((s) => s.y1));
|
|
1029
|
+
const bottom = Math.min(hys[hys.length - 1], ...group.v.map((s) => s.y0));
|
|
1030
|
+
const inside = inRange(bottom, top).filter((f) => {
|
|
1031
|
+
if (consumed.has(f)) return false;
|
|
1032
|
+
const cx = (f.x0 + f.x1) / 2;
|
|
1033
|
+
return cx >= x0 - 1 && cx <= x1 + 1;
|
|
1034
|
+
});
|
|
1035
|
+
if (inside.length < 2) return;
|
|
1036
|
+
const vxsGroup = clusterValues(group.v.map((s) => s.x), 1.5);
|
|
1037
|
+
let table = null;
|
|
1038
|
+
if (vxsGroup.length >= 3 || vxsGroup.length >= 2 && hys.length >= 3 && vxsGroup.some((x) => x > x0 + 4 && x < x1 - 4)) {
|
|
1039
|
+
table = gridTable(inside, group, hys, vxsGroup, x0, x1, top, bottom, page, dehyphenate, stats);
|
|
1040
|
+
}
|
|
1041
|
+
if (!table) {
|
|
1042
|
+
const result = alignedTable(inside, page, 2, dehyphenate, stats, hys.length >= 3 ? hys[1] : void 0);
|
|
1043
|
+
if (result && !result.leftover.length && !result.before.length) table = { ...result.table, ruled: true, confidence: 0.85 };
|
|
1044
|
+
}
|
|
1045
|
+
if (!table) return;
|
|
1046
|
+
inside.forEach((f) => consumed.add(f));
|
|
1047
|
+
atoms.push({
|
|
1048
|
+
text: "",
|
|
1049
|
+
x0,
|
|
1050
|
+
x1,
|
|
1051
|
+
y: bottom,
|
|
1052
|
+
top,
|
|
1053
|
+
bottom,
|
|
1054
|
+
size: median(inside.map((f) => f.size)),
|
|
1055
|
+
bold: false,
|
|
1056
|
+
italic: false,
|
|
1057
|
+
words: 0,
|
|
1058
|
+
table
|
|
1059
|
+
});
|
|
1060
|
+
});
|
|
1061
|
+
return { atoms, consumed };
|
|
1062
|
+
}
|
|
1063
|
+
function gridTable(inside, group, hys, vxsIn, x0, x1, top, bottom, page, dehyphenate, stats) {
|
|
1064
|
+
const xs = [...vxsIn];
|
|
1065
|
+
if (xs[0] > x0 + 4) xs.unshift(x0);
|
|
1066
|
+
if (xs[xs.length - 1] < x1 - 4) xs.push(x1);
|
|
1067
|
+
const rowsY = [...hys];
|
|
1068
|
+
if (rowsY[0] < top - 4) rowsY.unshift(top);
|
|
1069
|
+
if (rowsY[rowsY.length - 1] > bottom + 4) rowsY.push(bottom);
|
|
1070
|
+
const cols = xs.length - 1;
|
|
1071
|
+
const rows = rowsY.length - 1;
|
|
1072
|
+
if (cols < 2 || rows < 1 || cols > MAX_COLS || rows > MAX_TABLE_ROWS) return null;
|
|
1073
|
+
const grid = Array.from({ length: rows }, () => Array.from({ length: cols }, () => []));
|
|
1074
|
+
const ascRows = [...rowsY].reverse();
|
|
1075
|
+
for (const frag of inside) {
|
|
1076
|
+
const x = frag.x0 + Math.min(2, (frag.x1 - frag.x0) / 2);
|
|
1077
|
+
const c = lowerBound(xs, x + 1e-9) - 1;
|
|
1078
|
+
const yProbe = frag.y + frag.size * 0.3;
|
|
1079
|
+
const r = rows - (lowerBound(ascRows, yProbe + 1e-9) - 1) - 1;
|
|
1080
|
+
if (c >= 0 && c < cols && r >= 0 && r < rows) grid[r][c].push(frag);
|
|
1081
|
+
}
|
|
1082
|
+
const filled = grid.flat().filter((cell) => cell.length).length;
|
|
1083
|
+
if (filled < 2 || rows < 2 && cols < 2) return null;
|
|
1084
|
+
const vAt = xs.map(() => []);
|
|
1085
|
+
for (const seg of group.v) {
|
|
1086
|
+
const k = lowerBound(xs, seg.x - 2);
|
|
1087
|
+
if (k < xs.length && Math.abs(xs[k] - seg.x) <= 2) vAt[k].push(seg);
|
|
1088
|
+
}
|
|
1089
|
+
const hAt = rowsY.map(() => []);
|
|
1090
|
+
for (const seg of group.h) {
|
|
1091
|
+
const k = rows - lowerBound(ascRows, seg.y - 2);
|
|
1092
|
+
if (k >= 0 && k <= rows && Math.abs(rowsY[k] - seg.y) <= 2) hAt[k].push(seg);
|
|
1093
|
+
}
|
|
1094
|
+
const hasV = (k, y) => vAt[k].some((s) => y >= s.y0 - 2 && y <= s.y1 + 2);
|
|
1095
|
+
const hasH = (k, x) => hAt[k].some((s) => x >= s.x0 - 2 && x <= s.x1 + 2);
|
|
1096
|
+
const covered = grid.map((row) => row.map(() => false));
|
|
1097
|
+
const header = headerRowCount(grid);
|
|
1098
|
+
const out = [];
|
|
1099
|
+
for (let r = 0; r < rows; r++) {
|
|
1100
|
+
const midY = (rowsY[r] + rowsY[r + 1]) / 2;
|
|
1101
|
+
const row = [];
|
|
1102
|
+
for (let c = 0; c < cols; c++) {
|
|
1103
|
+
if (covered[r][c]) continue;
|
|
1104
|
+
let colSpan = 1;
|
|
1105
|
+
while (c + colSpan < cols && !hasV(c + colSpan, midY) && !grid[r][c + colSpan].length && !covered[r][c + colSpan]) colSpan++;
|
|
1106
|
+
let rowSpan = 1;
|
|
1107
|
+
const midX = (xs[c] + xs[c + colSpan]) / 2;
|
|
1108
|
+
while (r + rowSpan < rows && !hasH(r + rowSpan, midX) && !covered[r + rowSpan].slice(c, c + colSpan).some(Boolean) && grid[r + rowSpan].slice(c, c + colSpan).every((cell) => !cell.length)) {
|
|
1109
|
+
rowSpan++;
|
|
1110
|
+
}
|
|
1111
|
+
for (let rr = r; rr < r + rowSpan; rr++) for (let cc = c; cc < c + colSpan; cc++) covered[rr][cc] = true;
|
|
1112
|
+
row.push({ text: cellText(grid[r][c], dehyphenate, stats), colSpan, rowSpan, header: r < header });
|
|
1113
|
+
}
|
|
1114
|
+
out.push(row);
|
|
1115
|
+
}
|
|
1116
|
+
return { type: "table", page, confidence: 0.95, ruled: true, rows: out, columns: cols, headerRows: header };
|
|
1117
|
+
}
|
|
1118
|
+
function alignedTable(frags, page, minRows, dehyphenate, stats, headerRuleY) {
|
|
1119
|
+
const sorted = [...frags].sort((a, b) => b.y - a.y || a.x0 - b.x0);
|
|
1120
|
+
let rows = baselineRows(sorted).map((row) => row.sort((a, b) => a.x0 - b.x0));
|
|
1121
|
+
if (rows.length < minRows) return null;
|
|
1122
|
+
const multi = rows.filter((row) => row.length >= 2);
|
|
1123
|
+
if (multi.length < Math.min(minRows, 2)) return null;
|
|
1124
|
+
const spans = multi.flat().map((f) => [f.x0, f.x1]).sort((a, b) => a[0] - b[0]);
|
|
1125
|
+
const merged = [];
|
|
1126
|
+
for (const [a, b] of spans) {
|
|
1127
|
+
const last = merged[merged.length - 1];
|
|
1128
|
+
if (last && a <= last[1] + 1) last[1] = Math.max(last[1], b);
|
|
1129
|
+
else merged.push([a, b]);
|
|
1130
|
+
}
|
|
1131
|
+
if (merged.length < 2 || merged.length > MAX_COLS) return null;
|
|
1132
|
+
const edges = merged.map((m) => m[0]);
|
|
1133
|
+
const cols = merged.length;
|
|
1134
|
+
const colOf = (x) => {
|
|
1135
|
+
let c = 0;
|
|
1136
|
+
while (c + 1 < cols && x >= merged[c + 1][0] - 1) c++;
|
|
1137
|
+
return c;
|
|
1138
|
+
};
|
|
1139
|
+
const spanOf = (f, c) => {
|
|
1140
|
+
let span = 1;
|
|
1141
|
+
while (c + span < cols && f.x1 > merged[c + span][0] + 2) span++;
|
|
1142
|
+
return span;
|
|
1143
|
+
};
|
|
1144
|
+
const rowIsCells = (row) => {
|
|
1145
|
+
if (row.length >= 2) return true;
|
|
1146
|
+
const f = row[0];
|
|
1147
|
+
const c = colOf(f.x0);
|
|
1148
|
+
return spanOf(f, c) >= 2 && f.words <= 8 && Math.abs(f.x0 - edges[c]) <= Math.max(4, f.size * 0.6);
|
|
1149
|
+
};
|
|
1150
|
+
const before = [];
|
|
1151
|
+
const leftover = [];
|
|
1152
|
+
let first = 0;
|
|
1153
|
+
let end = rows.length;
|
|
1154
|
+
while (first < end && !rowIsCells(rows[first])) first++;
|
|
1155
|
+
while (end > first && !rowIsCells(rows[end - 1])) end--;
|
|
1156
|
+
rows.slice(0, first).forEach((row) => before.push(...row));
|
|
1157
|
+
rows.slice(end).forEach((row) => leftover.push(...row));
|
|
1158
|
+
rows = rows.slice(first, end);
|
|
1159
|
+
if (rows.length < minRows || rows.length > MAX_TABLE_ROWS) return null;
|
|
1160
|
+
const grid = [];
|
|
1161
|
+
const spansGrid = [];
|
|
1162
|
+
let prevRow = null;
|
|
1163
|
+
for (const row of rows) {
|
|
1164
|
+
const cells = Array.from({ length: cols }, () => []);
|
|
1165
|
+
const spanRow = Array.from({ length: cols }, () => 1);
|
|
1166
|
+
for (const f of row) {
|
|
1167
|
+
const c = colOf(f.x0);
|
|
1168
|
+
cells[c].push(f);
|
|
1169
|
+
spanRow[c] = Math.max(spanRow[c], row.length === 1 ? spanOf(f, c) : 1);
|
|
1170
|
+
}
|
|
1171
|
+
const continuation = prevRow !== null && grid.length > 0 && cells[0].length === 0 && grid[grid.length - 1][0].length > 0 && cells.every((cell, c) => !cell.length || grid[grid.length - 1][c].length > 0) && minOf(prevRow, (f) => f.bottom) - maxOf(row, (f) => f.top) < row[0].size * 0.5;
|
|
1172
|
+
if (continuation) {
|
|
1173
|
+
cells.forEach((cell, c) => grid[grid.length - 1][c].push(...cell));
|
|
1174
|
+
} else {
|
|
1175
|
+
grid.push(cells);
|
|
1176
|
+
spansGrid.push(spanRow);
|
|
1177
|
+
}
|
|
1178
|
+
prevRow = row;
|
|
1179
|
+
}
|
|
1180
|
+
if (grid.length < minRows) return null;
|
|
1181
|
+
const full = grid.filter((cells) => cells.filter((c) => c.length).length >= 2).length;
|
|
1182
|
+
if (full / grid.length < 0.6) return null;
|
|
1183
|
+
const cellsWithText = grid.flat().filter((c) => c.length);
|
|
1184
|
+
const meanWords = cellsWithText.reduce((sum, cell) => sum + cell.reduce((s, f) => s + f.words, 0), 0) / cellsWithText.length;
|
|
1185
|
+
if (meanWords > 12) return null;
|
|
1186
|
+
let header = headerRowCount(grid);
|
|
1187
|
+
if (headerRuleY !== void 0) {
|
|
1188
|
+
const above = rows.filter((row) => row[0].y > headerRuleY).length;
|
|
1189
|
+
if (above > 0 && above < grid.length) header = Math.max(header, Math.min(above, grid.length - 1));
|
|
1190
|
+
}
|
|
1191
|
+
const out = grid.map((cells, r) => {
|
|
1192
|
+
const row = [];
|
|
1193
|
+
for (let c = 0; c < cols; ) {
|
|
1194
|
+
const span = Math.min(spansGrid[r][c], cols - c);
|
|
1195
|
+
row.push({ text: cellText(cells[c], dehyphenate, stats), colSpan: span, rowSpan: 1, header: r < header });
|
|
1196
|
+
c += span;
|
|
1197
|
+
}
|
|
1198
|
+
return row;
|
|
1199
|
+
});
|
|
1200
|
+
const confidence = Math.min(
|
|
1201
|
+
0.9,
|
|
1202
|
+
0.5 + (grid.length >= 5 ? 0.1 : 0) + (cols >= 3 ? 0.1 : 0) + 0.2 * (full / grid.length) - (cols === 2 ? 0.05 : 0)
|
|
1203
|
+
);
|
|
1204
|
+
return {
|
|
1205
|
+
table: { type: "table", page, confidence, ruled: false, rows: out, columns: cols, headerRows: header },
|
|
1206
|
+
leftover,
|
|
1207
|
+
before
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
function readingOrder(items, body, detectColumns, depth, columnPages) {
|
|
1211
|
+
const byTop = [...items].sort((a, b) => b.top - a.top || a.x0 - b.x0);
|
|
1212
|
+
if (!detectColumns || items.length < 2 || depth > MAX_DEPTH) return [{ kind: "flow", items: byTop }];
|
|
1213
|
+
const left = minOf(items, (f) => f.x0);
|
|
1214
|
+
const right = maxOf(items, (f) => f.x1);
|
|
1215
|
+
const width = right - left;
|
|
1216
|
+
const isNarrow = (f) => f.x1 - f.x0 < width * 0.55;
|
|
1217
|
+
const narrow = items.filter(isNarrow);
|
|
1218
|
+
const minGutter = Math.max(body * 0.9, 6);
|
|
1219
|
+
const allowed = Math.max(1, Math.floor(narrow.length * 0.08));
|
|
1220
|
+
const events = [];
|
|
1221
|
+
for (const f of narrow) events.push([f.x0, 1], [f.x1, -1]);
|
|
1222
|
+
events.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
|
|
1223
|
+
const candidates = [];
|
|
1224
|
+
let depthNow = 0;
|
|
1225
|
+
let seenContent = false;
|
|
1226
|
+
let start = null;
|
|
1227
|
+
for (const [x, delta] of events) {
|
|
1228
|
+
depthNow += delta;
|
|
1229
|
+
if (depthNow > allowed) {
|
|
1230
|
+
if (start !== null && seenContent && x - start >= minGutter) candidates.push([start, x]);
|
|
1231
|
+
start = null;
|
|
1232
|
+
seenContent = true;
|
|
1233
|
+
} else if (start === null) start = x;
|
|
1234
|
+
}
|
|
1235
|
+
const ends = narrow.map((f) => f.x1).sort((a, b) => a - b);
|
|
1236
|
+
const starts = narrow.map((f) => f.x0).sort((a, b) => a - b);
|
|
1237
|
+
const gutters = [];
|
|
1238
|
+
for (const [a, b] of candidates) {
|
|
1239
|
+
const endBelow = lowerBound(ends, b) - 1;
|
|
1240
|
+
const left2 = endBelow >= 0 && ends[endBelow] > a ? ends[endBelow] : a;
|
|
1241
|
+
const startAbove = lowerBound(starts, a + 1e-9);
|
|
1242
|
+
const right2 = startAbove < starts.length && starts[startAbove] < b ? starts[startAbove] : b;
|
|
1243
|
+
if (right2 - left2 < minGutter) continue;
|
|
1244
|
+
const onLeft = lowerBound(ends, left2 + 1e-6);
|
|
1245
|
+
const onRight = starts.length - lowerBound(starts, right2 - 1e-6);
|
|
1246
|
+
const strays = narrow.length - onLeft - onRight;
|
|
1247
|
+
if (strays < Math.min(onLeft, onRight)) gutters.push([left2, right2]);
|
|
1248
|
+
}
|
|
1249
|
+
if (!gutters.length) return [{ kind: "flow", items: byTop }];
|
|
1250
|
+
const gutterEnds = gutters.map((g) => g[1]);
|
|
1251
|
+
const crosses = (f) => {
|
|
1252
|
+
const k = lowerBound(gutterEnds, f.x0 + 1 + 1e-9);
|
|
1253
|
+
return k < gutters.length && f.x1 > gutters[k][0] + 1 && f.x0 < gutters[k][1] - 1;
|
|
1254
|
+
};
|
|
1255
|
+
const columnOf = (f) => lowerBound(gutterEnds, f.x0 + 1 + 1e-9);
|
|
1256
|
+
const bands = [];
|
|
1257
|
+
for (const f of byTop) {
|
|
1258
|
+
const spanning = crosses(f);
|
|
1259
|
+
const band = bands[bands.length - 1];
|
|
1260
|
+
if (band && band.spanning === spanning) band.items.push(f);
|
|
1261
|
+
else bands.push({ spanning, items: [f] });
|
|
1262
|
+
}
|
|
1263
|
+
const segments = [];
|
|
1264
|
+
let sealed = false;
|
|
1265
|
+
const pushFlow = (list) => {
|
|
1266
|
+
if (!list.length) return;
|
|
1267
|
+
const last = segments[segments.length - 1];
|
|
1268
|
+
if (last && last.kind === "flow" && !sealed) last.items.push(...list);
|
|
1269
|
+
else segments.push({ kind: "flow", items: list });
|
|
1270
|
+
sealed = false;
|
|
1271
|
+
};
|
|
1272
|
+
let multiColumn = false;
|
|
1273
|
+
const isShortSpan = (f) => !f.table && isNarrow(f) && f.words <= 8;
|
|
1274
|
+
for (const band of bands) {
|
|
1275
|
+
const last = segments[segments.length - 1];
|
|
1276
|
+
if (band.spanning) {
|
|
1277
|
+
const lead = band.items[0];
|
|
1278
|
+
if (last && last.kind === "grid" && isShortSpan(lead) && minOf(last.items, (f) => f.bottom) - lead.top <= lead.size * 2) {
|
|
1279
|
+
last.items.push(lead);
|
|
1280
|
+
pushFlow(band.items.slice(1));
|
|
1281
|
+
} else pushFlow(band.items);
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
const columns = Array.from({ length: gutters.length + 1 }, () => []);
|
|
1285
|
+
band.items.forEach((f) => columns[columnOf(f)].push(f));
|
|
1286
|
+
const used = columns.filter((c) => c.length);
|
|
1287
|
+
if (used.length < 2) {
|
|
1288
|
+
pushFlow(band.items);
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
const prose = used.every((col) => {
|
|
1292
|
+
const text = col.filter((f) => !f.table);
|
|
1293
|
+
if (text.length < 2) return text.length === 0;
|
|
1294
|
+
const colLeft = minOf(text, (f) => f.x0);
|
|
1295
|
+
const colRight = maxOf(text, (f) => f.x1);
|
|
1296
|
+
const fill = text.reduce((sum, f) => sum + (f.x1 - f.x0), 0) / text.length / Math.max(1, colRight - colLeft);
|
|
1297
|
+
const words = text.reduce((sum, f) => sum + f.words, 0) / text.length;
|
|
1298
|
+
return fill >= 0.55 && words >= 3;
|
|
1299
|
+
});
|
|
1300
|
+
const tops = used.map((col) => [minOf(col, (f) => f.bottom), maxOf(col, (f) => f.top)]);
|
|
1301
|
+
const overlapping = tops.every(([b, t], i) => i === 0 || Math.min(t, tops[0][1]) - Math.max(b, tops[0][0]) > 0);
|
|
1302
|
+
if (prose && overlapping) {
|
|
1303
|
+
multiColumn = true;
|
|
1304
|
+
for (const col of used) segments.push(...readingOrder(col, body, detectColumns, depth + 1, columnPages));
|
|
1305
|
+
sealed = true;
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
const pulled = [];
|
|
1309
|
+
if (last && last.kind === "flow" && !sealed) {
|
|
1310
|
+
const tail = last.items[last.items.length - 1];
|
|
1311
|
+
if (isShortSpan(tail) && tail.bottom - maxOf(band.items, (f) => f.top) <= tail.size * 2) {
|
|
1312
|
+
pulled.push(last.items.pop());
|
|
1313
|
+
if (!last.items.length) segments.pop();
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
const prevSegment = segments[segments.length - 1];
|
|
1317
|
+
if (prevSegment && prevSegment.kind === "grid" && (pulled.length || prevSegment === last)) {
|
|
1318
|
+
prevSegment.items.push(...pulled, ...band.items);
|
|
1319
|
+
} else segments.push({ kind: "grid", items: [...pulled, ...band.items] });
|
|
1320
|
+
sealed = false;
|
|
1321
|
+
}
|
|
1322
|
+
if (multiColumn && depth === 0) columnPages.count++;
|
|
1323
|
+
return segments;
|
|
1324
|
+
}
|
|
1325
|
+
function flowLines(items, page) {
|
|
1326
|
+
const lines = [];
|
|
1327
|
+
const sorted = [...items].sort((a, b) => b.top - a.top || a.x0 - b.x0);
|
|
1328
|
+
for (const f of sorted) {
|
|
1329
|
+
if (f.table) {
|
|
1330
|
+
lines.push({ text: "", x0: f.x0, x1: f.x1, y: f.y, top: f.top, size: f.size, bold: false, page, table: f.table });
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
const last = lines[lines.length - 1];
|
|
1334
|
+
if (last && !last.table && Math.abs(last.y - f.y) <= Math.min(last.size, f.size) * 0.5) {
|
|
1335
|
+
last.text = `${last.text} ${f.text}`;
|
|
1336
|
+
last.x0 = Math.min(last.x0, f.x0);
|
|
1337
|
+
last.x1 = Math.max(last.x1, f.x1);
|
|
1338
|
+
} else {
|
|
1339
|
+
lines.push({ text: f.text, x0: f.x0, x1: f.x1, y: f.y, top: f.top, size: f.size, bold: f.bold, page });
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
return lines;
|
|
1343
|
+
}
|
|
1344
|
+
function joinLines(prev, next, dehyphenate, stats) {
|
|
1345
|
+
if (prev.endsWith("\xAD")) {
|
|
1346
|
+
stats.dehyphenated++;
|
|
1347
|
+
return prev.slice(0, -1) + next;
|
|
1348
|
+
}
|
|
1349
|
+
if (dehyphenate && /[A-Za-zÀ-ɏ]-$/.test(prev) && /^[a-zß-ɏ]/.test(next)) {
|
|
1350
|
+
stats.dehyphenated++;
|
|
1351
|
+
return prev.slice(0, -1) + next;
|
|
1352
|
+
}
|
|
1353
|
+
return `${prev} ${next}`;
|
|
1354
|
+
}
|
|
1355
|
+
function listMarker(text) {
|
|
1356
|
+
const glyph = BULLET_GLYPH_RE.exec(text);
|
|
1357
|
+
if (glyph) return { kind: "glyph", rest: text.slice(glyph[0].length), ordered: false };
|
|
1358
|
+
const dash = BULLET_DASH_RE.exec(text);
|
|
1359
|
+
if (dash) return { kind: "dash", rest: text.slice(dash[0].length), ordered: false };
|
|
1360
|
+
const ordered = ORDERED_RE.exec(text);
|
|
1361
|
+
if (ordered) {
|
|
1362
|
+
const token = ordered[1] ?? ordered[2];
|
|
1363
|
+
const kind = /^\d+$/.test(token) ? "num" : /^[ivxlc]{2,}$/i.test(token) || /^i$/i.test(token) ? "roman" : "alpha";
|
|
1364
|
+
return { kind, rest: text.slice(ordered[0].length), ordered: true, value: kind === "num" ? Number(token) : void 0 };
|
|
1365
|
+
}
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1368
|
+
function headingStyle(line, next, segRight, ctx) {
|
|
1369
|
+
if (!ctx.options.detectHeadings || line.table) return null;
|
|
1370
|
+
const text = line.text;
|
|
1371
|
+
const words = countWords(text);
|
|
1372
|
+
if (text.length > 200 || words > 25 || !/\p{L}/u.test(text)) return null;
|
|
1373
|
+
if (words > 15 && SENTENCE_END_RE.test(text)) return null;
|
|
1374
|
+
const ratio = line.size / ctx.body;
|
|
1375
|
+
if (ratio >= 1.15) {
|
|
1376
|
+
const confidence = Math.min(0.95, 0.6 + (ratio - 1.15) * 0.8 + (line.bold ? 0.1 : 0));
|
|
1377
|
+
return { key: Math.round(line.size * 2) / 2 + (line.bold ? 0.25 : 0), confidence, boldOnly: false };
|
|
1378
|
+
}
|
|
1379
|
+
const runsOn = !!next && !next.table && next.bold && Math.abs(next.size - line.size) < 0.5 && line.x1 >= segRight - 2 * line.size;
|
|
1380
|
+
if (line.bold && !ctx.boldBody && !runsOn && ratio >= 0.95 && text.length <= 100 && !/[.,;]$/.test(text)) {
|
|
1381
|
+
return { key: Math.round(line.size * 2) / 2 + 0.25, confidence: 0.6, boldOnly: true };
|
|
1382
|
+
}
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
function buildBlocks(lines, ctx) {
|
|
1386
|
+
const textLines = lines.filter((l) => !l.table);
|
|
1387
|
+
const segLeft = textLines.length ? minOf(textLines, (l) => l.x0) : 0;
|
|
1388
|
+
const segRight = textLines.length ? maxOf(textLines, (l) => l.x1) : 0;
|
|
1389
|
+
const kindCounts = /* @__PURE__ */ new Map();
|
|
1390
|
+
const markers = lines.map((line) => {
|
|
1391
|
+
if (!ctx.options.detectLists || line.table) return null;
|
|
1392
|
+
const marker = listMarker(line.text);
|
|
1393
|
+
if (marker) kindCounts.set(marker.kind, (kindCounts.get(marker.kind) ?? 0) + 1);
|
|
1394
|
+
return marker;
|
|
1395
|
+
});
|
|
1396
|
+
let list = null;
|
|
1397
|
+
let listStack = [];
|
|
1398
|
+
let lastItemLine = null;
|
|
1399
|
+
let para = null;
|
|
1400
|
+
let heading = null;
|
|
1401
|
+
const closeAll = () => {
|
|
1402
|
+
if (para) {
|
|
1403
|
+
const last = para.lines[para.lines.length - 1];
|
|
1404
|
+
const ended = SENTENCE_END_RE.test(last.text) || last.x1 < segRight - 3 * last.size;
|
|
1405
|
+
ctx.open = ended ? null : { block: para.block, size: last.size, lastText: para.block.text };
|
|
1406
|
+
} else ctx.open = null;
|
|
1407
|
+
para = null;
|
|
1408
|
+
list = null;
|
|
1409
|
+
listStack = [];
|
|
1410
|
+
lastItemLine = null;
|
|
1411
|
+
heading = null;
|
|
1412
|
+
};
|
|
1413
|
+
lines.forEach((line, index) => {
|
|
1414
|
+
const prev = index > 0 ? lines[index - 1] : null;
|
|
1415
|
+
if (line.table) {
|
|
1416
|
+
closeAll();
|
|
1417
|
+
ctx.open = null;
|
|
1418
|
+
ctx.blocks.push(line.table);
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
const style = headingStyle(line, lines[index + 1], segRight, ctx);
|
|
1422
|
+
if (style) {
|
|
1423
|
+
if (heading && heading.key === style.key && heading.lines < 3 && prev === heading.line && prev.y - line.y <= line.size * 1.6) {
|
|
1424
|
+
heading.block.text = joinLines(heading.block.text, line.text, ctx.options.dehyphenate, ctx.stats);
|
|
1425
|
+
heading.line = line;
|
|
1426
|
+
heading.lines++;
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
closeAll();
|
|
1430
|
+
ctx.open = null;
|
|
1431
|
+
const block2 = { type: "heading", level: 1, text: line.text, page: line.page, confidence: style.confidence };
|
|
1432
|
+
ctx.blocks.push(block2);
|
|
1433
|
+
ctx.headings.push({ block: block2, key: style.key, boldOnly: style.boldOnly });
|
|
1434
|
+
heading = { block: block2, line, key: style.key, lines: 1 };
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
heading = null;
|
|
1438
|
+
const marker = markers[index];
|
|
1439
|
+
const validMarker = marker && (marker.kind === "glyph" || (kindCounts.get(marker.kind) ?? 0) >= 2) && marker.rest.trim() !== "";
|
|
1440
|
+
if (validMarker) {
|
|
1441
|
+
const gapOk = lastItemLine && lastItemLine.y - line.y <= Math.max(ctx.pitch(line.size) * 2.2, line.size * 2.4);
|
|
1442
|
+
if (!list || !gapOk) {
|
|
1443
|
+
closeAll();
|
|
1444
|
+
ctx.open = null;
|
|
1445
|
+
list = { type: "list", page: line.page, confidence: 0.6, items: [] };
|
|
1446
|
+
ctx.blocks.push(list);
|
|
1447
|
+
listStack = [line.x0];
|
|
1448
|
+
}
|
|
1449
|
+
const tol = line.size * 0.5;
|
|
1450
|
+
while (listStack.length > 1 && line.x0 < listStack[listStack.length - 1] - tol) listStack.pop();
|
|
1451
|
+
if (line.x0 > listStack[listStack.length - 1] + tol) listStack.push(line.x0);
|
|
1452
|
+
else listStack[listStack.length - 1] = Math.min(listStack[listStack.length - 1], line.x0);
|
|
1453
|
+
const prevDepth = list.items.length ? list.items[list.items.length - 1].depth : -1;
|
|
1454
|
+
const depth = Math.min(listStack.length - 1, prevDepth + 1);
|
|
1455
|
+
const item = {
|
|
1456
|
+
text: collapse(marker.rest),
|
|
1457
|
+
depth,
|
|
1458
|
+
ordered: marker.ordered
|
|
1459
|
+
};
|
|
1460
|
+
if (marker.value !== void 0) item.start = marker.value;
|
|
1461
|
+
list.items.push(item);
|
|
1462
|
+
list.confidence = Math.min(0.95, (marker.kind === "glyph" ? 0.75 : 0.6) + 0.05 * list.items.length);
|
|
1463
|
+
lastItemLine = line;
|
|
1464
|
+
para = null;
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
if (list && lastItemLine && prev) {
|
|
1468
|
+
const markerX = listStack[listStack.length - 1];
|
|
1469
|
+
const continues = line.x0 > markerX + line.size * 0.3 && line.x0 <= markerX + line.size * 5 && prev.y - line.y <= ctx.pitch(line.size) * ctx.options.paragraphGap;
|
|
1470
|
+
if (continues) {
|
|
1471
|
+
const item = list.items[list.items.length - 1];
|
|
1472
|
+
item.text = joinLines(item.text, line.text, ctx.options.dehyphenate, ctx.stats);
|
|
1473
|
+
lastItemLine = line;
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
closeAll();
|
|
1477
|
+
}
|
|
1478
|
+
if (!para && ctx.open && index === 0 && /^[a-z]/.test(line.text) && Math.abs(ctx.open.size - line.size) <= line.size * 0.12) {
|
|
1479
|
+
ctx.open.block.text = joinLines(ctx.open.block.text, line.text, ctx.options.dehyphenate, ctx.stats);
|
|
1480
|
+
para = { block: ctx.open.block, lines: [line] };
|
|
1481
|
+
ctx.open = null;
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
if (para && prev && !prev.table) {
|
|
1485
|
+
const last = para.lines[para.lines.length - 1];
|
|
1486
|
+
const gap = last.y - line.y;
|
|
1487
|
+
const sameSize = Math.abs(last.size - line.size) <= last.size * 0.12;
|
|
1488
|
+
const closeEnough = gap > 0 && gap <= ctx.pitch(line.size) * ctx.options.paragraphGap;
|
|
1489
|
+
const indentEm = line.size * 0.8;
|
|
1490
|
+
const indented = line.x0 - segLeft >= indentEm && last.x0 - segLeft < indentEm && line.x0 - segLeft < line.size * 8;
|
|
1491
|
+
const shortEnded = last.x1 < segRight - 3 * last.size && SENTENCE_END_RE.test(last.text);
|
|
1492
|
+
if (sameSize && closeEnough && !indented && !shortEnded) {
|
|
1493
|
+
para.block.text = joinLines(para.block.text, line.text, ctx.options.dehyphenate, ctx.stats);
|
|
1494
|
+
para.lines.push(line);
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
closeAll();
|
|
1499
|
+
ctx.open = null;
|
|
1500
|
+
const block = { type: "paragraph", text: line.text, page: line.page };
|
|
1501
|
+
ctx.blocks.push(block);
|
|
1502
|
+
para = { block, lines: [line] };
|
|
1503
|
+
});
|
|
1504
|
+
closeAll();
|
|
1505
|
+
}
|
|
1506
|
+
function assignHeadingLevels(headings) {
|
|
1507
|
+
const keys = Array.from(new Set(headings.map((h) => h.key))).sort((a, b) => b - a);
|
|
1508
|
+
const levelOf = new Map(keys.map((key, i) => [key, Math.min(6, i + 1)]));
|
|
1509
|
+
headings.forEach((h) => {
|
|
1510
|
+
h.block.level = levelOf.get(h.key);
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
var DEFAULTS = {
|
|
1514
|
+
paragraphGap: 1.4,
|
|
1515
|
+
removeHeadersAndFooters: true,
|
|
1516
|
+
detectColumns: true,
|
|
1517
|
+
detectHeadings: true,
|
|
1518
|
+
detectLists: true,
|
|
1519
|
+
detectTables: true,
|
|
1520
|
+
dehyphenate: true
|
|
1521
|
+
};
|
|
1522
|
+
function analyzePdfLayout(pages, options = {}) {
|
|
1523
|
+
const opts = { ...DEFAULTS };
|
|
1524
|
+
Object.keys(options).forEach((key) => {
|
|
1525
|
+
if (options[key] !== void 0) opts[key] = options[key];
|
|
1526
|
+
});
|
|
1527
|
+
const fragPages = pages.map((page) => buildFragments(page.runs ?? []));
|
|
1528
|
+
const removed = opts.removeHeadersAndFooters ? removeHeadersAndFooters(fragPages) : { headers: 0, footers: 0, pageNumbers: 0 };
|
|
1529
|
+
const bySize = /* @__PURE__ */ new Map();
|
|
1530
|
+
let boldChars = 0;
|
|
1531
|
+
let totalChars = 0;
|
|
1532
|
+
fragPages.flat().forEach((f) => {
|
|
1533
|
+
const key = Math.round(f.size * 2) / 2;
|
|
1534
|
+
bySize.set(key, (bySize.get(key) ?? 0) + f.text.length);
|
|
1535
|
+
});
|
|
1536
|
+
let body = 10;
|
|
1537
|
+
let bodyChars = -1;
|
|
1538
|
+
bySize.forEach((chars, size) => {
|
|
1539
|
+
if (chars > bodyChars) {
|
|
1540
|
+
body = size;
|
|
1541
|
+
bodyChars = chars;
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
fragPages.flat().forEach((f) => {
|
|
1545
|
+
if (Math.abs(f.size - body) <= body * 0.05) {
|
|
1546
|
+
totalChars += f.text.length;
|
|
1547
|
+
if (f.bold) boldChars += f.text.length;
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
const pitches = /* @__PURE__ */ new Map();
|
|
1551
|
+
fragPages.forEach((frags) => {
|
|
1552
|
+
const rows = baselineRows([...frags].sort((a, b) => b.y - a.y || a.x0 - b.x0));
|
|
1553
|
+
for (let k = 1; k < rows.length; k++) {
|
|
1554
|
+
const a = rows[k - 1][0];
|
|
1555
|
+
const b = rows[k][0];
|
|
1556
|
+
if (Math.abs(a.size - b.size) > 0.5) continue;
|
|
1557
|
+
const d = a.y - b.y;
|
|
1558
|
+
if (d > 0 && d < a.size * 3) {
|
|
1559
|
+
const key = Math.round(b.size * 2) / 2;
|
|
1560
|
+
if (!pitches.has(key)) pitches.set(key, []);
|
|
1561
|
+
pitches.get(key).push(d);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
});
|
|
1565
|
+
const pitchMedians = /* @__PURE__ */ new Map();
|
|
1566
|
+
pitches.forEach((values, key) => pitchMedians.set(key, median(values)));
|
|
1567
|
+
const stats = { dehyphenated: 0 };
|
|
1568
|
+
const ctx = {
|
|
1569
|
+
body,
|
|
1570
|
+
boldBody: totalChars > 0 && boldChars / totalChars > 0.5,
|
|
1571
|
+
pitch: (size) => {
|
|
1572
|
+
const known = pitchMedians.get(Math.round(size * 2) / 2);
|
|
1573
|
+
return known && known >= size * 0.9 ? known : size * 1.2;
|
|
1574
|
+
},
|
|
1575
|
+
options: opts,
|
|
1576
|
+
stats,
|
|
1577
|
+
blocks: [],
|
|
1578
|
+
headings: [],
|
|
1579
|
+
open: null
|
|
1580
|
+
};
|
|
1581
|
+
const columnPages = { count: 0 };
|
|
1582
|
+
const items = [];
|
|
1583
|
+
fragPages.forEach((frags, pageIndex) => {
|
|
1584
|
+
const page = pageIndex + 1;
|
|
1585
|
+
let flowFrags = frags;
|
|
1586
|
+
const atoms = [];
|
|
1587
|
+
if (opts.detectTables && pages[pageIndex].rules?.length) {
|
|
1588
|
+
const ruled = ruledTables(frags, pages[pageIndex].rules, page, opts.dehyphenate, stats);
|
|
1589
|
+
flowFrags = frags.filter((f) => !ruled.consumed.has(f));
|
|
1590
|
+
atoms.push(...ruled.atoms);
|
|
1591
|
+
}
|
|
1592
|
+
const before = columnPages.count;
|
|
1593
|
+
const segments = readingOrder([...flowFrags, ...atoms], body, opts.detectColumns, 0, columnPages);
|
|
1594
|
+
if (columnPages.count > before) items.push({ type: "columns", page, confidence: 0.8, detail: "multi-column layout" });
|
|
1595
|
+
const units = [];
|
|
1596
|
+
let carry = [];
|
|
1597
|
+
for (const segment of segments) {
|
|
1598
|
+
if (segment.kind === "grid" && opts.detectTables) {
|
|
1599
|
+
const result = alignedTable(segment.items.filter((f) => !f.table), page, 3, opts.dehyphenate, stats);
|
|
1600
|
+
if (result) {
|
|
1601
|
+
const last = units[units.length - 1];
|
|
1602
|
+
if (result.before.length && last && last.kind === "flow") last.items.push(...carry, ...result.before);
|
|
1603
|
+
else if (result.before.length || carry.length) units.push({ kind: "flow", items: [...carry, ...result.before] });
|
|
1604
|
+
units.push({ kind: "table", table: result.table });
|
|
1605
|
+
carry = [...segment.items.filter((f) => f.table), ...result.leftover];
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
units.push({ kind: "flow", items: [...carry, ...segment.items] });
|
|
1610
|
+
carry = [];
|
|
1611
|
+
}
|
|
1612
|
+
if (carry.length) units.push({ kind: "flow", items: carry });
|
|
1613
|
+
for (const unit of units) {
|
|
1614
|
+
if (unit.kind === "table") {
|
|
1615
|
+
ctx.open = null;
|
|
1616
|
+
ctx.blocks.push(unit.table);
|
|
1617
|
+
} else buildBlocks(flowLines(unit.items, page), ctx);
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1620
|
+
assignHeadingLevels(ctx.headings);
|
|
1621
|
+
const counts = { headings: 0, lists: 0, tables: 0, paragraphs: 0 };
|
|
1622
|
+
const confidences = [];
|
|
1623
|
+
ctx.blocks.forEach((block) => {
|
|
1624
|
+
if (block.type === "heading") {
|
|
1625
|
+
counts.headings++;
|
|
1626
|
+
confidences.push(block.confidence);
|
|
1627
|
+
items.push({ type: "heading", page: block.page, confidence: block.confidence, detail: `H${block.level} "${truncate(block.text)}"` });
|
|
1628
|
+
} else if (block.type === "list") {
|
|
1629
|
+
counts.lists++;
|
|
1630
|
+
confidences.push(block.confidence);
|
|
1631
|
+
const depth = maxOf(block.items, (i) => i.depth) + 1;
|
|
1632
|
+
items.push({
|
|
1633
|
+
type: "list",
|
|
1634
|
+
page: block.page,
|
|
1635
|
+
confidence: block.confidence,
|
|
1636
|
+
detail: `${block.items[0]?.ordered ? "numbered" : "bulleted"} list, ${block.items.length} items${depth > 1 ? `, ${depth} levels` : ""}`
|
|
1637
|
+
});
|
|
1638
|
+
} else if (block.type === "table") {
|
|
1639
|
+
counts.tables++;
|
|
1640
|
+
confidences.push(block.confidence);
|
|
1641
|
+
items.push({
|
|
1642
|
+
type: "table",
|
|
1643
|
+
page: block.page,
|
|
1644
|
+
confidence: block.confidence,
|
|
1645
|
+
detail: `${block.rows.length}\xD7${block.columns} table${block.ruled ? " (ruled)" : ""}${block.headerRows ? ", header row" : ""}`
|
|
1646
|
+
});
|
|
1647
|
+
} else counts.paragraphs++;
|
|
1648
|
+
});
|
|
1649
|
+
items.sort((a, b) => a.page - b.page);
|
|
1650
|
+
return {
|
|
1651
|
+
blocks: ctx.blocks,
|
|
1652
|
+
report: {
|
|
1653
|
+
mode: "structured",
|
|
1654
|
+
pages: pages.length,
|
|
1655
|
+
counts,
|
|
1656
|
+
multiColumnPages: columnPages.count,
|
|
1657
|
+
confidence: confidences.length ? Math.round(confidences.reduce((a, b) => a + b, 0) / confidences.length * 100) / 100 : 1,
|
|
1658
|
+
items,
|
|
1659
|
+
removed,
|
|
1660
|
+
dehyphenated: stats.dehyphenated
|
|
1661
|
+
}
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
var truncate = (text) => text.length > 60 ? `${text.slice(0, 57)}\u2026` : text;
|
|
1665
|
+
function listHtml(items) {
|
|
1666
|
+
let html = "";
|
|
1667
|
+
const stack = [];
|
|
1668
|
+
for (const item of items) {
|
|
1669
|
+
const level = item.depth + 1;
|
|
1670
|
+
while (stack.length > level) html += `</li></${stack.pop()}>`;
|
|
1671
|
+
const tag = item.ordered ? "ol" : "ul";
|
|
1672
|
+
if (stack.length === level) {
|
|
1673
|
+
if (stack[stack.length - 1] !== tag) {
|
|
1674
|
+
html += `</li></${stack.pop()}>`;
|
|
1675
|
+
} else html += "</li>";
|
|
1676
|
+
}
|
|
1677
|
+
while (stack.length < level) {
|
|
1678
|
+
const start = item.ordered && item.start !== void 0 && item.start !== 1 ? ` start="${item.start}"` : "";
|
|
1679
|
+
html += `<${tag}${start}>`;
|
|
1680
|
+
stack.push(tag);
|
|
1681
|
+
}
|
|
1682
|
+
html += `<li><p>${escapeHtml(item.text)}</p>`;
|
|
1683
|
+
}
|
|
1684
|
+
while (stack.length) html += `</li></${stack.pop()}>`;
|
|
1685
|
+
return html;
|
|
1686
|
+
}
|
|
1687
|
+
function pdfLayoutBlocksToHtml(blocks) {
|
|
1688
|
+
let html = "";
|
|
1689
|
+
for (const block of blocks) {
|
|
1690
|
+
if (block.type === "heading") html += `<h${block.level}>${escapeHtml(block.text)}</h${block.level}>`;
|
|
1691
|
+
else if (block.type === "paragraph") html += `<p>${escapeHtml(block.text)}</p>`;
|
|
1692
|
+
else if (block.type === "list") html += listHtml(block.items);
|
|
1693
|
+
else {
|
|
1694
|
+
html += "<table><tbody>";
|
|
1695
|
+
for (const row of block.rows) {
|
|
1696
|
+
html += "<tr>";
|
|
1697
|
+
for (const cell of row) {
|
|
1698
|
+
const tag = cell.header ? "th" : "td";
|
|
1699
|
+
const attrs = `${cell.colSpan > 1 ? ` colspan="${cell.colSpan}"` : ""}${cell.rowSpan > 1 ? ` rowspan="${cell.rowSpan}"` : ""}`;
|
|
1700
|
+
html += `<${tag}${attrs}><p>${escapeHtml(cell.text)}</p></${tag}>`;
|
|
1701
|
+
}
|
|
1702
|
+
html += "</tr>";
|
|
1703
|
+
}
|
|
1704
|
+
html += "</tbody></table>";
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return html || "<p></p>";
|
|
1708
|
+
}
|
|
530
1709
|
|
|
531
1710
|
// src/import/pdf.ts
|
|
532
1711
|
var isTextItem = (item) => typeof item.str === "string";
|
|
533
|
-
function
|
|
1712
|
+
function median2(values) {
|
|
534
1713
|
if (!values.length) return 0;
|
|
535
1714
|
const sorted = [...values].sort((a, b) => a - b);
|
|
536
1715
|
const mid = sorted.length >> 1;
|
|
@@ -573,7 +1752,7 @@ function pdfTextItemsToParagraphs(items, options = {}) {
|
|
|
573
1752
|
const gap = lines[i - 1].y - lines[i].y;
|
|
574
1753
|
if (gap > 0) gaps.push(gap);
|
|
575
1754
|
}
|
|
576
|
-
const typical =
|
|
1755
|
+
const typical = median2(gaps);
|
|
577
1756
|
const factor = options.paragraphGap ?? 1.4;
|
|
578
1757
|
const paragraphs = [];
|
|
579
1758
|
let current = [];
|
|
@@ -600,6 +1779,228 @@ function pdfTextItemsToParagraphs(items, options = {}) {
|
|
|
600
1779
|
flush();
|
|
601
1780
|
return paragraphs;
|
|
602
1781
|
}
|
|
1782
|
+
function pdfTextItemsToRuns(items, font) {
|
|
1783
|
+
const runs = [];
|
|
1784
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1785
|
+
for (const item of items) {
|
|
1786
|
+
if (!isTextItem(item) || !item.str.trim()) continue;
|
|
1787
|
+
const t = item.transform ?? [];
|
|
1788
|
+
const fontSize = Math.hypot(t[2] ?? 0, t[3] ?? 0) || item.height || 10;
|
|
1789
|
+
let info;
|
|
1790
|
+
if (item.fontName && font) {
|
|
1791
|
+
if (!cache.has(item.fontName)) cache.set(item.fontName, font(item.fontName));
|
|
1792
|
+
info = cache.get(item.fontName);
|
|
1793
|
+
}
|
|
1794
|
+
runs.push({
|
|
1795
|
+
text: item.str,
|
|
1796
|
+
x: t[4] ?? 0,
|
|
1797
|
+
y: t[5] ?? 0,
|
|
1798
|
+
width: item.width,
|
|
1799
|
+
fontSize,
|
|
1800
|
+
fontName: info?.name ?? item.fontName,
|
|
1801
|
+
bold: info?.bold,
|
|
1802
|
+
italic: info?.italic
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
return runs;
|
|
1806
|
+
}
|
|
1807
|
+
var DEFAULT_OPS = {
|
|
1808
|
+
save: 10,
|
|
1809
|
+
restore: 11,
|
|
1810
|
+
transform: 12,
|
|
1811
|
+
moveTo: 13,
|
|
1812
|
+
lineTo: 14,
|
|
1813
|
+
curveTo: 15,
|
|
1814
|
+
curveTo2: 16,
|
|
1815
|
+
curveTo3: 17,
|
|
1816
|
+
closePath: 18,
|
|
1817
|
+
rectangle: 19,
|
|
1818
|
+
stroke: 20,
|
|
1819
|
+
closeStroke: 21,
|
|
1820
|
+
fill: 22,
|
|
1821
|
+
eoFill: 23,
|
|
1822
|
+
fillStroke: 24,
|
|
1823
|
+
eoFillStroke: 25,
|
|
1824
|
+
closeFillStroke: 26,
|
|
1825
|
+
closeEOFillStroke: 27,
|
|
1826
|
+
endPath: 28,
|
|
1827
|
+
constructPath: 91
|
|
1828
|
+
};
|
|
1829
|
+
var DRAW_OPS = { moveTo: 0, lineTo: 1, curveTo: 2, quadraticCurveTo: 3, closePath: 4 };
|
|
1830
|
+
var MAX_PAGE_RULES = 5e3;
|
|
1831
|
+
var IDENTITY = [1, 0, 0, 1, 0, 0];
|
|
1832
|
+
var multiply = (m, c) => [
|
|
1833
|
+
m[0] * c[0] + m[1] * c[2],
|
|
1834
|
+
m[0] * c[1] + m[1] * c[3],
|
|
1835
|
+
m[2] * c[0] + m[3] * c[2],
|
|
1836
|
+
m[2] * c[1] + m[3] * c[3],
|
|
1837
|
+
m[4] * c[0] + m[5] * c[2] + c[4],
|
|
1838
|
+
m[4] * c[1] + m[5] * c[3] + c[5]
|
|
1839
|
+
];
|
|
1840
|
+
var apply = (m, x, y) => [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
|
|
1841
|
+
function pdfOperatorListToRules(list, opsTable) {
|
|
1842
|
+
const OPS = { ...DEFAULT_OPS, ...opsTable ?? {} };
|
|
1843
|
+
const stroking = /* @__PURE__ */ new Set([OPS.stroke, OPS.closeStroke, OPS.fillStroke, OPS.eoFillStroke, OPS.closeFillStroke, OPS.closeEOFillStroke]);
|
|
1844
|
+
const filling = /* @__PURE__ */ new Set([OPS.fill, OPS.eoFill, OPS.fillStroke, OPS.eoFillStroke, OPS.closeFillStroke, OPS.closeEOFillStroke]);
|
|
1845
|
+
const rules = [];
|
|
1846
|
+
const stack = [];
|
|
1847
|
+
let ctm = IDENTITY;
|
|
1848
|
+
let lines = [];
|
|
1849
|
+
let rects = [];
|
|
1850
|
+
const num = (value) => typeof value === "number" && Number.isFinite(value) ? value : NaN;
|
|
1851
|
+
const addLine = (x1, y1, x2, y2) => {
|
|
1852
|
+
const [a, b] = apply(ctm, x1, y1);
|
|
1853
|
+
const [c, d] = apply(ctm, x2, y2);
|
|
1854
|
+
lines.push([a, b, c, d]);
|
|
1855
|
+
};
|
|
1856
|
+
const addRect = (x, y, w, h) => {
|
|
1857
|
+
const corners = [apply(ctm, x, y), apply(ctm, x + w, y), apply(ctm, x + w, y + h), apply(ctm, x, y + h)];
|
|
1858
|
+
const xs = corners.map((p) => p[0]);
|
|
1859
|
+
const ys = corners.map((p) => p[1]);
|
|
1860
|
+
rects.push([Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys)]);
|
|
1861
|
+
};
|
|
1862
|
+
const paint = (op) => {
|
|
1863
|
+
const stroke = stroking.has(op);
|
|
1864
|
+
const fill = filling.has(op);
|
|
1865
|
+
if (stroke) {
|
|
1866
|
+
for (const [x1, y1, x2, y2] of lines) rules.push({ x1, y1, x2, y2 });
|
|
1867
|
+
for (const [x0, y0, x1, y1] of rects) {
|
|
1868
|
+
rules.push({ x1: x0, y1: y0, x2: x1, y2: y0 }, { x1: x0, y1, x2: x1, y2: y1 });
|
|
1869
|
+
rules.push({ x1: x0, y1: y0, x2: x0, y2: y1 }, { x1, y1: y0, x2: x1, y2: y1 });
|
|
1870
|
+
}
|
|
1871
|
+
} else if (fill) {
|
|
1872
|
+
for (const [x0, y0, x1, y1] of rects) {
|
|
1873
|
+
if (y1 - y0 <= 2 && x1 - x0 > 2) rules.push({ x1: x0, y1: (y0 + y1) / 2, x2: x1, y2: (y0 + y1) / 2 });
|
|
1874
|
+
else if (x1 - x0 <= 2 && y1 - y0 > 2) rules.push({ x1: (x0 + x1) / 2, y1: y0, x2: (x0 + x1) / 2, y2: y1 });
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
lines = [];
|
|
1878
|
+
rects = [];
|
|
1879
|
+
};
|
|
1880
|
+
const readPath = (subOps, subArgs) => {
|
|
1881
|
+
let k = 0;
|
|
1882
|
+
let cx = 0;
|
|
1883
|
+
let cy = 0;
|
|
1884
|
+
let sx = 0;
|
|
1885
|
+
let sy = 0;
|
|
1886
|
+
for (let i = 0; i < subOps.length; i++) {
|
|
1887
|
+
const op = subOps[i];
|
|
1888
|
+
if (op === OPS.moveTo) {
|
|
1889
|
+
cx = sx = num(subArgs[k++]);
|
|
1890
|
+
cy = sy = num(subArgs[k++]);
|
|
1891
|
+
} else if (op === OPS.lineTo) {
|
|
1892
|
+
const x = num(subArgs[k++]);
|
|
1893
|
+
const y = num(subArgs[k++]);
|
|
1894
|
+
addLine(cx, cy, x, y);
|
|
1895
|
+
cx = x;
|
|
1896
|
+
cy = y;
|
|
1897
|
+
} else if (op === OPS.rectangle) {
|
|
1898
|
+
addRect(num(subArgs[k++]), num(subArgs[k++]), num(subArgs[k++]), num(subArgs[k++]));
|
|
1899
|
+
} else if (op === OPS.curveTo) {
|
|
1900
|
+
k += 4;
|
|
1901
|
+
cx = num(subArgs[k++]);
|
|
1902
|
+
cy = num(subArgs[k++]);
|
|
1903
|
+
} else if (op === OPS.curveTo2 || op === OPS.curveTo3) {
|
|
1904
|
+
k += 2;
|
|
1905
|
+
cx = num(subArgs[k++]);
|
|
1906
|
+
cy = num(subArgs[k++]);
|
|
1907
|
+
} else if (op === OPS.closePath) {
|
|
1908
|
+
if (cx !== sx || cy !== sy) addLine(cx, cy, sx, sy);
|
|
1909
|
+
cx = sx;
|
|
1910
|
+
cy = sy;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
const readDrawBuffer = (data) => {
|
|
1915
|
+
let cx = 0;
|
|
1916
|
+
let cy = 0;
|
|
1917
|
+
let sx = 0;
|
|
1918
|
+
let sy = 0;
|
|
1919
|
+
for (let k = 0; k < data.length; ) {
|
|
1920
|
+
const code = data[k++];
|
|
1921
|
+
if (code === DRAW_OPS.moveTo) {
|
|
1922
|
+
cx = sx = data[k++];
|
|
1923
|
+
cy = sy = data[k++];
|
|
1924
|
+
} else if (code === DRAW_OPS.lineTo) {
|
|
1925
|
+
const x = data[k++];
|
|
1926
|
+
const y = data[k++];
|
|
1927
|
+
addLine(cx, cy, x, y);
|
|
1928
|
+
cx = x;
|
|
1929
|
+
cy = y;
|
|
1930
|
+
} else if (code === DRAW_OPS.curveTo) {
|
|
1931
|
+
k += 4;
|
|
1932
|
+
cx = data[k++];
|
|
1933
|
+
cy = data[k++];
|
|
1934
|
+
} else if (code === DRAW_OPS.quadraticCurveTo) {
|
|
1935
|
+
k += 2;
|
|
1936
|
+
cx = data[k++];
|
|
1937
|
+
cy = data[k++];
|
|
1938
|
+
} else if (code === DRAW_OPS.closePath) {
|
|
1939
|
+
if (cx !== sx || cy !== sy) addLine(cx, cy, sx, sy);
|
|
1940
|
+
cx = sx;
|
|
1941
|
+
cy = sy;
|
|
1942
|
+
} else break;
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
for (let i = 0; i < list.fnArray.length && rules.length < MAX_PAGE_RULES; i++) {
|
|
1946
|
+
const fn = list.fnArray[i];
|
|
1947
|
+
const args = list.argsArray[i];
|
|
1948
|
+
if (fn === OPS.save) stack.push(ctm);
|
|
1949
|
+
else if (fn === OPS.restore) ctm = stack.pop() ?? IDENTITY;
|
|
1950
|
+
else if (fn === OPS.transform && args && args.length >= 6) {
|
|
1951
|
+
const m = Array.from({ length: 6 }, (_, k) => num(args[k]));
|
|
1952
|
+
if (m.every(Number.isFinite)) ctm = multiply(m, ctm);
|
|
1953
|
+
} else if (fn === OPS.constructPath && args) {
|
|
1954
|
+
const first = args[0];
|
|
1955
|
+
if (typeof first === "number") {
|
|
1956
|
+
const buffers = args[1];
|
|
1957
|
+
const data = buffers?.[0];
|
|
1958
|
+
if (data && typeof data.length === "number") readDrawBuffer(data);
|
|
1959
|
+
paint(first);
|
|
1960
|
+
} else if (first && typeof first.length === "number") {
|
|
1961
|
+
readPath(first, args[1] ?? []);
|
|
1962
|
+
}
|
|
1963
|
+
} else if (stroking.has(fn) || filling.has(fn)) paint(fn);
|
|
1964
|
+
else if (fn === OPS.endPath) {
|
|
1965
|
+
lines = [];
|
|
1966
|
+
rects = [];
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
return rules.filter((rule) => [rule.x1, rule.y1, rule.x2, rule.y2].every(Number.isFinite));
|
|
1970
|
+
}
|
|
1971
|
+
function fontResolver(page, content) {
|
|
1972
|
+
return (fontName) => {
|
|
1973
|
+
let info;
|
|
1974
|
+
try {
|
|
1975
|
+
if (page.commonObjs && (!page.commonObjs.has || page.commonObjs.has(fontName))) {
|
|
1976
|
+
const font = page.commonObjs.get(fontName);
|
|
1977
|
+
if (font && typeof font === "object") {
|
|
1978
|
+
info = {
|
|
1979
|
+
name: typeof font.name === "string" ? font.name : void 0,
|
|
1980
|
+
bold: font.bold || font.black ? true : void 0,
|
|
1981
|
+
italic: font.italic ? true : void 0
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
} catch {
|
|
1986
|
+
}
|
|
1987
|
+
const family = content.styles?.[fontName]?.fontFamily;
|
|
1988
|
+
if (!info?.name && family) info = { ...info, name: family };
|
|
1989
|
+
return info;
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
function plainReport(paragraphs, pages) {
|
|
1993
|
+
return {
|
|
1994
|
+
mode: "plain",
|
|
1995
|
+
pages,
|
|
1996
|
+
counts: { headings: 0, lists: 0, tables: 0, paragraphs },
|
|
1997
|
+
multiColumnPages: 0,
|
|
1998
|
+
confidence: 1,
|
|
1999
|
+
items: [],
|
|
2000
|
+
removed: { headers: 0, footers: 0, pageNumbers: 0 },
|
|
2001
|
+
dehyphenated: 0
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
603
2004
|
function createPdfImportAdapter(pdfjs, options = {}) {
|
|
604
2005
|
return {
|
|
605
2006
|
id: options.id ?? "pdf",
|
|
@@ -608,22 +2009,47 @@ function createPdfImportAdapter(pdfjs, options = {}) {
|
|
|
608
2009
|
extensions: [".pdf"],
|
|
609
2010
|
target: "document",
|
|
610
2011
|
async import(_input, context) {
|
|
2012
|
+
const call = context.options && typeof context.options === "object" ? context.options : {};
|
|
2013
|
+
const opts = { ...options, ...call, layout: { ...options.layout, ...call.layout } };
|
|
2014
|
+
const structured = opts.structure !== false;
|
|
611
2015
|
const data = new Uint8Array((await context.readArrayBuffer()).slice(0));
|
|
612
|
-
const doc = await pdfjs.getDocument({ ...
|
|
2016
|
+
const doc = await pdfjs.getDocument({ ...opts.documentParams, data }).promise;
|
|
613
2017
|
const paragraphs = [];
|
|
2018
|
+
const layoutPages = [];
|
|
2019
|
+
let pages = 0;
|
|
614
2020
|
try {
|
|
615
|
-
|
|
2021
|
+
pages = Math.min(doc.numPages, opts.maxPages ?? Infinity);
|
|
616
2022
|
for (let n = 1; n <= pages; n++) {
|
|
617
2023
|
const page = await doc.getPage(n);
|
|
618
|
-
|
|
619
|
-
|
|
2024
|
+
if (!structured) {
|
|
2025
|
+
const content = await page.getTextContent();
|
|
2026
|
+
paragraphs.push(...pdfTextItemsToParagraphs(content.items, opts));
|
|
2027
|
+
} else {
|
|
2028
|
+
let rules = [];
|
|
2029
|
+
if (opts.rulingLines !== false && typeof page.getOperatorList === "function") {
|
|
2030
|
+
try {
|
|
2031
|
+
rules = pdfOperatorListToRules(await page.getOperatorList(), pdfjs.OPS);
|
|
2032
|
+
} catch {
|
|
2033
|
+
rules = [];
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
const content = await page.getTextContent();
|
|
2037
|
+
layoutPages.push({ runs: pdfTextItemsToRuns(content.items, fontResolver(page, content)), rules });
|
|
2038
|
+
}
|
|
620
2039
|
page.cleanup?.();
|
|
621
2040
|
}
|
|
622
2041
|
} finally {
|
|
623
2042
|
await doc.destroy?.();
|
|
624
2043
|
}
|
|
625
|
-
|
|
626
|
-
|
|
2044
|
+
if (!structured) {
|
|
2045
|
+
const text = paragraphs.join("\n");
|
|
2046
|
+
return { html: plainTextToParagraphHtml(text), text, structure: plainReport(paragraphs.length, pages) };
|
|
2047
|
+
}
|
|
2048
|
+
const layout = { ...opts.layout };
|
|
2049
|
+
if (layout.paragraphGap === void 0 && opts.paragraphGap !== void 0) layout.paragraphGap = opts.paragraphGap;
|
|
2050
|
+
const { blocks, report } = analyzePdfLayout(layoutPages, layout);
|
|
2051
|
+
const html = sanitizeImportedHtml(pdfLayoutBlocksToHtml(blocks));
|
|
2052
|
+
return { html, text: htmlToPlainText(html), structure: report };
|
|
627
2053
|
}
|
|
628
2054
|
};
|
|
629
2055
|
}
|
|
@@ -722,15 +2148,29 @@ export {
|
|
|
722
2148
|
BLOCK_CHANGE_ATTRIBUTE,
|
|
723
2149
|
BUILT_IN_IMPORT_ADAPTERS,
|
|
724
2150
|
Bookmark,
|
|
2151
|
+
CHARACTER_STYLE_MARK_NAME,
|
|
725
2152
|
COMMENT_MARK_NAME,
|
|
2153
|
+
CONDITIONAL_FORMAT_ICON_SETS,
|
|
2154
|
+
CONDITIONAL_FORMAT_PRESETS,
|
|
2155
|
+
CONDITIONAL_FORMAT_STYLE_PRESETS,
|
|
2156
|
+
CONDITIONAL_FORMAT_TIME_PERIODS,
|
|
2157
|
+
CharacterStyle,
|
|
726
2158
|
ColorHighlighter,
|
|
727
2159
|
CommentStore,
|
|
728
2160
|
Comments,
|
|
2161
|
+
ConditionalFormatEngine,
|
|
729
2162
|
CrossReference,
|
|
2163
|
+
DATA_VALIDATION_ERROR_STYLE_OPTIONS,
|
|
2164
|
+
DATA_VALIDATION_OPERATOR_OPTIONS,
|
|
2165
|
+
DATA_VALIDATION_TYPE_OPTIONS,
|
|
730
2166
|
DEFAULT_AUTOCORRECT_EXCEPTIONS,
|
|
731
2167
|
DEFAULT_COLUMN_WIDTH,
|
|
2168
|
+
DEFAULT_CONDITIONAL_FORMAT_STYLE,
|
|
2169
|
+
DEFAULT_DATA_VALIDATION_MESSAGE,
|
|
2170
|
+
DEFAULT_DATA_VALIDATION_TITLE,
|
|
732
2171
|
DEFAULT_DOCX_MAX_IMAGE_SIZE,
|
|
733
2172
|
DEFAULT_ROW_HEIGHT,
|
|
2173
|
+
DEFAULT_STYLES,
|
|
734
2174
|
DEFAULT_ZIP_MAX_ENTRIES,
|
|
735
2175
|
DEFAULT_ZIP_MAX_TOTAL_SIZE,
|
|
736
2176
|
DELETION_MARK_NAME,
|
|
@@ -738,16 +2178,25 @@ export {
|
|
|
738
2178
|
DataSourceBinder,
|
|
739
2179
|
DependencyGraph,
|
|
740
2180
|
DirtyTracker,
|
|
2181
|
+
DocumentCompare,
|
|
2182
|
+
EMPTY_CONDITIONAL_FORMAT_OVERLAY,
|
|
2183
|
+
EMPTY_FIND_REPLACE_SNAPSHOT,
|
|
741
2184
|
EditorController,
|
|
2185
|
+
FIELD_ALIASES,
|
|
2186
|
+
FIND_OPTION_TOGGLES,
|
|
2187
|
+
FIND_PARAGRAPH_MARK,
|
|
742
2188
|
FORMAT_CHANGE_MARK_NAME,
|
|
743
2189
|
FORMULA_ERRORS,
|
|
744
2190
|
FileImport,
|
|
745
2191
|
FileImportController,
|
|
2192
|
+
FindReplace,
|
|
2193
|
+
FindReplaceStore,
|
|
746
2194
|
FontSize,
|
|
747
2195
|
Footnote,
|
|
748
2196
|
FootnoteReference,
|
|
749
2197
|
Footnotes,
|
|
750
2198
|
FormulaEvaluator,
|
|
2199
|
+
FormulaLambda,
|
|
751
2200
|
FormulaParser,
|
|
752
2201
|
GradientText,
|
|
753
2202
|
HistoryManager,
|
|
@@ -758,20 +2207,38 @@ export {
|
|
|
758
2207
|
ImportError,
|
|
759
2208
|
LoadingNode,
|
|
760
2209
|
MARKDOWN_MENTION_SPLIT_REGEX,
|
|
2210
|
+
MAX_DATA_SOURCE_FIELDS,
|
|
2211
|
+
MAX_DATA_SOURCE_RECORDS,
|
|
2212
|
+
MAX_DEFINED_NAME_LENGTH,
|
|
2213
|
+
MAX_FIND_PATTERN_LENGTH,
|
|
761
2214
|
MAX_FORMULA_ARRAY_SIZE,
|
|
2215
|
+
MAX_LAMBDA_DEPTH,
|
|
2216
|
+
MAX_MERGE_LENGTH,
|
|
2217
|
+
MAX_MERGE_OUTPUTS,
|
|
2218
|
+
MAX_NUMBER_FORMAT_CODE_CHARS,
|
|
2219
|
+
MAX_SHEET_NAME_LENGTH,
|
|
762
2220
|
MENTION_REGEX,
|
|
2221
|
+
MOVE_FROM_CLASS,
|
|
2222
|
+
MOVE_ID_ATTRIBUTE,
|
|
2223
|
+
MOVE_TO_CLASS,
|
|
763
2224
|
Markdown,
|
|
764
2225
|
Mention,
|
|
2226
|
+
NORMAL_STYLE_ID,
|
|
2227
|
+
NUMBER_FORMAT_PRESETS,
|
|
2228
|
+
NumberFormat,
|
|
765
2229
|
Outline,
|
|
766
2230
|
PIXERATE_DOCUMENT_MIME,
|
|
2231
|
+
ParagraphStyles,
|
|
767
2232
|
RichClipboard,
|
|
768
2233
|
SMILIE_REPLACEMENTS,
|
|
769
2234
|
SPREADSHEET_CLIPBOARD_MIME,
|
|
770
2235
|
SPREADSHEET_IMPORT_ADAPTERS,
|
|
771
2236
|
SPREADSHEET_TABLE_ACTIONS,
|
|
2237
|
+
STYLE_ID_ATTRIBUTE,
|
|
772
2238
|
SlashCommands,
|
|
773
2239
|
SmilieReplacer,
|
|
774
2240
|
SpreadsheetController,
|
|
2241
|
+
StyleRegistry,
|
|
775
2242
|
TEMPLATE_DEPTH_ERROR,
|
|
776
2243
|
TEMPLATE_LOOP_ERROR,
|
|
777
2244
|
TEMPLATE_REGEX,
|
|
@@ -787,49 +2254,85 @@ export {
|
|
|
787
2254
|
WHOLE_COLUMN_END_ROW,
|
|
788
2255
|
ZipArchive,
|
|
789
2256
|
ZipError,
|
|
2257
|
+
adjustRangeForStructuralChange,
|
|
2258
|
+
adjustRangesForStructuralChange,
|
|
790
2259
|
aggregateValues,
|
|
2260
|
+
analyzePdfLayout,
|
|
2261
|
+
applyDocumentComparison,
|
|
791
2262
|
applyFormulaSuggestion,
|
|
2263
|
+
applyReplacements,
|
|
792
2264
|
autocorrectPluginKey,
|
|
793
2265
|
bindDirtyToHistory,
|
|
794
2266
|
bindSpreadsheetTableActions,
|
|
2267
|
+
blendConditionalFormatColors,
|
|
795
2268
|
buildOutlineTree,
|
|
796
2269
|
buildSpreadsheetView,
|
|
2270
|
+
builtinNumberFormat,
|
|
2271
|
+
builtinNumberFormatId,
|
|
797
2272
|
capitalizeSentenceRules,
|
|
2273
|
+
captureSelectionFormat,
|
|
2274
|
+
cellFormatForNumberFormat,
|
|
798
2275
|
checkFormulaArgumentCount,
|
|
799
2276
|
clampMenuPosition,
|
|
2277
|
+
clearNumberFormatCache,
|
|
800
2278
|
colNameToIndex,
|
|
801
2279
|
columnDependencyKey,
|
|
802
2280
|
commentsPluginKey,
|
|
803
2281
|
compactVariableValues,
|
|
804
2282
|
compareCellValues,
|
|
2283
|
+
compareConditionValues,
|
|
2284
|
+
compareDocuments,
|
|
2285
|
+
compareHtml,
|
|
2286
|
+
compareInEditor,
|
|
805
2287
|
compareNumbers,
|
|
806
2288
|
compareValues,
|
|
2289
|
+
compileFindPattern,
|
|
807
2290
|
computeFillTarget,
|
|
808
2291
|
computeOutline,
|
|
809
2292
|
computeRowGroups,
|
|
2293
|
+
conditionSubject,
|
|
2294
|
+
conditionalFormatContrastColor,
|
|
2295
|
+
conditionalFormatIconCount,
|
|
2296
|
+
conditionalFormatNumber,
|
|
2297
|
+
conditionalFormatStyleString,
|
|
2298
|
+
copySheetName,
|
|
810
2299
|
createCommentStore,
|
|
2300
|
+
createConditionalFormatRule,
|
|
811
2301
|
createDirtyTracker,
|
|
812
2302
|
createDocxImportAdapter,
|
|
813
2303
|
createEditor,
|
|
814
2304
|
createFileImportController,
|
|
2305
|
+
createFindReplaceCommands,
|
|
815
2306
|
createHistoryManager,
|
|
816
2307
|
createImportAdapterRegistry,
|
|
817
2308
|
createImportContext,
|
|
818
2309
|
createMentionExtension,
|
|
819
2310
|
createOutlineStore,
|
|
2311
|
+
createParagraphStylesStore,
|
|
820
2312
|
createPdfImportAdapter,
|
|
821
2313
|
createReviewId,
|
|
822
2314
|
createRichTextPreset,
|
|
2315
|
+
createSearchBudget,
|
|
823
2316
|
createSpreadsheetClipboardData,
|
|
2317
|
+
createStyleRegistry,
|
|
824
2318
|
createZipImportAdapter,
|
|
825
2319
|
crossReferencePluginKey,
|
|
826
2320
|
csvImportAdapter,
|
|
2321
|
+
dateValueToSerial,
|
|
827
2322
|
defaultAutocorrectRules,
|
|
2323
|
+
defaultIconThresholds,
|
|
828
2324
|
defaultImportRegistry,
|
|
829
2325
|
defaultIsEqual,
|
|
2326
|
+
deleteSheetInFormula,
|
|
830
2327
|
describeBlockChange,
|
|
2328
|
+
describeConditionalFormat,
|
|
2329
|
+
describeConditionalTag,
|
|
2330
|
+
describeDataValidation,
|
|
831
2331
|
describeFormatChange,
|
|
832
2332
|
describeFormulaError,
|
|
2333
|
+
detectDelimiter,
|
|
2334
|
+
diffChanges,
|
|
2335
|
+
diffSequences,
|
|
833
2336
|
documentStructureCommandItems,
|
|
834
2337
|
docxImportAdapter,
|
|
835
2338
|
docxToDocumentImport,
|
|
@@ -837,25 +2340,47 @@ export {
|
|
|
837
2340
|
escapeHtml,
|
|
838
2341
|
escapeVariableText,
|
|
839
2342
|
evaluateCondition,
|
|
2343
|
+
evaluateConditionExpression,
|
|
2344
|
+
evaluateConditionalFormats,
|
|
840
2345
|
evaluatePromptTokens,
|
|
2346
|
+
expandReplacement,
|
|
841
2347
|
extractCellDependencies,
|
|
842
2348
|
extractInstructionNames,
|
|
843
2349
|
extractMentions,
|
|
844
2350
|
extractMentionsFromDoc,
|
|
2351
|
+
extractNameDependencies,
|
|
845
2352
|
extractTemplateNames,
|
|
846
2353
|
extractVariableNames,
|
|
847
2354
|
extractVariables,
|
|
848
2355
|
fileImportPluginKey,
|
|
849
2356
|
fillSeries,
|
|
2357
|
+
findAllMatches,
|
|
850
2358
|
findAutocorrection,
|
|
851
2359
|
findCommentRanges,
|
|
2360
|
+
findDataValidation,
|
|
852
2361
|
findHexColors,
|
|
853
2362
|
findImportAdapter,
|
|
2363
|
+
findInvalidCells,
|
|
2364
|
+
findReplacePluginKey,
|
|
2365
|
+
findTextMentions,
|
|
2366
|
+
foldCodePoint,
|
|
854
2367
|
footnotesMarkdownIt,
|
|
855
2368
|
footnotesPluginKey,
|
|
2369
|
+
forEachRangeCell,
|
|
856
2370
|
formatCellDisplay,
|
|
2371
|
+
formatCellForDisplay,
|
|
2372
|
+
formatComparisonOperand,
|
|
2373
|
+
formatConditionalTag,
|
|
2374
|
+
formatFindStatus,
|
|
2375
|
+
formatGeneralFit,
|
|
2376
|
+
formatMentionText,
|
|
2377
|
+
formatNumberFormatValue,
|
|
857
2378
|
formatReviewTime,
|
|
2379
|
+
formatRuleRanges,
|
|
2380
|
+
formatSheetPrefix,
|
|
2381
|
+
formatTextFunction,
|
|
858
2382
|
formatValueWithCode,
|
|
2383
|
+
formulaIdentifiers,
|
|
859
2384
|
fractionRules,
|
|
860
2385
|
getActiveHeading,
|
|
861
2386
|
getBookmarks,
|
|
@@ -864,11 +2389,16 @@ export {
|
|
|
864
2389
|
getCommentAuthor,
|
|
865
2390
|
getCommentIdsAt,
|
|
866
2391
|
getCommentStore,
|
|
2392
|
+
getConditionalFormatCss,
|
|
2393
|
+
getConditionalFormatIcon,
|
|
867
2394
|
getCrossReferenceTargets,
|
|
2395
|
+
getDataBarCss,
|
|
868
2396
|
getDocumentStructureCommandItems,
|
|
869
2397
|
getEditorMarkdown,
|
|
870
2398
|
getEditorText,
|
|
871
2399
|
getFillDirection,
|
|
2400
|
+
getFindReplaceState,
|
|
2401
|
+
getFindReplaceStore,
|
|
872
2402
|
getFootnotes,
|
|
873
2403
|
getFormulaArgumentSpecIndex,
|
|
874
2404
|
getFormulaCaretContext,
|
|
@@ -878,11 +2408,16 @@ export {
|
|
|
878
2408
|
getFormulaSignatureParts,
|
|
879
2409
|
getImportAccept,
|
|
880
2410
|
getLatestVersion,
|
|
2411
|
+
getMentionNodes,
|
|
2412
|
+
getNameManagerRows,
|
|
881
2413
|
getOutline,
|
|
2414
|
+
getParagraphStyleAt,
|
|
882
2415
|
getPromptDiagnostics,
|
|
883
2416
|
getRowSection,
|
|
884
2417
|
getSchemaSignature,
|
|
2418
|
+
getSheetTabMenuItems,
|
|
885
2419
|
getSpreadsheetMenuItems,
|
|
2420
|
+
getStyleRegistry,
|
|
886
2421
|
getSuppliedValue,
|
|
887
2422
|
getTableOfContentsEntries,
|
|
888
2423
|
getTableSections,
|
|
@@ -890,6 +2425,7 @@ export {
|
|
|
890
2425
|
getTrackChangesStore,
|
|
891
2426
|
getTrackedChangeAt,
|
|
892
2427
|
getTrackedChanges,
|
|
2428
|
+
getValidationListValues,
|
|
893
2429
|
getVariableFormFields,
|
|
894
2430
|
handleImageInsertion,
|
|
895
2431
|
htmlImportAdapter,
|
|
@@ -905,11 +2441,17 @@ export {
|
|
|
905
2441
|
instructionRegex,
|
|
906
2442
|
isBlankValue,
|
|
907
2443
|
isFormulaError,
|
|
2444
|
+
isFormulaLambda,
|
|
2445
|
+
isGeneralNumberFormat,
|
|
908
2446
|
isInsidePromptToken,
|
|
2447
|
+
isLambdaDefinition,
|
|
2448
|
+
isMoveSized,
|
|
2449
|
+
isParagraphStyleAvailable,
|
|
909
2450
|
isPromptValueSet,
|
|
910
2451
|
isSingleCellRange,
|
|
911
2452
|
isTrackChangesEnabled,
|
|
912
2453
|
isUnsafeZipPath,
|
|
2454
|
+
isValidStyleId,
|
|
913
2455
|
listFormulaFunctions,
|
|
914
2456
|
mapFormulaReferences,
|
|
915
2457
|
mapRawOffsetToResolved,
|
|
@@ -917,25 +2459,42 @@ export {
|
|
|
917
2459
|
markdownImportAdapter,
|
|
918
2460
|
markdownToTipTapHtml,
|
|
919
2461
|
matchConditionalTags,
|
|
2462
|
+
matchFields,
|
|
920
2463
|
matchesFilterRule,
|
|
2464
|
+
matchesTimePeriod,
|
|
2465
|
+
mergeRecords,
|
|
921
2466
|
navigateToHeading,
|
|
2467
|
+
nextSheetName,
|
|
2468
|
+
normalizeFieldKey,
|
|
2469
|
+
normalizeFieldNames,
|
|
922
2470
|
normalizeRange,
|
|
2471
|
+
numberFormatColorToCss,
|
|
2472
|
+
numberFormatForCellFormat,
|
|
923
2473
|
numberToText,
|
|
924
2474
|
offsetFormulaReferences,
|
|
925
2475
|
outlinePluginKey,
|
|
2476
|
+
paragraphStylesPluginKey,
|
|
926
2477
|
parseCellInput,
|
|
927
2478
|
parseCellReference,
|
|
2479
|
+
parseComparison,
|
|
2480
|
+
parseConditionExpression,
|
|
928
2481
|
parseCriteria,
|
|
929
2482
|
parseCsv,
|
|
2483
|
+
parseDataSource,
|
|
930
2484
|
parseFormula,
|
|
931
2485
|
parseHtmlTable,
|
|
932
2486
|
parseMentionSegments,
|
|
933
2487
|
parseNumberText,
|
|
934
2488
|
parseRange,
|
|
2489
|
+
parseReplacement,
|
|
935
2490
|
parseRichClipboardPayload,
|
|
2491
|
+
parseRuleRanges,
|
|
936
2492
|
parseTsv,
|
|
937
2493
|
parseVariableBody,
|
|
2494
|
+
pdfLayoutBlocksToHtml,
|
|
2495
|
+
pdfOperatorListToRules,
|
|
938
2496
|
pdfTextItemsToParagraphs,
|
|
2497
|
+
pdfTextItemsToRuns,
|
|
939
2498
|
pickImportFiles,
|
|
940
2499
|
plainTextImportAdapter,
|
|
941
2500
|
plainTextToParagraphHtml,
|
|
@@ -943,18 +2502,23 @@ export {
|
|
|
943
2502
|
plainTextToTipTapHtml,
|
|
944
2503
|
preprocessMarkdownFileLinks,
|
|
945
2504
|
preprocessMarkdownMentions,
|
|
2505
|
+
quoteSheetName,
|
|
946
2506
|
rangeContains,
|
|
947
2507
|
rangeContainsRange,
|
|
2508
|
+
rangesContain,
|
|
948
2509
|
rangesIntersect,
|
|
949
2510
|
readRichClipboard,
|
|
950
2511
|
readSpreadsheetClipboard,
|
|
951
2512
|
readZip,
|
|
952
2513
|
rebaseClipboardRows,
|
|
2514
|
+
recordToValues,
|
|
953
2515
|
registerFormulaFunction,
|
|
954
2516
|
registerImportAdapter,
|
|
955
2517
|
registerSpreadsheetImportAdapters,
|
|
956
2518
|
remapFormulaReferences,
|
|
957
2519
|
removeImageNode,
|
|
2520
|
+
renameNameInFormula,
|
|
2521
|
+
renameSheetInFormula,
|
|
958
2522
|
resolvePrompt,
|
|
959
2523
|
resolveTemplates,
|
|
960
2524
|
resolveTemplatesWithMapping,
|
|
@@ -965,20 +2529,34 @@ export {
|
|
|
965
2529
|
rowPassesFilters,
|
|
966
2530
|
rtfImportAdapter,
|
|
967
2531
|
rtfToPlainText,
|
|
2532
|
+
ruleAnchor,
|
|
2533
|
+
ruleFormulaAt,
|
|
2534
|
+
runSpreadsheetMenuItem,
|
|
2535
|
+
safeCSSValue,
|
|
968
2536
|
sanitizeHtml,
|
|
969
2537
|
sanitizeImportedHtml,
|
|
2538
|
+
searchDocument,
|
|
970
2539
|
searchFormulaFunctions,
|
|
971
2540
|
serialFromYmd,
|
|
972
2541
|
serializeCsv,
|
|
973
2542
|
serializeHtmlTable,
|
|
2543
|
+
serializeMergeOutputs,
|
|
974
2544
|
serializeRichClipboardPayload,
|
|
975
2545
|
serializeTsv,
|
|
2546
|
+
setMentionRoleAt,
|
|
2547
|
+
setMentionRoleInText,
|
|
2548
|
+
sheetDropIndex,
|
|
2549
|
+
sheetNameNeedsQuotes,
|
|
976
2550
|
shiftFormulaReferences,
|
|
2551
|
+
shiftRuleFormula,
|
|
977
2552
|
smartQuoteRules,
|
|
978
2553
|
smilieAutocorrectRules,
|
|
979
2554
|
sortCompareValues,
|
|
980
2555
|
sortZipEntryNames,
|
|
981
2556
|
stripMarkdownCode,
|
|
2557
|
+
subtractRange,
|
|
2558
|
+
subtractRangeFromRanges,
|
|
2559
|
+
summarizeImportStructure,
|
|
982
2560
|
symbolRules,
|
|
983
2561
|
syncFootnotes,
|
|
984
2562
|
tableOfContentsMarkdownIt,
|
|
@@ -989,12 +2567,17 @@ export {
|
|
|
989
2567
|
tokenizePrompt,
|
|
990
2568
|
tokenizePromptWithDiagnostics,
|
|
991
2569
|
trackChangesPluginKey,
|
|
2570
|
+
trackedChangeLabel,
|
|
992
2571
|
tsvImportAdapter,
|
|
993
2572
|
twoInitialCapitalsRules,
|
|
994
2573
|
unescapeVariableText,
|
|
995
2574
|
unregisterFormulaFunction,
|
|
996
2575
|
unregisterImportAdapter,
|
|
997
2576
|
updateImageSrc,
|
|
2577
|
+
validateCellInput,
|
|
2578
|
+
validateDefinedName,
|
|
2579
|
+
validateFindPattern,
|
|
2580
|
+
validateSheetName,
|
|
998
2581
|
variableRegex,
|
|
999
2582
|
wildcardToRegExp,
|
|
1000
2583
|
withoutDirty,
|