metanorma-document 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CLAUDE.md +3 -2
- data/Rakefile +30 -5
- data/frontend/dist/app.css +1 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/package-lock.json +7 -505
- data/frontend/tailwind.config.js +5 -0
- data/lib/metanorma/csa_document/root.rb +27 -0
- data/lib/metanorma/csa_document.rb +9 -0
- data/lib/metanorma/document/cli.rb +52 -0
- data/lib/metanorma/document/components/ancillary_blocks/sourcecode_body.rb +14 -0
- data/lib/metanorma/document/components/inline/comma_element.rb +3 -0
- data/lib/metanorma/document/components/inline/enum_comma_element.rb +3 -0
- data/lib/metanorma/document/components/inline/eref_element.rb +4 -1
- data/lib/metanorma/document/components/inline/fmt_termsource_element.rb +4 -2
- data/lib/metanorma/document/components/inline/math_element.rb +13 -7
- data/lib/metanorma/document/components/inline/vocabulary.rb +4 -0
- data/lib/metanorma/document/components/multi_paragraph/admonition_block.rb +6 -1
- data/lib/metanorma/document/components/paragraphs/paragraph_block.rb +3 -0
- data/lib/metanorma/document/components/reference_elements/callout.rb +3 -2
- data/lib/metanorma/document/components/tables/table_cell.rb +3 -0
- data/lib/metanorma/document/elements/input.rb +44 -0
- data/lib/metanorma/document/elements.rb +1 -0
- data/lib/metanorma/document/relaton/address.rb +5 -0
- data/lib/metanorma/document/relaton/affiliation.rb +3 -0
- data/lib/metanorma/document/relaton/bib_item_size.rb +8 -9
- data/lib/metanorma/document/relaton/bib_item_type.rb +3 -0
- data/lib/metanorma/document/relaton/bibliographic_date.rb +5 -0
- data/lib/metanorma/document/relaton/contact_method.rb +5 -0
- data/lib/metanorma/document/relaton/contribution_info.rb +6 -2
- data/lib/metanorma/document/relaton/contributor.rb +4 -0
- data/lib/metanorma/document/relaton/contributor_role.rb +3 -0
- data/lib/metanorma/document/relaton/copyright_association.rb +3 -0
- data/lib/metanorma/document/relaton/copyright_owner.rb +3 -0
- data/lib/metanorma/document/relaton/date_time.rb +3 -0
- data/lib/metanorma/document/relaton/document_identifier.rb +4 -0
- data/lib/metanorma/document/relaton/document_relation.rb +8 -0
- data/lib/metanorma/document/relaton/document_status.rb +4 -0
- data/lib/metanorma/document/relaton/formatted_address.rb +4 -0
- data/lib/metanorma/document/relaton/full_name.rb +14 -3
- data/lib/metanorma/document/relaton/keyword_type.rb +3 -0
- data/lib/metanorma/document/relaton/locality_stack.rb +6 -9
- data/lib/metanorma/document/relaton/localized_name.rb +8 -5
- data/lib/metanorma/document/relaton/logo_element.rb +5 -0
- data/lib/metanorma/document/relaton/medium_type.rb +5 -16
- data/lib/metanorma/document/relaton/org_identifier.rb +2 -0
- data/lib/metanorma/document/relaton/org_subdivision.rb +2 -0
- data/lib/metanorma/document/relaton/org_subdivision_identifier.rb +2 -0
- data/lib/metanorma/document/relaton/organization.rb +3 -0
- data/lib/metanorma/document/relaton/person.rb +7 -1
- data/lib/metanorma/document/relaton/person_identifier.rb +3 -0
- data/lib/metanorma/document/relaton/place_type.rb +5 -0
- data/lib/metanorma/document/relaton/region_element.rb +3 -9
- data/lib/metanorma/document/relaton/relaton_collection.rb +2 -0
- data/lib/metanorma/document/relaton/series_type.rb +7 -0
- data/lib/metanorma/document/relaton/typed_note.rb +4 -0
- data/lib/metanorma/document/relaton/typed_title_string.rb +4 -0
- data/lib/metanorma/document/relaton/typed_uri.rb +3 -8
- data/lib/metanorma/document/relaton/validity_type.rb +8 -10
- data/lib/metanorma/document/relaton/variant_full_name.rb +3 -0
- data/lib/metanorma/document/relaton/variant_org_name.rb +3 -0
- data/lib/metanorma/document/relaton/version_info.rb +5 -0
- data/lib/metanorma/document/relaton/vocab_id_type.rb +6 -12
- data/lib/metanorma/document/relaton.rb +0 -14
- data/lib/metanorma/document/version.rb +1 -1
- data/lib/metanorma/document.rb +1 -0
- data/lib/metanorma/html/base_renderer.rb +86 -234
- data/lib/metanorma/html/concerns/metadata_extraction.rb +61 -0
- data/lib/metanorma/html/concerns/presentation_validation.rb +61 -0
- data/lib/metanorma/html/concerns/svg_processing.rb +32 -0
- data/lib/metanorma/html/concerns/text_extraction.rb +93 -0
- data/lib/metanorma/html/concerns/toc_registry.rb +47 -0
- data/lib/metanorma/html/csa_renderer.rb +9 -0
- data/lib/metanorma/html/drops/figure_drop.rb +33 -10
- data/lib/metanorma/html/drops/sourcecode_drop.rb +3 -6
- data/lib/metanorma/html/flavor.rb +6 -1
- data/lib/metanorma/html/generator.rb +8 -1
- data/lib/metanorma/html/iso_renderer.rb +0 -142
- data/lib/metanorma/html/renderers/block_renderer.rb +10 -0
- data/lib/metanorma/html/renderers/element_order_traversal.rb +15 -1
- data/lib/metanorma/html/renderers/inline_renderer.rb +13 -75
- data/lib/metanorma/html/standard_renderer.rb +195 -35
- data/lib/metanorma/html.rb +1 -51
- data/lib/metanorma/iso_document/sections/iso_preface.rb +27 -13
- data/lib/metanorma/mirror/default_registry.rb +21 -0
- data/lib/metanorma/mirror/handlers/inline/catalog.rb +7 -12
- data/lib/metanorma/mirror/handlers/inline/rich_html_renderer.rb +2 -3
- data/lib/metanorma/mirror/handlers/sourcecode.rb +1 -1
- data/lib/metanorma/mirror/model/guide.rb +3 -2
- data/lib/metanorma/mirror/output/formats/inline_format.rb +64 -3
- data/lib/metanorma/mirror/output/pipeline.rb +1 -0
- data/lib/metanorma/mirror/output.rb +0 -2
- data/lib/metanorma/mirror/rewriter.rb +3 -1
- data/lib/metanorma/registers/setup.rb +10 -0
- data/lib/metanorma/standard_document/annotation_container.rb +2 -0
- data/lib/metanorma/standard_document/elements/input.rb +4 -25
- data/lib/metanorma/standard_document/metadata/metanorma_extension.rb +12 -2
- data/lib/metanorma/standard_document/metadata/presentation_metadata.rb +107 -0
- data/lib/metanorma/standard_document/metadata/semantic_metadata.rb +18 -0
- data/lib/metanorma/standard_document/metadata/unitsml/amount_of_substance.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/base_quantity.rb +34 -0
- data/lib/metanorma/standard_document/metadata/unitsml/dimension.rb +39 -0
- data/lib/metanorma/standard_document/metadata/unitsml/dimension_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/electric_current.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/enumerated_root_unit.rb +23 -0
- data/lib/metanorma/standard_document/metadata/unitsml/length.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/luminous_intensity.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/mass.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/namespace.rb +17 -0
- data/lib/metanorma/standard_document/metadata/unitsml/plane_angle.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix.rb +30 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_name.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/prefix_symbol.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/quantity.rb +28 -0
- data/lib/metanorma/standard_document/metadata/unitsml/quantity_name.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/quantity_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/root_units.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/thermodynamic_temperature.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/time.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit.rb +32 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_name.rb +21 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_set.rb +19 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_symbol.rb +36 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unit_system.rb +23 -0
- data/lib/metanorma/standard_document/metadata/unitsml/unitsml_root.rb +28 -0
- data/lib/metanorma/standard_document/metadata/unitsml.rb +39 -0
- data/lib/metanorma/standard_document/metadata.rb +4 -0
- data/lib/metanorma/standard_document/sections/misc_container.rb +8 -6
- data/lib/metanorma/standard_document/sections/sections.rb +7 -0
- data/lib/metanorma/un_document/blocks/un_admonition_block.rb +86 -0
- data/lib/metanorma/un_document/blocks.rb +9 -0
- data/lib/metanorma/un_document/root.rb +8 -0
- data/lib/metanorma/un_document/sections/un_abstract_section.rb +48 -0
- data/lib/metanorma/un_document/sections/un_preface.rb +19 -2
- data/lib/metanorma/un_document/sections.rb +1 -0
- data/lib/metanorma/un_document/un_text_element.rb +116 -0
- data/lib/metanorma/un_document.rb +2 -0
- data/script/benchmark_render.rb +35 -0
- data/tasks/roundtrip_samples.rake +1 -1
- metadata +63 -45
- data/.rubocop_todo.yml +0 -220
- data/TODO.finalize/01-split-multi-class-files.md +0 -8
- data/TODO.finalize/02-remove-data-dist-iso-document-frontend.md +0 -6
- data/TODO.finalize/03-align-frontend-iife-and-gha-build.md +0 -11
- data/TODO.finalize/04-theme-per-flavor-config-driven.md +0 -9
- data/TODO.finalize/05-migrate-all-html-to-liquid.md +0 -16
- data/TODO.finalize/06-integrate-pubid-library.md +0 -16
- data/TODO.finalize/07-replace-relaton-models-with-relaton-bib.md +0 -39
- data/TODO.finalize/08-refactor-renderer-architecture.md +0 -25
- data/TODO.finalize/09-eliminate-code-smells.md +0 -14
- data/TODO.finalize/10-comprehensive-spec-coverage.md +0 -24
- data/TODO.finalize/11-config-driven-flavor-metadata.md +0 -20
- data/TODO.finalize/12-add-frozen-string-literal.md +0 -6
- data/TODO.finalize/13-extract-composition-from-god-class.md +0 -96
- data/TODO.finalize/14-config-driven-section-ordering.md +0 -31
- data/TODO.finalize/15-theme-directories-per-flavor.md +0 -46
- data/TODO.finalize/16-theme-lutaml-model-schema.md +0 -44
- data/docs/html-renderer.adoc +0 -261
- data/lib/data/dist/iso_document/frontend/assets/index-mwzbzmnK.js +0 -22
- data/lib/data/dist/iso_document/frontend/assets/index-pGvKTNid.css +0 -1
- data/lib/data/dist/iso_document/frontend/assets/iso-red.svg +0 -53
- data/lib/data/dist/iso_document/frontend/index.html +0 -13
- data/lib/metanorma/document/relaton/bib_item_size_type.rb +0 -21
- data/lib/metanorma/document/relaton/bibliographic_date_type.rb +0 -22
- data/lib/metanorma/document/relaton/document_relation_type.rb +0 -31
- data/lib/metanorma/document/relaton/iso4217_code.rb +0 -17
- data/lib/metanorma/document/relaton/iso8601_date.rb +0 -17
- data/lib/metanorma/document/relaton/personal_identifier_type.rb +0 -21
- data/lib/metanorma/document/relaton/region_type.rb +0 -20
- data/lib/metanorma/document/relaton/series_type_type.rb +0 -21
- data/lib/metanorma/document/relaton/specific_locality_type.rb +0 -25
- data/lib/metanorma/document/relaton/title_type.rb +0 -21
- data/lib/metanorma/mirror/output/html_renderer.rb +0 -95
- data/lib/metanorma/mirror/output/html_renderers/block_renderers.rb +0 -178
- data/lib/metanorma/mirror/output/html_renderers/inline_renderer.rb +0 -61
- data/lib/metanorma/mirror/output/html_renderers/list_renderers.rb +0 -96
- data/lib/metanorma/mirror/output/html_renderers/mark_renderers.rb +0 -41
- data/lib/metanorma/mirror/output/html_renderers/section_renderers.rb +0 -129
- data/lib/metanorma/mirror/output/html_renderers/structural_renderers.rb +0 -80
- data/lib/metanorma/mirror/output/html_renderers/table_renderers.rb +0 -87
- data/lib/metanorma/mirror/output/html_renderers.rb +0 -76
- data/lib/metanorma/standard_document/annotation.rb +0 -37
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# 11 — Config-driven flavor metadata: eliminate boilerplate renderers — DONE
|
|
2
|
-
|
|
3
|
-
## What was done
|
|
4
|
-
All 13 theme YAML files contain publisher metadata:
|
|
5
|
-
```yaml
|
|
6
|
-
publishers:
|
|
7
|
-
- "ISO"
|
|
8
|
-
publisher_name: "ISO"
|
|
9
|
-
logos:
|
|
10
|
-
"ISO": "iso-logo.svg"
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
BaseRenderer reads publishers/logos from theme via `theme.publishers`, `theme.publisher_name`, `theme.logos`. No renderer code overrides these.
|
|
14
|
-
|
|
15
|
-
10 flavor renderers are empty shells (0 methods, just inherit IsoRenderer). They exist because `Generator` maps document classes to renderer classes, but all customization comes from theme YAML config.
|
|
16
|
-
|
|
17
|
-
Theme auto-resolves from document type via `FLAVOR_MAP` — no manual `theme` override needed in any renderer.
|
|
18
|
-
|
|
19
|
-
## Code quality requirements
|
|
20
|
-
Ensure code cleanliness and OOP and MECE and fully model-driven, semantically-driven and open/closed principle, DRY, performance. ultrathink. Always think about what can we improve here in architecture and code? Make sure we have good specs throughout. Never use private send methods (breaks encapsulation), instance_variable_set/get, and never use respond_to? (poor typing).
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# 12 — Add frozen_string_literal to all Ruby files — DONE
|
|
2
|
-
|
|
3
|
-
All `lib/` and `spec/` Ruby files already have `# frozen_string_literal: true` on line 1. No changes needed.
|
|
4
|
-
|
|
5
|
-
## Code quality requirements
|
|
6
|
-
Ensure code cleanliness and OOP and MECE and fully model-driven, semantically-driven and open/closed principle, DRY, performance. ultrathink. Always think about what can we improve here in architecture and code? Make sure we have good specs throughout. Never use private send methods (breaks encapsulation), instance_variable_set/get, and never use respond_to? (poor typing).
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# 13 — Extract module includes into composition — DONE
|
|
2
|
-
|
|
3
|
-
## Problem
|
|
4
|
-
BaseRenderer is a God class with 180+ public methods from 4 mixed-in modules:
|
|
5
|
-
- `InlineRendering` (~590 lines, 39 methods)
|
|
6
|
-
- `BlockRendering` (~295 lines, 24 methods)
|
|
7
|
-
- `SectionRendering` (~90 lines, 8 methods)
|
|
8
|
-
- `PubidRendering` (~55 lines, 2 methods)
|
|
9
|
-
|
|
10
|
-
Module includes break OCP and encapsulation — all module methods become public on the single class, making it impossible to reason about responsibilities in isolation.
|
|
11
|
-
|
|
12
|
-
## Architecture
|
|
13
|
-
|
|
14
|
-
Replace `include` with composition. Each module becomes a standalone class that receives a reference to the coordinator for cross-concern calls:
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
BaseRenderer (coordinator, ~50 methods)
|
|
18
|
-
├── InlineRenderer (inline elements, 39 methods)
|
|
19
|
-
├── BlockRenderer (block elements, 24 methods)
|
|
20
|
-
├── SectionRenderer (sections, 8 methods)
|
|
21
|
-
└── PubidRenderer (pubid parsing, 2 methods)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Cross-concern dependencies (one-way, clean extraction)
|
|
25
|
-
|
|
26
|
-
InlineRenderer needs from coordinator:
|
|
27
|
-
- `escape_html`, `safe_attr`, `element_attrs`, `capture_output`, `render_liquid`
|
|
28
|
-
- `render_paragraph`, `render_inline_element` (recursive dispatch)
|
|
29
|
-
- `@output`, `@footnote_collector`, `@index_term_collector`
|
|
30
|
-
|
|
31
|
-
BlockRenderer needs from coordinator:
|
|
32
|
-
- `escape_html`, `safe_attr`, `element_attrs`, `capture_output`, `render_liquid`
|
|
33
|
-
- `render_mixed_inline`, `render_inline_element`, `render_mixed_content_in_order`
|
|
34
|
-
- `walk_ordered`, `block_element?`, `render` (recursive dispatch)
|
|
35
|
-
- `@output`, `renderer_context`
|
|
36
|
-
|
|
37
|
-
SectionRenderer needs from coordinator:
|
|
38
|
-
- `escape_html`, `safe_attr`, `element_attrs`, `capture_output`, `render_liquid`
|
|
39
|
-
- `walk_ordered`, `render`, `render_note`, `extract_plain_text`
|
|
40
|
-
- `@output`
|
|
41
|
-
|
|
42
|
-
PubidRenderer needs from coordinator:
|
|
43
|
-
- `escape_html`, `flavor_name`
|
|
44
|
-
|
|
45
|
-
### Implementation plan
|
|
46
|
-
|
|
47
|
-
1. Create `InlineRenderer` class at `lib/metanorma/html/renderers/inline_renderer.rb`
|
|
48
|
-
- Receives `coordinator` in constructor
|
|
49
|
-
- Moves all methods from `InlineRendering` module
|
|
50
|
-
- Delegates shared utility calls to coordinator
|
|
51
|
-
2. Create `BlockRenderer` class at `lib/metanorma/html/renderers/block_renderer.rb`
|
|
52
|
-
- Same pattern
|
|
53
|
-
3. Create `SectionRenderer` class at `lib/metanorma/html/renderers/section_renderer.rb`
|
|
54
|
-
- Same pattern
|
|
55
|
-
4. Create `PubidRenderer` class at `lib/metanorma/html/renderers/pubid_renderer.rb`
|
|
56
|
-
- Same pattern
|
|
57
|
-
5. Update `BaseRenderer` to instantiate sub-renderers and delegate
|
|
58
|
-
6. Update `RendererContext` to delegate through coordinator's sub-renderers
|
|
59
|
-
7. Update all flavor renderers (IsoRenderer, StandardRenderer, etc.) for new API
|
|
60
|
-
8. Update all Drop classes that call `renderer.method_name`
|
|
61
|
-
9. Ensure all existing specs pass
|
|
62
|
-
|
|
63
|
-
### Delegation pattern
|
|
64
|
-
|
|
65
|
-
```ruby
|
|
66
|
-
class BaseRenderer
|
|
67
|
-
attr_reader :inline_renderer, :block_renderer, :section_renderer, :pubid_renderer
|
|
68
|
-
|
|
69
|
-
def initialize
|
|
70
|
-
@inline_renderer = InlineRenderer.new(self)
|
|
71
|
-
@block_renderer = BlockRenderer.new(self)
|
|
72
|
-
@section_renderer = SectionRenderer.new(self)
|
|
73
|
-
@pubid_renderer = PubidRenderer.new(self)
|
|
74
|
-
# ...
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Delegate for backward compatibility during migration
|
|
78
|
-
def render_paragraph(...) = @block_renderer.render_paragraph(...)
|
|
79
|
-
def render_em(...) = @inline_renderer.render_em(...)
|
|
80
|
-
# etc.
|
|
81
|
-
end
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Flavor renderers
|
|
85
|
-
|
|
86
|
-
Sub-renderers can be extended per flavor:
|
|
87
|
-
```ruby
|
|
88
|
-
class IsoSectionRenderer < SectionRenderer
|
|
89
|
-
def render_preface(preface, **)
|
|
90
|
-
# ISO-specific preface ordering
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## Code quality requirements
|
|
96
|
-
Ensure code cleanliness and OOP and MECE and fully model-driven, semantically-driven and open/closed principle, DRY, performance. ultrathink. Always think about what can we improve here in architecture and code? Make sure we have good specs throughout. Never use private send methods (breaks encapsulation), instance_variable_set/get, and never use respond_to? (poor typing).
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# 14 — Config-driven preface and clause ordering — DONE
|
|
2
|
-
|
|
3
|
-
## What was done
|
|
4
|
-
|
|
5
|
-
### Theme config attributes added:
|
|
6
|
-
- `preface_order` — array of section names, controls rendering order (default: `foreword introduction abstract clause acknowledgements executivesummary`)
|
|
7
|
-
- `preface_wrap` — boolean, wraps preface content in a container div with heading (default: `false`)
|
|
8
|
-
- `clause_order` — array of section names for clause ordering (default: `sections annex bibliography indexsect`)
|
|
9
|
-
- `toc_filter_types` — array of clause types to exclude from preface rendering (default: `[]`)
|
|
10
|
-
|
|
11
|
-
### All 13 theme YAML files updated:
|
|
12
|
-
- ISO, IEC, IEEE, IETF, ITU, IHO, CC, BIPM, OIML, PDFA, Ribose, ICC: default ordering
|
|
13
|
-
- OGC: `preface_order: [clause]`, `preface_wrap: true`, `toc_filter_types: [toc]`
|
|
14
|
-
|
|
15
|
-
### Code changes:
|
|
16
|
-
- `Theme` — added `preface_order`, `preface_wrap`, `clause_order`, `toc_filter_types` to VALID_KEYS, attr_accessor, and defaults
|
|
17
|
-
- `SectionRenderer` — config-driven `render_preface` reads from theme, delegates to `render_ordered_preface` or `render_wrapped_preface` based on `preface_wrap`
|
|
18
|
-
- `BaseRenderer` — added `render_preface` delegation to section_renderer
|
|
19
|
-
- `IsoRenderer` — deleted hardcoded `render_preface` method (config-driven version replaces it)
|
|
20
|
-
- `OgcRenderer` — deleted hardcoded `render_preface` override (now empty shell, all behavior from YAML)
|
|
21
|
-
- Template `_ogc_preface.html.liquid` renamed to `_wrapped_preface.html.liquid` (generic name)
|
|
22
|
-
|
|
23
|
-
### Specs added:
|
|
24
|
-
- `config_preface_spec.rb` — 8 specs covering ordered mode, wrapped mode, clause filtering, and delegation
|
|
25
|
-
- `theme_spec.rb` — 4 specs for section ordering defaults and OGC overrides
|
|
26
|
-
|
|
27
|
-
### Key principle enforced:
|
|
28
|
-
No flavor-specific knowledge (no "ogc", no hardcoded ordering) in generic renderer code. All behavior comes from theme YAML config.
|
|
29
|
-
|
|
30
|
-
## Code quality requirements
|
|
31
|
-
Ensure code cleanliness and OOP and MECE and fully model-driven, semantically-driven and open/closed principle, DRY, performance. ultrathink. Always think about what can we improve here in architecture and code? Make sure we have good specs throughout. Never use private send methods (breaks encapsulation), instance_variable_set/get, and never use respond_to? (poor typing).
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# 15 — Theme directories per flavor with data-centric config — DONE
|
|
2
|
-
|
|
3
|
-
## What was done
|
|
4
|
-
|
|
5
|
-
### Theme class changes:
|
|
6
|
-
- Added `theme_dir` attribute (set when loaded from directory, nil for flat file themes)
|
|
7
|
-
- `Theme.load(flavor)` now checks for directory format first (`data/themes/{flavor}/theme.yaml`), falls back to flat file (`data/themes/{flavor}.yaml`)
|
|
8
|
-
- Extracted `from_file`, `from_directory`, `apply_overrides` class methods for clean separation
|
|
9
|
-
- Added `theme_templates_dir` — returns `{theme_dir}/templates/` if it exists
|
|
10
|
-
- Added `theme_assets_dir` — returns `{theme_dir}/assets/` if it exists
|
|
11
|
-
- Added `theme_css_path` — returns `{theme_dir}/custom.css` if it exists
|
|
12
|
-
- Added `resolve_template(template_name)` — checks flavor templates dir first, falls back to shared templates
|
|
13
|
-
- Added `resolve_asset(filename)` — checks flavor assets dir, returns nil if not found
|
|
14
|
-
|
|
15
|
-
### BaseRenderer changes:
|
|
16
|
-
- `render_liquid` uses `theme.resolve_template(template_name)` instead of hardcoded `File.join(TEMPLATES_ROOT, ...)`
|
|
17
|
-
- `load_logo_svg` checks `theme.resolve_asset(filename)` before shared `LOGO_DIR`
|
|
18
|
-
- `build_styles` appends `theme.theme_css_path` content if present
|
|
19
|
-
|
|
20
|
-
### Directory-based theme structure (opt-in):
|
|
21
|
-
```
|
|
22
|
-
data/themes/
|
|
23
|
-
iso.yaml # flat file — still works as before
|
|
24
|
-
ogc.yaml # flat file — still works as before
|
|
25
|
-
{flavor}/ # directory format — new support
|
|
26
|
-
theme.yaml # palette, fonts, layout, ordering, publisher metadata
|
|
27
|
-
custom.css # per-flavor CSS overrides (optional)
|
|
28
|
-
templates/ # per-flavor Liquid template overrides (optional)
|
|
29
|
-
_cover.html.liquid
|
|
30
|
-
assets/ # per-flavor assets: logos, images (optional)
|
|
31
|
-
{flavor}-logo.svg
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Backward compatibility:
|
|
35
|
-
- All 13 existing flat YAML theme files continue to work unchanged
|
|
36
|
-
- `theme_dir` is nil for flat-file themes, so resolution always falls through to shared paths
|
|
37
|
-
- No migration needed — directory format is opt-in
|
|
38
|
-
|
|
39
|
-
### Specs added:
|
|
40
|
-
- 12 new specs in `theme_spec.rb` covering directory loading, template/asset/CSS resolution, backward compat
|
|
41
|
-
|
|
42
|
-
### Future consideration:
|
|
43
|
-
When theme config moves to per-flavor gems, `Theme.load` can be extended to search gem data directories. The API (`theme.resolve_template`, `theme.resolve_asset`, etc.) stays the same — only the path resolution changes.
|
|
44
|
-
|
|
45
|
-
## Code quality requirements
|
|
46
|
-
Ensure code cleanliness and OOP and MECE and fully model-driven, semantically-driven and open/closed principle, DRY, performance. ultrathink. Always think about what can we improve here in architecture and code? Make sure we have good specs throughout. Never use private send methods (breaks encapsulation), instance_variable_set/get, and never use respond_to? (poor typing).
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# 16 — Theme as lutaml-model with YAML schema — DONE
|
|
2
|
-
|
|
3
|
-
## What was done
|
|
4
|
-
|
|
5
|
-
Converted `Theme` from a plain Ruby class with `attr_accessor` + `VALID_KEYS` + manual YAML parsing to a proper `Lutaml::Model::Serializable` with typed attributes.
|
|
6
|
-
|
|
7
|
-
### Schema definition
|
|
8
|
-
- 65 typed attributes declared with lutaml-model `attribute` DSL
|
|
9
|
-
- Types: `:string` (colors, fonts, CSS), `:boolean` (preface_wrap), `:hash` (logos)
|
|
10
|
-
- Collection arrays: `:string, collection: true` (publishers, preface_order, clause_order, toc_filter_types)
|
|
11
|
-
- All defaults declared via `default: -> { ... }` procs
|
|
12
|
-
- Nil-by-default attributes (accent_deep, warm, dark_note_bg, etc.) have no default
|
|
13
|
-
|
|
14
|
-
### What was eliminated
|
|
15
|
-
- `VALID_KEYS` constant — no longer needed, attribute declarations ARE the schema
|
|
16
|
-
- `SETTERS` constant — lutaml-model handles key→setter mapping
|
|
17
|
-
- Manual `initialize` with 60+ instance variable assignments — lutaml-model handles initialization
|
|
18
|
-
- `apply_overrides` method — `from_yaml` handles deserialization
|
|
19
|
-
- `require "yaml"` + `YAML.safe_load_file` — `File.read(path)` + `from_yaml` replaces it
|
|
20
|
-
|
|
21
|
-
### What was preserved
|
|
22
|
-
- `theme_dir` as regular `attr_accessor` (not a YAML attribute, set programmatically)
|
|
23
|
-
- `THEMES_DIR`, `TEMPLATES_ROOT` constants
|
|
24
|
-
- All behavior methods: `to_css_root`, `to_css_extras`, `resolve_template`, `resolve_asset`, etc.
|
|
25
|
-
- `load(flavor)`, `from_file`, `from_directory` class methods
|
|
26
|
-
- Full backward compatibility — all 111 theme specs pass unchanged
|
|
27
|
-
|
|
28
|
-
### Schema introspection
|
|
29
|
-
```ruby
|
|
30
|
-
Metanorma::Html::Theme.attributes.size # => 65
|
|
31
|
-
Metanorma::Html::Theme.attributes[:preface_wrap].type # => Lutaml::Model::Type::Boolean
|
|
32
|
-
Metanorma::Html::Theme.attributes[:publishers].collection? # => true
|
|
33
|
-
Metanorma::Html::Theme.attributes[:logos].type # => Lutaml::Model::Type::Hash
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Why this matters
|
|
37
|
-
- **Flavor authors** get schema-level documentation — every valid key, its type, and default value is declared in one place
|
|
38
|
-
- **Type safety** — wrong types in YAML are caught at load time by lutaml-model
|
|
39
|
-
- **No silent ignores** — with the old `VALID_KEYS` + `SETTERS` pattern, unknown keys were silently skipped. Now lutaml-model handles key mapping
|
|
40
|
-
- **Round-tripping** — themes can be loaded, modified, and serialized back to YAML via `to_yaml`
|
|
41
|
-
- **Future-proof** — when theme configs move to per-flavor gems, the model stays the same; only the load path changes
|
|
42
|
-
|
|
43
|
-
## Code quality requirements
|
|
44
|
-
Ensure code cleanliness and OOP and MECE and fully model-driven, semantically-driven and open/closed principle, DRY, performance. ultrathink. Always think about what can we improve here in architecture and code? Make sure we have good specs throughout. Never use private send methods (breaks encapsulation), instance_variable_set/get, and never use respond_to? (poor typing).
|
data/docs/html-renderer.adoc
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
= HTML Renderer Architecture
|
|
2
|
-
|
|
3
|
-
== Overview
|
|
4
|
-
|
|
5
|
-
The HTML renderer converts a Metanorma document model (parsed from presentation XML) into a complete, self-contained HTML document. It produces all body content, header, footer, table of contents, CSS theming, and JavaScript interactivity.
|
|
6
|
-
|
|
7
|
-
== Pipeline
|
|
8
|
-
|
|
9
|
-
....
|
|
10
|
-
Generator.generate(doc)
|
|
11
|
-
├── Auto-selects renderer by document class
|
|
12
|
-
├── Renderer.new
|
|
13
|
-
└── renderer.generate_full_document(doc)
|
|
14
|
-
├── Header (publisher logos, document title)
|
|
15
|
-
├── ToC sidebar
|
|
16
|
-
├── Body content (recursive render)
|
|
17
|
-
├── Footnotes
|
|
18
|
-
├── Footer (copyright)
|
|
19
|
-
└── Asset pipeline (inline CSS + JS)
|
|
20
|
-
....
|
|
21
|
-
|
|
22
|
-
== Renderer Hierarchy
|
|
23
|
-
|
|
24
|
-
[source,ruby]
|
|
25
|
-
BaseRenderer # Core HTML rendering, document assembly, CSS/JS pipeline
|
|
26
|
-
└── StandardRenderer # Terms, definitions, annexes, bibliography
|
|
27
|
-
├── IsoRenderer # ISO cover page, copyright, title formatting
|
|
28
|
-
│ ├── IccRenderer # ICC publisher styling
|
|
29
|
-
│ └── PdfaRenderer # PDF Association publisher styling
|
|
30
|
-
├── IecRenderer # IEC-specific formatting
|
|
31
|
-
├── IeeeRenderer # IEEE-specific formatting
|
|
32
|
-
├── IetfRenderer # IETF-specific formatting
|
|
33
|
-
├── IhoRenderer # IHO-specific formatting
|
|
34
|
-
├── ItuRenderer # ITU-specific formatting
|
|
35
|
-
├── OgcRenderer # OGC-specific formatting
|
|
36
|
-
├── OimlRenderer # OIML-specific formatting
|
|
37
|
-
├── BipmRenderer # BIPM-specific formatting
|
|
38
|
-
├── CcRenderer # CC-specific formatting
|
|
39
|
-
└── RiboseRenderer # Ribose-specific formatting
|
|
40
|
-
|
|
41
|
-
=== Renderer Selection
|
|
42
|
-
|
|
43
|
-
The `Generator` uses a two-tier lookup:
|
|
44
|
-
|
|
45
|
-
1. **Taste match**: If the document's publisher matches a registered taste, use that renderer.
|
|
46
|
-
2. **Model class**: Walk the ancestor chain from most specific to `BaseRenderer`.
|
|
47
|
-
|
|
48
|
-
[source,ruby]
|
|
49
|
-
# ICC documents are IsoDocument::Root but use IccRenderer
|
|
50
|
-
Metanorma::Html::Generator.register_taste(
|
|
51
|
-
Metanorma::IsoDocument::Root,
|
|
52
|
-
"ICC",
|
|
53
|
-
Metanorma::Html::IccRenderer
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
== Class Name Ownership
|
|
57
|
-
|
|
58
|
-
The HTML renderer owns its class names entirely. **No XML-originated class names appear in the HTML output.**
|
|
59
|
-
|
|
60
|
-
The XML document model's `class_attr` is read as **input only** to determine semantic role. The renderer maps XML roles to HTML-specific class names via `SPAN_ROLE_CLASSES`:
|
|
61
|
-
|
|
62
|
-
[source,ruby]
|
|
63
|
-
SPAN_ROLE_CLASSES = {
|
|
64
|
-
"boldtitle" => "title-text",
|
|
65
|
-
"citefig" => "xref-fig",
|
|
66
|
-
"citesec" => "xref-section",
|
|
67
|
-
"fmt-element-name" => "element-label",
|
|
68
|
-
"fmt-obligation" => "obligation-text",
|
|
69
|
-
# ...
|
|
70
|
-
}.freeze
|
|
71
|
-
|
|
72
|
-
Block-level classes (`note-block`, `formula`, `figure`, etc.) are assigned by the renderer based on what it's rendering — never carried over from XML.
|
|
73
|
-
|
|
74
|
-
Inline span classes go through `html_class_for_span`:
|
|
75
|
-
|
|
76
|
-
[source,ruby]
|
|
77
|
-
def html_class_for_span(xml_class)
|
|
78
|
-
SPAN_ROLE_CLASSES[xml_class] || "span-#{xml_class}"
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
Raw XML content (e.g., boilerplate) passes through Nokogiri post-processing that remaps any remaining XML class names.
|
|
82
|
-
|
|
83
|
-
== Drop Pattern
|
|
84
|
-
|
|
85
|
-
Block elements (notes, examples, sourcecode, formulas, figures, admonitions) use the Drop pattern to separate data capture from template rendering.
|
|
86
|
-
|
|
87
|
-
=== How It Works
|
|
88
|
-
|
|
89
|
-
. A `Drop` class captures rendered content via `RendererContext`
|
|
90
|
-
. The Drop passes pre-rendered HTML strings to a Liquid template
|
|
91
|
-
. The template reads Drop attributes and outputs final HTML
|
|
92
|
-
|
|
93
|
-
[source,ruby]
|
|
94
|
-
# In the renderer:
|
|
95
|
-
def render_note(note, **_opts)
|
|
96
|
-
drop = Drops::NoteDrop.from_model(note, renderer: renderer_context)
|
|
97
|
-
@output << render_liquid("_note.html.liquid", { "block" => drop })
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# In the Drop:
|
|
101
|
-
class NoteDrop < BlockElementDrop
|
|
102
|
-
def self.from_model(note, renderer:)
|
|
103
|
-
content_html = renderer.capture_output do
|
|
104
|
-
note.content.each { |para| renderer.render_paragraph(para) }
|
|
105
|
-
end
|
|
106
|
-
new(id: renderer.safe_attr(note, :id),
|
|
107
|
-
label_html: renderer.escape_html(label),
|
|
108
|
-
content_html: content_html,
|
|
109
|
-
css_class: "note-block")
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
=== BlockElementDrop
|
|
114
|
-
|
|
115
|
-
All block drops inherit from `BlockElementDrop`, which provides common attributes:
|
|
116
|
-
|
|
117
|
-
`id` :: HTML element id
|
|
118
|
-
`type` :: Block type identifier
|
|
119
|
-
`label_html` :: Pre-rendered label (e.g., "NOTE", "EXAMPLE 1")
|
|
120
|
-
`content_html` :: Pre-rendered inner content
|
|
121
|
-
`css_class` :: HTML-specific class name
|
|
122
|
-
|
|
123
|
-
=== RendererContext
|
|
124
|
-
|
|
125
|
-
`RendererContext` is a facade inside `BaseRenderer` that exposes only the rendering methods Drops need. Drops call renderer methods through this facade — the renderer's private interface stays encapsulated.
|
|
126
|
-
|
|
127
|
-
[source,ruby]
|
|
128
|
-
class RendererContext
|
|
129
|
-
def safe_attr(obj, method_name)
|
|
130
|
-
def escape_html(text)
|
|
131
|
-
def extract_block_label(block, default)
|
|
132
|
-
def extract_plain_text(node)
|
|
133
|
-
def capture_output(&block)
|
|
134
|
-
def render_paragraph(p)
|
|
135
|
-
def render_mixed_inline(node)
|
|
136
|
-
def render_inline_element(el)
|
|
137
|
-
def render_unordered_list(ul)
|
|
138
|
-
def render_ordered_list(ol)
|
|
139
|
-
def render_definition_list(dl)
|
|
140
|
-
def render_table(table)
|
|
141
|
-
def render_figure(figure)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
== Liquid Templates
|
|
145
|
-
|
|
146
|
-
HTML structure is defined in `.liquid` templates under `lib/metanorma/html/templates/`.
|
|
147
|
-
|
|
148
|
-
[horizontal]
|
|
149
|
-
`document.html.liquid` :: Full document shell (`<html>`, `<head>`, `<body>`)
|
|
150
|
-
`_header.html.liquid` :: Sticky header with publisher logos
|
|
151
|
-
`_footer.html.liquid` :: Footer with copyright
|
|
152
|
-
`_cover.html.liquid` :: Generic cover page layout
|
|
153
|
-
`_iso_cover.html.liquid` :: ISO-specific cover page
|
|
154
|
-
`_iso_doc_title.html.liquid` :: ISO document title rendering
|
|
155
|
-
`_doc_title.html.liquid` :: Generic document title rendering
|
|
156
|
-
`_footnotes.html.liquid` :: Footnotes section
|
|
157
|
-
`_note.html.liquid` :: Note block
|
|
158
|
-
`_example.html.liquid` :: Example block
|
|
159
|
-
`_sourcecode.html.liquid` :: Source code block
|
|
160
|
-
`_formula.html.liquid` :: Formula block
|
|
161
|
-
`_figure.html.liquid` :: Figure block
|
|
162
|
-
`_admonition.html.liquid` :: Admonition block
|
|
163
|
-
|
|
164
|
-
Templates use `Liquid::LocalFileSystem` for partials (prefixed with `_`). The `render_liquid` method handles template caching.
|
|
165
|
-
|
|
166
|
-
=== Template Example
|
|
167
|
-
|
|
168
|
-
`_note.html.liquid`:
|
|
169
|
-
|
|
170
|
-
[source,liquid]
|
|
171
|
-
----
|
|
172
|
-
<div{% if block.id %} id="{{ block.id }}"{% endif %} class="{{ block.css_class }}">
|
|
173
|
-
{% if block.label_html %}
|
|
174
|
-
<p class="note-label"><strong>{{ block.label_html }}</strong></p>
|
|
175
|
-
{% endif %}
|
|
176
|
-
<div class="note-content">
|
|
177
|
-
{{ block.content_html }}
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
180
|
-
----
|
|
181
|
-
|
|
182
|
-
== Theming
|
|
183
|
-
|
|
184
|
-
Each renderer has a `Theme` object controlling colors, typography, and layout. Theme properties are emitted as CSS custom properties (`--mn-primary`, `--font-body`, etc.).
|
|
185
|
-
|
|
186
|
-
[source,ruby]
|
|
187
|
-
class MyRenderer < Metanorma::Html::StandardRenderer
|
|
188
|
-
def theme
|
|
189
|
-
@theme ||= begin
|
|
190
|
-
t = Theme.new
|
|
191
|
-
t.primary = "#1a5276"
|
|
192
|
-
t.accent = "#2e86c1"
|
|
193
|
-
t.font_body = '"Charter", serif'
|
|
194
|
-
t
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
=== Theme Properties
|
|
200
|
-
|
|
201
|
-
[horizontal]
|
|
202
|
-
`primary` :: Primary brand color
|
|
203
|
-
`accent` :: Accent/highlight color
|
|
204
|
-
`gradient` :: Header gradient
|
|
205
|
-
`font_body` :: Body text font stack
|
|
206
|
-
`font_sans` :: Sans-serif font stack
|
|
207
|
-
`font_mono` :: Monospace font stack
|
|
208
|
-
`font_url` :: Google Fonts URL
|
|
209
|
-
`note_border` :: Note block border color
|
|
210
|
-
`note_bg` :: Note block background
|
|
211
|
-
`example_border` :: Example block border color
|
|
212
|
-
`example_bg` :: Example block background
|
|
213
|
-
`admonition_border` :: Admonition border color
|
|
214
|
-
`admonition_bg` :: Admonition background
|
|
215
|
-
`extra_css` :: Additional CSS string appended after defaults
|
|
216
|
-
|
|
217
|
-
== Presentation XML
|
|
218
|
-
|
|
219
|
-
The HTML renderer expects **presentation XML** (not source XML). Presentation XML contains `fmt-*` display elements alongside semantic elements:
|
|
220
|
-
|
|
221
|
-
- `fmt-title` — formatted section/block titles
|
|
222
|
-
- `fmt-xref` — formatted cross-reference text
|
|
223
|
-
- `fmt-link` — formatted link text
|
|
224
|
-
- `fmt-concept` — formatted concept references
|
|
225
|
-
- `fmt-definition` — formatted term definitions
|
|
226
|
-
- `fmt-preferred` — formatted preferred term names
|
|
227
|
-
|
|
228
|
-
The renderer prioritizes `fmt-*` elements for rendering, falling back to semantic elements when display elements are absent.
|
|
229
|
-
|
|
230
|
-
== Asset Pipeline
|
|
231
|
-
|
|
232
|
-
The `AssetPipeline` compiles CSS and JavaScript from modular source files into inline `<style>` and `<script>` blocks for self-contained output.
|
|
233
|
-
|
|
234
|
-
=== CSS
|
|
235
|
-
|
|
236
|
-
[horizontal]
|
|
237
|
-
`data/stylesheets/base/` :: Reset, typography, layout, dark mode, print
|
|
238
|
-
`data/stylesheets/components/` :: Component stylesheets (inline, tables, notes, etc.)
|
|
239
|
-
|
|
240
|
-
=== JavaScript
|
|
241
|
-
|
|
242
|
-
[horizontal]
|
|
243
|
-
`data/javascripts/core/` :: Reader, theme, scroll, navigation, reveal
|
|
244
|
-
`data/javascripts/components/` :: ToC, search, lightbox, code copy, glossary, etc.
|
|
245
|
-
|
|
246
|
-
== Extending
|
|
247
|
-
|
|
248
|
-
To add a new flavor renderer:
|
|
249
|
-
|
|
250
|
-
. Subclass the appropriate base (usually `IsoRenderer` or `StandardRenderer`)
|
|
251
|
-
. Override `theme` with brand colors/fonts
|
|
252
|
-
. Override `publisher_logo_map` with logo filenames
|
|
253
|
-
. Register with the Generator:
|
|
254
|
-
|
|
255
|
-
[source,ruby]
|
|
256
|
-
Metanorma::Html::Generator.register(
|
|
257
|
-
Metanorma::MyDocument::Root,
|
|
258
|
-
Metanorma::Html::MyRenderer
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
To customize how a specific block renders, override the `render_*` method and either emit HTML directly or use the Drop pattern with a new template.
|