docvortex 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. docvortex/__init__.py +21 -0
  2. docvortex/analyzers/__init__.py +3 -0
  3. docvortex/analyzers/native/__init__.py +37 -0
  4. docvortex/analyzers/native/_shared/__init__.py +3 -0
  5. docvortex/analyzers/native/_shared/hyperlink.py +16 -0
  6. docvortex/analyzers/native/_shared/image.py +8 -0
  7. docvortex/analyzers/native/_shared/markup/__init__.py +47 -0
  8. docvortex/analyzers/native/_shared/markup/anchors.py +30 -0
  9. docvortex/analyzers/native/_shared/markup/formula.py +37 -0
  10. docvortex/analyzers/native/_shared/markup/projector.py +57 -0
  11. docvortex/analyzers/native/_shared/markup/styles.py +19 -0
  12. docvortex/analyzers/native/_shared/mathml.py +17 -0
  13. docvortex/analyzers/native/_shared/names.py +7 -0
  14. docvortex/analyzers/native/_shared/xycut.py +414 -0
  15. docvortex/analyzers/native/contracts.py +44 -0
  16. docvortex/analyzers/native/csv.py +351 -0
  17. docvortex/analyzers/native/epub/__init__.py +18 -0
  18. docvortex/analyzers/native/epub/constants.py +45 -0
  19. docvortex/analyzers/native/epub/converter.py +80 -0
  20. docvortex/analyzers/native/epub/errors.py +20 -0
  21. docvortex/analyzers/native/epub/metadata.py +31 -0
  22. docvortex/analyzers/native/epub/package.py +649 -0
  23. docvortex/analyzers/native/epub/xhtml.py +306 -0
  24. docvortex/analyzers/native/html/__init__.py +6 -0
  25. docvortex/analyzers/native/html/anchors.py +271 -0
  26. docvortex/analyzers/native/html/constants.py +25 -0
  27. docvortex/analyzers/native/html/contracts.py +7 -0
  28. docvortex/analyzers/native/html/converter.py +117 -0
  29. docvortex/analyzers/native/html/document.py +389 -0
  30. docvortex/analyzers/native/html/errors.py +12 -0
  31. docvortex/analyzers/native/html/resources.py +365 -0
  32. docvortex/analyzers/native/html/selector.py +421 -0
  33. docvortex/analyzers/native/models.py +209 -0
  34. docvortex/analyzers/native/ofd/__init__.py +14 -0
  35. docvortex/analyzers/native/ofd/constants.py +59 -0
  36. docvortex/analyzers/native/ofd/converter.py +31 -0
  37. docvortex/analyzers/native/ofd/errors.py +16 -0
  38. docvortex/analyzers/native/ofd/geometry.py +215 -0
  39. docvortex/analyzers/native/ofd/images.py +124 -0
  40. docvortex/analyzers/native/ofd/metadata.py +53 -0
  41. docvortex/analyzers/native/ofd/models.py +170 -0
  42. docvortex/analyzers/native/ofd/package.py +346 -0
  43. docvortex/analyzers/native/ofd/path.py +201 -0
  44. docvortex/analyzers/native/ofd/reading_order.py +293 -0
  45. docvortex/analyzers/native/ofd/resources.py +122 -0
  46. docvortex/analyzers/native/ofd/scene.py +347 -0
  47. docvortex/analyzers/native/ofd/table.py +240 -0
  48. docvortex/analyzers/native/ofd/text.py +521 -0
  49. docvortex/analyzers/native/office/__init__.py +3 -0
  50. docvortex/analyzers/native/office/doc/__init__.py +3 -0
  51. docvortex/analyzers/native/office/doc/bookmarks.py +81 -0
  52. docvortex/analyzers/native/office/doc/doc_converter.py +573 -0
  53. docvortex/analyzers/native/office/doc/fib.py +261 -0
  54. docvortex/analyzers/native/office/doc/fields.py +101 -0
  55. docvortex/analyzers/native/office/doc/formatting.py +171 -0
  56. docvortex/analyzers/native/office/doc/images.py +162 -0
  57. docvortex/analyzers/native/office/doc/lists.py +356 -0
  58. docvortex/analyzers/native/office/doc/models.py +164 -0
  59. docvortex/analyzers/native/office/doc/parser.py +851 -0
  60. docvortex/analyzers/native/office/doc/pieces.py +256 -0
  61. docvortex/analyzers/native/office/doc/records.py +40 -0
  62. docvortex/analyzers/native/office/doc/sprm.py +269 -0
  63. docvortex/analyzers/native/office/doc/styles.py +215 -0
  64. docvortex/analyzers/native/office/docx/__init__.py +3 -0
  65. docvortex/analyzers/native/office/docx/context.py +71 -0
  66. docvortex/analyzers/native/office/docx/docx_converter.py +614 -0
  67. docvortex/analyzers/native/office/docx/equationxml.py +119 -0
  68. docvortex/analyzers/native/office/docx/fields.py +816 -0
  69. docvortex/analyzers/native/office/docx/formatting_types.py +23 -0
  70. docvortex/analyzers/native/office/docx/main.py +50 -0
  71. docvortex/analyzers/native/office/docx/numbering.py +491 -0
  72. docvortex/analyzers/native/office/docx/office_xml.py +57 -0
  73. docvortex/analyzers/native/office/docx/package_normalizer.py +248 -0
  74. docvortex/analyzers/native/office/docx/resources.py +526 -0
  75. docvortex/analyzers/native/office/docx/styles.py +693 -0
  76. docvortex/analyzers/native/office/docx/tables.py +515 -0
  77. docvortex/analyzers/native/office/equation/__init__.py +3 -0
  78. docvortex/analyzers/native/office/equation/image.py +470 -0
  79. docvortex/analyzers/native/office/equation/latex_dict.py +324 -0
  80. docvortex/analyzers/native/office/equation/mtef.py +885 -0
  81. docvortex/analyzers/native/office/equation/mtef_v5.py +941 -0
  82. docvortex/analyzers/native/office/equation/omml.py +561 -0
  83. docvortex/analyzers/native/office/equation/ooxml.py +62 -0
  84. docvortex/analyzers/native/office/errors.py +33 -0
  85. docvortex/analyzers/native/office/image.py +307 -0
  86. docvortex/analyzers/native/office/legacy/__init__.py +3 -0
  87. docvortex/analyzers/native/office/legacy/binary.py +43 -0
  88. docvortex/analyzers/native/office/legacy/officeart.py +362 -0
  89. docvortex/analyzers/native/office/legacy/ole.py +110 -0
  90. docvortex/analyzers/native/office/limits.py +12 -0
  91. docvortex/analyzers/native/office/odf/__init__.py +3 -0
  92. docvortex/analyzers/native/office/odf/chart.py +76 -0
  93. docvortex/analyzers/native/office/odf/constants.py +70 -0
  94. docvortex/analyzers/native/office/odf/converters.py +403 -0
  95. docvortex/analyzers/native/office/odf/errors.py +18 -0
  96. docvortex/analyzers/native/office/odf/metadata.py +91 -0
  97. docvortex/analyzers/native/office/odf/models.py +176 -0
  98. docvortex/analyzers/native/office/odf/package.py +270 -0
  99. docvortex/analyzers/native/office/odf/styles.py +329 -0
  100. docvortex/analyzers/native/office/odf/table.py +469 -0
  101. docvortex/analyzers/native/office/odf/text.py +1002 -0
  102. docvortex/analyzers/native/office/ooxml_chart.py +1016 -0
  103. docvortex/analyzers/native/office/opc.py +38 -0
  104. docvortex/analyzers/native/office/ppt/__init__.py +3 -0
  105. docvortex/analyzers/native/office/ppt/models.py +118 -0
  106. docvortex/analyzers/native/office/ppt/parser.py +1895 -0
  107. docvortex/analyzers/native/office/ppt/ppt_converter.py +292 -0
  108. docvortex/analyzers/native/office/ppt/records.py +131 -0
  109. docvortex/analyzers/native/office/ppt/style_text.py +247 -0
  110. docvortex/analyzers/native/office/pptx/__init__.py +3 -0
  111. docvortex/analyzers/native/office/pptx/context.py +113 -0
  112. docvortex/analyzers/native/office/pptx/lists.py +558 -0
  113. docvortex/analyzers/native/office/pptx/main.py +20 -0
  114. docvortex/analyzers/native/office/pptx/package_normalizer.py +321 -0
  115. docvortex/analyzers/native/office/pptx/pptx_converter.py +323 -0
  116. docvortex/analyzers/native/office/pptx/resources.py +329 -0
  117. docvortex/analyzers/native/office/pptx/shapes.py +393 -0
  118. docvortex/analyzers/native/office/pptx/text_styles.py +625 -0
  119. docvortex/analyzers/native/office/pptx/titles.py +178 -0
  120. docvortex/analyzers/native/office/rich_text.py +420 -0
  121. docvortex/analyzers/native/office/rtf/__init__.py +3 -0
  122. docvortex/analyzers/native/office/rtf/converter.py +708 -0
  123. docvortex/analyzers/native/office/rtf/lexer.py +213 -0
  124. docvortex/analyzers/native/office/rtf/math.py +339 -0
  125. docvortex/analyzers/native/office/rtf/models.py +185 -0
  126. docvortex/analyzers/native/office/rtf/parser.py +1553 -0
  127. docvortex/analyzers/native/office/spreadsheet/__init__.py +3 -0
  128. docvortex/analyzers/native/office/spreadsheet/html.py +81 -0
  129. docvortex/analyzers/native/office/spreadsheet/models.py +79 -0
  130. docvortex/analyzers/native/office/spreadsheet/projector.py +928 -0
  131. docvortex/analyzers/native/office/streams.py +18 -0
  132. docvortex/analyzers/native/office/xls/__init__.py +3 -0
  133. docvortex/analyzers/native/office/xls/chart.py +132 -0
  134. docvortex/analyzers/native/office/xls/embedded_chart.py +299 -0
  135. docvortex/analyzers/native/office/xls/models.py +109 -0
  136. docvortex/analyzers/native/office/xls/number_format.py +521 -0
  137. docvortex/analyzers/native/office/xls/parser.py +1145 -0
  138. docvortex/analyzers/native/office/xls/records.py +201 -0
  139. docvortex/analyzers/native/office/xls/strings.py +205 -0
  140. docvortex/analyzers/native/office/xls/xls_converter.py +354 -0
  141. docvortex/analyzers/native/office/xlsx/__init__.py +3 -0
  142. docvortex/analyzers/native/office/xlsx/main.py +20 -0
  143. docvortex/analyzers/native/office/xlsx/ooxml_ole.py +522 -0
  144. docvortex/analyzers/native/office/xlsx/package_normalizer.py +310 -0
  145. docvortex/analyzers/native/office/xlsx/xlsx_converter.py +716 -0
  146. docvortex/analyzers/native/pdf/__init__.py +3 -0
  147. docvortex/analyzers/native/pdf/auxiliary_text.py +1671 -0
  148. docvortex/analyzers/native/pdf/char_geometry.py +1662 -0
  149. docvortex/analyzers/native/pdf/code_blocks.py +535 -0
  150. docvortex/analyzers/native/pdf/formulas.py +1985 -0
  151. docvortex/analyzers/native/pdf/geometry.py +281 -0
  152. docvortex/analyzers/native/pdf/graphics.py +1501 -0
  153. docvortex/analyzers/native/pdf/index_blocks.py +268 -0
  154. docvortex/analyzers/native/pdf/inline/__init__.py +3 -0
  155. docvortex/analyzers/native/pdf/inline/common.py +112 -0
  156. docvortex/analyzers/native/pdf/inline/detection.py +590 -0
  157. docvortex/analyzers/native/pdf/inline/matching.py +1185 -0
  158. docvortex/analyzers/native/pdf/inline/materialize.py +457 -0
  159. docvortex/analyzers/native/pdf/inline/scripts.py +975 -0
  160. docvortex/analyzers/native/pdf/inline/types.py +385 -0
  161. docvortex/analyzers/native/pdf/line_layout.py +1106 -0
  162. docvortex/analyzers/native/pdf/line_merging.py +1223 -0
  163. docvortex/analyzers/native/pdf/models.py +246 -0
  164. docvortex/analyzers/native/pdf/native_text.py +1004 -0
  165. docvortex/analyzers/native/pdf/pipeline.py +1390 -0
  166. docvortex/analyzers/native/pdf/script_geometry.py +636 -0
  167. docvortex/analyzers/native/pdf/shared.py +30 -0
  168. docvortex/analyzers/native/pdf/spatial_text.py +383 -0
  169. docvortex/analyzers/native/pdf/table_annotations.py +446 -0
  170. docvortex/analyzers/native/pdf/table_constants.py +48 -0
  171. docvortex/analyzers/native/pdf/table_detection.py +227 -0
  172. docvortex/analyzers/native/pdf/table_filled_grid.py +218 -0
  173. docvortex/analyzers/native/pdf/table_geometry.py +40 -0
  174. docvortex/analyzers/native/pdf/table_materialization.py +444 -0
  175. docvortex/analyzers/native/pdf/table_recovery/__init__.py +15 -0
  176. docvortex/analyzers/native/pdf/table_recovery/candidate.py +356 -0
  177. docvortex/analyzers/native/pdf/table_recovery/contracts.py +154 -0
  178. docvortex/analyzers/native/pdf/table_recovery/engine.py +609 -0
  179. docvortex/analyzers/native/pdf/table_recovery/geometry.py +164 -0
  180. docvortex/analyzers/native/pdf/table_recovery/sparse_common.py +85 -0
  181. docvortex/analyzers/native/pdf/table_recovery/sparse_hybrid.py +804 -0
  182. docvortex/analyzers/native/pdf/table_recovery/sparse_multiline.py +1122 -0
  183. docvortex/analyzers/native/pdf/table_recovery/text.py +414 -0
  184. docvortex/analyzers/native/pdf/table_recovery/text_grid.py +618 -0
  185. docvortex/analyzers/native/pdf/table_recovery/vector.py +1931 -0
  186. docvortex/analyzers/native/pdf/table_rows.py +34 -0
  187. docvortex/analyzers/native/pdf/table_rules.py +1129 -0
  188. docvortex/analyzers/native/pdf/table_text_styles.py +283 -0
  189. docvortex/analyzers/native/pdf/tables.py +147 -0
  190. docvortex/analyzers/native/pdf/text_assembly/__init__.py +3 -0
  191. docvortex/analyzers/native/pdf/text_assembly/annotations.py +581 -0
  192. docvortex/analyzers/native/pdf/text_assembly/assembly.py +292 -0
  193. docvortex/analyzers/native/pdf/text_assembly/common.py +477 -0
  194. docvortex/analyzers/native/pdf/text_assembly/footnotes.py +394 -0
  195. docvortex/analyzers/native/pdf/text_assembly/merging.py +1274 -0
  196. docvortex/analyzers/native/pdf/text_assembly/rows.py +692 -0
  197. docvortex/analyzers/native/pdf/text_blocks.py +82 -0
  198. docvortex/analyzers/native/pdf/text_styles.py +55 -0
  199. docvortex/analyzers/native/pdf/title_analysis/__init__.py +3 -0
  200. docvortex/analyzers/native/pdf/title_analysis/body_profile.py +215 -0
  201. docvortex/analyzers/native/pdf/title_analysis/common.py +117 -0
  202. docvortex/analyzers/native/pdf/title_analysis/document_profile.py +164 -0
  203. docvortex/analyzers/native/pdf/title_analysis/lane_titles.py +758 -0
  204. docvortex/analyzers/native/pdf/title_analysis/page_titles.py +1024 -0
  205. docvortex/analyzers/native/pdf/title_analysis/prototype.py +194 -0
  206. docvortex/analyzers/native/pdf/title_analysis/structural.py +1081 -0
  207. docvortex/analyzers/native/pdf/titles.py +75 -0
  208. docvortex/analyzers/native/pdf/typography.py +19 -0
  209. docvortex/analyzers/native/pdf/visual_annotations.py +1262 -0
  210. docvortex/api.py +180 -0
  211. docvortex/assets/__init__.py +5 -0
  212. docvortex/assets/store.py +51 -0
  213. docvortex/cli.py +54 -0
  214. docvortex/codecs/__init__.py +3 -0
  215. docvortex/codecs/html/__init__.py +22 -0
  216. docvortex/codecs/html/contracts.py +236 -0
  217. docvortex/codecs/html/materializer.py +331 -0
  218. docvortex/codecs/html/parser.py +763 -0
  219. docvortex/codecs/html/resources.py +34 -0
  220. docvortex/codecs/json.py +17 -0
  221. docvortex/content/__init__.py +5 -0
  222. docvortex/content/inline.py +248 -0
  223. docvortex/content/markup/__init__.py +44 -0
  224. docvortex/content/markup/anchors.py +188 -0
  225. docvortex/content/markup/formula.py +280 -0
  226. docvortex/content/markup/projector.py +1237 -0
  227. docvortex/content/markup/styles.py +327 -0
  228. docvortex/content/mathml.py +167 -0
  229. docvortex/content/normalization.py +188 -0
  230. docvortex/content/spans.py +183 -0
  231. docvortex/content/table/__init__.py +18 -0
  232. docvortex/content/table/blocks.py +152 -0
  233. docvortex/content/table/content.py +425 -0
  234. docvortex/content/table/document.py +104 -0
  235. docvortex/content/table/html.py +399 -0
  236. docvortex/content/table/models.py +76 -0
  237. docvortex/content/table/rules.py +42 -0
  238. docvortex/content/table/structure.py +221 -0
  239. docvortex/content/tree.py +5 -0
  240. docvortex/document/__init__.py +3 -0
  241. docvortex/document/contracts.py +22 -0
  242. docvortex/document/detection.py +389 -0
  243. docvortex/document/filetypes.py +175 -0
  244. docvortex/document/page_range.py +167 -0
  245. docvortex/document/pdf/__init__.py +19 -0
  246. docvortex/document/pdf/classify.py +1138 -0
  247. docvortex/document/pdf/constants.py +132 -0
  248. docvortex/document/pdf/diagnostics.py +350 -0
  249. docvortex/document/pdf/document.py +582 -0
  250. docvortex/document/pdf/font_runtime.py +335 -0
  251. docvortex/document/pdf/geometry.py +31 -0
  252. docvortex/document/pdf/images.py +654 -0
  253. docvortex/document/pdf/native_annotations.py +367 -0
  254. docvortex/document/pdf/native_contracts.py +169 -0
  255. docvortex/document/pdf/native_coordinates.py +216 -0
  256. docvortex/document/pdf/native_lifecycle.py +16 -0
  257. docvortex/document/pdf/native_objects.py +902 -0
  258. docvortex/document/pdf/native_text_geometry.py +315 -0
  259. docvortex/document/pdf/pdfium.py +325 -0
  260. docvortex/document/pdf/raster.py +46 -0
  261. docvortex/document/pdf/text/__init__.py +62 -0
  262. docvortex/document/pdf/text/contracts.py +211 -0
  263. docvortex/document/pdf/text/extract.py +165 -0
  264. docvortex/document/pdf/text/geometry.py +16 -0
  265. docvortex/document/pdf/text/groups.py +162 -0
  266. docvortex/document/pdf/visual_geometry.py +201 -0
  267. docvortex/document/pdf/visuals.py +343 -0
  268. docvortex/document/source.py +92 -0
  269. docvortex/errors.py +21 -0
  270. docvortex/export/__init__.py +3 -0
  271. docvortex/export/bundle.py +98 -0
  272. docvortex/export/files.py +66 -0
  273. docvortex/export/middle.py +208 -0
  274. docvortex/foundation/__init__.py +3 -0
  275. docvortex/foundation/geometry.py +125 -0
  276. docvortex/foundation/hyperlink.py +65 -0
  277. docvortex/foundation/image.py +48 -0
  278. docvortex/foundation/image_encoding.py +30 -0
  279. docvortex/foundation/image_payload.py +280 -0
  280. docvortex/foundation/language.py +92 -0
  281. docvortex/foundation/platform.py +38 -0
  282. docvortex/foundation/text.py +153 -0
  283. docvortex/foundation/type_identity.py +20 -0
  284. docvortex/foundation/xml_names.py +20 -0
  285. docvortex/options.py +30 -0
  286. docvortex/postprocess/__init__.py +3 -0
  287. docvortex/postprocess/content.py +53 -0
  288. docvortex/postprocess/document.py +19 -0
  289. docvortex/postprocess/lists.py +236 -0
  290. docvortex/postprocess/page_blocks.py +214 -0
  291. docvortex/postprocess/pages.py +95 -0
  292. docvortex/postprocess/paragraphs.py +580 -0
  293. docvortex/postprocess/visual.py +715 -0
  294. docvortex/render/__init__.py +48 -0
  295. docvortex/render/_internal/__init__.py +3 -0
  296. docvortex/render/_internal/common/__init__.py +3 -0
  297. docvortex/render/_internal/common/context.py +43 -0
  298. docvortex/render/_internal/common/html_table.py +178 -0
  299. docvortex/render/_internal/common/index.py +33 -0
  300. docvortex/render/_internal/common/list_items.py +158 -0
  301. docvortex/render/_internal/common/planner.py +140 -0
  302. docvortex/render/_internal/docx/__init__.py +3 -0
  303. docvortex/render/_internal/docx/assets.py +202 -0
  304. docvortex/render/_internal/docx/inline.py +434 -0
  305. docvortex/render/_internal/docx/math.py +220 -0
  306. docvortex/render/_internal/docx/renderer.py +905 -0
  307. docvortex/render/_internal/docx/styles.py +195 -0
  308. docvortex/render/_internal/docx/table.py +442 -0
  309. docvortex/render/_internal/epub/__init__.py +5 -0
  310. docvortex/render/_internal/epub/assets.py +173 -0
  311. docvortex/render/_internal/epub/package.py +249 -0
  312. docvortex/render/_internal/epub/renderer.py +1156 -0
  313. docvortex/render/_internal/html/__init__.py +3 -0
  314. docvortex/render/_internal/html/inline.py +346 -0
  315. docvortex/render/_internal/html/renderer.py +1041 -0
  316. docvortex/render/_internal/html/sanitizer.py +478 -0
  317. docvortex/render/_internal/html/table.py +121 -0
  318. docvortex/render/_internal/latex/__init__.py +1 -0
  319. docvortex/render/_internal/latex/assets.py +85 -0
  320. docvortex/render/_internal/latex/inline.py +145 -0
  321. docvortex/render/_internal/latex/renderer.py +506 -0
  322. docvortex/render/_internal/latex/table.py +347 -0
  323. docvortex/render/_internal/markdown/__init__.py +3 -0
  324. docvortex/render/_internal/markdown/assets.py +78 -0
  325. docvortex/render/_internal/markdown/blocks.py +635 -0
  326. docvortex/render/_internal/markdown/escaping.py +51 -0
  327. docvortex/render/_internal/markdown/inline.py +260 -0
  328. docvortex/render/_internal/markdown/renderer.py +93 -0
  329. docvortex/render/_internal/markdown/table.py +281 -0
  330. docvortex/render/_internal/pdf/__init__.py +3 -0
  331. docvortex/render/_internal/pdf/assets.py +197 -0
  332. docvortex/render/_internal/pdf/formula.py +417 -0
  333. docvortex/render/_internal/pdf/inline.py +343 -0
  334. docvortex/render/_internal/pdf/renderer.py +734 -0
  335. docvortex/render/_internal/pdf/styles.py +206 -0
  336. docvortex/render/_internal/pdf/table.py +272 -0
  337. docvortex/render/_internal/structured_content/__init__.py +3 -0
  338. docvortex/render/_internal/structured_content/renderer.py +193 -0
  339. docvortex/render/api.py +199 -0
  340. docvortex/render/contracts.py +205 -0
  341. docvortex/render/docx.py +38 -0
  342. docvortex/render/epub.py +35 -0
  343. docvortex/render/fragments.py +70 -0
  344. docvortex/render/html.py +29 -0
  345. docvortex/render/latex.py +24 -0
  346. docvortex/render/markdown.py +50 -0
  347. docvortex/render/pdf.py +25 -0
  348. docvortex/render/structured_content.py +23 -0
  349. docvortex/resources/epub/docvortex.css +91 -0
  350. docvortex/resources/fasttext-langdetect/lid.176.ftz +0 -0
  351. docvortex/resources/fonts/DroidSansFallbackFull.ttf +0 -0
  352. docvortex/resources/fonts/NOTICE +190 -0
  353. docvortex/resources/fonts/manifest.json +9 -0
  354. docvortex/resources/html/docvortex.css +601 -0
  355. docvortex/resources/html/docvortex.min.css +1 -0
  356. docvortex/result.py +91 -0
  357. docvortex/schema.py +1141 -0
  358. docvortex/version.py +3 -0
  359. docvortex-0.2.1.dist-info/METADATA +193 -0
  360. docvortex-0.2.1.dist-info/RECORD +364 -0
  361. docvortex-0.2.1.dist-info/WHEEL +5 -0
  362. docvortex-0.2.1.dist-info/entry_points.txt +2 -0
  363. docvortex-0.2.1.dist-info/licenses/LICENSE.md +21 -0
  364. docvortex-0.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3 @@
1
+ """HTML renderer 的内部实现。"""
2
+
3
+ __all__: list[str] = []
@@ -0,0 +1,346 @@
1
+ """Middle JSON 2.0 行内 Span 到安全 HTML 的序列化。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import html
6
+ import ipaddress
7
+ import re
8
+ from dataclasses import dataclass
9
+ from urllib.parse import urlsplit
10
+
11
+ from ....content.inline import join_inline_spans
12
+ from ....schema import CodeInlineSpan, EquationInlineSpan, HyperlinkSpan, InlineSpan, TextSpan
13
+ from .sanitizer import sanitize_link_url
14
+
15
+
16
+ _AUTOLINK_TLD_PATTERN = r"(?:[A-Za-z]{2,63}|xn--[A-Za-z0-9-]{2,59})"
17
+ _AUTOLINK_DOMAIN_PATTERN = rf"(?:[A-Za-z0-9](?:[A-Za-z0-9-]{{0,61}}[A-Za-z0-9])?\.){{1,10}}{_AUTOLINK_TLD_PATTERN}"
18
+ _AUTOLINK_EMAIL_EDGE_PATTERN = r"[A-Za-z0-9!#$%&'*+/=?^_{|}~-]"
19
+ _AUTOLINK_EMAIL_PATTERN = (
20
+ rf"{_AUTOLINK_EMAIL_EDGE_PATTERN}"
21
+ rf"(?:[A-Za-z0-9.!#$%&'*+/=?^_{{|}}~-]{{0,62}}{_AUTOLINK_EMAIL_EDGE_PATTERN})?"
22
+ rf"@{_AUTOLINK_DOMAIN_PATTERN}"
23
+ )
24
+ _AUTOLINK_EXPLICIT_HOST_PATTERN = rf"(?:{_AUTOLINK_DOMAIN_PATTERN}|localhost|(?:\d{{1,3}}\.){{3}}\d{{1,3}}|\[[0-9A-Fa-f:.]+\])"
25
+ _AUTOLINK_URL_TAIL_PATTERN = r"(?::\d{1,5})?(?:[/?#](?:(?!https?://)[A-Za-z0-9._~:/?#\[\]@!$&()*+,;=%-])*)?"
26
+ _AUTOLINK_RE = re.compile(
27
+ rf"(?:(?P<email>(?<![A-Za-z0-9._%+@-]){_AUTOLINK_EMAIL_PATTERN})"
28
+ rf"|(?P<explicit>https?://{_AUTOLINK_EXPLICIT_HOST_PATTERN}{_AUTOLINK_URL_TAIL_PATTERN})"
29
+ rf"|(?P<www>(?<![A-Za-z0-9._%+@-])www\.{_AUTOLINK_DOMAIN_PATTERN}{_AUTOLINK_URL_TAIL_PATTERN})"
30
+ rf"|(?P<domain>(?<![A-Za-z0-9._%+@-]){_AUTOLINK_DOMAIN_PATTERN}{_AUTOLINK_URL_TAIL_PATTERN}))",
31
+ re.IGNORECASE,
32
+ )
33
+ _AUTOLINK_UNSUPPORTED_SCHEME_RE = re.compile(r"[A-Za-z][A-Za-z0-9+.-]*:[^\s]*$")
34
+ _AUTOLINK_TRAILING_PUNCTUATION = ".,;:!?,。;:!?、"
35
+ _AUTOLINK_CLOSING_PAIRS = {")": "(", "]": "[", "}": "{", ")": "(", "】": "【", "》": "《"}
36
+ _AUTOLINK_COMMON_BARE_TLDS = frozenset(
37
+ {
38
+ "ai",
39
+ "app",
40
+ "au",
41
+ "biz",
42
+ "br",
43
+ "ca",
44
+ "cloud",
45
+ "cn",
46
+ "com",
47
+ "de",
48
+ "dev",
49
+ "edu",
50
+ "eu",
51
+ "fr",
52
+ "gov",
53
+ "hk",
54
+ "in",
55
+ "info",
56
+ "io",
57
+ "jp",
58
+ "kr",
59
+ "net",
60
+ "nl",
61
+ "nz",
62
+ "online",
63
+ "org",
64
+ "ru",
65
+ "sg",
66
+ "shop",
67
+ "site",
68
+ "store",
69
+ "tech",
70
+ "tw",
71
+ "uk",
72
+ "xyz",
73
+ }
74
+ )
75
+
76
+
77
+ @dataclass(frozen=True, slots=True)
78
+ class HtmlInlineResult:
79
+ """保存一段行内 HTML 及其是否包含需由 MathJax 处理的公式。"""
80
+
81
+ html: str
82
+ has_math: bool = False
83
+
84
+
85
+ def render_inline_content_html(content: list[InlineSpan]) -> HtmlInlineResult:
86
+ """把一段 MiddleJson 行内内容渲染为安全 HTML。"""
87
+ return render_inline_spans_html(content)
88
+
89
+
90
+ def render_joined_inline_contents_html(contents: list[list[InlineSpan]]) -> HtmlInlineResult:
91
+ """按共享物理段落边界规则合并多段内容后渲染 HTML。"""
92
+ return render_inline_spans_html(join_inline_spans(contents))
93
+
94
+
95
+ def render_inline_spans_html(
96
+ spans: list[InlineSpan],
97
+ *,
98
+ linkify_text: bool = True,
99
+ separate_adjacent_math: bool = False,
100
+ preserve_newlines: bool = False,
101
+ ) -> HtmlInlineResult:
102
+ """渲染行内 Span,可分隔相邻公式或给 pre-wrap 容器保留原始换行。"""
103
+ parts: list[str] = []
104
+ has_math = False
105
+ previous_was_math = False
106
+ for span in spans:
107
+ rendered = _render_inline_span_html(
108
+ span,
109
+ linkify_text=linkify_text,
110
+ preserve_newlines=preserve_newlines,
111
+ )
112
+ if not rendered.html:
113
+ continue
114
+ current_is_math = isinstance(span, EquationInlineSpan)
115
+ if separate_adjacent_math and previous_was_math and current_is_math:
116
+ parts.append(" ")
117
+ parts.append(rendered.html)
118
+ has_math = rendered.has_math or has_math
119
+ previous_was_math = current_is_math
120
+ return HtmlInlineResult("".join(parts), has_math)
121
+
122
+
123
+ def render_math_html(latex: str, *, display: bool) -> HtmlInlineResult:
124
+ """把裸 LaTeX 放入只由 MathJax 扫描的行内或行间公式载体。"""
125
+ normalized = latex.strip()
126
+ if not normalized:
127
+ return HtmlInlineResult("")
128
+ attribute_latex = html.escape(_normalize_html_text(normalized), quote=True)
129
+ normalized = _neutralize_math_closing_delimiter(normalized, "]" if display else ")")
130
+ escaped = _escape_text(normalized)
131
+ if display:
132
+ return HtmlInlineResult(
133
+ '<div class="docvortex-math docvortex-math--block" data-block-type="equation" '
134
+ f'data-formula-display="block" data-docvortex-latex="{attribute_latex}">\\[\n{escaped}\n\\]</div>',
135
+ has_math=True,
136
+ )
137
+ return HtmlInlineResult(
138
+ '<span class="docvortex-math docvortex-math--inline" data-block-type="equation" '
139
+ f'data-formula-display="inline" data-docvortex-latex="{attribute_latex}">\\({escaped}\\)</span>',
140
+ has_math=True,
141
+ )
142
+
143
+
144
+ def _render_inline_span_html(
145
+ span: InlineSpan,
146
+ *,
147
+ linkify_text: bool,
148
+ preserve_newlines: bool,
149
+ ) -> HtmlInlineResult:
150
+ """把一个结构化行内 Span 映射为 HTML。"""
151
+ if isinstance(span, TextSpan):
152
+ rendered = HtmlInlineResult(
153
+ _render_text_html(
154
+ span.content,
155
+ linkify_text=linkify_text,
156
+ preserve_newlines=preserve_newlines,
157
+ )
158
+ )
159
+ styled_html = _apply_html_styles(rendered.html, span.styles)
160
+ if span.styles and _needs_whitespace_preservation(span.content):
161
+ styled_html = f'<span class="docvortex-preserve-whitespace">{styled_html}</span>'
162
+ return HtmlInlineResult(styled_html)
163
+ if isinstance(span, CodeInlineSpan):
164
+ return HtmlInlineResult(f"<code>{_escape_text(span.content)}</code>")
165
+ if isinstance(span, EquationInlineSpan):
166
+ return render_math_html(span.content, display=False)
167
+ if isinstance(span, HyperlinkSpan):
168
+ children = render_inline_spans_html(
169
+ list(span.content),
170
+ linkify_text=False,
171
+ preserve_newlines=preserve_newlines,
172
+ )
173
+ safe_url = sanitize_link_url(span.url)
174
+ if not safe_url or safe_url == ".":
175
+ return children
176
+ href = html.escape(safe_url, quote=True)
177
+ return HtmlInlineResult(
178
+ f'<a href="{href}" rel="noopener noreferrer">{children.html}</a>',
179
+ children.has_math,
180
+ )
181
+ raise TypeError(f"Unsupported inline span: {type(span).__name__}")
182
+
183
+
184
+ def _render_text_html(
185
+ content: str,
186
+ *,
187
+ linkify_text: bool,
188
+ preserve_newlines: bool,
189
+ ) -> str:
190
+ """转义普通文本,并按需把安全 URL-like 候选转换为链接。"""
191
+ if not linkify_text:
192
+ return _escape_text_with_breaks(content, preserve_newlines=preserve_newlines)
193
+
194
+ parts: list[str] = []
195
+ cursor = 0
196
+ for match in _AUTOLINK_RE.finditer(content):
197
+ candidate = match.group(0)
198
+ candidate, trailing = _trim_autolink_candidate(candidate)
199
+ if not candidate or _is_embedded_autolink_candidate(content, match, candidate):
200
+ continue
201
+ href = _autolink_href(match, candidate)
202
+ if href is None:
203
+ continue
204
+ parts.append(_escape_text_with_breaks(content[cursor : match.start()], preserve_newlines=preserve_newlines))
205
+ escaped_href = html.escape(href, quote=True)
206
+ escaped_label = _escape_text_with_breaks(candidate, preserve_newlines=preserve_newlines)
207
+ parts.append(f'<a href="{escaped_href}" rel="noopener noreferrer">{escaped_label}</a>')
208
+ cursor = match.end() - len(trailing)
209
+ parts.append(_escape_text_with_breaks(content[cursor:], preserve_newlines=preserve_newlines))
210
+ return "".join(parts)
211
+
212
+
213
+ def _trim_autolink_candidate(candidate: str) -> tuple[str, str]:
214
+ """去除 URL 尾部句读和不平衡右括号,并返回应保留的原文后缀。"""
215
+ end = len(candidate)
216
+ while end and candidate[end - 1] in _AUTOLINK_TRAILING_PUNCTUATION:
217
+ end -= 1
218
+ changed = True
219
+ while end and changed:
220
+ changed = False
221
+ closing = candidate[end - 1]
222
+ opening = _AUTOLINK_CLOSING_PAIRS.get(closing)
223
+ if opening is not None and candidate[:end].count(closing) > candidate[:end].count(opening):
224
+ end -= 1
225
+ changed = True
226
+ return candidate[:end], candidate[end:]
227
+
228
+
229
+ def _is_embedded_autolink_candidate(
230
+ content: str,
231
+ match: re.Match[str],
232
+ candidate: str,
233
+ ) -> bool:
234
+ """拒绝未知协议、相对路径和裸 IP 内部的模糊候选。"""
235
+ if match.group("explicit") is not None:
236
+ return False
237
+ prefix = content[max(0, match.start() - 32) : match.start()]
238
+ if _AUTOLINK_UNSUPPORTED_SCHEME_RE.search(prefix) is not None:
239
+ return True
240
+ if match.group("email") is not None:
241
+ return False
242
+ if match.start() and content[match.start() - 1] in "/\\":
243
+ return True
244
+ host = candidate.split("/", 1)[0].split("?", 1)[0].split("#", 1)[0].split(":", 1)[0]
245
+ try:
246
+ ipaddress.ip_address(host)
247
+ except ValueError:
248
+ return False
249
+ return True
250
+
251
+
252
+ def _autolink_href(match: re.Match[str], candidate: str) -> str | None:
253
+ """把候选转换为显式安全 href,并验证端口和显式 IP 地址。"""
254
+ if match.group("email") is not None:
255
+ if ".." in candidate.rsplit("@", 1)[0]:
256
+ return None
257
+ href = f"mailto:{candidate}"
258
+ elif match.group("explicit") is not None:
259
+ href = candidate
260
+ else:
261
+ if match.group("domain") is not None and not _is_allowed_bare_domain(candidate):
262
+ return None
263
+ href = f"https://{candidate}"
264
+ try:
265
+ parsed = urlsplit(href)
266
+ _ = parsed.port
267
+ if parsed.hostname and re.fullmatch(r"\d+(?:\.\d+){3}", parsed.hostname):
268
+ ipaddress.ip_address(parsed.hostname)
269
+ except ValueError:
270
+ return None
271
+ return sanitize_link_url(href)
272
+
273
+
274
+ def _is_allowed_bare_domain(candidate: str) -> bool:
275
+ """仅允许工程常用 TLD 的无协议裸域名,减少文件名和股票代码误判。"""
276
+ authority = re.split(r"[/?#]", candidate, maxsplit=1)[0]
277
+ host = authority.rsplit(":", 1)[0]
278
+ tld = host.rsplit(".", 1)[-1].lower()
279
+ return tld in _AUTOLINK_COMMON_BARE_TLDS
280
+
281
+
282
+ def _escape_text_with_breaks(content: str, *, preserve_newlines: bool) -> str:
283
+ """转义文本,并按调用方要求把换行转换为 HTML br。"""
284
+ escaped = _escape_text(content)
285
+ return escaped if preserve_newlines else escaped.replace("\n", "<br>\n")
286
+
287
+
288
+ def _apply_html_styles(content: str, styles: list[str]) -> str:
289
+ """按 Markdown renderer 的稳定顺序应用共享富文本样式。"""
290
+ if not content:
291
+ return content
292
+ if "superscript" in styles:
293
+ content = f"<sup>{content}</sup>"
294
+ elif "subscript" in styles:
295
+ content = f"<sub>{content}</sub>"
296
+ if "underline" in styles:
297
+ content = f"<u>{content}</u>"
298
+ if "bold" in styles:
299
+ content = f"<strong>{content}</strong>"
300
+ if "italic" in styles:
301
+ content = f"<em>{content}</em>"
302
+ if "strikethrough" in styles:
303
+ content = f"<s>{content}</s>"
304
+ if "emphasis" in styles:
305
+ content = f'<span class="docvortex-text-emphasis">{content}</span>'
306
+ return content
307
+
308
+
309
+ def _escape_text(content: str) -> str:
310
+ """转义普通文本,并替换 HTML 不允许的 C0 控制字符。"""
311
+ return html.escape(_normalize_html_text(content), quote=False)
312
+
313
+
314
+ def _normalize_html_text(content: str) -> str:
315
+ """统一换行并替换 HTML 属性和正文都不允许的控制字符。"""
316
+ normalized = content.replace("\r\n", "\n").replace("\r", "\n")
317
+ return re.sub(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\ud800-\udfff]", "\ufffd", normalized)
318
+
319
+
320
+ def _needs_whitespace_preservation(content: str) -> bool:
321
+ """判断富文本是否包含浏览器默认会折叠的有效空白。"""
322
+ return bool(content and (content != content.strip(" \t\n") or " " in content or "\t" in content or "\n" in content))
323
+
324
+
325
+ def _neutralize_math_closing_delimiter(latex: str, closing: str) -> str:
326
+ """把公式体内奇数反斜杠引出的结束定界符改写为等价 TeX,防止提前闭合。"""
327
+ token = re.escape(closing)
328
+
329
+ def _replace(match: re.Match[str]) -> str:
330
+ """保留成对反斜杠,并把最后一个定界反斜杠改为 mathclose。"""
331
+ slashes = match.group("slashes")
332
+ if len(slashes) % 2 == 0:
333
+ return match.group(0)
334
+ prefix = "\\" * (len(slashes) - 1)
335
+ return f"{prefix}\\mathclose{{{closing}}}"
336
+
337
+ return re.sub(rf"(?P<slashes>\\+){token}", _replace, latex)
338
+
339
+
340
+ __all__ = [
341
+ "HtmlInlineResult",
342
+ "render_inline_content_html",
343
+ "render_inline_spans_html",
344
+ "render_joined_inline_contents_html",
345
+ "render_math_html",
346
+ ]