uniword 1.2.4 → 1.3.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.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +223 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/config/ooxml/schemas/shared_types.yml +5 -4
  5. data/data/schemas/ecma/dc.xsd +118 -0
  6. data/data/schemas/ecma/dcmitype.xsd +50 -0
  7. data/data/schemas/ecma/dcterms.xsd +331 -0
  8. data/data/schemas/ecma/opc-coreProperties.xsd +2 -2
  9. data/data/schemas/ecma/xml.xsd +117 -0
  10. data/lib/uniword/builder/bibliography_builder.rb +1 -1
  11. data/lib/uniword/builder/chart_builder.rb +21 -9
  12. data/lib/uniword/builder/comment_anchorer.rb +221 -0
  13. data/lib/uniword/builder/document_builder.rb +97 -6
  14. data/lib/uniword/builder/has_borders.rb +8 -1
  15. data/lib/uniword/builder/image_builder.rb +6 -5
  16. data/lib/uniword/builder/run_utils.rb +2 -0
  17. data/lib/uniword/builder.rb +1 -0
  18. data/lib/uniword/cli/fonts_cli.rb +52 -0
  19. data/lib/uniword/cli/main.rb +110 -24
  20. data/lib/uniword/cli/page_cli.rb +85 -0
  21. data/lib/uniword/cli/styles_cli.rb +204 -0
  22. data/lib/uniword/cli/theme_cli.rb +88 -0
  23. data/lib/uniword/cli/toc_cli.rb +22 -2
  24. data/lib/uniword/comment.rb +20 -15
  25. data/lib/uniword/comment_range.rb +3 -3
  26. data/lib/uniword/comments_part.rb +51 -19
  27. data/lib/uniword/configuration/configuration_loader.rb +5 -3
  28. data/lib/uniword/configuration.rb +93 -1
  29. data/lib/uniword/content_types.rb +19 -39
  30. data/lib/uniword/document_factory.rb +9 -1
  31. data/lib/uniword/document_writer.rb +16 -5
  32. data/lib/uniword/docx/chart_part.rb +34 -0
  33. data/lib/uniword/docx/custom_xml_item.rb +83 -0
  34. data/lib/uniword/docx/header_footer_part.rb +140 -0
  35. data/lib/uniword/docx/header_footer_part_collection.rb +135 -0
  36. data/lib/uniword/docx/header_footer_view.rb +225 -0
  37. data/lib/uniword/docx/id_allocator.rb +132 -38
  38. data/lib/uniword/docx/package.rb +223 -35
  39. data/lib/uniword/docx/package_defaults.rb +58 -78
  40. data/lib/uniword/docx/package_integrity_checker.rb +312 -0
  41. data/lib/uniword/docx/package_serialization.rb +116 -234
  42. data/lib/uniword/docx/part.rb +106 -0
  43. data/lib/uniword/docx/part_collection.rb +123 -0
  44. data/lib/uniword/docx/reconciler/body.rb +59 -68
  45. data/lib/uniword/docx/reconciler/fix.rb +46 -0
  46. data/lib/uniword/docx/reconciler/fix_codes.rb +37 -30
  47. data/lib/uniword/docx/reconciler/helpers.rb +9 -1
  48. data/lib/uniword/docx/reconciler/notes.rb +17 -8
  49. data/lib/uniword/docx/reconciler/package_structure.rb +169 -221
  50. data/lib/uniword/docx/reconciler/parts.rb +42 -16
  51. data/lib/uniword/docx/reconciler/referential_integrity.rb +297 -123
  52. data/lib/uniword/docx/reconciler/tables.rb +78 -16
  53. data/lib/uniword/docx/reconciler/theme.rb +7 -4
  54. data/lib/uniword/docx/reconciler.rb +40 -15
  55. data/lib/uniword/docx.rb +10 -0
  56. data/lib/uniword/drawingml/blip.rb +0 -1
  57. data/lib/uniword/drawingml/color_scheme.rb +5 -7
  58. data/lib/uniword/drawingml/font_scheme.rb +4 -8
  59. data/lib/uniword/drawingml/theme.rb +12 -7
  60. data/lib/uniword/errors.rb +8 -1
  61. data/lib/uniword/footer.rb +4 -0
  62. data/lib/uniword/header.rb +4 -0
  63. data/lib/uniword/hyperlink.rb +1 -1
  64. data/lib/uniword/image.rb +6 -6
  65. data/lib/uniword/lazy_loader.rb +1 -2
  66. data/lib/uniword/model_attribute_access.rb +20 -4
  67. data/lib/uniword/ooxml/dotx_package.rb +42 -2
  68. data/lib/uniword/ooxml/part_definition.rb +171 -0
  69. data/lib/uniword/ooxml/part_registry.rb +311 -0
  70. data/lib/uniword/ooxml/relationships/image_relationship.rb +1 -1
  71. data/lib/uniword/ooxml/relationships/package_relationships.rb +20 -22
  72. data/lib/uniword/ooxml/schema/element_serializer.rb +8 -4
  73. data/lib/uniword/ooxml/types/hex_color_value.rb +38 -0
  74. data/lib/uniword/ooxml/types/ooxml_boolean.rb +27 -14
  75. data/lib/uniword/ooxml/types/ooxml_boolean_optional.rb +21 -16
  76. data/lib/uniword/ooxml/types/theme_color_value.rb +22 -0
  77. data/lib/uniword/ooxml/types/unsigned_decimal_number.rb +30 -0
  78. data/lib/uniword/ooxml/types.rb +10 -0
  79. data/lib/uniword/ooxml.rb +2 -0
  80. data/lib/uniword/properties/alignment.rb +8 -3
  81. data/lib/uniword/properties/border.rb +52 -6
  82. data/lib/uniword/properties/cell_vertical_align.rb +4 -1
  83. data/lib/uniword/properties/color_value.rb +8 -3
  84. data/lib/uniword/properties/highlight.rb +9 -5
  85. data/lib/uniword/properties/shading.rb +4 -3
  86. data/lib/uniword/properties/tab_stop.rb +6 -1
  87. data/lib/uniword/properties/table_justification.rb +4 -1
  88. data/lib/uniword/properties/underline.rb +4 -2
  89. data/lib/uniword/properties/vertical_align.rb +6 -3
  90. data/lib/uniword/resource/theme_processor.rb +1 -1
  91. data/lib/uniword/review/review_manager.rb +23 -9
  92. data/lib/uniword/revision.rb +9 -9
  93. data/lib/uniword/schema/model_generator.rb +31 -15
  94. data/lib/uniword/shared_types/hex_color.rb +4 -1
  95. data/lib/uniword/shared_types/pixel_measure.rb +4 -1
  96. data/lib/uniword/shared_types/point_measure.rb +4 -1
  97. data/lib/uniword/shared_types/text_alignment.rb +6 -1
  98. data/lib/uniword/shared_types/twips_measure.rb +4 -1
  99. data/lib/uniword/spreadsheetml/phonetic_pr.rb +1 -1
  100. data/lib/uniword/spreadsheetml/shared_string_table.rb +2 -2
  101. data/lib/uniword/spreadsheetml/table_formula.rb +1 -1
  102. data/lib/uniword/template/variable_resolver.rb +40 -3
  103. data/lib/uniword/themes/theme_transformation.rb +56 -42
  104. data/lib/uniword/toc/toc_generator.rb +2 -0
  105. data/lib/uniword/validation/checkers/footnote_reference_checker.rb +4 -1
  106. data/lib/uniword/validation/engine.rb +35 -0
  107. data/lib/uniword/validation/link_checker.rb +1 -1
  108. data/lib/uniword/validation/opc_validator.rb +0 -1
  109. data/lib/uniword/validation/report/layer_result.rb +0 -1
  110. data/lib/uniword/validation/report/terminal_formatter.rb +0 -1
  111. data/lib/uniword/validation/report/verification_report.rb +0 -2
  112. data/lib/uniword/validation/report.rb +20 -0
  113. data/lib/uniword/validation/rules/base.rb +10 -2
  114. data/lib/uniword/validation/rules/bookmark_pairing_rule.rb +38 -0
  115. data/lib/uniword/validation/rules/bookmark_uniqueness_rule.rb +48 -0
  116. data/lib/uniword/validation/rules/bookmarks_rule.rb +0 -2
  117. data/lib/uniword/validation/rules/content_types_coverage_rule.rb +0 -2
  118. data/lib/uniword/validation/rules/core_properties_namespace_rule.rb +0 -2
  119. data/lib/uniword/validation/rules/document_body_rule.rb +25 -0
  120. data/lib/uniword/validation/rules/document_context.rb +8 -1
  121. data/lib/uniword/validation/rules/empty_paragraphs_rule.rb +27 -0
  122. data/lib/uniword/validation/rules/font_table_signature_rule.rb +0 -2
  123. data/lib/uniword/validation/rules/fonts_rule.rb +0 -2
  124. data/lib/uniword/validation/rules/footnotes_rule.rb +0 -2
  125. data/lib/uniword/validation/rules/headers_footers_rule.rb +0 -2
  126. data/lib/uniword/validation/rules/images_rule.rb +0 -2
  127. data/lib/uniword/validation/rules/mc_ignorable_namespace_rule.rb +0 -2
  128. data/lib/uniword/validation/rules/model_context.rb +32 -0
  129. data/lib/uniword/validation/rules/model_rule.rb +34 -0
  130. data/lib/uniword/validation/rules/numbering_preservation_rule.rb +0 -2
  131. data/lib/uniword/validation/rules/numbering_rule.rb +0 -2
  132. data/lib/uniword/validation/rules/relationship_integrity_rule.rb +0 -1
  133. data/lib/uniword/validation/rules/rsid_rule.rb +0 -2
  134. data/lib/uniword/validation/rules/section_properties_rule.rb +0 -2
  135. data/lib/uniword/validation/rules/settings_rule.rb +0 -2
  136. data/lib/uniword/validation/rules/settings_values_rule.rb +0 -2
  137. data/lib/uniword/validation/rules/style_references_rule.rb +0 -2
  138. data/lib/uniword/validation/rules/table_grid_rule.rb +27 -0
  139. data/lib/uniword/validation/rules/table_properties_rule.rb +27 -0
  140. data/lib/uniword/validation/rules/tables_rule.rb +0 -2
  141. data/lib/uniword/validation/rules/theme_completeness_rule.rb +0 -2
  142. data/lib/uniword/validation/rules/theme_rule.rb +0 -2
  143. data/lib/uniword/validation/rules.rb +61 -23
  144. data/lib/uniword/validation/schema_registry.rb +11 -0
  145. data/lib/uniword/validation/validators/document_semantics_validator.rb +1 -9
  146. data/lib/uniword/validation/validators/xml_schema_validator.rb +0 -2
  147. data/lib/uniword/validation/validators.rb +0 -9
  148. data/lib/uniword/validation/verify_orchestrator.rb +0 -7
  149. data/lib/uniword/validation.rb +7 -2
  150. data/lib/uniword/version.rb +1 -1
  151. data/lib/uniword/vml/imagedata.rb +0 -1
  152. data/lib/uniword/wordprocessingml/attached_template.rb +0 -1
  153. data/lib/uniword/wordprocessingml/deleted_text.rb +1 -1
  154. data/lib/uniword/wordprocessingml/document_root.rb +211 -21
  155. data/lib/uniword/wordprocessingml/endnotes.rb +4 -0
  156. data/lib/uniword/wordprocessingml/font.rb +1 -1
  157. data/lib/uniword/wordprocessingml/font_replacer.rb +147 -0
  158. data/lib/uniword/wordprocessingml/footnotes.rb +4 -0
  159. data/lib/uniword/wordprocessingml/hdr_shape_defaults.rb +0 -1
  160. data/lib/uniword/wordprocessingml/hyperlink.rb +0 -1
  161. data/lib/uniword/wordprocessingml/level.rb +6 -20
  162. data/lib/uniword/wordprocessingml/math_pr.rb +0 -11
  163. data/lib/uniword/wordprocessingml/numbering_definition.rb +16 -8
  164. data/lib/uniword/wordprocessingml/page_setup.rb +181 -0
  165. data/lib/uniword/wordprocessingml/paragraph_properties.rb +33 -28
  166. data/lib/uniword/wordprocessingml/rsids.rb +0 -2
  167. data/lib/uniword/wordprocessingml/run.rb +3 -0
  168. data/lib/uniword/wordprocessingml/run_properties.rb +20 -50
  169. data/lib/uniword/wordprocessingml/section_properties.rb +2 -2
  170. data/lib/uniword/wordprocessingml/settings.rb +8 -34
  171. data/lib/uniword/wordprocessingml/shape_defaults.rb +0 -1
  172. data/lib/uniword/wordprocessingml/style.rb +4 -3
  173. data/lib/uniword/wordprocessingml/style_cleanup.rb +198 -0
  174. data/lib/uniword/wordprocessingml/table_cell_properties.rb +6 -6
  175. data/lib/uniword/wordprocessingml/table_properties.rb +10 -15
  176. data/lib/uniword/wordprocessingml/update_fields.rb +27 -0
  177. data/lib/uniword/wordprocessingml/w14_attributes.rb +30 -2
  178. data/lib/uniword/wordprocessingml.rb +4 -0
  179. data/lib/uniword.rb +27 -2
  180. metadata +38 -19
  181. data/config/validation_rules.yml +0 -60
  182. data/config/warning_rules.yml +0 -57
  183. data/lib/uniword/validation/document_validator.rb +0 -272
  184. data/lib/uniword/validation/structural_validator.rb +0 -116
  185. data/lib/uniword/validation/validators/content_type_validator.rb +0 -165
  186. data/lib/uniword/validation/validators/file_structure_validator.rb +0 -104
  187. data/lib/uniword/validation/validators/ooxml_part_validator.rb +0 -128
  188. data/lib/uniword/validation/validators/relationship_validator.rb +0 -147
  189. data/lib/uniword/validation/validators/zip_integrity_validator.rb +0 -110
  190. data/lib/uniword/validators/element_validator.rb +0 -93
  191. data/lib/uniword/validators/paragraph_validator.rb +0 -116
  192. data/lib/uniword/validators/table_validator.rb +0 -134
  193. data/lib/uniword/validators.rb +0 -9
  194. data/lib/uniword/warnings/warning.rb +0 -130
  195. data/lib/uniword/warnings/warning_collector.rb +0 -229
  196. data/lib/uniword/warnings/warning_report.rb +0 -159
  197. data/lib/uniword/warnings.rb +0 -9
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uniword
4
+ module Wordprocessingml
5
+ # Removes styles from a document's style definitions — Word's
6
+ # Styles-pane management as an API.
7
+ #
8
+ # `#remove_unused` deletes styles that no content references,
9
+ # directly (pStyle/rStyle/tblStyle in body, headers, footers, notes,
10
+ # comments) or transitively (basedOn/link/next chains from a used
11
+ # style, numbering level pStyle). Default styles (w:default="1")
12
+ # are never removed.
13
+ #
14
+ # @example Declutter a document
15
+ # cleanup = StyleCleanup.new(document)
16
+ # removed = cleanup.remove_unused # => ["ObsoleteStyle", ...]
17
+ class StyleCleanup
18
+ # @param document [DocumentRoot] Document to clean (mutated)
19
+ def initialize(document)
20
+ @document = document
21
+ end
22
+
23
+ # Remove one style by id (unless protected).
24
+ #
25
+ # @param style_id [String] Style id (w:styleId)
26
+ # @return [Boolean] true when the style was removed
27
+ def remove?(style_id)
28
+ return false if protected_id?(style_id)
29
+
30
+ before = styles.size
31
+ styles.delete_if { |style| style.styleId == style_id }
32
+ styles.size < before
33
+ end
34
+
35
+ # Ids of styles no content references.
36
+ #
37
+ # @return [Array<String>] Unreferenced, unprotected style ids
38
+ def unused_ids
39
+ used = used_ids
40
+ styles.filter_map(&:styleId).uniq - used - protected_ids
41
+ end
42
+
43
+ # Remove every unreferenced style.
44
+ #
45
+ # @return [Array<String>] Ids of removed styles
46
+ def remove_unused
47
+ ids = unused_ids
48
+ ids.each { |id| remove?(id) }
49
+ ids
50
+ end
51
+
52
+ private
53
+
54
+ def styles
55
+ @document.styles_configuration.styles
56
+ end
57
+
58
+ def protected_ids
59
+ styles.select(&:default).map(&:styleId)
60
+ end
61
+
62
+ def protected_id?(style_id)
63
+ protected_ids.include?(style_id)
64
+ end
65
+
66
+ # Ids referenced anywhere: content, notes, headers/footers,
67
+ # comments, numbering levels, and style-to-style chains.
68
+ def used_ids
69
+ used = content_style_ids + chain_seed_ids
70
+ expand_chains(used)
71
+ end
72
+
73
+ def content_style_ids
74
+ ids = []
75
+ walk_all_paragraphs do |paragraph|
76
+ ids.concat(paragraph_style_ids(paragraph))
77
+ ids.concat(run_style_ids(paragraph))
78
+ end
79
+ ids.concat(table_style_ids)
80
+ ids.concat(numbering_style_ids)
81
+ ids
82
+ end
83
+
84
+ # Styles referenced by other styles (basedOn/link/next) — chains
85
+ # are expanded from these too.
86
+ def chain_seed_ids
87
+ styles.flat_map { |style| chain_links(style) }
88
+ end
89
+
90
+ def chain_links(style)
91
+ [style.basedOn&.val, style.link&.val, style.nextStyle&.val].compact
92
+ end
93
+
94
+ def expand_chains(ids)
95
+ expanded = ids.to_set
96
+ loop do
97
+ additions = chain_additions(expanded)
98
+ break if additions.empty?
99
+
100
+ additions.each { |id| expanded << id }
101
+ end
102
+ expanded.to_a
103
+ end
104
+
105
+ def chain_additions(expanded)
106
+ styles.select { |style| expanded.include?(style.styleId) }
107
+ .flat_map { |style| chain_links(style) }
108
+ .reject { |id| expanded.include?(id) }
109
+ end
110
+
111
+ def paragraph_style_ids(paragraph)
112
+ Array(paragraph.properties&.style).filter_map(&:value)
113
+ end
114
+
115
+ def run_style_ids(paragraph)
116
+ paragraph_runs(paragraph)
117
+ .filter_map { |run| run.properties&.style&.value }
118
+ end
119
+
120
+ def paragraph_runs(paragraph)
121
+ (paragraph.runs || []) +
122
+ (paragraph.hyperlinks || []).flat_map(&:runs)
123
+ end
124
+
125
+ def table_style_ids
126
+ ids = []
127
+ walk_tables(@document.body) do |table|
128
+ ids << table.properties&.style&.val
129
+ end
130
+ ids.compact
131
+ end
132
+
133
+ def numbering_style_ids
134
+ numbering_definitions.flat_map do |definition|
135
+ (definition.levels || []).filter_map { |level| level.pStyle&.val }
136
+ end
137
+ end
138
+
139
+ def numbering_definitions
140
+ @document.numbering_configuration&.definitions || []
141
+ end
142
+
143
+ # Paragraphs in body (incl. table cells), headers/footers,
144
+ # notes, comments.
145
+ def walk_all_paragraphs(&block)
146
+ each_container { |container| walk_paragraphs(container, &block) }
147
+ end
148
+
149
+ def walk_paragraphs(container, &block)
150
+ return unless container
151
+
152
+ (container.paragraphs || []).each(&block)
153
+ walk_tables(container) { |table| walk_table_rows(table, &block) }
154
+ end
155
+
156
+ def walk_table_rows(table, &block)
157
+ (table.rows || []).each do |row|
158
+ (row.cells || []).each { |cell| walk_paragraphs(cell, &block) }
159
+ end
160
+ end
161
+
162
+ def walk_tables(container, &block)
163
+ return unless container
164
+
165
+ (container.tables || []).each do |table|
166
+ yield table
167
+ walk_table_cells(table, &block)
168
+ end
169
+ end
170
+
171
+ def walk_table_cells(table, &block)
172
+ (table.rows || []).each do |row|
173
+ (row.cells || []).each { |cell| walk_tables(cell, &block) }
174
+ end
175
+ end
176
+
177
+ def each_container(&block)
178
+ yield @document.body if @document.body
179
+ header_footer_containers.each(&block)
180
+ note_containers.each(&block)
181
+ end
182
+
183
+ def header_footer_containers
184
+ (@document.header_footer_parts || []).filter_map do |part|
185
+ part.content if part.content.is_a?(Lutaml::Model::Serializable)
186
+ end
187
+ end
188
+
189
+ def note_containers
190
+ [
191
+ @document.footnotes&.footnote_entries,
192
+ @document.endnotes&.endnote_entries,
193
+ @document.comments&.comments,
194
+ ].flatten.compact
195
+ end
196
+ end
197
+ end
198
+ end
@@ -28,18 +28,18 @@ module Uniword
28
28
  namespace Uniword::Ooxml::Namespaces::WordProcessingML
29
29
  mixed_content
30
30
 
31
+ map_element "cnfStyle", to: :cnf_style, render_nil: false
31
32
  map_element "tcW", to: :cell_width, render_nil: false
32
- map_element "tcBorders", to: :borders, render_nil: false
33
- map_element "shd", to: :shading, render_nil: false
34
- map_element "vAlign", to: :vertical_align, render_nil: false
35
33
  map_element "gridSpan", to: :grid_span, render_nil: false
36
34
  map_element "vMerge", to: :v_merge, render_nil: false
37
- map_element "tcMar", to: :tc_mar, render_nil: false
38
- map_element "cnfStyle", to: :cnf_style, render_nil: false
35
+ map_element "tcBorders", to: :borders, render_nil: false
36
+ map_element "shd", to: :shading, render_nil: false
39
37
  map_element "noWrap", to: :no_wrap, render_nil: false
40
- map_element "hideMark", to: :hide_mark, render_nil: false
38
+ map_element "tcMar", to: :tc_mar, render_nil: false
41
39
  map_element "textDirection", to: :text_direction,
42
40
  render_nil: false
41
+ map_element "vAlign", to: :vertical_align, render_nil: false
42
+ map_element "hideMark", to: :hide_mark, render_nil: false
43
43
  end
44
44
  end
45
45
  end
@@ -84,26 +84,21 @@ module Uniword
84
84
  namespace Uniword::Ooxml::Namespaces::WordProcessingML
85
85
  mixed_content
86
86
 
87
- # High-priority mappings (Phase 4 Session 1-2)
87
+ # ECMA-376 CT_TblPrBase schema sequence:
88
+ # tblStyle, tblpPr, tblOverlap, bidiVisual, tblStyleRowBandSize,
89
+ # tblStyleColBandSize, tblW, jc, tblCellSpacing, tblInd, tblBorders,
90
+ # shd, tblLayout, tblCellMar, tblLook, tblCaption, tblDescription
91
+ map_element "tblStyle", to: :style, render_nil: false
88
92
  map_element "tblW", to: :table_width, render_nil: false
93
+ map_element "jc", to: :alignment, render_nil: false
94
+ map_element "tblCellSpacing", to: :cell_spacing, render_nil: false
95
+ map_element "tblInd", to: :table_indent, render_nil: false
96
+ map_element "tblBorders", to: :table_borders, render_nil: false
89
97
  map_element "shd", to: :shading, render_nil: false
98
+ map_element "tblLayout", to: :table_layout, render_nil: false
90
99
  map_element "tblCellMar", to: :table_cell_margin, render_nil: false
91
100
  map_element "tblLook", to: :table_look, render_nil: false
92
101
  map_element "tblCaption", to: :caption, render_nil: false
93
-
94
- # Table indentation - critical for table styles
95
- map_element "tblInd", to: :table_indent, render_nil: false
96
- # Table cell spacing
97
- map_element "tblCellSpacing", to: :cell_spacing, render_nil: false
98
- # Table alignment
99
- map_element "jc", to: :alignment, render_nil: false
100
- # Table layout
101
- map_element "tblLayout", to: :table_layout, render_nil: false
102
- # Table style reference
103
- map_element "tblStyle", to: :style, render_nil: false
104
-
105
- # Table borders
106
- map_element "tblBorders", to: :table_borders, render_nil: false
107
102
  end
108
103
 
109
104
  def initialize(attrs = {})
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Uniword
6
+ module Wordprocessingml
7
+ # Update fields when the document is opened
8
+ #
9
+ # Element: <w:updateFields>
10
+ #
11
+ # When true, Word updates all fields (TOC, page numbers, cross
12
+ # references) the first time the document is opened — generated
13
+ # documents show correct field values without a manual F9.
14
+ class UpdateFields < Lutaml::Model::Serializable
15
+ attribute :value, Ooxml::Types::OoxmlBoolean,
16
+ default: -> { true }
17
+
18
+ xml do
19
+ element "updateFields"
20
+ namespace Uniword::Ooxml::Namespaces::WordProcessingML
21
+
22
+ map_attribute "val", to: :value, render_nil: false,
23
+ render_default: false
24
+ end
25
+ end
26
+ end
27
+ end
@@ -16,15 +16,43 @@ module Uniword
16
16
  # W16CID namespace for Word 2016+ citation identifiers
17
17
  W16CID_NAMESPACE = Uniword::Ooxml::Namespaces::Word2016Cid
18
18
 
19
- # Typed attribute for w14:paraId
19
+ # ST_LongHexNumber (ECMA-376): exactly 8 hexadecimal digits
20
+ LONG_HEX_NUMBER_PATTERN = /\A[0-9A-Fa-f]{8}\z/
21
+
22
+ # Validate an ST_LongHexNumber value at cast time
23
+ #
24
+ # @param value [Object] the raw value
25
+ # @return [String, nil, Object] the validated value
26
+ # @raise [Lutaml::Model::Type::InvalidValueError] when the value is
27
+ # not 8 hexadecimal digits
28
+ def self.cast_long_hex_number(value)
29
+ casted = Lutaml::Model::Type::String.cast(value)
30
+ return casted if casted.nil? ||
31
+ Lutaml::Model::Utils.uninitialized?(casted)
32
+ return casted if LONG_HEX_NUMBER_PATTERN.match?(casted)
33
+
34
+ raise Lutaml::Model::Type::InvalidValueError.new(
35
+ value, ["ST_LongHexNumber: 8 hexadecimal digits"]
36
+ )
37
+ end
38
+
39
+ # Typed attribute for w14:paraId (ST_LongHexNumber)
20
40
  class W14ParaId < Lutaml::Model::Type::String
41
+ def self.cast(value, _options = {})
42
+ Wordprocessingml.cast_long_hex_number(value)
43
+ end
44
+
21
45
  xml do
22
46
  namespace W14_NAMESPACE
23
47
  end
24
48
  end
25
49
 
26
- # Typed attribute for w14:textId
50
+ # Typed attribute for w14:textId (ST_LongHexNumber)
27
51
  class W14TextId < Lutaml::Model::Type::String
52
+ def self.cast(value, _options = {})
53
+ Wordprocessingml.cast_long_hex_number(value)
54
+ end
55
+
28
56
  xml do
29
57
  namespace W14_NAMESPACE
30
58
  end
@@ -64,6 +64,7 @@ module Uniword
64
64
  # Structure and metadata
65
65
  autoload :Level, "uniword/wordprocessingml/level"
66
66
  autoload :Style, "uniword/wordprocessingml/style"
67
+ autoload :StyleCleanup, "uniword/wordprocessingml/style_cleanup"
67
68
  autoload :StructuredDocumentTag,
68
69
  "uniword/wordprocessingml/structured_document_tag"
69
70
  autoload :StructuredDocumentTagProperties,
@@ -72,6 +73,7 @@ module Uniword
72
73
  autoload :PageSize, "uniword/wordprocessingml/page_size"
73
74
  autoload :PageMargins, "uniword/wordprocessingml/page_margins"
74
75
  autoload :PageNumbering, "uniword/wordprocessingml/page_numbering"
76
+ autoload :PageSetup, "uniword/wordprocessingml/page_setup"
75
77
  autoload :Columns, "uniword/wordprocessingml/columns"
76
78
  autoload :HeaderReference, "uniword/wordprocessingml/header_reference"
77
79
  autoload :FooterReference, "uniword/wordprocessingml/footer_reference"
@@ -130,6 +132,7 @@ module Uniword
130
132
 
131
133
  # Fonts
132
134
  autoload :Font, "uniword/wordprocessingml/font"
135
+ autoload :FontReplacer, "uniword/wordprocessingml/font_replacer"
133
136
  autoload :Fonts, "uniword/wordprocessingml/fonts"
134
137
  autoload :FontTable, "uniword/wordprocessingml/font_table"
135
138
 
@@ -191,6 +194,7 @@ module Uniword
191
194
  autoload :Next, "uniword/wordprocessingml/next"
192
195
  autoload :Link, "uniword/wordprocessingml/link"
193
196
  autoload :UiPriority, "uniword/wordprocessingml/ui_priority"
197
+ autoload :UpdateFields, "uniword/wordprocessingml/update_fields"
194
198
  autoload :LatentStyles, "uniword/wordprocessingml/latent_styles"
195
199
  autoload :ParagraphStyle, "uniword/wordprocessingml/paragraph_style"
196
200
  autoload :CharacterStyle, "uniword/wordprocessingml/character_style"
data/lib/uniword.rb CHANGED
@@ -101,7 +101,6 @@ module Uniword
101
101
  autoload :Template, "uniword/template"
102
102
  autoload :TemplateManager, "uniword/template_manager"
103
103
  autoload :Visitor, "uniword/visitor"
104
- autoload :Validators, "uniword/validators"
105
104
  autoload :Stylesets, "uniword/stylesets"
106
105
  autoload :Infrastructure, "uniword/infrastructure"
107
106
  autoload :Accessibility, "uniword/accessibility"
@@ -114,7 +113,6 @@ module Uniword
114
113
  autoload :Configuration, "uniword/configuration"
115
114
  autoload :Transformation, "uniword/transformation"
116
115
  autoload :Validation, "uniword/validation"
117
- autoload :Warnings, "uniword/warnings"
118
116
  autoload :Mhtml, "uniword/mhtml"
119
117
  autoload :Themes, "uniword/themes"
120
118
  autoload :Resource, "uniword/resource"
@@ -135,6 +133,9 @@ module Uniword
135
133
  # CLI
136
134
  autoload :CLI, "uniword/cli/main"
137
135
  autoload :GenerateCLI, "uniword/cli/generate_cli"
136
+ autoload :FontsCLI, "uniword/cli/fonts_cli"
137
+ autoload :PageCLI, "uniword/cli/page_cli"
138
+ autoload :StylesCLI, "uniword/cli/styles_cli"
138
139
  autoload :DiffCLI, "uniword/cli/diff_cli"
139
140
  autoload :TemplateCLI, "uniword/cli/template_cli"
140
141
  autoload :CLIHelpers, "uniword/cli/helpers"
@@ -250,6 +251,30 @@ module Uniword
250
251
  Wordprocessingml::DocumentRoot.new
251
252
  end
252
253
 
254
+ # Get the global runtime configuration (memoized)
255
+ #
256
+ # @return [Configuration] The global configuration instance
257
+ #
258
+ # @example
259
+ # Uniword.configuration.validate_on_save # => true
260
+ def configuration
261
+ @configuration ||= Configuration.new
262
+ end
263
+
264
+ # Configure global runtime policy
265
+ #
266
+ # @yieldparam config [Configuration] The global configuration instance
267
+ # @return [Configuration] The global configuration instance
268
+ #
269
+ # @example
270
+ # Uniword.configure do |config|
271
+ # config.xsd_validation = true
272
+ # end
273
+ def configure
274
+ yield(configuration)
275
+ configuration
276
+ end
277
+
253
278
  # Load document from file
254
279
  #
255
280
  # @param path [String] File path
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uniword
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-15 00:00:00.000000000 Z
11
+ date: 2026-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logger
@@ -182,8 +182,6 @@ files:
182
182
  - config/system_profiles.yml
183
183
  - config/theme_mapping.yml
184
184
  - config/transformation_rules.yml
185
- - config/validation_rules.yml
186
- - config/warning_rules.yml
187
185
  - data/color_schemes/amber.yml
188
186
  - data/color_schemes/azure.yml
189
187
  - data/color_schemes/burgundy.yml
@@ -476,10 +474,14 @@ files:
476
474
  - data/resources/document_elements/zh-TW/tables.yml
477
475
  - data/resources/document_elements/zh-TW/watermarks.yml
478
476
  - data/resources/font_registry.yml
477
+ - data/schemas/ecma/dc.xsd
478
+ - data/schemas/ecma/dcmitype.xsd
479
+ - data/schemas/ecma/dcterms.xsd
479
480
  - data/schemas/ecma/opc-contentTypes.xsd
480
481
  - data/schemas/ecma/opc-coreProperties.xsd
481
482
  - data/schemas/ecma/opc-digSig.xsd
482
483
  - data/schemas/ecma/opc-relationships.xsd
484
+ - data/schemas/ecma/xml.xsd
483
485
  - data/schemas/iso/dml-chart.xsd
484
486
  - data/schemas/iso/dml-chartDrawing.xsd
485
487
  - data/schemas/iso/dml-diagram.xsd
@@ -631,6 +633,7 @@ files:
631
633
  - lib/uniword/builder/base_builder.rb
632
634
  - lib/uniword/builder/bibliography_builder.rb
633
635
  - lib/uniword/builder/chart_builder.rb
636
+ - lib/uniword/builder/comment_anchorer.rb
634
637
  - lib/uniword/builder/comment_builder.rb
635
638
  - lib/uniword/builder/deterministic_id.rb
636
639
  - lib/uniword/builder/document_builder.rb
@@ -728,15 +731,18 @@ files:
728
731
  - lib/uniword/chart/y_values.rb
729
732
  - lib/uniword/cli.rb
730
733
  - lib/uniword/cli/diff_cli.rb
734
+ - lib/uniword/cli/fonts_cli.rb
731
735
  - lib/uniword/cli/generate_cli.rb
732
736
  - lib/uniword/cli/headers_cli.rb
733
737
  - lib/uniword/cli/helpers.rb
734
738
  - lib/uniword/cli/images_cli.rb
735
739
  - lib/uniword/cli/main.rb
740
+ - lib/uniword/cli/page_cli.rb
736
741
  - lib/uniword/cli/protect_cli.rb
737
742
  - lib/uniword/cli/resources_cli.rb
738
743
  - lib/uniword/cli/review_cli.rb
739
744
  - lib/uniword/cli/spellcheck_cli.rb
745
+ - lib/uniword/cli/styles_cli.rb
740
746
  - lib/uniword/cli/styleset_cli.rb
741
747
  - lib/uniword/cli/template_cli.rb
742
748
  - lib/uniword/cli/theme_cli.rb
@@ -809,14 +815,23 @@ files:
809
815
  - lib/uniword/document_variables/variable_scope.rb
810
816
  - lib/uniword/document_writer.rb
811
817
  - lib/uniword/docx.rb
818
+ - lib/uniword/docx/chart_part.rb
819
+ - lib/uniword/docx/custom_xml_item.rb
812
820
  - lib/uniword/docx/document_statistics.rb
821
+ - lib/uniword/docx/header_footer_part.rb
822
+ - lib/uniword/docx/header_footer_part_collection.rb
823
+ - lib/uniword/docx/header_footer_view.rb
813
824
  - lib/uniword/docx/id_allocator.rb
814
825
  - lib/uniword/docx/package.rb
815
826
  - lib/uniword/docx/package_defaults.rb
827
+ - lib/uniword/docx/package_integrity_checker.rb
816
828
  - lib/uniword/docx/package_serialization.rb
829
+ - lib/uniword/docx/part.rb
830
+ - lib/uniword/docx/part_collection.rb
817
831
  - lib/uniword/docx/profile.rb
818
832
  - lib/uniword/docx/reconciler.rb
819
833
  - lib/uniword/docx/reconciler/body.rb
834
+ - lib/uniword/docx/reconciler/fix.rb
820
835
  - lib/uniword/docx/reconciler/fix_codes.rb
821
836
  - lib/uniword/docx/reconciler/helpers.rb
822
837
  - lib/uniword/docx/reconciler/notes.rb
@@ -1096,6 +1111,8 @@ files:
1096
1111
  - lib/uniword/ooxml/dotx_package.rb
1097
1112
  - lib/uniword/ooxml/namespaces.rb
1098
1113
  - lib/uniword/ooxml/package_file.rb
1114
+ - lib/uniword/ooxml/part_definition.rb
1115
+ - lib/uniword/ooxml/part_registry.rb
1099
1116
  - lib/uniword/ooxml/relationships.rb
1100
1117
  - lib/uniword/ooxml/relationships/hyperlink_relationship.rb
1101
1118
  - lib/uniword/ooxml/relationships/image_relationship.rb
@@ -1125,10 +1142,13 @@ files:
1125
1142
  - lib/uniword/ooxml/types/dcterms_created_type.rb
1126
1143
  - lib/uniword/ooxml/types/dcterms_modified_type.rb
1127
1144
  - lib/uniword/ooxml/types/dcterms_w3cdtf_type.rb
1145
+ - lib/uniword/ooxml/types/hex_color_value.rb
1128
1146
  - lib/uniword/ooxml/types/mc_ignorable_type.rb
1129
1147
  - lib/uniword/ooxml/types/ooxml_boolean.rb
1130
1148
  - lib/uniword/ooxml/types/ooxml_boolean_optional.rb
1131
1149
  - lib/uniword/ooxml/types/relationship_id.rb
1150
+ - lib/uniword/ooxml/types/theme_color_value.rb
1151
+ - lib/uniword/ooxml/types/unsigned_decimal_number.rb
1132
1152
  - lib/uniword/ooxml/types/variant_types.rb
1133
1153
  - lib/uniword/page_borders.rb
1134
1154
  - lib/uniword/paragraph_border.rb
@@ -1479,28 +1499,35 @@ files:
1479
1499
  - lib/uniword/validation/checkers/file_reference_checker.rb
1480
1500
  - lib/uniword/validation/checkers/footnote_reference_checker.rb
1481
1501
  - lib/uniword/validation/checkers/internal_link_checker.rb
1482
- - lib/uniword/validation/document_validator.rb
1502
+ - lib/uniword/validation/engine.rb
1483
1503
  - lib/uniword/validation/layer_validation_result.rb
1484
1504
  - lib/uniword/validation/layer_validator.rb
1485
1505
  - lib/uniword/validation/link_checker.rb
1486
1506
  - lib/uniword/validation/link_validator.rb
1487
1507
  - lib/uniword/validation/opc_validator.rb
1508
+ - lib/uniword/validation/report.rb
1488
1509
  - lib/uniword/validation/report/layer_result.rb
1489
1510
  - lib/uniword/validation/report/terminal_formatter.rb
1490
1511
  - lib/uniword/validation/report/validation_issue.rb
1491
1512
  - lib/uniword/validation/report/verification_report.rb
1492
1513
  - lib/uniword/validation/rules.rb
1493
1514
  - lib/uniword/validation/rules/base.rb
1515
+ - lib/uniword/validation/rules/bookmark_pairing_rule.rb
1516
+ - lib/uniword/validation/rules/bookmark_uniqueness_rule.rb
1494
1517
  - lib/uniword/validation/rules/bookmarks_rule.rb
1495
1518
  - lib/uniword/validation/rules/content_types_coverage_rule.rb
1496
1519
  - lib/uniword/validation/rules/core_properties_namespace_rule.rb
1520
+ - lib/uniword/validation/rules/document_body_rule.rb
1497
1521
  - lib/uniword/validation/rules/document_context.rb
1522
+ - lib/uniword/validation/rules/empty_paragraphs_rule.rb
1498
1523
  - lib/uniword/validation/rules/font_table_signature_rule.rb
1499
1524
  - lib/uniword/validation/rules/fonts_rule.rb
1500
1525
  - lib/uniword/validation/rules/footnotes_rule.rb
1501
1526
  - lib/uniword/validation/rules/headers_footers_rule.rb
1502
1527
  - lib/uniword/validation/rules/images_rule.rb
1503
1528
  - lib/uniword/validation/rules/mc_ignorable_namespace_rule.rb
1529
+ - lib/uniword/validation/rules/model_context.rb
1530
+ - lib/uniword/validation/rules/model_rule.rb
1504
1531
  - lib/uniword/validation/rules/numbering_preservation_rule.rb
1505
1532
  - lib/uniword/validation/rules/numbering_rule.rb
1506
1533
  - lib/uniword/validation/rules/registry.rb
@@ -1510,26 +1537,18 @@ files:
1510
1537
  - lib/uniword/validation/rules/settings_rule.rb
1511
1538
  - lib/uniword/validation/rules/settings_values_rule.rb
1512
1539
  - lib/uniword/validation/rules/style_references_rule.rb
1540
+ - lib/uniword/validation/rules/table_grid_rule.rb
1541
+ - lib/uniword/validation/rules/table_properties_rule.rb
1513
1542
  - lib/uniword/validation/rules/tables_rule.rb
1514
1543
  - lib/uniword/validation/rules/theme_completeness_rule.rb
1515
1544
  - lib/uniword/validation/rules/theme_rule.rb
1516
1545
  - lib/uniword/validation/schema_registry.rb
1517
- - lib/uniword/validation/structural_validator.rb
1518
1546
  - lib/uniword/validation/validation_report.rb
1519
1547
  - lib/uniword/validation/validation_result.rb
1520
1548
  - lib/uniword/validation/validators.rb
1521
- - lib/uniword/validation/validators/content_type_validator.rb
1522
1549
  - lib/uniword/validation/validators/document_semantics_validator.rb
1523
- - lib/uniword/validation/validators/file_structure_validator.rb
1524
- - lib/uniword/validation/validators/ooxml_part_validator.rb
1525
- - lib/uniword/validation/validators/relationship_validator.rb
1526
1550
  - lib/uniword/validation/validators/xml_schema_validator.rb
1527
- - lib/uniword/validation/validators/zip_integrity_validator.rb
1528
1551
  - lib/uniword/validation/verify_orchestrator.rb
1529
- - lib/uniword/validators.rb
1530
- - lib/uniword/validators/element_validator.rb
1531
- - lib/uniword/validators/paragraph_validator.rb
1532
- - lib/uniword/validators/table_validator.rb
1533
1552
  - lib/uniword/version.rb
1534
1553
  - lib/uniword/visitor.rb
1535
1554
  - lib/uniword/visitor/base_visitor.rb
@@ -1594,10 +1613,6 @@ files:
1594
1613
  - lib/uniword/vml_word/border_left.rb
1595
1614
  - lib/uniword/vml_word/border_right.rb
1596
1615
  - lib/uniword/vml_word/border_top.rb
1597
- - lib/uniword/warnings.rb
1598
- - lib/uniword/warnings/warning.rb
1599
- - lib/uniword/warnings/warning_collector.rb
1600
- - lib/uniword/warnings/warning_report.rb
1601
1616
  - lib/uniword/watermark.rb
1602
1617
  - lib/uniword/watermark/manager.rb
1603
1618
  - lib/uniword/word2010_ext.rb
@@ -1666,6 +1681,7 @@ files:
1666
1681
  - lib/uniword/wordprocessingml/fallback.rb
1667
1682
  - lib/uniword/wordprocessingml/field_char.rb
1668
1683
  - lib/uniword/wordprocessingml/font.rb
1684
+ - lib/uniword/wordprocessingml/font_replacer.rb
1669
1685
  - lib/uniword/wordprocessingml/font_table.rb
1670
1686
  - lib/uniword/wordprocessingml/fonts.rb
1671
1687
  - lib/uniword/wordprocessingml/footer.rb
@@ -1727,6 +1743,7 @@ files:
1727
1743
  - lib/uniword/wordprocessingml/page_defaults.rb
1728
1744
  - lib/uniword/wordprocessingml/page_margins.rb
1729
1745
  - lib/uniword/wordprocessingml/page_numbering.rb
1746
+ - lib/uniword/wordprocessingml/page_setup.rb
1730
1747
  - lib/uniword/wordprocessingml/page_size.rb
1731
1748
  - lib/uniword/wordprocessingml/paragraph.rb
1732
1749
  - lib/uniword/wordprocessingml/paragraph_borders.rb
@@ -1782,6 +1799,7 @@ files:
1782
1799
  - lib/uniword/wordprocessingml/structured_document_tag/text.rb
1783
1800
  - lib/uniword/wordprocessingml/structured_document_tag_properties.rb
1784
1801
  - lib/uniword/wordprocessingml/style.rb
1802
+ - lib/uniword/wordprocessingml/style_cleanup.rb
1785
1803
  - lib/uniword/wordprocessingml/style_name.rb
1786
1804
  - lib/uniword/wordprocessingml/style_pane_format_filter.rb
1787
1805
  - lib/uniword/wordprocessingml/style_pane_sort_method.rb
@@ -1816,6 +1834,7 @@ files:
1816
1834
  - lib/uniword/wordprocessingml/title_pg.rb
1817
1835
  - lib/uniword/wordprocessingml/tr_height.rb
1818
1836
  - lib/uniword/wordprocessingml/ui_priority.rb
1837
+ - lib/uniword/wordprocessingml/update_fields.rb
1819
1838
  - lib/uniword/wordprocessingml/val_int.rb
1820
1839
  - lib/uniword/wordprocessingml/w14_attributes.rb
1821
1840
  - lib/uniword/wordprocessingml/w14_doc_id.rb