metanorma-document 0.2.9 → 0.2.12

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 (390) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +164 -66
  3. data/CLAUDE.md +26 -0
  4. data/README.adoc +144 -0
  5. data/Rakefile +14 -2
  6. data/TODO.finalize/01-split-multi-class-files.md +8 -0
  7. data/TODO.finalize/02-remove-data-dist-iso-document-frontend.md +6 -0
  8. data/TODO.finalize/03-align-frontend-iife-and-gha-build.md +11 -0
  9. data/TODO.finalize/04-theme-per-flavor-config-driven.md +9 -0
  10. data/TODO.finalize/05-migrate-all-html-to-liquid.md +16 -0
  11. data/TODO.finalize/06-integrate-pubid-library.md +16 -0
  12. data/TODO.finalize/07-replace-relaton-models-with-relaton-bib.md +39 -0
  13. data/TODO.finalize/08-refactor-renderer-architecture.md +25 -0
  14. data/TODO.finalize/09-eliminate-code-smells.md +14 -0
  15. data/TODO.finalize/10-comprehensive-spec-coverage.md +24 -0
  16. data/TODO.finalize/11-config-driven-flavor-metadata.md +20 -0
  17. data/TODO.finalize/12-add-frozen-string-literal.md +6 -0
  18. data/TODO.finalize/13-extract-composition-from-god-class.md +96 -0
  19. data/TODO.finalize/14-config-driven-section-ordering.md +31 -0
  20. data/TODO.finalize/15-theme-directories-per-flavor.md +46 -0
  21. data/TODO.finalize/16-theme-lutaml-model-schema.md +44 -0
  22. data/data/javascripts/components/mn-footnotes.js +68 -0
  23. data/data/javascripts/components/mn-lightbox.js +18 -2
  24. data/data/javascripts/components/mn-shortcuts.js +2 -0
  25. data/data/javascripts/core/mn-navigation.js +8 -0
  26. data/data/javascripts/core/mn-theme.js +9 -9
  27. data/data/logos/oiml-logo-full-dark.svg +1 -0
  28. data/data/logos/oiml-logo-full-light.svg +1 -0
  29. data/data/logos/oiml-logo-icon-dark.svg +1 -0
  30. data/data/logos/oiml-logo-icon-light.svg +1 -0
  31. data/data/logos/oiml-logo.svg +1 -0
  32. data/data/logos/pdfa-logo.svg +31 -94
  33. data/data/stylesheets/base/_layout.css +3 -0
  34. data/data/stylesheets/base/_reset.css +3 -3
  35. data/data/stylesheets/base/_typography.css +0 -5
  36. data/data/stylesheets/components/bibliography.css +3 -3
  37. data/data/stylesheets/components/cover.css +3 -1
  38. data/data/stylesheets/components/figure.css +13 -1
  39. data/data/stylesheets/components/footnote.css +65 -5
  40. data/data/stylesheets/components/formula.css +44 -0
  41. data/data/stylesheets/components/header.css +17 -2
  42. data/data/stylesheets/components/inline.css +1 -1
  43. data/data/stylesheets/components/table.css +15 -2
  44. data/data/stylesheets/components/term.css +0 -1
  45. data/data/themes/bipm.yaml +60 -0
  46. data/data/themes/cc.yaml +43 -0
  47. data/data/themes/icc.yaml +39 -0
  48. data/data/themes/iec.yaml +44 -0
  49. data/data/themes/ieee.yaml +43 -0
  50. data/data/themes/ietf.yaml +45 -0
  51. data/data/themes/iho.yaml +46 -0
  52. data/data/themes/iso.yaml +40 -0
  53. data/data/themes/itu.yaml +45 -0
  54. data/data/themes/ogc.yaml +51 -0
  55. data/data/themes/oiml.yaml +56 -0
  56. data/data/themes/pdfa.yaml +44 -0
  57. data/data/themes/ribose.yaml +43 -0
  58. data/exe/metanorma-document +11 -0
  59. data/frontend/e2e/sample-html.test.ts +256 -0
  60. data/frontend/index.html +12 -0
  61. data/frontend/package-lock.json +4725 -0
  62. data/frontend/package.json +32 -0
  63. data/frontend/postcss.config.js +6 -0
  64. data/frontend/src/App.vue +79 -0
  65. data/frontend/src/app.ts +21 -0
  66. data/frontend/src/components/AppSidebar.vue +77 -0
  67. data/frontend/src/components/DocumentReader.vue +180 -0
  68. data/frontend/src/components/MirrorRenderer.vue +23 -0
  69. data/frontend/src/components/ReadingProgressBar.vue +29 -0
  70. data/frontend/src/components/TextRenderer.vue +131 -0
  71. data/frontend/src/components/TocItem.vue +57 -0
  72. data/frontend/src/components/TopBar.vue +49 -0
  73. data/frontend/src/components/__tests__/MirrorRenderer.test.ts +178 -0
  74. data/frontend/src/components/blocks/AdmonitionBlock.vue +74 -0
  75. data/frontend/src/components/blocks/ClauseBlock.vue +53 -0
  76. data/frontend/src/components/blocks/ExampleBlock.vue +21 -0
  77. data/frontend/src/components/blocks/FallbackBlock.vue +18 -0
  78. data/frontend/src/components/blocks/FigureBlock.vue +26 -0
  79. data/frontend/src/components/blocks/FootnotesBlock.vue +25 -0
  80. data/frontend/src/components/blocks/ListBlocks.vue +62 -0
  81. data/frontend/src/components/blocks/NoteBlock.vue +21 -0
  82. data/frontend/src/components/blocks/ParagraphBlock.vue +25 -0
  83. data/frontend/src/components/blocks/QuoteBlock.vue +25 -0
  84. data/frontend/src/components/blocks/ReviewBlock.vue +39 -0
  85. data/frontend/src/components/blocks/SourcecodeBlock.vue +52 -0
  86. data/frontend/src/components/blocks/TableBlock.vue +48 -0
  87. data/frontend/src/components/blocks/index.ts +36 -0
  88. data/frontend/src/stores/__tests__/documentStore.fixture.test.ts +272 -0
  89. data/frontend/src/stores/__tests__/documentStore.test.ts +143 -0
  90. data/frontend/src/stores/__tests__/ebookStore.test.ts +145 -0
  91. data/frontend/src/stores/__tests__/uiStore.test.ts +42 -0
  92. data/frontend/src/stores/documentStore.ts +153 -0
  93. data/frontend/src/stores/ebookStore.ts +179 -0
  94. data/frontend/src/stores/uiStore.ts +32 -0
  95. data/frontend/src/styles.css +156 -0
  96. data/frontend/src/types/__tests__/rendering-contract.test.ts +172 -0
  97. data/frontend/src/types/rendering-contract.ts +209 -0
  98. data/frontend/src/utils/__tests__/typeMetadata.test.ts +102 -0
  99. data/frontend/src/utils/typeMetadata.ts +121 -0
  100. data/frontend/tailwind.config.js +18 -0
  101. data/frontend/test/fixtures/iso-document.json +271 -0
  102. data/frontend/tmp/debug_e2e.cjs +46 -0
  103. data/frontend/tsconfig.json +25 -0
  104. data/frontend/tsconfig.node.json +11 -0
  105. data/frontend/vite.config.ts +37 -0
  106. data/frontend/vitest.e2e.config.ts +9 -0
  107. data/lib/metanorma/bipm_document/metadata/bipm_bibliographic_item.rb +0 -14
  108. data/lib/metanorma/bipm_document/metadata/depiction_element.rb +18 -0
  109. data/lib/metanorma/bipm_document/metadata.rb +1 -1
  110. data/lib/metanorma/document/cli.rb +116 -0
  111. data/lib/metanorma/document/components/ancillary_blocks/callout_annotation.rb +27 -0
  112. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_block.rb +0 -65
  113. data/lib/metanorma/document/components/ancillary_blocks/sourcecode_body.rb +18 -0
  114. data/lib/metanorma/document/components/ancillary_blocks.rb +4 -0
  115. data/lib/metanorma/document/components/bib_data/bib_data.rb +7 -0
  116. data/lib/metanorma/document/components/blocks/classification_value.rb +21 -0
  117. data/lib/metanorma/document/components/blocks/permission_model.rb +28 -0
  118. data/lib/metanorma/document/components/blocks/recommendation_model.rb +28 -0
  119. data/lib/metanorma/document/components/blocks/requirement_base.rb +30 -0
  120. data/lib/metanorma/document/components/blocks/requirement_classification.rb +20 -0
  121. data/lib/metanorma/document/components/blocks/requirement_description.rb +43 -0
  122. data/lib/metanorma/document/components/blocks/requirement_inherit.rb +24 -0
  123. data/lib/metanorma/document/components/blocks/requirement_model.rb +0 -131
  124. data/lib/metanorma/document/components/blocks.rb +8 -7
  125. data/lib/metanorma/document/components/id_elements/image.rb +2 -0
  126. data/lib/metanorma/document/components/inline/asciimath_element.rb +2 -0
  127. data/lib/metanorma/document/components/inline/attribution_element.rb +2 -0
  128. data/lib/metanorma/document/components/inline/bcp14_element.rb +2 -0
  129. data/lib/metanorma/document/components/inline/biblio_tag_element.rb +2 -0
  130. data/lib/metanorma/document/components/inline/br_element.rb +2 -0
  131. data/lib/metanorma/document/components/inline/comma_element.rb +2 -0
  132. data/lib/metanorma/document/components/inline/concept_element.rb +2 -0
  133. data/lib/metanorma/document/components/inline/display_text_element.rb +2 -0
  134. data/lib/metanorma/document/components/inline/em_raw_element.rb +2 -0
  135. data/lib/metanorma/document/components/inline/enum_comma_element.rb +2 -0
  136. data/lib/metanorma/document/components/inline/eref_element.rb +2 -0
  137. data/lib/metanorma/document/components/inline/fmt_admitted_element.rb +4 -0
  138. data/lib/metanorma/document/components/inline/fmt_annotation_body_element.rb +4 -0
  139. data/lib/metanorma/document/components/inline/fmt_annotation_end_element.rb +4 -0
  140. data/lib/metanorma/document/components/inline/fmt_annotation_start_element.rb +4 -0
  141. data/lib/metanorma/document/components/inline/fmt_concept_element.rb +4 -0
  142. data/lib/metanorma/document/components/inline/fmt_definition_element.rb +4 -0
  143. data/lib/metanorma/document/components/inline/fmt_fn_body_element.rb +4 -0
  144. data/lib/metanorma/document/components/inline/fmt_fn_label_element.rb +4 -0
  145. data/lib/metanorma/document/components/inline/fmt_footnote_container_element.rb +4 -0
  146. data/lib/metanorma/document/components/inline/fmt_identifier_element.rb +4 -0
  147. data/lib/metanorma/document/components/inline/fmt_name_element.rb +4 -0
  148. data/lib/metanorma/document/components/inline/fmt_preferred_element.rb +4 -0
  149. data/lib/metanorma/document/components/inline/fmt_sourcecode_element.rb +4 -0
  150. data/lib/metanorma/document/components/inline/fmt_stem_element.rb +10 -0
  151. data/lib/metanorma/document/components/inline/fmt_termsource_element.rb +4 -0
  152. data/lib/metanorma/document/components/inline/fmt_title_element.rb +4 -0
  153. data/lib/metanorma/document/components/inline/fmt_xref_element.rb +4 -0
  154. data/lib/metanorma/document/components/inline/fmt_xref_label_element.rb +4 -0
  155. data/lib/metanorma/document/components/inline/fn_element.rb +2 -0
  156. data/lib/metanorma/document/components/inline/link_element.rb +2 -0
  157. data/lib/metanorma/document/components/inline/localized_string_element.rb +2 -0
  158. data/lib/metanorma/document/components/inline/localized_strings_element.rb +2 -0
  159. data/lib/metanorma/document/components/inline/location_element.rb +24 -0
  160. data/lib/metanorma/document/components/inline/math_element.rb +2 -0
  161. data/lib/metanorma/document/components/inline/name_with_id_element.rb +4 -0
  162. data/lib/metanorma/document/components/inline/rendered_display.rb +23 -0
  163. data/lib/metanorma/document/components/inline/rendered_math_element.rb +21 -0
  164. data/lib/metanorma/document/components/inline/semantic_content.rb +51 -0
  165. data/lib/metanorma/document/components/inline/semantic_math_element.rb +20 -0
  166. data/lib/metanorma/document/components/inline/semx_child_element.rb +2 -0
  167. data/lib/metanorma/document/components/inline/semx_element.rb +13 -1
  168. data/lib/metanorma/document/components/inline/small_cap_element.rb +2 -0
  169. data/lib/metanorma/document/components/inline/span_element.rb +10 -15
  170. data/lib/metanorma/document/components/inline/stem_inline_element.rb +7 -1
  171. data/lib/metanorma/document/components/inline/strong_raw_element.rb +2 -0
  172. data/lib/metanorma/document/components/inline/sub_element.rb +2 -0
  173. data/lib/metanorma/document/components/inline/sup_element.rb +2 -0
  174. data/lib/metanorma/document/components/inline/tab_element.rb +2 -0
  175. data/lib/metanorma/document/components/inline/title_with_annotation_element.rb +4 -0
  176. data/lib/metanorma/document/components/inline/tt_element.rb +2 -0
  177. data/lib/metanorma/document/components/inline/variant_title_element.rb +2 -0
  178. data/lib/metanorma/document/components/inline/vocabulary.rb +184 -0
  179. data/lib/metanorma/document/components/inline/xref_element.rb +10 -0
  180. data/lib/metanorma/document/components/inline.rb +12 -0
  181. data/lib/metanorma/document/components/multi_paragraph/quote_author_element.rb +20 -0
  182. data/lib/metanorma/document/components/multi_paragraph/quote_block.rb +0 -29
  183. data/lib/metanorma/document/components/multi_paragraph.rb +2 -0
  184. data/lib/metanorma/document/components/reference_elements/source_element.rb +0 -31
  185. data/lib/metanorma/document/components/reference_elements/source_modification.rb +21 -0
  186. data/lib/metanorma/document/components/reference_elements/source_origin.rb +28 -0
  187. data/lib/metanorma/document/components/reference_elements.rb +2 -2
  188. data/lib/metanorma/document/components/tables/col_element.rb +18 -0
  189. data/lib/metanorma/document/components/tables/col_group_element.rb +18 -0
  190. data/lib/metanorma/document/components/tables/table_block.rb +0 -22
  191. data/lib/metanorma/document/components/tables/table_body_section.rb +16 -0
  192. data/lib/metanorma/document/components/tables/table_foot_section.rb +16 -0
  193. data/lib/metanorma/document/components/tables/table_head_section.rb +16 -0
  194. data/lib/metanorma/document/components/tables/table_section.rb +0 -25
  195. data/lib/metanorma/document/components/tables.rb +5 -3
  196. data/lib/metanorma/document/relaton/address.rb +0 -27
  197. data/lib/metanorma/document/relaton/bib_item_locality.rb +3 -12
  198. data/lib/metanorma/document/relaton/copyright_association.rb +0 -10
  199. data/lib/metanorma/document/relaton/copyright_owner.rb +16 -0
  200. data/lib/metanorma/document/relaton/edition.rb +4 -7
  201. data/lib/metanorma/document/relaton/formatted_address.rb +29 -0
  202. data/lib/metanorma/document/relaton/logo_element.rb +18 -0
  203. data/lib/metanorma/document/relaton/organization.rb +0 -14
  204. data/lib/metanorma/document/relaton/phone.rb +3 -9
  205. data/lib/metanorma/document/relaton/place_type.rb +0 -13
  206. data/lib/metanorma/document/relaton/price_type.rb +3 -9
  207. data/lib/metanorma/document/relaton/region_element.rb +18 -0
  208. data/lib/metanorma/document/relaton.rb +6 -1
  209. data/lib/metanorma/document/version.rb +1 -1
  210. data/lib/metanorma/document.rb +2 -0
  211. data/lib/metanorma/html/asset_pipeline.rb +1 -0
  212. data/lib/metanorma/html/base_renderer.rb +261 -1008
  213. data/lib/metanorma/html/bipm_renderer.rb +15 -144
  214. data/lib/metanorma/html/cc_renderer.rb +1 -45
  215. data/lib/metanorma/html/component/base.rb +2 -7
  216. data/lib/metanorma/html/component/index_section.rb +41 -43
  217. data/lib/metanorma/html/drops/admonition_drop.rb +1 -4
  218. data/lib/metanorma/html/drops/biblio_entry_drop.rb +50 -0
  219. data/lib/metanorma/html/drops/block_element_drop.rb +7 -2
  220. data/lib/metanorma/html/drops/example_drop.rb +1 -4
  221. data/lib/metanorma/html/drops/figure_drop.rb +31 -22
  222. data/lib/metanorma/html/drops/footnote_drop.rb +1 -1
  223. data/lib/metanorma/html/drops/formula_drop.rb +45 -16
  224. data/lib/metanorma/html/drops/note_drop.rb +9 -7
  225. data/lib/metanorma/html/drops/sourcecode_drop.rb +12 -5
  226. data/lib/metanorma/html/drops.rb +2 -0
  227. data/lib/metanorma/html/generator.rb +2 -2
  228. data/lib/metanorma/html/icc_renderer.rb +0 -39
  229. data/lib/metanorma/html/iec_renderer.rb +1 -44
  230. data/lib/metanorma/html/ieee_renderer.rb +1 -45
  231. data/lib/metanorma/html/ietf_renderer.rb +1 -48
  232. data/lib/metanorma/html/iho_renderer.rb +1 -46
  233. data/lib/metanorma/html/iso_renderer.rb +290 -343
  234. data/lib/metanorma/html/itu_renderer.rb +1 -45
  235. data/lib/metanorma/html/ogc_renderer.rb +15 -76
  236. data/lib/metanorma/html/oiml_renderer.rb +18 -38
  237. data/lib/metanorma/html/pdfa_renderer.rb +0 -39
  238. data/lib/metanorma/html/renderers/block_renderer.rb +372 -0
  239. data/lib/metanorma/html/renderers/inline_renderer.rb +655 -0
  240. data/lib/metanorma/html/renderers/pubid_renderer.rb +69 -0
  241. data/lib/metanorma/html/renderers/section_renderer.rb +193 -0
  242. data/lib/metanorma/html/renderers.rb +8 -0
  243. data/lib/metanorma/html/ribose_renderer.rb +1 -45
  244. data/lib/metanorma/html/standard_renderer.rb +341 -229
  245. data/lib/metanorma/html/templates/_audio.html.liquid +1 -0
  246. data/lib/metanorma/html/templates/_biblio_entry.html.liquid +1 -0
  247. data/lib/metanorma/html/templates/_bipm_cover.html.liquid +27 -0
  248. data/lib/metanorma/html/templates/_boilerplate.html.liquid +1 -0
  249. data/lib/metanorma/html/templates/_bookmark.html.liquid +1 -0
  250. data/lib/metanorma/html/templates/_br.html.liquid +1 -0
  251. data/lib/metanorma/html/templates/_definition_list.html.liquid +6 -0
  252. data/lib/metanorma/html/templates/_element.html.liquid +1 -0
  253. data/lib/metanorma/html/templates/_fn_marker.html.liquid +1 -0
  254. data/lib/metanorma/html/templates/_footnotes.html.liquid +6 -6
  255. data/lib/metanorma/html/templates/_formula.html.liquid +1 -1
  256. data/lib/metanorma/html/templates/_header.html.liquid +1 -1
  257. data/lib/metanorma/html/templates/_heading.html.liquid +1 -0
  258. data/lib/metanorma/html/templates/_image.html.liquid +1 -0
  259. data/lib/metanorma/html/templates/_inline_span.html.liquid +1 -0
  260. data/lib/metanorma/html/templates/_iso_cover.html.liquid +1 -1
  261. data/lib/metanorma/html/templates/_link.html.liquid +1 -0
  262. data/lib/metanorma/html/templates/_list.html.liquid +3 -0
  263. data/lib/metanorma/html/templates/_list_item.html.liquid +1 -0
  264. data/lib/metanorma/html/templates/_main_content.html.liquid +1 -0
  265. data/lib/metanorma/html/templates/_math_container.html.liquid +1 -0
  266. data/lib/metanorma/html/templates/_paragraph.html.liquid +1 -0
  267. data/lib/metanorma/html/templates/_prefatory_section.html.liquid +1 -0
  268. data/lib/metanorma/html/templates/_pubid_identifier.html.liquid +1 -0
  269. data/lib/metanorma/html/templates/_quote.html.liquid +4 -0
  270. data/lib/metanorma/html/templates/_ref_date.html.liquid +1 -0
  271. data/lib/metanorma/html/templates/_ref_title.html.liquid +1 -0
  272. data/lib/metanorma/html/templates/_section.html.liquid +5 -0
  273. data/lib/metanorma/html/templates/_standard_cover.html.liquid +31 -0
  274. data/lib/metanorma/html/templates/_standard_doc_title.html.liquid +3 -0
  275. data/lib/metanorma/html/templates/_stem_span.html.liquid +1 -0
  276. data/lib/metanorma/html/templates/_table.html.liquid +9 -0
  277. data/lib/metanorma/html/templates/_term_domain.html.liquid +1 -0
  278. data/lib/metanorma/html/templates/_term_example.html.liquid +1 -0
  279. data/lib/metanorma/html/templates/_term_note.html.liquid +1 -0
  280. data/lib/metanorma/html/templates/_term_number.html.liquid +1 -0
  281. data/lib/metanorma/html/templates/_term_source.html.liquid +1 -0
  282. data/lib/metanorma/html/templates/_term_text_note.html.liquid +1 -0
  283. data/lib/metanorma/html/templates/_video.html.liquid +1 -0
  284. data/lib/metanorma/html/templates/_wrapped_preface.html.liquid +1 -0
  285. data/lib/metanorma/html/templates/document.html.liquid +4 -0
  286. data/lib/metanorma/html/theme.rb +180 -107
  287. data/lib/metanorma/html.rb +13 -0
  288. data/lib/metanorma/ietf_document/metadata/ietf_bib_data_extension_type.rb +0 -25
  289. data/lib/metanorma/ietf_document/metadata/pi_settings.rb +32 -0
  290. data/lib/metanorma/ietf_document/metadata.rb +2 -0
  291. data/lib/metanorma/iso_document/metadata/doctype_element.rb +20 -0
  292. data/lib/metanorma/iso_document/metadata/iso_bib_data_extension_type.rb +0 -48
  293. data/lib/metanorma/iso_document/metadata/iso_bibliographic_item.rb +0 -72
  294. data/lib/metanorma/iso_document/metadata/iso_document_status.rb +0 -30
  295. data/lib/metanorma/iso_document/metadata/iso_localized_title.rb +4 -1
  296. data/lib/metanorma/iso_document/metadata/language_element.rb +18 -0
  297. data/lib/metanorma/iso_document/metadata/project_number.rb +22 -0
  298. data/lib/metanorma/iso_document/metadata/script_element.rb +18 -0
  299. data/lib/metanorma/iso_document/metadata/stage_element.rb +26 -0
  300. data/lib/metanorma/iso_document/metadata/stagename_element.rb +18 -0
  301. data/lib/metanorma/iso_document/metadata/structured_identifier.rb +0 -17
  302. data/lib/metanorma/iso_document/metadata/title_collection.rb +1 -0
  303. data/lib/metanorma/iso_document/metadata.rb +9 -4
  304. data/lib/metanorma/iso_document/terms/iso_term.rb +0 -13
  305. data/lib/metanorma/iso_document/terms/term_domain_element.rb +18 -0
  306. data/lib/metanorma/iso_document/terms.rb +1 -0
  307. data/lib/metanorma/itu_document/metadata/itu_bib_data_extension_type.rb +0 -37
  308. data/lib/metanorma/itu_document/metadata/meeting_date.rb +18 -0
  309. data/lib/metanorma/itu_document/metadata/meeting_element.rb +18 -0
  310. data/lib/metanorma/itu_document/metadata/study_period.rb +18 -0
  311. data/lib/metanorma/itu_document/metadata.rb +3 -4
  312. data/lib/metanorma/mirror/default_registry.rb +170 -0
  313. data/lib/metanorma/mirror/handler_registry.rb +60 -0
  314. data/lib/metanorma/mirror/handler_result.rb +37 -0
  315. data/lib/metanorma/mirror/handlers/admonition.rb +18 -0
  316. data/lib/metanorma/mirror/handlers/example.rb +21 -0
  317. data/lib/metanorma/mirror/handlers/figure.rb +53 -0
  318. data/lib/metanorma/mirror/handlers/formula.rb +35 -0
  319. data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +159 -0
  320. data/lib/metanorma/mirror/handlers/inline/text_extractor.rb +116 -0
  321. data/lib/metanorma/mirror/handlers/inline.rb +225 -0
  322. data/lib/metanorma/mirror/handlers/list.rb +110 -0
  323. data/lib/metanorma/mirror/handlers/note.rb +26 -0
  324. data/lib/metanorma/mirror/handlers/paragraph.rb +19 -0
  325. data/lib/metanorma/mirror/handlers/quote.rb +16 -0
  326. data/lib/metanorma/mirror/handlers/review.rb +19 -0
  327. data/lib/metanorma/mirror/handlers/section.rb +149 -0
  328. data/lib/metanorma/mirror/handlers/sourcecode.rb +27 -0
  329. data/lib/metanorma/mirror/handlers/structural.rb +68 -0
  330. data/lib/metanorma/mirror/handlers/table.rb +81 -0
  331. data/lib/metanorma/mirror/handlers/term.rb +100 -0
  332. data/lib/metanorma/mirror/handlers.rb +60 -0
  333. data/lib/metanorma/mirror/id_strategy/positional.rb +166 -0
  334. data/lib/metanorma/mirror/id_strategy/preserve.rb +12 -0
  335. data/lib/metanorma/mirror/id_strategy.rb +34 -0
  336. data/lib/metanorma/mirror/math_util.rb +53 -0
  337. data/lib/metanorma/mirror/metadata.rb +37 -0
  338. data/lib/metanorma/mirror/metanorma_to_mirror.rb +101 -0
  339. data/lib/metanorma/mirror/model/container.rb +47 -0
  340. data/lib/metanorma/mirror/model/factory.rb +52 -0
  341. data/lib/metanorma/mirror/model/guide.rb +25 -0
  342. data/lib/metanorma/mirror/model/leaf.rb +17 -0
  343. data/lib/metanorma/mirror/model/mark.rb +53 -0
  344. data/lib/metanorma/mirror/model/node.rb +47 -0
  345. data/lib/metanorma/mirror/model/soft_break.rb +33 -0
  346. data/lib/metanorma/mirror/model/text.rb +34 -0
  347. data/lib/metanorma/mirror/model.rb +16 -0
  348. data/lib/metanorma/mirror/output/builder.rb +39 -0
  349. data/lib/metanorma/mirror/output/formats/base_format.rb +90 -0
  350. data/lib/metanorma/mirror/output/formats/inline_format.rb +81 -0
  351. data/lib/metanorma/mirror/output/formats.rb +53 -0
  352. data/lib/metanorma/mirror/output/html_renderer.rb +95 -0
  353. data/lib/metanorma/mirror/output/html_renderers/block_renderers.rb +178 -0
  354. data/lib/metanorma/mirror/output/html_renderers/inline_renderer.rb +61 -0
  355. data/lib/metanorma/mirror/output/html_renderers/list_renderers.rb +96 -0
  356. data/lib/metanorma/mirror/output/html_renderers/mark_renderers.rb +64 -0
  357. data/lib/metanorma/mirror/output/html_renderers/section_renderers.rb +129 -0
  358. data/lib/metanorma/mirror/output/html_renderers/structural_renderers.rb +80 -0
  359. data/lib/metanorma/mirror/output/html_renderers/table_renderers.rb +87 -0
  360. data/lib/metanorma/mirror/output/html_renderers.rb +76 -0
  361. data/lib/metanorma/mirror/output/pipeline.rb +92 -0
  362. data/lib/metanorma/mirror/output/pipeline_context.rb +22 -0
  363. data/lib/metanorma/mirror/output.rb +14 -0
  364. data/lib/metanorma/mirror/rewriter.rb +121 -0
  365. data/lib/metanorma/mirror/safe_attr.rb +16 -0
  366. data/lib/metanorma/mirror/serialization/json_serializer.rb +25 -0
  367. data/lib/metanorma/mirror/serialization/yaml_serializer.rb +20 -0
  368. data/lib/metanorma/mirror/serialization.rb +10 -0
  369. data/lib/metanorma/mirror/transformer.rb +22 -0
  370. data/lib/metanorma/mirror.rb +32 -0
  371. data/lib/metanorma/standard_document/annotation.rb +37 -0
  372. data/lib/metanorma/standard_document/block_attributes.rb +15 -2
  373. data/lib/metanorma/standard_document/blocks/block_source.rb +0 -23
  374. data/lib/metanorma/standard_document/blocks/source_origin_element.rb +23 -0
  375. data/lib/metanorma/standard_document/blocks.rb +1 -1
  376. data/lib/metanorma/standard_document/terms/term_expression.rb +0 -31
  377. data/lib/metanorma/standard_document/terms/term_name_element.rb +29 -0
  378. data/lib/metanorma/standard_document/terms.rb +1 -0
  379. data/script/render_both.rb +18 -0
  380. metadata +262 -13
  381. data/.github/workflows/rake.yml +0 -21
  382. data/.github/workflows/release.yml +0 -25
  383. data/.github/workflows/roundtrip-samples.yml +0 -132
  384. data/.gitignore +0 -19
  385. data/.rspec +0 -3
  386. data/.rubocop.yml +0 -22
  387. data/Gemfile +0 -28
  388. data/bin/console +0 -15
  389. data/bin/setup +0 -8
  390. data/metanorma-document.gemspec +0 -35
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ module Output
6
+ module HtmlRenderers
7
+ module TableRenderers
8
+ WRAPPER_TAGS = {
9
+ "table_head" => "thead",
10
+ "table_foot" => "tfoot",
11
+ "table_body" => "tbody",
12
+ }.freeze
13
+
14
+ def self.register(registry)
15
+ registry.register_node_handler("table",
16
+ instance_method(:render_table))
17
+ registry.register_node_handler("table_head",
18
+ instance_method(:render_table_section))
19
+ registry.register_node_handler("table_body",
20
+ instance_method(:render_table_section))
21
+ registry.register_node_handler("table_foot",
22
+ instance_method(:render_table_section))
23
+ end
24
+
25
+ def render_table(node, depth: 0)
26
+ sections = node.content.grep(Model::Container)
27
+
28
+ HtmlRenderers.build do |doc|
29
+ attrs = { class: "mn-table" }
30
+ attrs[:id] = node.attrs["id"] if node.attrs["id"]
31
+ doc.div(attrs) do
32
+ if node.attrs["title"]
33
+ doc.div(class: "mn-table__header") do
34
+ doc.text node.attrs["title"]
35
+ end
36
+ end
37
+ doc.table do
38
+ sections.each do |section|
39
+ HtmlRenderers.embed(doc, build_table_section(section))
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def render_table_section(node, depth: 0)
47
+ build_table_section(node)
48
+ end
49
+
50
+ private
51
+
52
+ def build_table_section(section)
53
+ wrapper_tag = WRAPPER_TAGS[section.type] || "tbody"
54
+ cell_tag = wrapper_tag == "thead" ? "th" : "td"
55
+
56
+ HtmlRenderers.build do |doc|
57
+ doc.public_send(wrapper_tag) do
58
+ section.content.each do |row|
59
+ next unless row.is_a?(Model::Container) && row.type == "table_row"
60
+
61
+ doc.tr do
62
+ row.content.each do |cell|
63
+ next unless cell.is_a?(Model::Container)
64
+
65
+ HtmlRenderers.embed(doc, build_table_cell(cell, cell_tag))
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def build_table_cell(cell, cell_tag)
74
+ HtmlRenderers.build do |doc|
75
+ attrs = {}
76
+ attrs[:colspan] = cell.attrs["colspan"] if cell.attrs["colspan"]
77
+ attrs[:rowspan] = cell.attrs["rowspan"] if cell.attrs["rowspan"]
78
+ doc.public_send(cell_tag, attrs) do
79
+ HtmlRenderers.embed(doc, render_inline(cell.content))
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+
5
+ module Metanorma
6
+ module Mirror
7
+ module Output
8
+ module HtmlRenderers
9
+ autoload :StructuralRenderers,
10
+ "#{__dir__}/html_renderers/structural_renderers"
11
+ autoload :SectionRenderers,
12
+ "#{__dir__}/html_renderers/section_renderers"
13
+ autoload :BlockRenderers, "#{__dir__}/html_renderers/block_renderers"
14
+ autoload :ListRenderers, "#{__dir__}/html_renderers/list_renderers"
15
+ autoload :TableRenderers, "#{__dir__}/html_renderers/table_renderers"
16
+ autoload :InlineRenderer, "#{__dir__}/html_renderers/inline_renderer"
17
+ autoload :MarkRenderers, "#{__dir__}/html_renderers/mark_renderers"
18
+
19
+ MODULES = %i[
20
+ StructuralRenderers
21
+ SectionRenderers
22
+ BlockRenderers
23
+ ListRenderers
24
+ TableRenderers
25
+ InlineRenderer
26
+ MarkRenderers
27
+ ].freeze
28
+
29
+ def self.register_all(renderer_class)
30
+ MODULES.each do |mod_name|
31
+ const_get(mod_name).register(renderer_class)
32
+ end
33
+ end
34
+
35
+ # Build a single HTML root element via Nokogiri::HTML4::Builder.
36
+ # Returns the rendered HTML string.
37
+ def self.build(&)
38
+ builder = Nokogiri::HTML4::Builder.new(&)
39
+ builder.doc.root.to_html
40
+ end
41
+
42
+ # Build an HTML fragment (multiple roots permitted) via
43
+ # Nokogiri::HTML4::Builder. Returns the rendered HTML string.
44
+ def self.build_fragment(&)
45
+ fragment = Nokogiri::HTML4::DocumentFragment.parse("")
46
+ Nokogiri::HTML4::Builder.with(fragment, &)
47
+ fragment.to_html
48
+ end
49
+
50
+ # Embed a pre-rendered HTML string under the current builder node
51
+ # without re-escaping.
52
+ def self.embed(doc, html_string)
53
+ return if html_string.nil? || html_string.to_s.empty?
54
+
55
+ doc << Nokogiri::HTML4::DocumentFragment.parse(html_string.to_s)
56
+ end
57
+
58
+ # Wrap a pre-rendered HTML string in a tag. Used by mark handlers.
59
+ def self.wrap(tag, inner_html, **attrs)
60
+ Nokogiri::HTML4::Builder.new do |doc|
61
+ doc.public_send(tag, attrs) do
62
+ doc.parent.inner_html = inner_html.to_s
63
+ end
64
+ end.doc.root.to_html
65
+ end
66
+
67
+ # Escape text for safe inclusion in HTML body content.
68
+ def self.escape_text(text)
69
+ return "" unless text
70
+
71
+ CGI.escapeHTML(text.to_s)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ module Output
6
+ class Pipeline
7
+ attr_reader :steps, :context
8
+
9
+ def initialize(xml_path:, steps: nil, flavor: nil, title: nil,
10
+ id_strategy: nil)
11
+ @steps = steps || [Steps::ParseXml, Steps::TransformMirror, Steps::AttachMetadata]
12
+ @context = PipelineContext.new(
13
+ xml_path: xml_path,
14
+ flavor: flavor,
15
+ title: title || File.basename(xml_path, ".*"),
16
+ id_strategy: id_strategy,
17
+ )
18
+ end
19
+
20
+ def process
21
+ @steps.each { |step_class| step_class.new.call(@context) }
22
+ Model::Guide.new(
23
+ content: @context.content,
24
+ meta: @context.meta,
25
+ title: @context.title,
26
+ )
27
+ end
28
+
29
+ module Steps
30
+ class ParseXml
31
+ def call(context)
32
+ flavor = context.flavor || infer_flavor(context.xml_path)
33
+ doc_class = flavor_class(flavor)
34
+ xml_content = File.read(context.xml_path)
35
+ context.parsed = doc_class.from_xml(xml_content)
36
+ end
37
+
38
+ def self.flavor_map
39
+ @flavor_map ||= Metanorma.constants.each_with_object({}) do |c, map|
40
+ next unless c.to_s.end_with?("Document")
41
+
42
+ flavor = c.to_s.delete_suffix("Document").downcase
43
+ map[flavor] = c.to_s
44
+ end.freeze
45
+ end
46
+
47
+ def infer_flavor(xml_path)
48
+ basename = File.basename(xml_path, ".*")
49
+ from_name = basename.split("-").first.to_s.downcase
50
+ return from_name if self.class.flavor_map.key?(from_name)
51
+
52
+ File.dirname(xml_path).split("/").reverse_each do |seg|
53
+ prefix = seg.split("-").first.to_s.downcase
54
+ return prefix if self.class.flavor_map.key?(prefix)
55
+ end
56
+
57
+ nil
58
+ end
59
+
60
+ def flavor_class(flavor)
61
+ class_name = self.class.flavor_map[flavor] || "StandardDocument"
62
+ Metanorma.const_get(class_name).const_get(:Root)
63
+ end
64
+ end
65
+
66
+ class TransformMirror
67
+ def call(context)
68
+ id_strategy = context.id_strategy || Mirror::DEFAULT_ID_STRATEGY
69
+ transformer = Mirror::Transformer.new(id_strategy: id_strategy)
70
+ context.content = transformer.from_metanorma(context.parsed)
71
+ end
72
+ end
73
+
74
+ class AttachMetadata
75
+ def call(context)
76
+ parsed = context.parsed
77
+ return unless parsed
78
+
79
+ bibdata = SafeAttr.read(parsed, :bibdata)
80
+ return unless bibdata
81
+
82
+ meta = {}
83
+ meta["title"] = Metadata.title_from_bibdata(bibdata)
84
+ meta["flavor"] = context.flavor if context.flavor
85
+ context.meta = meta
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ module Output
6
+ class PipelineContext
7
+ attr_reader :xml_path, :flavor, :title, :id_strategy
8
+ attr_accessor :parsed, :content, :meta
9
+
10
+ def initialize(xml_path:, flavor: nil, title: nil, id_strategy: nil)
11
+ @xml_path = xml_path
12
+ @flavor = flavor
13
+ @title = title
14
+ @id_strategy = id_strategy
15
+ @parsed = nil
16
+ @content = nil
17
+ @meta = {}
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ module Output
6
+ autoload :Pipeline, "#{__dir__}/output/pipeline"
7
+ autoload :PipelineContext, "#{__dir__}/output/pipeline_context"
8
+ autoload :Builder, "#{__dir__}/output/builder"
9
+ autoload :HtmlRenderers, "#{__dir__}/output/html_renderers"
10
+ autoload :HtmlRenderer, "#{__dir__}/output/html_renderer"
11
+ autoload :Formats, "#{__dir__}/output/formats"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ # Rewrites a mirror Model graph with configurable type-skipping and
6
+ # per-type customization. Despite living in the reverse-conversion
7
+ # namespace, this class produces a Model graph (not Metanorma XML) —
8
+ # the output is a fully model-driven representation that can be
9
+ # serialized via Model#to_h or rendered via Output::HtmlRenderer.
10
+ #
11
+ # Instance API:
12
+ # Rewriter.new(skip: Set.new(%w[review footnotes]))
13
+ # rewriter.skip("my_type")
14
+ # rewriter.register("my_type") { |n, r| ... }
15
+ #
16
+ # Class API (seeds defaults copied into each new instance):
17
+ # Rewriter.skip("review") # adds to defaults
18
+ # Rewriter.register("my_type") { |n, r| ... }
19
+ #
20
+ # Two Rewriter instances do not share state. Class-level mutation only
21
+ # affects instances created afterwards (the default snapshot is copied
22
+ # at `new` time).
23
+ class Rewriter
24
+ DEFAULT_SKIPPED_TYPES = %w[review footnotes].freeze
25
+
26
+ class << self
27
+ # Default skip set, copied into each new instance.
28
+ def default_skipped_types
29
+ @default_skipped_types ||= Set.new(DEFAULT_SKIPPED_TYPES)
30
+ end
31
+
32
+ # Default builder map, copied into each new instance.
33
+ def default_builders
34
+ @default_builders ||= {}
35
+ end
36
+
37
+ # Add a type to the default skip set. Affects instances created
38
+ # afterwards; existing instances are unchanged.
39
+ def skip(type)
40
+ default_skipped_types << type
41
+ self
42
+ end
43
+
44
+ # Register a builder for a type at the default level. Affects
45
+ # instances created afterwards; existing instances are unchanged.
46
+ def register(type, &block)
47
+ default_builders[type] = block
48
+ self
49
+ end
50
+ end
51
+
52
+ def initialize(skip: nil, builders: nil)
53
+ @skipped_types = skip || self.class.default_skipped_types.dup
54
+ @builders = builders || self.class.default_builders.dup
55
+ end
56
+
57
+ attr_reader :skipped_types, :builders
58
+
59
+ def skip(type)
60
+ skipped_types << type
61
+ self
62
+ end
63
+
64
+ def skipped?(type)
65
+ skipped_types.include?(type)
66
+ end
67
+
68
+ def register(type, &block)
69
+ builders[type] = block
70
+ self
71
+ end
72
+
73
+ def call(mirror_node)
74
+ build(mirror_node)
75
+ end
76
+
77
+ def build(node)
78
+ return nil unless node
79
+
80
+ return rewrite_string(node) if node.is_a?(String)
81
+
82
+ node.accept_rewriter(self)
83
+ end
84
+
85
+ def rewrite_container(node)
86
+ return nil if skipped?(node.type)
87
+
88
+ builder = builders[node.type]
89
+ return builder.call(node, self) if builder
90
+
91
+ Model::Container.new(
92
+ type: node.type,
93
+ attrs: node.attrs,
94
+ content: build_children(node.content),
95
+ )
96
+ end
97
+
98
+ def rewrite_leaf(node)
99
+ return nil if skipped?(node.type)
100
+
101
+ Model::Leaf.new(type: node.type, attrs: node.attrs)
102
+ end
103
+
104
+ def rewrite_text(node)
105
+ Model::Text.new(text: node.text, marks: node.marks)
106
+ end
107
+
108
+ def rewrite_soft_break(_node)
109
+ Model::SoftBreak.new
110
+ end
111
+
112
+ def rewrite_string(string)
113
+ Model::Text.new(text: string)
114
+ end
115
+
116
+ def build_children(content)
117
+ Array(content).filter_map { |child| build(child) }
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ module SafeAttr
6
+ def self.read(element, attr_name)
7
+ return nil unless element.is_a?(Lutaml::Model::Serializable)
8
+
9
+ klass = element.class
10
+ return nil unless klass.attributes.key?(attr_name)
11
+
12
+ element.public_send(attr_name)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Metanorma
6
+ module Mirror
7
+ module Serialization
8
+ class JsonSerializer
9
+ def self.serialize(node)
10
+ data = node.is_a?(Model::Container) ? node.to_h : node
11
+ data.to_json
12
+ end
13
+
14
+ def self.serialize_pretty(node)
15
+ data = node.is_a?(Model::Container) ? node.to_h : node
16
+ JSON.pretty_generate(data)
17
+ end
18
+
19
+ def self.deserialize(json_string)
20
+ Model::Factory.from_h(JSON.parse(json_string))
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Metanorma
6
+ module Mirror
7
+ module Serialization
8
+ class YamlSerializer
9
+ def self.serialize(node)
10
+ data = node.is_a?(Model::Container) ? node.to_h : node
11
+ data.to_yaml
12
+ end
13
+
14
+ def self.deserialize(yaml_string)
15
+ Model::Factory.from_h(YAML.safe_load(yaml_string))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ module Serialization
6
+ autoload :JsonSerializer, "#{__dir__}/serialization/json_serializer"
7
+ autoload :YamlSerializer, "#{__dir__}/serialization/yaml_serializer"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ class Transformer
6
+ def initialize(registry: Mirror.default_registry, id_strategy: Mirror::DEFAULT_ID_STRATEGY)
7
+ @registry = registry
8
+ @id_strategy = id_strategy
9
+ end
10
+
11
+ def from_metanorma(root)
12
+ document = MetanormaToMirror.new(registry: @registry,
13
+ id_strategy: @id_strategy).call(root)
14
+ @id_strategy.finalize!(document)
15
+ end
16
+
17
+ def rewrite(mirror_node)
18
+ Rewriter.new.call(mirror_node)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Mirror
5
+ class Error < StandardError; end
6
+
7
+ autoload :SafeAttr, "#{__dir__}/mirror/safe_attr"
8
+ autoload :MathUtil, "#{__dir__}/mirror/math_util"
9
+ autoload :Metadata, "#{__dir__}/mirror/metadata"
10
+ autoload :Model, "#{__dir__}/mirror/model"
11
+ autoload :HandlerResult, "#{__dir__}/mirror/handler_result"
12
+ autoload :Transformer, "#{__dir__}/mirror/transformer"
13
+ autoload :MetanormaToMirror, "#{__dir__}/mirror/metanorma_to_mirror"
14
+ autoload :Rewriter, "#{__dir__}/mirror/rewriter"
15
+ autoload :HandlerRegistry, "#{__dir__}/mirror/handler_registry"
16
+ autoload :Handlers, "#{__dir__}/mirror/handlers"
17
+ autoload :IdStrategy, "#{__dir__}/mirror/id_strategy"
18
+ autoload :Output, "#{__dir__}/mirror/output"
19
+ autoload :Serialization, "#{__dir__}/mirror/serialization"
20
+ autoload :DefaultRegistry, "#{__dir__}/mirror/default_registry"
21
+
22
+ DEFAULT_ID_STRATEGY = IdStrategy::Preserve.new
23
+
24
+ def self.default_registry
25
+ @default_registry ||= build_default_registry
26
+ end
27
+
28
+ def self.build_default_registry
29
+ DefaultRegistry.build
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module StandardDocument
5
+ class AnnotationContainer < Lutaml::Model::Serializable
6
+ class Annotation < Lutaml::Model::Serializable
7
+ attribute :id, :string
8
+ attribute :reviewer, :string
9
+ attribute :from, :string
10
+ attribute :to, :string
11
+ attribute :type, :string
12
+ attribute :date, :string
13
+ attribute :paragraphs,
14
+ Metanorma::Document::Components::Paragraphs::ParagraphBlock,
15
+ collection: true
16
+
17
+ xml do
18
+ element "annotation"
19
+ map_attribute "id", to: :id
20
+ map_attribute "reviewer", to: :reviewer
21
+ map_attribute "from", to: :from
22
+ map_attribute "to", to: :to
23
+ map_attribute "type", to: :type
24
+ map_attribute "date", to: :date
25
+ map_element "p", to: :paragraphs
26
+ end
27
+ end
28
+
29
+ attribute :annotations, Annotation, collection: true
30
+
31
+ xml do
32
+ element "annotation-container"
33
+ map_element "annotation", to: :annotations
34
+ end
35
+ end
36
+ end
37
+ end
@@ -52,14 +52,27 @@ module Metanorma
52
52
  end
53
53
 
54
54
  # Provides `blocks` method for ordered-content section types.
55
- # Returns child nodes in document order via `each_mixed_content`.
55
+ # Returns child block-level nodes in document order via `each_mixed_content`,
56
+ # excluding metadata/inline elements like titles and annotations.
56
57
  module OrderedContent
58
+ NON_BLOCK_TYPES = [
59
+ Metanorma::Document::Components::Inline::TitleWithAnnotationElement,
60
+ Metanorma::Document::Components::Inline::FmtTitleElement,
61
+ Metanorma::Document::Components::Inline::VariantTitleElement,
62
+ Metanorma::Document::Components::Inline::FmtXrefLabelElement,
63
+ Metanorma::Document::Components::Inline::FmtAnnotationStartElement,
64
+ Metanorma::Document::Components::Inline::FmtAnnotationEndElement,
65
+ ].freeze
66
+
57
67
  def blocks
58
68
  @blocks ||=
59
69
  begin
60
70
  result = []
61
71
  each_mixed_content do |node|
62
- result << node unless node.is_a?(String)
72
+ next if node.is_a?(String)
73
+ next if NON_BLOCK_TYPES.any? { |t| node.is_a?(t) }
74
+
75
+ result << node
63
76
  end
64
77
  result
65
78
  end
@@ -3,29 +3,6 @@
3
3
  module Metanorma
4
4
  module StandardDocument
5
5
  module Blocks
6
- # Reference origin within a block source: <origin bibitemid="..." citeas="...">
7
- # Schema: isodoc.rnc — origin = element origin { erefType | termref }
8
- class SourceOriginElement < Lutaml::Model::Serializable
9
- attribute :bibitemid, :string
10
- attribute :type, :string
11
- attribute :citeas, :string
12
- attribute :locality_stack, Metanorma::Document::Relaton::LocalityStack,
13
- collection: true
14
-
15
- xml do
16
- element "origin"
17
- map_attribute "bibitemid", to: :bibitemid
18
- map_attribute "type", to: :type
19
- map_attribute "citeas", to: :citeas
20
- map_element "localityStack", to: :locality_stack
21
- end
22
- end
23
-
24
- # Bibliographic source for a block: <source status="..." type="...">
25
- # <origin bibitemid="..." citeas="..."/>
26
- # <modification>...</modification>?
27
- # </source>
28
- # Schema: isodoc.rnc BlockSource = source*
29
6
  class BlockSourceElement < Lutaml::Model::Serializable
30
7
  attribute :status, :string
31
8
  attribute :type, :string
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module StandardDocument
5
+ module Blocks
6
+ class SourceOriginElement < Lutaml::Model::Serializable
7
+ attribute :bibitemid, :string
8
+ attribute :type, :string
9
+ attribute :citeas, :string
10
+ attribute :locality_stack, Metanorma::Document::Relaton::LocalityStack,
11
+ collection: true
12
+
13
+ xml do
14
+ element "origin"
15
+ map_attribute "bibitemid", to: :bibitemid
16
+ map_attribute "type", to: :type
17
+ map_attribute "citeas", to: :citeas
18
+ map_element "localityStack", to: :locality_stack
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -6,7 +6,7 @@ module Metanorma
6
6
  autoload :AmendBlock, "#{__dir__}/blocks/amend_block"
7
7
  autoload :AmendContentBlock, "#{__dir__}/blocks/amend_content_block"
8
8
  autoload :BlockSourceElement, "#{__dir__}/blocks/block_source"
9
- autoload :SourceOriginElement, "#{__dir__}/blocks/block_source"
9
+ autoload :SourceOriginElement, "#{__dir__}/blocks/source_origin_element"
10
10
  autoload :AutoNumber, "#{__dir__}/blocks/auto_number"
11
11
  autoload :ChangeType, "#{__dir__}/blocks/change_type"
12
12
  autoload :ElementName, "#{__dir__}/blocks/element_name"