metanorma-document 0.5.0 → 0.5.2.pre.alpha.1
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.
- checksums.yaml +4 -4
- data/README.adoc +81 -0
- data/Rakefile +3 -7
- data/data/stylesheets/base/_dark.css +3 -3
- data/data/stylesheets/base/_print.css +1 -1
- data/data/stylesheets/components/term.css +4 -2
- data/data/themes/ogc.yaml +5 -0
- data/lib/metanorma/basic_document/ancillary_blocks/figure_block.rb +2 -2
- data/lib/metanorma/basic_document/multi_paragraph/admonition_block.rb +2 -2
- data/lib/metanorma/document/cli.rb +134 -0
- data/lib/metanorma/document/components/ancillary_blocks/figure_block.rb +5 -0
- data/lib/metanorma/document/components/ancillary_blocks/fmt_figure_element.rb +47 -0
- data/lib/metanorma/document/components/ancillary_blocks/formula_block.rb +2 -0
- data/lib/metanorma/document/components/ancillary_blocks/imagemap_element.rb +73 -0
- data/lib/metanorma/document/components/ancillary_blocks/literal_block.rb +2 -0
- data/lib/metanorma/document/components/ancillary_blocks/sourcecode_block.rb +2 -0
- data/lib/metanorma/document/components/ancillary_blocks/svg_target_element.rb +27 -0
- data/lib/metanorma/document/components/ancillary_blocks/svgmap_element.rb +28 -0
- data/lib/metanorma/document/components/ancillary_blocks.rb +4 -0
- data/lib/metanorma/document/components/bib_data/bibliographic_item.rb +4 -0
- data/lib/metanorma/document/components/blocks/fmt_provision.rb +25 -0
- data/lib/metanorma/document/components/blocks/note_block.rb +8 -0
- data/lib/metanorma/document/components/blocks/permission_model.rb +9 -0
- data/lib/metanorma/document/components/blocks/recommendation_model.rb +9 -0
- data/lib/metanorma/document/components/blocks/requirement_base.rb +12 -0
- data/lib/metanorma/document/components/blocks/requirement_import.rb +23 -0
- data/lib/metanorma/document/components/blocks/requirement_measurement_target.rb +23 -0
- data/lib/metanorma/document/components/blocks/requirement_model.rb +9 -0
- data/lib/metanorma/document/components/blocks/requirement_specification.rb +23 -0
- data/lib/metanorma/document/components/blocks/requirement_verification.rb +23 -0
- data/lib/metanorma/document/components/blocks.rb +8 -0
- data/lib/metanorma/document/components/data_types/formatted_string.rb +9 -0
- data/lib/metanorma/document/components/id_elements/image.rb +4 -0
- data/lib/metanorma/document/components/inline/columnbreak_element.rb +17 -0
- data/lib/metanorma/document/components/inline/concept_element.rb +18 -0
- data/lib/metanorma/document/components/inline/date_element.rb +29 -0
- data/lib/metanorma/document/components/inline/display_text_element.rb +2 -0
- data/lib/metanorma/document/components/inline/em_raw_element.rb +6 -7
- data/lib/metanorma/document/components/inline/eref_element.rb +48 -22
- data/lib/metanorma/document/components/inline/eref_stack.rb +23 -0
- data/lib/metanorma/document/components/inline/error_message.rb +28 -0
- data/lib/metanorma/document/components/inline/fmt_date_element.rb +28 -0
- data/lib/metanorma/document/components/inline/fmt_date_inline_element.rb +26 -0
- data/lib/metanorma/document/components/inline/fmt_eref_element.rb +25 -0
- data/lib/metanorma/document/components/inline/fmt_origin_element.rb +24 -0
- data/lib/metanorma/document/components/inline/fmt_preferred_element.rb +3 -0
- data/lib/metanorma/document/components/inline/fmt_source_element.rb +31 -0
- data/lib/metanorma/document/components/inline/fn_element.rb +11 -0
- data/lib/metanorma/document/components/inline/link_element.rb +8 -0
- data/lib/metanorma/document/components/inline/name_with_id_element.rb +2 -0
- data/lib/metanorma/document/components/inline/refterm_element.rb +21 -0
- data/lib/metanorma/document/components/inline/semx_element.rb +22 -0
- data/lib/metanorma/document/components/inline/sourcelocality_stack_element.rb +27 -0
- data/lib/metanorma/document/components/inline/span_element.rb +2 -0
- data/lib/metanorma/document/components/inline/stem_inline_element.rb +2 -0
- data/lib/metanorma/document/components/inline/strong_raw_element.rb +6 -9
- data/lib/metanorma/document/components/inline/sub_element.rb +2 -0
- data/lib/metanorma/document/components/inline/termref_element.rb +24 -0
- data/lib/metanorma/document/components/inline/title_with_annotation_element.rb +10 -31
- data/lib/metanorma/document/components/inline/variant_title_element.rb +2 -0
- data/lib/metanorma/document/components/inline/vocabulary.rb +36 -0
- data/lib/metanorma/document/components/inline.rb +23 -0
- data/lib/metanorma/document/components/lists/dd_element.rb +6 -1
- data/lib/metanorma/document/components/lists/definition.rb +2 -0
- data/lib/metanorma/document/components/lists/definition_list.rb +3 -0
- data/lib/metanorma/document/components/lists/dt_element.rb +3 -0
- data/lib/metanorma/document/components/lists/fmt_list_element.rb +73 -0
- data/lib/metanorma/document/components/lists/list_item.rb +3 -0
- data/lib/metanorma/document/components/lists/ordered_list.rb +4 -2
- data/lib/metanorma/document/components/lists/unordered_list.rb +2 -0
- data/lib/metanorma/document/components/lists.rb +2 -0
- data/lib/metanorma/document/components/multi_paragraph/quote_block.rb +16 -0
- data/lib/metanorma/document/components/multi_paragraph/review_block.rb +2 -2
- data/lib/metanorma/document/components/paragraphs/paragraph_block.rb +15 -0
- data/lib/metanorma/document/components/reference_elements/citation.rb +7 -0
- data/lib/metanorma/document/components/reference_elements/source_element.rb +4 -0
- data/lib/metanorma/document/components/semantic/node.rb +46 -0
- data/lib/metanorma/document/components/semantic.rb +11 -0
- data/lib/metanorma/document/components/tables/header_table_cell.rb +1 -0
- data/lib/metanorma/document/components/tables/table_cell.rb +70 -44
- data/lib/metanorma/document/components/tables/text_table_cell.rb +1 -0
- data/lib/metanorma/document/components/tables/text_table_row.rb +2 -0
- data/lib/metanorma/document/components/text_elements/ruby_annotation_element.rb +26 -0
- data/lib/metanorma/document/components/text_elements/ruby_element.rb +41 -6
- data/lib/metanorma/document/components/text_elements/ruby_pronunciation_element.rb +25 -0
- data/lib/metanorma/document/components/text_elements/strike_element.rb +3 -0
- data/lib/metanorma/document/components/text_elements/underline_element.rb +3 -0
- data/lib/metanorma/document/components/text_elements.rb +2 -0
- data/lib/metanorma/document/components.rb +1 -0
- data/lib/metanorma/document/grammar_vocabulary.rb +109 -0
- data/lib/metanorma/document/mirror_seed.rb +253 -0
- data/lib/metanorma/document/mko/collection.rb +168 -0
- data/lib/metanorma/document/mko/exporter.rb +17 -0
- data/lib/metanorma/document/mko/project.rb +1110 -0
- data/lib/metanorma/document/mko.rb +122 -0
- data/lib/metanorma/document/model_access.rb +44 -0
- data/lib/metanorma/document/native_models.rb +319 -0
- data/lib/metanorma/document/plain_text.rb +39 -0
- data/lib/metanorma/document/relaton/version_info.rb +4 -0
- data/lib/metanorma/document/version.rb +1 -1
- data/lib/metanorma/document.rb +19 -26
- data/lib/metanorma/{collection → document_collection}/directive.rb +1 -1
- data/lib/metanorma/{collection → document_collection}/doc_container.rb +6 -2
- data/lib/metanorma/{collection → document_collection}/entry.rb +2 -2
- data/lib/metanorma/{collection → document_collection}/root.rb +2 -2
- data/lib/metanorma/document_collection.rb +10 -0
- data/lib/metanorma/html/base_renderer.rb +105 -28
- data/lib/metanorma/html/component/footnote_collector.rb +21 -20
- data/lib/metanorma/html/concerns/metadata_extraction.rb +8 -3
- data/lib/metanorma/html/concerns/presentation_validation.rb +1 -2
- data/lib/metanorma/html/concerns/text_extraction.rb +154 -35
- data/lib/metanorma/html/concerns.rb +19 -0
- data/lib/metanorma/html/drops/admonition_drop.rb +1 -1
- data/lib/metanorma/html/drops/example_drop.rb +8 -1
- data/lib/metanorma/html/drops/footnote_drop.rb +1 -1
- data/lib/metanorma/html/drops/note_drop.rb +31 -4
- data/lib/metanorma/html/drops/sourcecode_drop.rb +22 -4
- data/lib/metanorma/html/generator.rb +11 -187
- data/lib/metanorma/html/renderer_delegation.rb +2 -2
- data/lib/metanorma/html/renderers/block_renderer.rb +246 -51
- data/lib/metanorma/html/renderers/inline_renderer.rb +144 -17
- data/lib/metanorma/html/renderers/section_renderer.rb +12 -2
- data/lib/metanorma/html/renderers/semantic_renderer.rb +487 -0
- data/lib/metanorma/html/renderers.rb +2 -0
- data/lib/metanorma/html/standard_renderer.rb +743 -81
- data/lib/metanorma/html/templates/_agency_cover.html.liquid +30 -0
- data/lib/metanorma/html/templates/_columnbreak.html.liquid +1 -0
- data/lib/metanorma/html/templates/_cover.html.liquid +3 -0
- data/lib/metanorma/html/templates/_example.html.liquid +1 -1
- data/lib/metanorma/html/templates/_main_content.html.liquid +1 -1
- data/lib/metanorma/html/templates/_note.html.liquid +1 -1
- data/lib/metanorma/html/templates/_paragraph.html.liquid +1 -1
- data/lib/metanorma/html/templates/_ruby.html.liquid +1 -0
- data/lib/metanorma/html/templates/_sourcecode.html.liquid +4 -3
- data/lib/metanorma/html/templates/_standard_cover.html.liquid +54 -3
- data/lib/metanorma/html/templates/_term_number.html.liquid +1 -1
- data/lib/metanorma/html.rb +30 -15
- data/tasks/flavors.rake +116 -0
- data/tasks/grammar.rake +28 -0
- data/tasks/roundtrip_samples.rake +48 -34
- metadata +121 -416
- data/frontend/dist/app.css +0 -1
- data/frontend/dist/app.iife.js +0 -24
- data/lib/metanorma/bipm_document/metadata/bipm_bib_data_extension_type.rb +0 -20
- data/lib/metanorma/bipm_document/metadata/bipm_bibliographic_item.rb +0 -17
- data/lib/metanorma/bipm_document/metadata/bipm_structured_identifier.rb +0 -21
- data/lib/metanorma/bipm_document/metadata/depiction_element.rb +0 -18
- data/lib/metanorma/bipm_document/metadata.rb +0 -15
- data/lib/metanorma/bipm_document/root.rb +0 -25
- data/lib/metanorma/bipm_document.rb +0 -8
- data/lib/metanorma/bsi_document/metadata/bsi_bib_data_extension_type.rb +0 -10
- data/lib/metanorma/bsi_document/metadata/bsi_bibliographic_item.rb +0 -15
- data/lib/metanorma/bsi_document/metadata.rb +0 -12
- data/lib/metanorma/bsi_document/root.rb +0 -29
- data/lib/metanorma/bsi_document/sections/bsi_annex_section.rb +0 -25
- data/lib/metanorma/bsi_document/sections/bsi_clause_section.rb +0 -25
- data/lib/metanorma/bsi_document/sections/bsi_sections.rb +0 -27
- data/lib/metanorma/bsi_document/sections.rb +0 -11
- data/lib/metanorma/bsi_document.rb +0 -11
- data/lib/metanorma/cc_document/metadata/cc_bib_data_extension_type.rb +0 -12
- data/lib/metanorma/cc_document/metadata/cc_bibliographic_item.rb +0 -17
- data/lib/metanorma/cc_document/metadata.rb +0 -11
- data/lib/metanorma/cc_document/root.rb +0 -25
- data/lib/metanorma/cc_document.rb +0 -8
- data/lib/metanorma/collection.rb +0 -10
- data/lib/metanorma/csa_document/root.rb +0 -27
- data/lib/metanorma/csa_document.rb +0 -9
- data/lib/metanorma/gb_document/metadata/gb_bib_data_extension_type.rb +0 -10
- data/lib/metanorma/gb_document/metadata/gb_bibliographic_item.rb +0 -15
- data/lib/metanorma/gb_document/metadata.rb +0 -12
- data/lib/metanorma/gb_document/root.rb +0 -29
- data/lib/metanorma/gb_document.rb +0 -10
- data/lib/metanorma/generic_document/root.rb +0 -31
- data/lib/metanorma/generic_document.rb +0 -7
- data/lib/metanorma/html/bipm_renderer.rb +0 -23
- data/lib/metanorma/html/cc_renderer.rb +0 -9
- data/lib/metanorma/html/csa_renderer.rb +0 -9
- data/lib/metanorma/html/flavor.rb +0 -50
- data/lib/metanorma/html/flavor_registry.rb +0 -49
- data/lib/metanorma/html/icc_renderer.rb +0 -10
- data/lib/metanorma/html/iec_renderer.rb +0 -9
- data/lib/metanorma/html/ieee_renderer.rb +0 -9
- data/lib/metanorma/html/ietf_renderer.rb +0 -9
- data/lib/metanorma/html/iho_renderer.rb +0 -9
- data/lib/metanorma/html/iso_renderer.rb +0 -535
- data/lib/metanorma/html/itu_renderer.rb +0 -9
- data/lib/metanorma/html/ogc_renderer.rb +0 -23
- data/lib/metanorma/html/pdfa_renderer.rb +0 -10
- data/lib/metanorma/html/ribose_renderer.rb +0 -9
- data/lib/metanorma/html/templates/_bipm_cover.html.liquid +0 -27
- data/lib/metanorma/html/templates/_iso_cover.html.liquid +0 -31
- data/lib/metanorma/html/templates/_iso_doc_title.html.liquid +0 -3
- data/lib/metanorma/iec_document/root.rb +0 -27
- data/lib/metanorma/iec_document.rb +0 -9
- data/lib/metanorma/ieee_document/metadata/ieee_bib_data_extension_type.rb +0 -18
- data/lib/metanorma/ieee_document/metadata/ieee_bibliographic_item.rb +0 -20
- data/lib/metanorma/ieee_document/metadata/ieee_structured_identifier.rb +0 -25
- data/lib/metanorma/ieee_document/metadata.rb +0 -14
- data/lib/metanorma/ieee_document/root.rb +0 -29
- data/lib/metanorma/ieee_document/sections/ieee_sections.rb +0 -31
- data/lib/metanorma/ieee_document/sections.rb +0 -9
- data/lib/metanorma/ieee_document.rb +0 -11
- data/lib/metanorma/ietf_document/metadata/ietf_bib_data_extension_type.rb +0 -31
- data/lib/metanorma/ietf_document/metadata/ietf_bibliographic_item.rb +0 -51
- data/lib/metanorma/ietf_document/metadata/ietf_editorial_group.rb +0 -17
- data/lib/metanorma/ietf_document/metadata/pi_settings.rb +0 -32
- data/lib/metanorma/ietf_document/metadata.rb +0 -16
- data/lib/metanorma/ietf_document/root.rb +0 -30
- data/lib/metanorma/ietf_document/sections/ietf_annex_section.rb +0 -26
- data/lib/metanorma/ietf_document/sections/ietf_clause_section.rb +0 -26
- data/lib/metanorma/ietf_document/sections/ietf_content_section.rb +0 -25
- data/lib/metanorma/ietf_document/sections/ietf_sections.rb +0 -35
- data/lib/metanorma/ietf_document/sections.rb +0 -12
- data/lib/metanorma/ietf_document.rb +0 -11
- data/lib/metanorma/iho_document/metadata/iho_bib_data_extension_type.rb +0 -23
- data/lib/metanorma/iho_document/metadata/iho_bibliographic_item.rb +0 -20
- data/lib/metanorma/iho_document/metadata/iho_editorial_group.rb +0 -19
- data/lib/metanorma/iho_document/metadata/iho_series.rb +0 -22
- data/lib/metanorma/iho_document/metadata/iho_sub_group.rb +0 -18
- data/lib/metanorma/iho_document/metadata.rb +0 -15
- data/lib/metanorma/iho_document/root.rb +0 -25
- data/lib/metanorma/iho_document.rb +0 -8
- data/lib/metanorma/iso_document/annotation_container.rb +0 -7
- data/lib/metanorma/iso_document/blocks/iso_admonition_block.rb +0 -27
- data/lib/metanorma/iso_document/blocks/iso_admonition_type.rb +0 -25
- data/lib/metanorma/iso_document/blocks.rb +0 -12
- data/lib/metanorma/iso_document/boilerplate.rb +0 -7
- data/lib/metanorma/iso_document/metadata/abstract_title.rb +0 -36
- data/lib/metanorma/iso_document/metadata/doc_identifier.rb +0 -26
- data/lib/metanorma/iso_document/metadata/doctype_element.rb +0 -20
- data/lib/metanorma/iso_document/metadata/ics.rb +0 -19
- data/lib/metanorma/iso_document/metadata/iec_document_category.rb +0 -23
- data/lib/metanorma/iso_document/metadata/iso_bib_data_extension_type.rb +0 -38
- data/lib/metanorma/iso_document/metadata/iso_bibliographic_item.rb +0 -103
- data/lib/metanorma/iso_document/metadata/iso_document_id.rb +0 -46
- data/lib/metanorma/iso_document/metadata/iso_document_stage_codes.rb +0 -26
- data/lib/metanorma/iso_document/metadata/iso_document_status.rb +0 -26
- data/lib/metanorma/iso_document/metadata/iso_document_substage_codes.rb +0 -26
- data/lib/metanorma/iso_document/metadata/iso_document_type.rb +0 -25
- data/lib/metanorma/iso_document/metadata/iso_localized_title.rb +0 -61
- data/lib/metanorma/iso_document/metadata/iso_project_group.rb +0 -32
- data/lib/metanorma/iso_document/metadata/iso_sub_group.rb +0 -38
- data/lib/metanorma/iso_document/metadata/language_element.rb +0 -18
- data/lib/metanorma/iso_document/metadata/metanorma_extension.rb +0 -9
- data/lib/metanorma/iso_document/metadata/project_number.rb +0 -22
- data/lib/metanorma/iso_document/metadata/script_element.rb +0 -18
- data/lib/metanorma/iso_document/metadata/stage_element.rb +0 -26
- data/lib/metanorma/iso_document/metadata/stagename_element.rb +0 -18
- data/lib/metanorma/iso_document/metadata/structured_identifier.rb +0 -16
- data/lib/metanorma/iso_document/metadata/title_amd.rb +0 -12
- data/lib/metanorma/iso_document/metadata/title_amendment_prefix.rb +0 -12
- data/lib/metanorma/iso_document/metadata/title_collection.rb +0 -47
- data/lib/metanorma/iso_document/metadata/title_full.rb +0 -12
- data/lib/metanorma/iso_document/metadata/title_intro.rb +0 -12
- data/lib/metanorma/iso_document/metadata/title_main.rb +0 -12
- data/lib/metanorma/iso_document/metadata/title_part.rb +0 -12
- data/lib/metanorma/iso_document/metadata/title_part_prefix.rb +0 -12
- data/lib/metanorma/iso_document/metadata.rb +0 -44
- data/lib/metanorma/iso_document/root.rb +0 -26
- data/lib/metanorma/iso_document/sections/colophon.rb +0 -3
- data/lib/metanorma/iso_document/sections/iso_abstract_section.rb +0 -15
- data/lib/metanorma/iso_document/sections/iso_amendment_clause.rb +0 -24
- data/lib/metanorma/iso_document/sections/iso_annex_section.rb +0 -50
- data/lib/metanorma/iso_document/sections/iso_clause_section.rb +0 -49
- data/lib/metanorma/iso_document/sections/iso_foreword_section.rb +0 -33
- data/lib/metanorma/iso_document/sections/iso_preface.rb +0 -51
- data/lib/metanorma/iso_document/sections/iso_sections.rb +0 -51
- data/lib/metanorma/iso_document/sections/iso_terms_section.rb +0 -76
- data/lib/metanorma/iso_document/sections.rb +0 -17
- data/lib/metanorma/iso_document/terms/iso_term.rb +0 -71
- data/lib/metanorma/iso_document/terms/iso_term_collection.rb +0 -20
- data/lib/metanorma/iso_document/terms/term_definition.rb +0 -30
- data/lib/metanorma/iso_document/terms/term_designation.rb +0 -44
- data/lib/metanorma/iso_document/terms/term_domain_element.rb +0 -18
- data/lib/metanorma/iso_document/terms/term_example.rb +0 -40
- data/lib/metanorma/iso_document/terms/term_expression.rb +0 -10
- data/lib/metanorma/iso_document/terms/term_note.rb +0 -42
- data/lib/metanorma/iso_document/terms/term_origin.rb +0 -4
- data/lib/metanorma/iso_document/terms/term_source.rb +0 -21
- data/lib/metanorma/iso_document/terms/verbal_definition.rb +0 -42
- data/lib/metanorma/iso_document/terms.rb +0 -21
- data/lib/metanorma/iso_document.rb +0 -15
- data/lib/metanorma/itu_document/metadata/itu_bib_data_extension_type.rb +0 -26
- data/lib/metanorma/itu_document/metadata/itu_bibliographic_item.rb +0 -21
- data/lib/metanorma/itu_document/metadata/itu_series.rb +0 -22
- data/lib/metanorma/itu_document/metadata/itu_structured_identifier.rb +0 -23
- data/lib/metanorma/itu_document/metadata/meeting_date.rb +0 -18
- data/lib/metanorma/itu_document/metadata/meeting_element.rb +0 -18
- data/lib/metanorma/itu_document/metadata/study_period.rb +0 -18
- data/lib/metanorma/itu_document/metadata.rb +0 -18
- data/lib/metanorma/itu_document/root.rb +0 -25
- data/lib/metanorma/itu_document.rb +0 -8
- data/lib/metanorma/jis_document/metadata/jis_bib_data_extension_type.rb +0 -10
- data/lib/metanorma/jis_document/metadata/jis_bibliographic_item.rb +0 -15
- data/lib/metanorma/jis_document/metadata.rb +0 -12
- data/lib/metanorma/jis_document/root.rb +0 -29
- data/lib/metanorma/jis_document/sections/jis_annex_section.rb +0 -20
- data/lib/metanorma/jis_document/sections.rb +0 -9
- data/lib/metanorma/jis_document.rb +0 -11
- data/lib/metanorma/m3d_document/metadata/m3d_bib_data_extension_type.rb +0 -10
- data/lib/metanorma/m3d_document/metadata/m3d_bibliographic_item.rb +0 -15
- data/lib/metanorma/m3d_document/metadata.rb +0 -12
- data/lib/metanorma/m3d_document/root.rb +0 -29
- data/lib/metanorma/m3d_document.rb +0 -10
- data/lib/metanorma/mirror/default_registry.rb +0 -191
- data/lib/metanorma/mirror/handler_registry.rb +0 -60
- data/lib/metanorma/mirror/handler_result.rb +0 -37
- data/lib/metanorma/mirror/handlers/admonition.rb +0 -18
- data/lib/metanorma/mirror/handlers/example.rb +0 -21
- data/lib/metanorma/mirror/handlers/figure.rb +0 -53
- data/lib/metanorma/mirror/handlers/formula.rb +0 -35
- data/lib/metanorma/mirror/handlers/inline/catalog.rb +0 -52
- data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +0 -158
- data/lib/metanorma/mirror/handlers/inline/text_extractor.rb +0 -116
- data/lib/metanorma/mirror/handlers/inline.rb +0 -226
- data/lib/metanorma/mirror/handlers/list.rb +0 -110
- data/lib/metanorma/mirror/handlers/note.rb +0 -26
- data/lib/metanorma/mirror/handlers/paragraph.rb +0 -19
- data/lib/metanorma/mirror/handlers/quote.rb +0 -16
- data/lib/metanorma/mirror/handlers/review.rb +0 -19
- data/lib/metanorma/mirror/handlers/section.rb +0 -149
- data/lib/metanorma/mirror/handlers/sourcecode.rb +0 -27
- data/lib/metanorma/mirror/handlers/structural.rb +0 -68
- data/lib/metanorma/mirror/handlers/table.rb +0 -81
- data/lib/metanorma/mirror/handlers/term.rb +0 -100
- data/lib/metanorma/mirror/handlers.rb +0 -60
- data/lib/metanorma/mirror/id_strategy/positional.rb +0 -166
- data/lib/metanorma/mirror/id_strategy/preserve.rb +0 -12
- data/lib/metanorma/mirror/id_strategy.rb +0 -34
- data/lib/metanorma/mirror/math_util.rb +0 -53
- data/lib/metanorma/mirror/metadata.rb +0 -37
- data/lib/metanorma/mirror/model/container.rb +0 -47
- data/lib/metanorma/mirror/model/factory.rb +0 -52
- data/lib/metanorma/mirror/model/guide.rb +0 -26
- data/lib/metanorma/mirror/model/leaf.rb +0 -17
- data/lib/metanorma/mirror/model/mark.rb +0 -53
- data/lib/metanorma/mirror/model/node.rb +0 -47
- data/lib/metanorma/mirror/model/soft_break.rb +0 -33
- data/lib/metanorma/mirror/model/text.rb +0 -34
- data/lib/metanorma/mirror/model.rb +0 -16
- data/lib/metanorma/mirror/output/builder.rb +0 -39
- data/lib/metanorma/mirror/output/formats/base_format.rb +0 -90
- data/lib/metanorma/mirror/output/formats/inline_format.rb +0 -142
- data/lib/metanorma/mirror/output/formats.rb +0 -53
- data/lib/metanorma/mirror/output/pipeline.rb +0 -93
- data/lib/metanorma/mirror/output/pipeline_context.rb +0 -22
- data/lib/metanorma/mirror/output.rb +0 -12
- data/lib/metanorma/mirror/rewriter.rb +0 -123
- data/lib/metanorma/mirror/safe_attr.rb +0 -16
- data/lib/metanorma/mirror/serialization/json_serializer.rb +0 -25
- data/lib/metanorma/mirror/serialization/yaml_serializer.rb +0 -20
- data/lib/metanorma/mirror/serialization.rb +0 -10
- data/lib/metanorma/mirror/transformer.rb +0 -110
- data/lib/metanorma/mirror.rb +0 -31
- data/lib/metanorma/nist_document/metadata/nist_bib_data_extension_type.rb +0 -10
- data/lib/metanorma/nist_document/metadata/nist_bibliographic_item.rb +0 -15
- data/lib/metanorma/nist_document/metadata.rb +0 -12
- data/lib/metanorma/nist_document/root.rb +0 -29
- data/lib/metanorma/nist_document/sections/errata.rb +0 -16
- data/lib/metanorma/nist_document/sections/errata_clause.rb +0 -20
- data/lib/metanorma/nist_document/sections/errata_row.rb +0 -22
- data/lib/metanorma/nist_document/sections/nist_preface.rb +0 -30
- data/lib/metanorma/nist_document/sections.rb +0 -12
- data/lib/metanorma/nist_document.rb +0 -11
- data/lib/metanorma/ogc_document/metadata/ogc_bib_data_extension_type.rb +0 -12
- data/lib/metanorma/ogc_document/metadata/ogc_bibliographic_item.rb +0 -19
- data/lib/metanorma/ogc_document/metadata.rb +0 -12
- data/lib/metanorma/ogc_document/root.rb +0 -25
- data/lib/metanorma/ogc_document.rb +0 -8
- data/lib/metanorma/plateau_document/metadata/plateau_bibliographic_item.rb +0 -13
- data/lib/metanorma/plateau_document/metadata.rb +0 -10
- data/lib/metanorma/plateau_document/root.rb +0 -29
- data/lib/metanorma/plateau_document.rb +0 -10
- data/lib/metanorma/registers/setup.rb +0 -166
- data/lib/metanorma/registers.rb +0 -7
- data/lib/metanorma/ribose_document/metadata/ribose_bib_data_extension_type.rb +0 -20
- data/lib/metanorma/ribose_document/metadata/ribose_bibliographic_item.rb +0 -18
- data/lib/metanorma/ribose_document/metadata.rb +0 -12
- data/lib/metanorma/ribose_document/root.rb +0 -26
- data/lib/metanorma/ribose_document.rb +0 -8
- data/lib/metanorma/standard_document/annotation_container.rb +0 -39
- data/lib/metanorma/standard_document/block_attributes.rb +0 -281
- data/lib/metanorma/standard_document/blocks/amend_block.rb +0 -50
- data/lib/metanorma/standard_document/blocks/amend_content_block.rb +0 -35
- data/lib/metanorma/standard_document/blocks/auto_number.rb +0 -20
- data/lib/metanorma/standard_document/blocks/block_source.rb +0 -22
- data/lib/metanorma/standard_document/blocks/change_type.rb +0 -21
- data/lib/metanorma/standard_document/blocks/element_name.rb +0 -22
- data/lib/metanorma/standard_document/blocks/form.rb +0 -38
- data/lib/metanorma/standard_document/blocks/image_map_area_type.rb +0 -24
- data/lib/metanorma/standard_document/blocks/image_map_area_type_type.rb +0 -21
- data/lib/metanorma/standard_document/blocks/image_map_block.rb +0 -32
- data/lib/metanorma/standard_document/blocks/image_map_coords.rb +0 -19
- data/lib/metanorma/standard_document/blocks/image_map_radius.rb +0 -19
- data/lib/metanorma/standard_document/blocks/multilingual_rendering_type.rb +0 -21
- data/lib/metanorma/standard_document/blocks/passthrough.rb +0 -3
- data/lib/metanorma/standard_document/blocks/requirement_model.rb +0 -20
- data/lib/metanorma/standard_document/blocks/source_origin_element.rb +0 -23
- data/lib/metanorma/standard_document/blocks/standard_admonition_block.rb +0 -32
- data/lib/metanorma/standard_document/blocks/standard_block.rb +0 -28
- data/lib/metanorma/standard_document/blocks/standard_block_no_notes.rb +0 -34
- data/lib/metanorma/standard_document/blocks/standard_example_block.rb +0 -30
- data/lib/metanorma/standard_document/blocks/standard_figure_block.rb +0 -32
- data/lib/metanorma/standard_document/blocks/standard_formula_block.rb +0 -30
- data/lib/metanorma/standard_document/blocks/standard_note_block.rb +0 -64
- data/lib/metanorma/standard_document/blocks/standard_paragraph_block.rb +0 -25
- data/lib/metanorma/standard_document/blocks/standard_quote_block.rb +0 -29
- data/lib/metanorma/standard_document/blocks/standard_sourcecode_block.rb +0 -32
- data/lib/metanorma/standard_document/blocks/standard_table_block.rb +0 -39
- data/lib/metanorma/standard_document/blocks/svg_map_block.rb +0 -23
- data/lib/metanorma/standard_document/blocks/svg_target_type.rb +0 -20
- data/lib/metanorma/standard_document/blocks/table_col.rb +0 -16
- data/lib/metanorma/standard_document/blocks/to_c.rb +0 -17
- data/lib/metanorma/standard_document/blocks.rb +0 -60
- data/lib/metanorma/standard_document/boilerplate.rb +0 -32
- data/lib/metanorma/standard_document/elements/add.rb +0 -3
- data/lib/metanorma/standard_document/elements/del.rb +0 -3
- data/lib/metanorma/standard_document/elements/form_input.rb +0 -27
- data/lib/metanorma/standard_document/elements/input.rb +0 -12
- data/lib/metanorma/standard_document/elements/input_type.rb +0 -27
- data/lib/metanorma/standard_document/elements/label.rb +0 -19
- data/lib/metanorma/standard_document/elements/option.rb +0 -27
- data/lib/metanorma/standard_document/elements/orientation_type.rb +0 -27
- data/lib/metanorma/standard_document/elements/select.rb +0 -32
- data/lib/metanorma/standard_document/elements/standard_page_break_element.rb +0 -22
- data/lib/metanorma/standard_document/elements/textarea.rb +0 -25
- data/lib/metanorma/standard_document/elements.rb +0 -20
- data/lib/metanorma/standard_document/lists/standard_definition.rb +0 -24
- data/lib/metanorma/standard_document/lists/standard_definition_list.rb +0 -30
- data/lib/metanorma/standard_document/lists/standard_definition_term.rb +0 -27
- data/lib/metanorma/standard_document/lists/standard_unordered_list.rb +0 -28
- data/lib/metanorma/standard_document/lists/unordered_checkable_list_item.rb +0 -26
- data/lib/metanorma/standard_document/lists.rb +0 -17
- data/lib/metanorma/standard_document/metadata/editorial_group_type.rb +0 -25
- data/lib/metanorma/standard_document/metadata/ics_type.rb +0 -26
- data/lib/metanorma/standard_document/metadata/metanorma_extension.rb +0 -26
- data/lib/metanorma/standard_document/metadata/presentation_metadata.rb +0 -107
- data/lib/metanorma/standard_document/metadata/semantic_metadata.rb +0 -18
- data/lib/metanorma/standard_document/metadata/standard_bib_data.rb +0 -25
- data/lib/metanorma/standard_document/metadata/standard_bib_data_extension_type.rb +0 -37
- data/lib/metanorma/standard_document/metadata/structured_identifier_type.rb +0 -48
- data/lib/metanorma/standard_document/metadata/technical_committee_type.rb +0 -27
- data/lib/metanorma/standard_document/metadata/unitsml/amount_of_substance.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/base_quantity.rb +0 -34
- data/lib/metanorma/standard_document/metadata/unitsml/dimension.rb +0 -39
- data/lib/metanorma/standard_document/metadata/unitsml/dimension_set.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/electric_current.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/enumerated_root_unit.rb +0 -23
- data/lib/metanorma/standard_document/metadata/unitsml/length.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/luminous_intensity.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/mass.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/namespace.rb +0 -17
- data/lib/metanorma/standard_document/metadata/unitsml/plane_angle.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/prefix.rb +0 -30
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_name.rb +0 -21
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_set.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_symbol.rb +0 -21
- data/lib/metanorma/standard_document/metadata/unitsml/quantity.rb +0 -28
- data/lib/metanorma/standard_document/metadata/unitsml/quantity_name.rb +0 -21
- data/lib/metanorma/standard_document/metadata/unitsml/quantity_set.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/root_units.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/thermodynamic_temperature.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/time.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/unit.rb +0 -32
- data/lib/metanorma/standard_document/metadata/unitsml/unit_name.rb +0 -21
- data/lib/metanorma/standard_document/metadata/unitsml/unit_set.rb +0 -19
- data/lib/metanorma/standard_document/metadata/unitsml/unit_symbol.rb +0 -36
- data/lib/metanorma/standard_document/metadata/unitsml/unit_system.rb +0 -23
- data/lib/metanorma/standard_document/metadata/unitsml/unitsml_root.rb +0 -28
- data/lib/metanorma/standard_document/metadata/unitsml.rb +0 -39
- data/lib/metanorma/standard_document/metadata.rb +0 -23
- data/lib/metanorma/standard_document/namespace.rb +0 -11
- data/lib/metanorma/standard_document/refs/reference_to_term.rb +0 -26
- data/lib/metanorma/standard_document/refs/reference_to_termbase.rb +0 -27
- data/lib/metanorma/standard_document/refs/standoc_locality_stack.rb +0 -24
- data/lib/metanorma/standard_document/refs/standoc_reference_to_citation_element.rb +0 -27
- data/lib/metanorma/standard_document/refs/standoc_reference_to_id_element.rb +0 -36
- data/lib/metanorma/standard_document/refs/xref_case_type.rb +0 -27
- data/lib/metanorma/standard_document/refs/xref_connective_type.rb +0 -27
- data/lib/metanorma/standard_document/refs/xref_target_type.rb +0 -25
- data/lib/metanorma/standard_document/refs.rb +0 -18
- data/lib/metanorma/standard_document/root.rb +0 -10
- data/lib/metanorma/standard_document/root_attributes.rb +0 -78
- data/lib/metanorma/standard_document/sections/abstract.rb +0 -19
- data/lib/metanorma/standard_document/sections/acknowledgements.rb +0 -19
- data/lib/metanorma/standard_document/sections/annex_section.rb +0 -69
- data/lib/metanorma/standard_document/sections/bibliography_section.rb +0 -20
- data/lib/metanorma/standard_document/sections/boilerplate_type.rb +0 -32
- data/lib/metanorma/standard_document/sections/clause_hierarchical_section.rb +0 -32
- data/lib/metanorma/standard_document/sections/clause_section.rb +0 -91
- data/lib/metanorma/standard_document/sections/colophon.rb +0 -16
- data/lib/metanorma/standard_document/sections/definition_section.rb +0 -72
- data/lib/metanorma/standard_document/sections/floating_section_title.rb +0 -23
- data/lib/metanorma/standard_document/sections/floating_title.rb +0 -27
- data/lib/metanorma/standard_document/sections/foreword.rb +0 -19
- data/lib/metanorma/standard_document/sections/introduction.rb +0 -20
- data/lib/metanorma/standard_document/sections/misc_container.rb +0 -31
- data/lib/metanorma/standard_document/sections/normative_type.rb +0 -29
- data/lib/metanorma/standard_document/sections/preface.rb +0 -36
- data/lib/metanorma/standard_document/sections/sections.rb +0 -47
- data/lib/metanorma/standard_document/sections/standard_content_section.rb +0 -41
- data/lib/metanorma/standard_document/sections/standard_hierarchical_section.rb +0 -30
- data/lib/metanorma/standard_document/sections/standard_references_section.rb +0 -74
- data/lib/metanorma/standard_document/sections/standard_section.rb +0 -39
- data/lib/metanorma/standard_document/sections/terms_section.rb +0 -61
- data/lib/metanorma/standard_document/sections.rb +0 -34
- data/lib/metanorma/standard_document/standard_document_type.rb +0 -15
- data/lib/metanorma/standard_document/terms/abbreviation_type.rb +0 -27
- data/lib/metanorma/standard_document/terms/concept.rb +0 -42
- data/lib/metanorma/standard_document/terms/definition_collection.rb +0 -24
- data/lib/metanorma/standard_document/terms/designation.rb +0 -31
- data/lib/metanorma/standard_document/terms/expression_designation.rb +0 -38
- data/lib/metanorma/standard_document/terms/expression_type.rb +0 -27
- data/lib/metanorma/standard_document/terms/grammar_gender.rb +0 -27
- data/lib/metanorma/standard_document/terms/grammar_info.rb +0 -36
- data/lib/metanorma/standard_document/terms/graphical_symbol_designation.rb +0 -25
- data/lib/metanorma/standard_document/terms/letter_symbol_designation.rb +0 -27
- data/lib/metanorma/standard_document/terms/non_verbal_representation.rb +0 -33
- data/lib/metanorma/standard_document/terms/related_term.rb +0 -31
- data/lib/metanorma/standard_document/terms/related_term_type.rb +0 -28
- data/lib/metanorma/standard_document/terms/term.rb +0 -66
- data/lib/metanorma/standard_document/terms/term_collection.rb +0 -24
- data/lib/metanorma/standard_document/terms/term_definition.rb +0 -29
- data/lib/metanorma/standard_document/terms/term_expression.rb +0 -20
- data/lib/metanorma/standard_document/terms/term_name_element.rb +0 -29
- data/lib/metanorma/standard_document/terms/term_source.rb +0 -29
- data/lib/metanorma/standard_document/terms/term_source_status.rb +0 -29
- data/lib/metanorma/standard_document/terms/term_source_type.rb +0 -21
- data/lib/metanorma/standard_document/terms/verbal_expression.rb +0 -35
- data/lib/metanorma/standard_document/terms.rb +0 -33
- data/lib/metanorma/standard_document.rb +0 -27
- data/lib/metanorma/un_document/blocks/un_admonition_block.rb +0 -86
- data/lib/metanorma/un_document/blocks.rb +0 -9
- data/lib/metanorma/un_document/metadata/un_bib_data_extension_type.rb +0 -10
- data/lib/metanorma/un_document/metadata/un_bibliographic_item.rb +0 -15
- data/lib/metanorma/un_document/metadata.rb +0 -12
- data/lib/metanorma/un_document/root.rb +0 -37
- data/lib/metanorma/un_document/sections/un_abstract_section.rb +0 -48
- data/lib/metanorma/un_document/sections/un_preface.rb +0 -40
- data/lib/metanorma/un_document/sections/un_sections.rb +0 -24
- data/lib/metanorma/un_document/sections.rb +0 -11
- data/lib/metanorma/un_document/un_text_element.rb +0 -116
- data/lib/metanorma/un_document.rb +0 -13
|
@@ -0,0 +1,1110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
module Mko
|
|
5
|
+
# The projection: typed document model -> knowledge objects.
|
|
6
|
+
# Dispatches on model classes only (BasicDocument/StandardDocument
|
|
7
|
+
# vocabulary); carries zero flavor knowledge. All attribute access is
|
|
8
|
+
# keyed on lutaml attribute declarations — flavor classes may omit
|
|
9
|
+
# attributes the base trees carry.
|
|
10
|
+
class Project
|
|
11
|
+
include Metanorma::Document::ModelAccess
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def call(model, presentation: nil, assets: nil)
|
|
15
|
+
new(model, presentation: presentation, assets: assets).call
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def initialize(model, presentation: nil, assets: nil)
|
|
20
|
+
@model = model
|
|
21
|
+
@presentation = presentation
|
|
22
|
+
@assets = assets
|
|
23
|
+
@units = []
|
|
24
|
+
@units_by_id = {}
|
|
25
|
+
# model element -> unit, by object identity: what re-orders
|
|
26
|
+
# children into document order from element_order
|
|
27
|
+
@element_units = {}
|
|
28
|
+
@edges = []
|
|
29
|
+
@numbers = {}
|
|
30
|
+
@structure = []
|
|
31
|
+
# document order (#56): assigned at emission, never re-derived
|
|
32
|
+
@ordinal = 0
|
|
33
|
+
# units register (#55): entries + symbol lookup for formula refs
|
|
34
|
+
@unitsml = []
|
|
35
|
+
@units_by_symbol = {}
|
|
36
|
+
# The document language resolution (#53 item 3): every unit's
|
|
37
|
+
# lang carries its provenance — markup, heuristic, default, or
|
|
38
|
+
# the explicit fallback (Mko::Language).
|
|
39
|
+
@document_lang = resolve_document_lang(model)
|
|
40
|
+
@lang = @document_lang
|
|
41
|
+
@flavor = flavor_of(model)
|
|
42
|
+
@doc_date = published_on(model)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# One export = one instance: the walk's state (@units, @edges,
|
|
46
|
+
# @numbers, @structure) is owned by this export, never shared.
|
|
47
|
+
def call
|
|
48
|
+
collect_numbers(@presentation)
|
|
49
|
+
build_units_register(@model)
|
|
50
|
+
walk_root(@model)
|
|
51
|
+
identity = build_identity(@model)
|
|
52
|
+
@edges.concat(document_relation_edges(identity))
|
|
53
|
+
# Native object models (Glossarist concepts, Relaton bibdata)
|
|
54
|
+
# come from the model layer; the projection only serializes.
|
|
55
|
+
Mko::Result.new(document: identity, units: @units, edges: @edges,
|
|
56
|
+
unitsml: @unitsml,
|
|
57
|
+
glossary: Document::NativeModels.glossarist_concepts(
|
|
58
|
+
@model, lang: @lang.lang, date: @doc_date
|
|
59
|
+
),
|
|
60
|
+
bibdata: Document::NativeModels.relaton_bibdata(@model),
|
|
61
|
+
bibliography:
|
|
62
|
+
Document::NativeModels.relaton_bibliography(@model),
|
|
63
|
+
identifiers: build_identifiers(@model),
|
|
64
|
+
assets: @assets&.entries || [], flavor: @flavor)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Cross-document relations from the bibliographic record, as
|
|
68
|
+
# edges: doc:<short> -> ext:<identifier>, kind = the Relaton
|
|
69
|
+
# relation type verbatim (obsoletes, hasSuccessor, hasPart,
|
|
70
|
+
# updates, ...). Relaton's own vocabulary, no lossy mapping —
|
|
71
|
+
# consumers already carry the relaton type tables.
|
|
72
|
+
def document_relation_edges(identity)
|
|
73
|
+
Array(identity.relations).filter_map do |rel|
|
|
74
|
+
to = Document::PlainText.call(rel.to)
|
|
75
|
+
next if to.empty?
|
|
76
|
+
|
|
77
|
+
Schema::Edge.new(from: "doc:#{identity.ids.short}",
|
|
78
|
+
to: "ext:#{to}", kind: rel.type)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def published_on(model)
|
|
83
|
+
bib = val(model, :bibdata)
|
|
84
|
+
vals(bib, :date).filter_map { |d| scalar(val(d, :on)) }.first
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Base-quantity attr -> SI vector symbol; the model-side spelling
|
|
88
|
+
# of Mko::Units::BASE_QUANTITY_SYMBOLS (which is keyed by XML
|
|
89
|
+
# element name). Composition itself is shared: vectorize.
|
|
90
|
+
DIMENSION_SYMBOLS = {
|
|
91
|
+
length: "L", mass: "M", time: "T", electric_current: "I",
|
|
92
|
+
thermodynamic_temperature: "Θ", amount_of_substance: "N",
|
|
93
|
+
luminous_intensity: "J", plane_angle: "φ"
|
|
94
|
+
}.freeze
|
|
95
|
+
# Hand-entered status fields contradict their own succession
|
|
96
|
+
# links (#53 item 4: 58 of 224 OIML families); edges are
|
|
97
|
+
# structure. Derived from the Relaton relations verbatim:
|
|
98
|
+
# superseded iff this record names a successor.
|
|
99
|
+
SUCCESSOR_TYPES = %w[hasSuccessor obsoletedBy succeededBy
|
|
100
|
+
supersededBy updatedBy].freeze
|
|
101
|
+
# Prose containers hold paragraphs and lists (lists are not
|
|
102
|
+
# separate units — their content belongs in the clause text).
|
|
103
|
+
# Composed in document order via element_order, like
|
|
104
|
+
# extract_plain_text, but scoped to prose: tables/figures/
|
|
105
|
+
# formulas are their own units and stay out.
|
|
106
|
+
SECTION_PROSE_SOURCES = {
|
|
107
|
+
"p" => :paragraphs, "ul" => :unordered_lists,
|
|
108
|
+
"ol" => :ordered_lists, "dl" => :definition_lists
|
|
109
|
+
}.freeze
|
|
110
|
+
BLOCK_SOURCES = {
|
|
111
|
+
"table" => :tables, "figure" => :figures, "formula" => :formulas,
|
|
112
|
+
"note" => :notes, "example" => :examples,
|
|
113
|
+
"sourcecode" => :sourcecode_blocks,
|
|
114
|
+
# image maps: their wrapped figures are the content — each
|
|
115
|
+
# emits as a figure unit, the map's link geometry rides the
|
|
116
|
+
# native mirror object
|
|
117
|
+
"svgmap" => :svgmaps, "imagemap" => :imagemaps
|
|
118
|
+
}.freeze
|
|
119
|
+
# Element-name -> mapped attributes, for re-ordering a section's
|
|
120
|
+
# child units into document order from element_order (the same
|
|
121
|
+
# interleave trick section_text uses for prose). "clause" and
|
|
122
|
+
# "term" cover both tree spellings (subsections/clause, term/terms).
|
|
123
|
+
SECTION_CHILD_SOURCES = {
|
|
124
|
+
"clause" => %i[subsections clause], "terms" => %i[terms],
|
|
125
|
+
"term" => %i[term terms],
|
|
126
|
+
"table" => %i[tables], "figure" => %i[figures],
|
|
127
|
+
"svgmap" => %i[svgmaps], "imagemap" => %i[imagemaps],
|
|
128
|
+
"formula" => %i[formulas], "note" => %i[notes],
|
|
129
|
+
"example" => %i[examples], "sourcecode" => %i[sourcecode_blocks],
|
|
130
|
+
"requirement" => %i[requirement],
|
|
131
|
+
"recommendation" => %i[recommendation],
|
|
132
|
+
"permission" => %i[permission],
|
|
133
|
+
"p" => %i[paragraphs]
|
|
134
|
+
}.freeze
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def flavor_of(model)
|
|
139
|
+
val(model, :flavor) ||
|
|
140
|
+
model.class.name.to_s.split("::")[1]&.downcase
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Element-level language resolution (#53 item 3): the element's
|
|
144
|
+
# own :lang wins the day the models map xml:lang
|
|
145
|
+
# (metanorma-standoc#1243) — markup stays authoritative; with no
|
|
146
|
+
# xml:lang in scope the element's own prose decides (the stopword
|
|
147
|
+
# langid the RAG consumer shares — a translated annex tags
|
|
148
|
+
# itself); else the enclosing scope, then the document default,
|
|
149
|
+
# stands. Returns the resolution to restore when the scope ends.
|
|
150
|
+
def push_element_lang(element, text: nil)
|
|
151
|
+
previous = @lang
|
|
152
|
+
@lang = Mko::Language.resolve(own: val(element, :lang),
|
|
153
|
+
text: text, inherited: previous,
|
|
154
|
+
default: @document_lang)
|
|
155
|
+
previous
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# The document-level chain: the root's :lang the day the models
|
|
159
|
+
# map the root xml:lang, else the declared bibdata language, else
|
|
160
|
+
# detection over the document's own prose, else the explicit
|
|
161
|
+
# fallback.
|
|
162
|
+
def resolve_document_lang(model)
|
|
163
|
+
Mko::Language.document(markup: val(model, :lang),
|
|
164
|
+
declared: first_lang(model),
|
|
165
|
+
text: document_sample(model))
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def first_lang(model)
|
|
169
|
+
bib = val(model, :bibdata)
|
|
170
|
+
scalar(vals(bib, :language).first)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# The document-level detection sample: the direct prose of every
|
|
174
|
+
# top-level section (SAMPLE_WORDS caps what detect reads).
|
|
175
|
+
def document_sample(model)
|
|
176
|
+
parts = []
|
|
177
|
+
each_top_section(model) do |s|
|
|
178
|
+
text = section_text(s)
|
|
179
|
+
parts << text unless text.empty?
|
|
180
|
+
end
|
|
181
|
+
parts.join("\n")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# -- numbering (presentation model) ----------------------------
|
|
185
|
+
|
|
186
|
+
def collect_numbers(presentation)
|
|
187
|
+
return unless presentation
|
|
188
|
+
|
|
189
|
+
# Two passes, deliberately: the harvest gathers EVERY semx
|
|
190
|
+
# autonum fragment (the preface's TOC processed last carries
|
|
191
|
+
# bare fragments that would otherwise shadow the composed
|
|
192
|
+
# numbers of sections already walked — observed on R 60-1,
|
|
193
|
+
# metanorma-document#93); the number_tree pass then recomposes
|
|
194
|
+
# and its writes win. The passes are sequential PHASES, not
|
|
195
|
+
# combinable loops — combining them re-opens the shadowing.
|
|
196
|
+
# rubocop:disable Style/CombinableLoops
|
|
197
|
+
each_top_section(presentation) { |s| harvest_autonums(s) }
|
|
198
|
+
each_top_section(presentation) { |s| number_tree(s, nil) }
|
|
199
|
+
# rubocop:enable Style/CombinableLoops
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# The 0.4.x emitter no longer carries clause numbers in section
|
|
203
|
+
# fmt-titles — they ride the TOC's semx autonum fragments, each
|
|
204
|
+
# keyed by the source clause's id. Register them globally; the
|
|
205
|
+
# walk resolves each section's own anchor against the registry.
|
|
206
|
+
def harvest_autonums(model)
|
|
207
|
+
return unless serializable?(model)
|
|
208
|
+
|
|
209
|
+
if val(model, :element_attr) == "autonum"
|
|
210
|
+
src = val(model, :source)
|
|
211
|
+
text = Document::PlainText.call(model)
|
|
212
|
+
@numbers[src] = text if src && !text.empty?
|
|
213
|
+
end
|
|
214
|
+
model.class.attributes.each_value do |attr|
|
|
215
|
+
next if attr.name.nil?
|
|
216
|
+
|
|
217
|
+
raw = model.public_send(attr.name)
|
|
218
|
+
next if raw.nil?
|
|
219
|
+
|
|
220
|
+
Array(raw).each { |v| harvest_autonums(v) }
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def each_top_section(model, &)
|
|
225
|
+
sections = val(model, :sections)
|
|
226
|
+
walk_container(sections, &)
|
|
227
|
+
preface = val(model, :preface)
|
|
228
|
+
walk_container(preface, &)
|
|
229
|
+
vals(model, :annex).each(&)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def walk_container(container, &)
|
|
233
|
+
vals(container, :clause).each(&)
|
|
234
|
+
vals(container, :terms).each(&)
|
|
235
|
+
# preface-shaped containers declare :foreword/:introduction
|
|
236
|
+
# sections — OIML-CS admin documents keep their whole body
|
|
237
|
+
# there (semantic XML serializes an empty <sections>)
|
|
238
|
+
vals(container, :foreword).each(&)
|
|
239
|
+
vals(container, :introduction).each(&)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Term entries: the iso tree declares them as :term with nested
|
|
243
|
+
# terms-sections in :terms; the standoc tree maps them to :terms.
|
|
244
|
+
def term_entries(tsec)
|
|
245
|
+
entries = vals(tsec, :term)
|
|
246
|
+
entries = vals(tsec, :terms) if entries.empty?
|
|
247
|
+
entries
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def nested_terms_sections(tsec)
|
|
251
|
+
vals(tsec, :term).empty? ? [] : vals(tsec, :terms)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def number_tree(section, parent)
|
|
255
|
+
register_number(section, parent)
|
|
256
|
+
vals(section, :subsections).each { |s| number_tree(s, section) }
|
|
257
|
+
vals(section, :clause).each { |s| number_tree(s, section) }
|
|
258
|
+
vals(section, :terms).each do |tsec|
|
|
259
|
+
register_number(tsec, section)
|
|
260
|
+
term_entries(tsec).each { |t| register_number(t, tsec) }
|
|
261
|
+
nested_terms_sections(tsec).each { |nested| number_tree(nested, section) }
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def register_number(element, parent)
|
|
266
|
+
anchor = element_anchor(element, parent)
|
|
267
|
+
return unless anchor
|
|
268
|
+
|
|
269
|
+
autonum = section_autonum(element)
|
|
270
|
+
return unless autonum && !autonum.empty?
|
|
271
|
+
|
|
272
|
+
@numbers[anchor] = compose_autonum(parent, autonum)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# The 0.4.x TOC renders BARE fragments for iso-tree terms sections
|
|
276
|
+
# ("7" where the clause tree says "3.7" — metanorma-document#93):
|
|
277
|
+
# the harvest keyed them by source id and nothing composed parent
|
|
278
|
+
# chains, so terms-section units cited the bare fragment (or fell
|
|
279
|
+
# back to their parent's anchor) and every term under them cited
|
|
280
|
+
# it too. A bare fragment composes under its registered parent; a
|
|
281
|
+
# composed autonum ("3.7", "A.1") already carries its chain.
|
|
282
|
+
def compose_autonum(parent, autonum)
|
|
283
|
+
return autonum if autonum.include?(".")
|
|
284
|
+
|
|
285
|
+
pnum = parent && @numbers[element_anchor(parent)]
|
|
286
|
+
pnum && !pnum.empty? ? "#{pnum}.#{autonum}" : autonum
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def section_autonum(section)
|
|
290
|
+
autonum = val(section, :autonum)
|
|
291
|
+
return autonum if autonum && !autonum.empty?
|
|
292
|
+
|
|
293
|
+
fmt = val(section, :fmt_title)
|
|
294
|
+
fmt ? fmt_autonum(fmt) : nil
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Clause numbers live in presentation fmt-title spans as semx
|
|
298
|
+
# autonum fragments ("1" + "." + "2" -> "1.2").
|
|
299
|
+
def fmt_autonum(fmt_title)
|
|
300
|
+
parts = []
|
|
301
|
+
collect_semx_autonums(fmt_title, parts)
|
|
302
|
+
parts.empty? ? nil : parts.join(".")
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def collect_semx_autonums(element, out)
|
|
306
|
+
return unless serializable?(element)
|
|
307
|
+
|
|
308
|
+
if val(element, :element_attr) == "autonum"
|
|
309
|
+
text = Document::PlainText.call(element)
|
|
310
|
+
out << text unless text.empty?
|
|
311
|
+
end
|
|
312
|
+
element.class.attributes.each_value do |attr|
|
|
313
|
+
next if attr.name.nil?
|
|
314
|
+
|
|
315
|
+
raw = element.public_send(attr.name)
|
|
316
|
+
next if raw.nil?
|
|
317
|
+
|
|
318
|
+
Array(raw).each do |v|
|
|
319
|
+
collect_semx_autonums(v, out)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# -- units register (#55) ---------------------------------------
|
|
325
|
+
|
|
326
|
+
# The register from the model's typed UnitsML container. The
|
|
327
|
+
# container rides the root-level metanorma-extension (semantic
|
|
328
|
+
# XML puts UnitsML beside presentation-metadata); some trees also
|
|
329
|
+
# nest an extension under bibdata/ext — both are checked. A
|
|
330
|
+
# projection of what the source carries: no re-parsing, no
|
|
331
|
+
# invention.
|
|
332
|
+
def build_units_register(model)
|
|
333
|
+
root = [val(model, :metanorma_extension),
|
|
334
|
+
val(val_any(val(model, :bibdata), :ext, :extension),
|
|
335
|
+
:metanorma_extension)]
|
|
336
|
+
.filter_map { |mnx| val(mnx, :unitsml) }.first
|
|
337
|
+
return [] unless root
|
|
338
|
+
|
|
339
|
+
dimensions = dimension_vectors(root)
|
|
340
|
+
quantity_kinds = dimension_quantity_kinds(root)
|
|
341
|
+
pairs = vals(val(root, :unit_set), :unit).map do |unit|
|
|
342
|
+
[unit, unit_entry(unit, dimensions, quantity_kinds)]
|
|
343
|
+
end
|
|
344
|
+
entries = pairs.map(&:last)
|
|
345
|
+
by_id = entries.to_h { |e| [e.id, e] }
|
|
346
|
+
prefixes = prefix_symbols(root)
|
|
347
|
+
pairs.each do |unit, entry|
|
|
348
|
+
expr = si_expression(unit, by_id, prefixes)
|
|
349
|
+
entry.si_expression = expr if expr
|
|
350
|
+
end
|
|
351
|
+
@units_by_symbol = entries.each_with_object({}) do |e, h|
|
|
352
|
+
h[e.symbol] = e.id if e.symbol
|
|
353
|
+
end
|
|
354
|
+
@unitsml = entries
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def unit_entry(unit, dimensions, quantity_kinds)
|
|
358
|
+
url = val(unit, :dimension_url).to_s.sub("#", "")
|
|
359
|
+
Mko::Units::Entry.new(
|
|
360
|
+
id: val(unit, :id),
|
|
361
|
+
symbol: html_symbol(unit),
|
|
362
|
+
name: scalar(val(unit, :unit_name)),
|
|
363
|
+
quantity_kind: quantity_kinds[url],
|
|
364
|
+
dimension_url: url.empty? ? nil : url,
|
|
365
|
+
dimension: dimensions[url],
|
|
366
|
+
)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# The display symbol: the HTML-typed UnitSymbol, else the first.
|
|
370
|
+
# Composite symbols carry XML whitespace from pretty-printing —
|
|
371
|
+
# squashed, never significant.
|
|
372
|
+
def html_symbol(unit)
|
|
373
|
+
symbols = vals(unit, :unit_symbol)
|
|
374
|
+
pick = symbols.find { |s| val(s, :type) == "HTML" } || symbols.first
|
|
375
|
+
return nil unless pick
|
|
376
|
+
|
|
377
|
+
text = vals(pick, :text).map { |t| scalar(t).to_s.strip }.join(" ")
|
|
378
|
+
text = text.gsub(/\s+/, " ").strip
|
|
379
|
+
text.empty? ? Document::PlainText.call(pick) : text
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def dimension_vectors(root)
|
|
383
|
+
vals(val(root, :dimension_set), :dimension)
|
|
384
|
+
.to_h do |dim|
|
|
385
|
+
[val(dim, :id), Mko::Units.vectorize(
|
|
386
|
+
DIMENSION_SYMBOLS.filter_map do |attr, sym|
|
|
387
|
+
part = val(dim, attr) or next
|
|
388
|
+
[sym, val(part, :power_numerator),
|
|
389
|
+
val(part, :power_denominator)]
|
|
390
|
+
end,
|
|
391
|
+
)]
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Quantity kinds keyed by dimension URL: a unit's kind is the
|
|
396
|
+
# name of the quantity with the same dimension.
|
|
397
|
+
def dimension_quantity_kinds(root)
|
|
398
|
+
vals(val(root, :quantity_set), :quantity)
|
|
399
|
+
.each_with_object({}) do |q, h|
|
|
400
|
+
url = val(q, :dimension_url).to_s.sub("#", "")
|
|
401
|
+
name = vals(q, :quantity_name).map { |n| scalar(n) }
|
|
402
|
+
.reject(&:empty?).first
|
|
403
|
+
h[url] ||= name if name && !url.empty?
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def prefix_symbols(root)
|
|
408
|
+
vals(val(root, :prefix_set), :prefix)
|
|
409
|
+
.to_h do |p|
|
|
410
|
+
[val(p, :id), vals(p, :prefix_symbol)
|
|
411
|
+
.map { |s| scalar(s) }.join]
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# The unit's composition as the source enumerates it: root-unit
|
|
416
|
+
# symbols with prefixes and powers, resolved within the register.
|
|
417
|
+
def si_expression(unit, by_id, prefixes)
|
|
418
|
+
parts = vals(val(unit, :root_units), :enumerated_root_unit)
|
|
419
|
+
.filter_map do |eru|
|
|
420
|
+
sym = by_id[val(eru, :unit)]&.symbol or next
|
|
421
|
+
sym = "#{prefixes[val(eru, :prefix)]}#{sym}"
|
|
422
|
+
power = val(eru, :power_numerator)
|
|
423
|
+
power && power != 1 ? "#{sym}^#{power}" : sym
|
|
424
|
+
end
|
|
425
|
+
parts.empty? ? nil : parts.join("·")
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# -- identity ----------------------------------------------------
|
|
429
|
+
|
|
430
|
+
# Identity comes from the native pubid parser first (one parser,
|
|
431
|
+
# every publisher it covers); the series-letter regex remains as
|
|
432
|
+
# the fallback for publishers pubid does not model. Nil-safe: an unparseable canonical yields nils (fields absent in
|
|
433
|
+
# JSON), never a crash — unknown shapes stay visible, not fatal.
|
|
434
|
+
def parse_identity(canonical)
|
|
435
|
+
native = Document::NativeModels.pubid_identity(canonical)
|
|
436
|
+
return native if native
|
|
437
|
+
|
|
438
|
+
m = canonical.to_s.match(/\A(?:[A-Z][A-Za-z0-9&-]*\s+)?([A-Z])\s*(\d+)(?:-(\d+|[A-Za-z][A-Za-z0-9]*))?\b/)
|
|
439
|
+
m ? [m[1], m[2], m[3]] : []
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def build_identity(model)
|
|
443
|
+
bib = val(model, :bibdata)
|
|
444
|
+
ids = docids(bib)
|
|
445
|
+
canonical = ids.find { |d| val(d, :primary) && docid_text(d) }
|
|
446
|
+
&.then { |d| docid_text(d) } ||
|
|
447
|
+
ids.reject { |d| docid_is_urn?(d) }
|
|
448
|
+
.filter_map { |d| docid_text(d) }.first
|
|
449
|
+
series, number, part = parse_identity(canonical)
|
|
450
|
+
Schema::Document.new(
|
|
451
|
+
ids: Schema::Ids.new(
|
|
452
|
+
canonical: canonical,
|
|
453
|
+
short: Mko.slug(canonical),
|
|
454
|
+
series: series,
|
|
455
|
+
number: number,
|
|
456
|
+
part: part,
|
|
457
|
+
docid: ids.filter_map { |d| docid_text(d) },
|
|
458
|
+
urn: ids.select { |d| docid_is_urn?(d) }
|
|
459
|
+
.filter_map { |d| docid_text(d) },
|
|
460
|
+
),
|
|
461
|
+
flavor: @flavor,
|
|
462
|
+
doctype: doctype_text(bib),
|
|
463
|
+
titles: build_titles(bib),
|
|
464
|
+
edition: scalar(val(bib, :edition)),
|
|
465
|
+
languages: vals(bib, :language).filter_map { |l| scalar(l) },
|
|
466
|
+
status: build_status(bib),
|
|
467
|
+
derived_status: derived_status(build_relations(bib)),
|
|
468
|
+
dates: build_dates(bib),
|
|
469
|
+
relations: build_relations(bib),
|
|
470
|
+
structure: @structure,
|
|
471
|
+
)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def scalar(value)
|
|
475
|
+
return nil if value.nil?
|
|
476
|
+
return value.map { |v| scalar(v) }.join(" ") if value.is_a?(Array)
|
|
477
|
+
return value.to_s unless serializable?(value)
|
|
478
|
+
|
|
479
|
+
Document::PlainText.call(value)
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# Flavors rename some metadata attributes (e.g. the iso tree uses
|
|
483
|
+
# titles/doc_identifier). Prefer the base name; fall back by name.
|
|
484
|
+
def val_any(obj, *names)
|
|
485
|
+
names.each do |n|
|
|
486
|
+
v = val(obj, n)
|
|
487
|
+
return v unless v.nil?
|
|
488
|
+
end
|
|
489
|
+
nil
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# Doctype: base tree is a scalar; iso-style trees nest typed doctype
|
|
493
|
+
# elements under bibdata extensions.
|
|
494
|
+
def doctype_text(bib)
|
|
495
|
+
dt = val_any(bib, :doctype)
|
|
496
|
+
dt = val(val(bib, :ext), :doctype_element) if dt.nil?
|
|
497
|
+
return nil if dt.nil?
|
|
498
|
+
|
|
499
|
+
dt = Array(dt).first if dt.is_a?(Array)
|
|
500
|
+
abbr = val(dt, :abbreviation)
|
|
501
|
+
return abbr.to_s unless abbr.to_s.empty?
|
|
502
|
+
|
|
503
|
+
value = val(dt, :value)
|
|
504
|
+
return value.to_s unless value.to_s.empty?
|
|
505
|
+
|
|
506
|
+
scalar(dt)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def derived_status(relations)
|
|
510
|
+
has_successor = relations.any? do |r|
|
|
511
|
+
SUCCESSOR_TYPES.include?(r.type) && r.to && !r.to.empty?
|
|
512
|
+
end
|
|
513
|
+
has_successor ? "superseded" : nil
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
def build_titles(bib)
|
|
517
|
+
vals_any(bib, :title, :titles).map do |t|
|
|
518
|
+
Schema::TitleEntry.new(lang: val(t, :language)&.to_s,
|
|
519
|
+
text: Document::PlainText.call(t))
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def build_status(bib)
|
|
524
|
+
st = val(bib, :status)
|
|
525
|
+
return nil unless st
|
|
526
|
+
|
|
527
|
+
stage = Array(val(st, :stage)).first
|
|
528
|
+
Schema::StatusInfo.new(
|
|
529
|
+
stage: stage ? scalar(stage) : nil,
|
|
530
|
+
substage: scalar(val(st, :substage)),
|
|
531
|
+
abbreviation: stage ? val(stage, :abbreviation) : nil,
|
|
532
|
+
)
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
def build_dates(bib)
|
|
536
|
+
vals(bib, :date).map do |d|
|
|
537
|
+
Schema::DateEntry.new(type: val(d, :type),
|
|
538
|
+
on: scalar(val(d, :on)))
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
def build_relations(bib)
|
|
543
|
+
vals(bib, :relation).map do |r|
|
|
544
|
+
item = val(r, :bibitem)
|
|
545
|
+
to = docids(item).filter_map { |d| docid_text(d) }.first
|
|
546
|
+
Schema::RelationEntry.new(type: val(r, :type), to: to)
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def build_identifiers(model)
|
|
551
|
+
infos = Document::NativeModels.pubid_identifiers(model).map do |e|
|
|
552
|
+
pubid = e[:pubid] && JSON.parse(e[:pubid].to_json)
|
|
553
|
+
Schema::IdentifierInfo.new(
|
|
554
|
+
original: e[:original], type: e[:type],
|
|
555
|
+
primary: e[:primary], parsed: pubid
|
|
556
|
+
)
|
|
557
|
+
end
|
|
558
|
+
Schema::Identifiers.new(identifiers: infos)
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
def vals_any(obj, *names)
|
|
562
|
+
names.filter_map { |n| val(obj, n) }.flat_map { |v| Array(v) }
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
def docid_is_urn?(docid)
|
|
566
|
+
val(docid, :type) == "URN" || docid_text(docid).to_s.start_with?("urn:")
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
# -- the walk ----------------------------------------------------
|
|
570
|
+
|
|
571
|
+
# The iso tree declares Term entries as :term (so a terms
|
|
572
|
+
# section is recognizable by that declaration); the standoc tree
|
|
573
|
+
# maps them to :terms. The 0.4.x clause models declare :term
|
|
574
|
+
# too (clauses may embed term containers), so the declaration
|
|
575
|
+
# alone misclassifies every ISO clause as a terms section —
|
|
576
|
+
# require actual term entries.
|
|
577
|
+
def terms_section?(obj)
|
|
578
|
+
serializable?(obj) && obj.class.attributes.key?(:term) &&
|
|
579
|
+
!vals(obj, :term).empty?
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def walk_child_section(section, type: "clause")
|
|
583
|
+
if terms_section?(section)
|
|
584
|
+
walk_terms_section(section)
|
|
585
|
+
else
|
|
586
|
+
walk_section(section, type: type)
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def walk_root(model)
|
|
591
|
+
sections = val(model, :sections)
|
|
592
|
+
walk_container(sections) { |s| walk_child_section(s) }
|
|
593
|
+
preface = val(model, :preface)
|
|
594
|
+
walk_container(preface) { |s| walk_child_section(s, type: "clause") }
|
|
595
|
+
vals(model, :annex).each { |a| walk_section(a, type: "annex") }
|
|
596
|
+
walk_bibliography(model)
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
# Sections scope the element-level language (#53 item 3): the
|
|
600
|
+
# section's resolution — its own xml:lang the day the models map
|
|
601
|
+
# it, else its own prose, else the enclosing scope — applies to
|
|
602
|
+
# every unit emitted inside.
|
|
603
|
+
def walk_section(section, type: "clause", parent: nil, breadcrumb: [])
|
|
604
|
+
text = section_text(section)
|
|
605
|
+
restore_lang = push_element_lang(section, text: text)
|
|
606
|
+
begin
|
|
607
|
+
anchor = element_anchor(section)
|
|
608
|
+
number = @numbers[anchor] || section_autonum(section)
|
|
609
|
+
|
|
610
|
+
title = Document::PlainText.call(val(section, :title))
|
|
611
|
+
unit = emit_unit(
|
|
612
|
+
type: type, anchor: anchor, number: number, title: title,
|
|
613
|
+
parent: parent, breadcrumb: breadcrumb,
|
|
614
|
+
obligation: val(section, :obligation),
|
|
615
|
+
text: text, model: section
|
|
616
|
+
)
|
|
617
|
+
crumb = breadcrumb + [number ? "#{number} #{title}" : title]
|
|
618
|
+
node = Schema::StructureNode.new(id: unit.id, number: number,
|
|
619
|
+
title: title)
|
|
620
|
+
@structure << node
|
|
621
|
+
children = walk_blocks(section, unit.id, crumb)
|
|
622
|
+
vals(section, :subsections).each do |sub|
|
|
623
|
+
child = walk_section(sub, parent: unit.id, breadcrumb: crumb)
|
|
624
|
+
node.children << child if child
|
|
625
|
+
children << child if child
|
|
626
|
+
end
|
|
627
|
+
vals(section, :clause).each do |sub|
|
|
628
|
+
child = walk_section(sub, parent: unit.id, breadcrumb: crumb)
|
|
629
|
+
node.children << child if child
|
|
630
|
+
children << child if child
|
|
631
|
+
end
|
|
632
|
+
vals(section, :terms).each do |tsec|
|
|
633
|
+
ts_unit = walk_terms_section(tsec, parent: unit.id,
|
|
634
|
+
breadcrumb: crumb)
|
|
635
|
+
children << ts_unit if ts_unit
|
|
636
|
+
end
|
|
637
|
+
finalize_section(unit,
|
|
638
|
+
ordered_child_ids(section, children.map(&:id)))
|
|
639
|
+
node
|
|
640
|
+
ensure
|
|
641
|
+
@lang = restore_lang
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def walk_terms_section(tsec, parent: nil, breadcrumb: [])
|
|
646
|
+
text = section_text(tsec)
|
|
647
|
+
restore_lang = push_element_lang(tsec, text: text)
|
|
648
|
+
begin
|
|
649
|
+
anchor = element_anchor(tsec)
|
|
650
|
+
number = @numbers[anchor] || section_autonum(tsec)
|
|
651
|
+
title = Document::PlainText.call(val(tsec, :title))
|
|
652
|
+
unit = emit_unit(
|
|
653
|
+
type: "clause", anchor: anchor, number: number, title: title,
|
|
654
|
+
parent: parent, breadcrumb: breadcrumb,
|
|
655
|
+
obligation: val(tsec, :obligation), text: text,
|
|
656
|
+
model: tsec
|
|
657
|
+
)
|
|
658
|
+
crumb = breadcrumb + [title]
|
|
659
|
+
children = term_entries(tsec).map do |t|
|
|
660
|
+
walk_term(t, parent: unit.id, breadcrumb: crumb,
|
|
661
|
+
section: tsec)
|
|
662
|
+
end
|
|
663
|
+
nested_terms_sections(tsec).each do |nested|
|
|
664
|
+
children << walk_terms_section(nested, parent: unit.id,
|
|
665
|
+
breadcrumb: crumb)
|
|
666
|
+
end
|
|
667
|
+
vals_any(tsec, :paragraphs, :p).each do |p|
|
|
668
|
+
children << emit_unit(type: "note", anchor: element_anchor(p),
|
|
669
|
+
parent: unit.id, breadcrumb: crumb,
|
|
670
|
+
text: Document::PlainText.call(p), model: p)
|
|
671
|
+
end
|
|
672
|
+
finalize_section(unit, ordered_child_ids(tsec, children.map(&:id)))
|
|
673
|
+
unit
|
|
674
|
+
ensure
|
|
675
|
+
@lang = restore_lang
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
def walk_term(term, parent:, breadcrumb:, section: nil)
|
|
680
|
+
anchor = element_anchor(term, section)
|
|
681
|
+
number = @numbers[anchor]
|
|
682
|
+
designations = vals(term, :preferred)
|
|
683
|
+
.map { |d| Document::PlainText.call(d) }.reject(&:empty?)
|
|
684
|
+
# both trees declare the synonym attrs as :admitted/:deprecates
|
|
685
|
+
admitted = vals(term, :admitted)
|
|
686
|
+
.map { |d| Document::PlainText.call(d) }.reject(&:empty?)
|
|
687
|
+
deprecated = vals(term, :deprecates)
|
|
688
|
+
.map { |d| Document::PlainText.call(d) }.reject(&:empty?)
|
|
689
|
+
definition = Document::PlainText.call(val(term, :definition))
|
|
690
|
+
sources = vals(term, :source).map do |src|
|
|
691
|
+
Schema::TermSourceEntry.new(
|
|
692
|
+
citeas: vals(src, :origin).first&.citeas,
|
|
693
|
+
)
|
|
694
|
+
end
|
|
695
|
+
payload = Schema::TermPayload.new(
|
|
696
|
+
concept: anchor, designations: designations,
|
|
697
|
+
admitted: admitted, deprecated: deprecated,
|
|
698
|
+
definition: definition, sources: sources
|
|
699
|
+
)
|
|
700
|
+
unit = emit_unit(
|
|
701
|
+
type: "term", anchor: anchor, number: number,
|
|
702
|
+
title: designations.first, parent: parent,
|
|
703
|
+
breadcrumb: breadcrumb, text: definition, model: term,
|
|
704
|
+
payload: payload
|
|
705
|
+
)
|
|
706
|
+
@edges << Schema::Edge.new(
|
|
707
|
+
from: unit.id, to: "concept:#{anchor}", kind: "defines",
|
|
708
|
+
)
|
|
709
|
+
sources.filter_map(&:citeas).each do |citeas|
|
|
710
|
+
cited = Document::PlainText.call(citeas)
|
|
711
|
+
next if cited.empty?
|
|
712
|
+
|
|
713
|
+
@edges << Schema::Edge.new(
|
|
714
|
+
from: unit.id, to: "ext:#{cited}", kind: "cites",
|
|
715
|
+
)
|
|
716
|
+
end
|
|
717
|
+
unit
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def section_text(section)
|
|
721
|
+
collections = SECTION_PROSE_SOURCES.each_with_object({}) do |(_name, attr), h|
|
|
722
|
+
h[attr] = vals(section, attr)
|
|
723
|
+
end
|
|
724
|
+
indices = Hash.new(0)
|
|
725
|
+
parts = []
|
|
726
|
+
# element_order is nil on programmatically built (unparsed)
|
|
727
|
+
# models — the declaration-order fallback below covers them
|
|
728
|
+
Array(section.element_order).each do |el|
|
|
729
|
+
next unless el.is_a?(Lutaml::Xml::Element)
|
|
730
|
+
|
|
731
|
+
attr = SECTION_PROSE_SOURCES[el.name.to_s] or next
|
|
732
|
+
item = collections[attr][indices[attr]]
|
|
733
|
+
indices[attr] += 1
|
|
734
|
+
text = Document::PlainText.call(item) if item
|
|
735
|
+
parts << text if text && !text.empty?
|
|
736
|
+
end
|
|
737
|
+
# element_order unavailable: fall back to declaration order
|
|
738
|
+
if parts.empty?
|
|
739
|
+
parts = collections.values.flatten.filter_map do |item|
|
|
740
|
+
text = Document::PlainText.call(item)
|
|
741
|
+
text unless text.empty?
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
parts.join("\n")
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
def walk_blocks(section, parent_id, breadcrumb)
|
|
748
|
+
BLOCK_SOURCES.flat_map do |type, attr|
|
|
749
|
+
vals(section, attr)
|
|
750
|
+
.flat_map { |block| Array(send("walk_#{type}", block, parent_id, breadcrumb)) }
|
|
751
|
+
end + walk_requirements(section, parent_id, breadcrumb)
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
def walk_table(table, parent_id, breadcrumb)
|
|
755
|
+
head_row = vals(val(table, :thead), :tr).first
|
|
756
|
+
columns = vals(head_row, :th).map do |cell|
|
|
757
|
+
Schema::TableColumn.new(label: Document::PlainText.call(cell))
|
|
758
|
+
end
|
|
759
|
+
rows = vals(val(table, :tbody), :tr).map do |tr|
|
|
760
|
+
vals(tr, :td).map { |cell| Document::PlainText.call(cell) }.join(" | ")
|
|
761
|
+
end
|
|
762
|
+
payload = Schema::TablePayload.new(
|
|
763
|
+
caption: Document::PlainText.call(val(table, :name)),
|
|
764
|
+
columns: columns, rows: rows,
|
|
765
|
+
mirror: Document::NativeModels.mirror_object(table)
|
|
766
|
+
)
|
|
767
|
+
emit_unit(
|
|
768
|
+
type: "table", anchor: element_anchor(table),
|
|
769
|
+
number: val(table, :autonum),
|
|
770
|
+
title: payload.caption, parent: parent_id,
|
|
771
|
+
breadcrumb: breadcrumb, text: payload.embed_text,
|
|
772
|
+
model: table, payload: payload
|
|
773
|
+
)
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
# Image maps: the wrapped figures are the content — each emits
|
|
777
|
+
# as a figure unit (caption, image, native mirror); the map's
|
|
778
|
+
# link geometry travels in the mirror object.
|
|
779
|
+
def walk_svgmap(svgmap, parent_id, breadcrumb)
|
|
780
|
+
vals(svgmap, :figure).map do |figure|
|
|
781
|
+
walk_figure(figure, parent_id, breadcrumb)
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
def walk_imagemap(imagemap, parent_id, breadcrumb)
|
|
786
|
+
vals(imagemap, :figure).map do |figure|
|
|
787
|
+
walk_figure(figure, parent_id, breadcrumb)
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
def walk_figure(figure, parent_id, breadcrumb)
|
|
792
|
+
caption = Document::PlainText.call(val(figure, :name))
|
|
793
|
+
img = val(figure, :image)
|
|
794
|
+
uri = val(figure, :source) || val(img, :source) ||
|
|
795
|
+
val(img, :filename)
|
|
796
|
+
alt = val(figure, :alt) || val(img, :alt)
|
|
797
|
+
# retrievability invariant (#53 item 1): an uncaptioned figure
|
|
798
|
+
# still carries retrievable text — its alt text
|
|
799
|
+
retrievable = [caption, alt].compact.reject { |s| s.to_s.empty? }
|
|
800
|
+
payload = Schema::FigurePayload.new(
|
|
801
|
+
alt: alt, uri: uri,
|
|
802
|
+
asset: @assets&.attach(uri),
|
|
803
|
+
caption: caption,
|
|
804
|
+
mirror: Document::NativeModels.mirror_object(figure)
|
|
805
|
+
)
|
|
806
|
+
emit_unit(
|
|
807
|
+
type: "figure", anchor: element_anchor(figure),
|
|
808
|
+
number: val(figure, :autonum), title: caption,
|
|
809
|
+
parent: parent_id, breadcrumb: breadcrumb,
|
|
810
|
+
text: retrievable.join(". "), model: figure, payload: payload
|
|
811
|
+
)
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
def walk_formula(formula, parent_id, breadcrumb)
|
|
815
|
+
stem = val(formula, :stem)
|
|
816
|
+
asciimath = val(stem, :asciimath)&.value
|
|
817
|
+
mathml = mathml_of(stem)
|
|
818
|
+
description = Document::PlainText.call(val(formula, :name))
|
|
819
|
+
# Native math object: Plurimath's own serializations (it has no
|
|
820
|
+
# data to_json; to_* are the native forms). Derived encodings
|
|
821
|
+
# are marked with their converter — never canonical (#55).
|
|
822
|
+
plurimath = Document::NativeModels.plurimath_formula(formula)
|
|
823
|
+
payload = Schema::FormulaPayload.new(
|
|
824
|
+
asciimath: asciimath, mathml: mathml,
|
|
825
|
+
units: register_refs(asciimath),
|
|
826
|
+
latex: derived_form(plurimath, :to_latex),
|
|
827
|
+
omml: derived_form(plurimath, :to_omml),
|
|
828
|
+
description: description
|
|
829
|
+
)
|
|
830
|
+
emit_unit(
|
|
831
|
+
type: "formula", anchor: element_anchor(formula),
|
|
832
|
+
number: val(formula, :autonum), title: description,
|
|
833
|
+
parent: parent_id, breadcrumb: breadcrumb,
|
|
834
|
+
text: [asciimath, description].compact.join(" — "),
|
|
835
|
+
model: formula, payload: payload
|
|
836
|
+
)
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
def derived_form(plurimath, serializer)
|
|
840
|
+
form = plurimath&.public_send(serializer)
|
|
841
|
+
form && Schema::FormulaPayload::DerivedForm.new(
|
|
842
|
+
form: form, converter: "plurimath",
|
|
843
|
+
)
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
# Units a formula uses: the unitsml() tokens of its AsciiMath,
|
|
847
|
+
# resolved against the bundle register by symbol — so consumers
|
|
848
|
+
# compare quantity kinds, never unit strings (#55).
|
|
849
|
+
def register_refs(asciimath)
|
|
850
|
+
asciimath.to_s.scan(/unitsml\(([^)]+)\)/)
|
|
851
|
+
.map(&:first).filter_map { |sym| @units_by_symbol[sym] }
|
|
852
|
+
.uniq
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
def mathml_of(stem)
|
|
856
|
+
math = val(stem, :math)
|
|
857
|
+
return nil unless math
|
|
858
|
+
|
|
859
|
+
math.to_xml
|
|
860
|
+
rescue StandardError
|
|
861
|
+
nil
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
def walk_note(note, parent_id, breadcrumb)
|
|
865
|
+
emit_unit(
|
|
866
|
+
type: "note", anchor: element_anchor(note), parent: parent_id,
|
|
867
|
+
breadcrumb: breadcrumb, text: Document::PlainText.call(note), model: note
|
|
868
|
+
)
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
def walk_example(example, parent_id, breadcrumb)
|
|
872
|
+
emit_unit(
|
|
873
|
+
type: "example", anchor: element_anchor(example),
|
|
874
|
+
parent: parent_id, breadcrumb: breadcrumb,
|
|
875
|
+
text: Document::PlainText.call(example), model: example
|
|
876
|
+
)
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
def walk_sourcecode(block, parent_id, breadcrumb)
|
|
880
|
+
emit_unit(
|
|
881
|
+
type: "sourcecode", anchor: element_anchor(block),
|
|
882
|
+
number: val(block, :autonum),
|
|
883
|
+
title: Document::PlainText.call(val(block, :name)),
|
|
884
|
+
parent: parent_id, breadcrumb: breadcrumb,
|
|
885
|
+
text: Document::PlainText.call(block), model: block
|
|
886
|
+
)
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
def walk_requirements(section, parent_id, breadcrumb)
|
|
890
|
+
%i[requirement recommendation permission].flat_map do |attr|
|
|
891
|
+
vals(section, attr)
|
|
892
|
+
.map { |req| walk_requirement(req, parent_id, breadcrumb) }
|
|
893
|
+
end
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
def walk_requirement(req, parent_id, breadcrumb)
|
|
897
|
+
payload = requirement_payload(req)
|
|
898
|
+
unit = emit_unit(
|
|
899
|
+
type: "requirement", anchor: element_anchor(req),
|
|
900
|
+
number: val(req, :autonum), title: payload.identifier,
|
|
901
|
+
parent: parent_id, breadcrumb: breadcrumb,
|
|
902
|
+
obligation: val(req, :obligation), text: payload.statement,
|
|
903
|
+
model: req, payload: payload
|
|
904
|
+
)
|
|
905
|
+
klass = requirement_class(req)
|
|
906
|
+
if klass
|
|
907
|
+
@edges << Schema::Edge.new(
|
|
908
|
+
from: unit.id, to: "class:#{klass}", kind: "class_of",
|
|
909
|
+
)
|
|
910
|
+
end
|
|
911
|
+
vals(req, :requirement).each do |sub|
|
|
912
|
+
walk_requirement(sub, unit.id, breadcrumb)
|
|
913
|
+
end
|
|
914
|
+
unit
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
def requirement_payload(req)
|
|
918
|
+
statement = vals(req, :description).map { |d| Document::PlainText.call(d) }
|
|
919
|
+
.reject(&:empty?).join("\n")
|
|
920
|
+
Schema::RequirementPayload.new(
|
|
921
|
+
identifier: val(req, :anchor) || val(req, :id),
|
|
922
|
+
klass: requirement_class(req),
|
|
923
|
+
obligation: val(req, :obligation),
|
|
924
|
+
subject: val(req, :subject), statement: statement,
|
|
925
|
+
inherits: vals(req, :inherit).filter_map do |i|
|
|
926
|
+
text = Array(val(i, :text)).join
|
|
927
|
+
next text unless text.empty?
|
|
928
|
+
|
|
929
|
+
val(Array(val(i, :eref)).first, :citeas)
|
|
930
|
+
end
|
|
931
|
+
)
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
def requirement_class(req)
|
|
935
|
+
vals(req, :classification).find { |c| val(c, :tag) == "class" }
|
|
936
|
+
.then { |c| c && Document::PlainText.call(val(c, :value)) }
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
def walk_bibliography(model)
|
|
940
|
+
bibs = val(model, :bibliography)
|
|
941
|
+
Array(bibs).each { |bib_section| walk_references_section(bib_section) }
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
def walk_references_section(bib_section)
|
|
945
|
+
vals(bib_section, :references).each do |refs|
|
|
946
|
+
title = Document::PlainText.call(val(refs, :title))
|
|
947
|
+
section_unit = emit_unit(
|
|
948
|
+
type: "clause", anchor: element_anchor(refs), title: title,
|
|
949
|
+
parent: nil, breadcrumb: [], text: nil, model: refs
|
|
950
|
+
)
|
|
951
|
+
# The base tree maps entries as :bibitem; the standoc/iso
|
|
952
|
+
# tree nests BibliographicItems in :references.
|
|
953
|
+
items = vals(refs, :bibitem)
|
|
954
|
+
items = vals(refs, :references) if items.empty?
|
|
955
|
+
children = items.map do |item|
|
|
956
|
+
key = val(item, :anchor) || val(item, :id)
|
|
957
|
+
cited = docid_text(vals(item, :docidentifier).first) ||
|
|
958
|
+
Document::PlainText.call(val(item, :formatted_ref))
|
|
959
|
+
payload = Schema::ReferencePayload.new(key: key, cited: cited)
|
|
960
|
+
unit = emit_unit(
|
|
961
|
+
type: "reference", anchor: key, title: cited,
|
|
962
|
+
parent: section_unit.id, breadcrumb: [title].compact,
|
|
963
|
+
text: cited, model: item, payload: payload
|
|
964
|
+
)
|
|
965
|
+
if cited && !cited.empty?
|
|
966
|
+
@edges << Schema::Edge.new(
|
|
967
|
+
from: unit.id, to: "ext:#{cited}", kind: "cites",
|
|
968
|
+
)
|
|
969
|
+
end
|
|
970
|
+
unit
|
|
971
|
+
end
|
|
972
|
+
finalize_section(section_unit, children.map(&:id))
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
# -- unit assembly -------------------------------------------------
|
|
977
|
+
|
|
978
|
+
# Document order, not walk order (#56): children are the ids of
|
|
979
|
+
# this section's direct units, interleaved as the author wrote
|
|
980
|
+
# them. Falls back to emission order when element_order is not
|
|
981
|
+
# available; unmapped stragglers append so no child is lost.
|
|
982
|
+
def ordered_child_ids(section, emitted)
|
|
983
|
+
return emitted if emitted.empty?
|
|
984
|
+
|
|
985
|
+
pools = SECTION_CHILD_SOURCES.each_with_object({}) do |(name, attrs), h|
|
|
986
|
+
h[name] = { list: attrs.flat_map { |a| vals(section, a) }, idx: 0 }
|
|
987
|
+
end
|
|
988
|
+
ordered = []
|
|
989
|
+
Array(section.element_order).each do |el|
|
|
990
|
+
next unless el.is_a?(Lutaml::Xml::Element)
|
|
991
|
+
|
|
992
|
+
pool = pools[el.name.to_s] or next
|
|
993
|
+
item = pool[:list][pool[:idx]]
|
|
994
|
+
pool[:idx] += 1
|
|
995
|
+
unit = item && @element_units[item]
|
|
996
|
+
ordered << unit.id if unit
|
|
997
|
+
end
|
|
998
|
+
return emitted if ordered.empty?
|
|
999
|
+
|
|
1000
|
+
ordered + (emitted - ordered)
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
# The section contract (#56): coverage payload, retrievable text,
|
|
1004
|
+
# and a hash over the finalized content. Runs after the section's
|
|
1005
|
+
# children are walked — summaries and membership are only known
|
|
1006
|
+
# then.
|
|
1007
|
+
def finalize_section(unit, child_ids)
|
|
1008
|
+
children = child_ids.filter_map { |id| @units_by_id[id] }
|
|
1009
|
+
payload = Schema::SectionPayload.new(
|
|
1010
|
+
summary: section_summary(unit, children), children: child_ids,
|
|
1011
|
+
)
|
|
1012
|
+
# Retrievability invariant: a container section with no direct
|
|
1013
|
+
# prose still carries retrievable text — its summary
|
|
1014
|
+
unit.text = payload.summary if unit.text.to_s.empty?
|
|
1015
|
+
unit.payload = payload_hash(payload)
|
|
1016
|
+
unit.hash = content_hash(unit.text, payload)
|
|
1017
|
+
unit
|
|
1018
|
+
end
|
|
1019
|
+
|
|
1020
|
+
# Deterministic composition — title plus the covered sub-clauses.
|
|
1021
|
+
# Never model-inferred: consumers may build their own LLM
|
|
1022
|
+
# summaries, but the shipped default requires none.
|
|
1023
|
+
def section_summary(unit, children)
|
|
1024
|
+
head = [unit.number, unit.title].compact
|
|
1025
|
+
.reject { |s| s.to_s.empty? }.join(" ")
|
|
1026
|
+
covered = children.filter_map do |c|
|
|
1027
|
+
parts = [c.number, c.title].compact.reject { |s| s.to_s.empty? }
|
|
1028
|
+
parts.empty? ? nil : parts.join(" ")
|
|
1029
|
+
end
|
|
1030
|
+
return head if covered.empty?
|
|
1031
|
+
|
|
1032
|
+
[head.empty? ? nil : "#{head}.", "Covers: #{covered.join('; ')}."]
|
|
1033
|
+
.compact.join(" ")
|
|
1034
|
+
end
|
|
1035
|
+
|
|
1036
|
+
# rubocop:disable-next Metrics/ParameterLists
|
|
1037
|
+
def emit_unit(type:, anchor:, parent:, breadcrumb:, text:, model:,
|
|
1038
|
+
payload: nil, number: nil, title: nil, obligation: nil)
|
|
1039
|
+
anchor ||= content_anchor(model, type)
|
|
1040
|
+
id = "u:#{anchor}"
|
|
1041
|
+
cite_as = citation_anchor(anchor: anchor, number: number,
|
|
1042
|
+
parent: parent)
|
|
1043
|
+
unit = Schema::Unit.new(
|
|
1044
|
+
id: id, type: type, anchor: anchor, number: number,
|
|
1045
|
+
ordinal: @ordinal, cite_as: cite_as, title: title,
|
|
1046
|
+
parent: parent, breadcrumb: breadcrumb.compact,
|
|
1047
|
+
obligation: obligation, lang: @lang.lang,
|
|
1048
|
+
lang_source: @lang.source, text: text,
|
|
1049
|
+
payload: payload_hash(payload), hash: content_hash(text, payload)
|
|
1050
|
+
)
|
|
1051
|
+
@ordinal += 1
|
|
1052
|
+
@units << unit
|
|
1053
|
+
@units_by_id[id] = unit
|
|
1054
|
+
@element_units[model] = unit if model
|
|
1055
|
+
if parent
|
|
1056
|
+
@edges << Schema::Edge.new(from: id, to: parent, kind: "part_of")
|
|
1057
|
+
end
|
|
1058
|
+
unit
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
# Embedded objects cite their containing clause: a table in §4.1.2
|
|
1062
|
+
# is cited as 4.1.2, not as its own anchor. Top-level sections and
|
|
1063
|
+
# parentless units cite their own number/anchor.
|
|
1064
|
+
def citation_anchor(anchor:, number:, parent:)
|
|
1065
|
+
own = number || anchor
|
|
1066
|
+
if parent && @units_by_id
|
|
1067
|
+
pu = @units_by_id[parent]
|
|
1068
|
+
if pu && %w[clause annex].include?(pu.type)
|
|
1069
|
+
return (pu.number || pu.anchor || own).to_s
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
own&.to_s
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
def payload_hash(payload)
|
|
1076
|
+
return nil unless payload
|
|
1077
|
+
|
|
1078
|
+
JSON.parse(payload.to_json)
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
def content_hash(text, payload)
|
|
1082
|
+
basis = text.to_s + payload.to_json
|
|
1083
|
+
"sha256:#{Digest::SHA256.hexdigest(basis)[0, 16]}"
|
|
1084
|
+
end
|
|
1085
|
+
|
|
1086
|
+
def content_anchor(model, type)
|
|
1087
|
+
basis = "#{model.class.name}:#{type}"
|
|
1088
|
+
"h-#{Digest::SHA256.hexdigest(basis)[0, 10]}"
|
|
1089
|
+
end
|
|
1090
|
+
|
|
1091
|
+
# Semantic anchors (anchor="term-paddy") are the human-meaningful,
|
|
1092
|
+
# cross-render-stable identifiers; GUIDs are the last resort. The
|
|
1093
|
+
# presentation model repeats the same anchor, so numbering joins
|
|
1094
|
+
# survive the preference.
|
|
1095
|
+
def element_anchor(element, parent_section = nil)
|
|
1096
|
+
anchor = val(element, :anchor)
|
|
1097
|
+
return anchor if anchor && !anchor.empty?
|
|
1098
|
+
|
|
1099
|
+
id = val(element, :id)
|
|
1100
|
+
return id if id && !id.empty?
|
|
1101
|
+
|
|
1102
|
+
semx = val(element, :semx_id)
|
|
1103
|
+
return semx if semx && !semx.empty?
|
|
1104
|
+
|
|
1105
|
+
pid = val(parent_section, :id) || val(parent_section, :anchor)
|
|
1106
|
+
pid && "#{pid}-x#{@units.size + 1}"
|
|
1107
|
+
end
|
|
1108
|
+
end
|
|
1109
|
+
end
|
|
1110
|
+
end
|