uniword 1.5.1 → 1.5.3
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/CHANGELOG.md +54 -0
- data/lib/uniword/batch/operation/file_result.rb +39 -0
- data/lib/uniword/batch/operation/repair_task.rb +34 -0
- data/lib/uniword/batch/operation/report.rb +66 -0
- data/lib/uniword/batch/operation/runner.rb +30 -0
- data/lib/uniword/batch/operation/task.rb +40 -0
- data/lib/uniword/batch/operation/verify_task.rb +27 -0
- data/lib/uniword/batch/operation.rb +22 -0
- data/lib/uniword/batch.rb +1 -0
- data/lib/uniword/caption/caption_builder.rb +120 -0
- data/lib/uniword/caption/counter.rb +61 -0
- data/lib/uniword/caption/cross_reference.rb +44 -0
- data/lib/uniword/caption.rb +24 -0
- data/lib/uniword/cli/main.rb +134 -0
- data/lib/uniword/cli/review_cli.rb +34 -0
- data/lib/uniword/configuration.rb +17 -0
- data/lib/uniword/diff/semantic/change.rb +66 -0
- data/lib/uniword/diff/semantic/engine.rb +31 -0
- data/lib/uniword/diff/semantic/paragraph_comparator.rb +195 -0
- data/lib/uniword/diff/semantic/result.rb +53 -0
- data/lib/uniword/diff/semantic.rb +26 -0
- data/lib/uniword/diff.rb +1 -0
- data/lib/uniword/docx/deterministic_output.rb +47 -0
- data/lib/uniword/docx.rb +1 -0
- data/lib/uniword/find_replace/body_scope.rb +23 -0
- data/lib/uniword/find_replace/comment_scope.rb +23 -0
- data/lib/uniword/find_replace/endnote_scope.rb +23 -0
- data/lib/uniword/find_replace/engine.rb +84 -0
- data/lib/uniword/find_replace/footer_scope.rb +24 -0
- data/lib/uniword/find_replace/footnote_scope.rb +23 -0
- data/lib/uniword/find_replace/header_scope.rb +24 -0
- data/lib/uniword/find_replace/matcher.rb +23 -0
- data/lib/uniword/find_replace/paragraph_walker.rb +61 -0
- data/lib/uniword/find_replace/regex_matcher.rb +38 -0
- data/lib/uniword/find_replace/result.rb +54 -0
- data/lib/uniword/find_replace/scope.rb +98 -0
- data/lib/uniword/find_replace/string_matcher.rb +72 -0
- data/lib/uniword/find_replace/styles_scope.rb +38 -0
- data/lib/uniword/find_replace.rb +29 -0
- data/lib/uniword/infrastructure/zip_packager.rb +28 -1
- data/lib/uniword/lint/builtin_rules/banned_words.rb +35 -0
- data/lib/uniword/lint/builtin_rules/max_paragraph_length.rb +32 -0
- data/lib/uniword/lint/builtin_rules/require_body.rb +23 -0
- data/lib/uniword/lint/builtin_rules/required_style.rb +31 -0
- data/lib/uniword/lint/builtin_rules.rb +23 -0
- data/lib/uniword/lint/engine.rb +32 -0
- data/lib/uniword/lint/result.rb +59 -0
- data/lib/uniword/lint/rule.rb +77 -0
- data/lib/uniword/lint/ruleset.rb +65 -0
- data/lib/uniword/lint.rb +17 -0
- data/lib/uniword/plugin/cli_command.rb +30 -0
- data/lib/uniword/plugin/loader.rb +43 -0
- data/lib/uniword/plugin/registry.rb +83 -0
- data/lib/uniword/plugin/transformer.rb +50 -0
- data/lib/uniword/plugin/validator.rb +34 -0
- data/lib/uniword/plugin.rb +25 -0
- data/lib/uniword/redact/engine.rb +52 -0
- data/lib/uniword/redact/pattern.rb +23 -0
- data/lib/uniword/redact/pattern_library.rb +60 -0
- data/lib/uniword/redact/result.rb +42 -0
- data/lib/uniword/redact.rb +15 -0
- data/lib/uniword/version.rb +1 -1
- data/lib/uniword/wordprocessingml/document_styling.rb +131 -0
- data/lib/uniword/wordprocessingml/settings.rb +2 -0
- data/lib/uniword/wordprocessingml/track_changes.rb +19 -0
- data/lib/uniword/wordprocessingml.rb +1 -0
- data/lib/uniword.rb +16 -0
- metadata +56 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Redact
|
|
5
|
+
# Redaction orchestrator. Runs each pattern through the
|
|
6
|
+
# FindReplace engine and aggregates per-pattern counts.
|
|
7
|
+
#
|
|
8
|
+
# Open/closed: adding a new pattern = `PatternLibrary.register`
|
|
9
|
+
# call. Engine unchanged.
|
|
10
|
+
class Engine
|
|
11
|
+
# @param document [Wordprocessingml::DocumentRoot]
|
|
12
|
+
# @param patterns [Array<Pattern>, :pii] patterns to apply
|
|
13
|
+
# (`:pii` selects the default library)
|
|
14
|
+
# @param scope [Symbol, Array<Symbol>, :all] find-replace scope
|
|
15
|
+
def initialize(document:, patterns: :pii, scope: :all)
|
|
16
|
+
@document = document
|
|
17
|
+
@patterns = resolve_patterns(patterns)
|
|
18
|
+
@scope = scope
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Redact::Result]
|
|
22
|
+
def run
|
|
23
|
+
result = Result.new
|
|
24
|
+
return result if @patterns.empty?
|
|
25
|
+
|
|
26
|
+
@patterns.each do |pattern|
|
|
27
|
+
matcher = FindReplace::RegexMatcher.new(pattern: pattern.regex,
|
|
28
|
+
replacement: pattern.replacement)
|
|
29
|
+
fr = FindReplace::Engine.new(document: @document,
|
|
30
|
+
matcher: matcher,
|
|
31
|
+
scopes: @scope).run
|
|
32
|
+
result.add(pattern.name, fr.count)
|
|
33
|
+
end
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def resolve_patterns(patterns)
|
|
40
|
+
return PatternLibrary.all if patterns == :pii
|
|
41
|
+
return [] if patterns.nil? || patterns.empty?
|
|
42
|
+
|
|
43
|
+
list = Array(patterns)
|
|
44
|
+
if list.all?(Symbol)
|
|
45
|
+
PatternLibrary.select(list)
|
|
46
|
+
else
|
|
47
|
+
list
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Redact
|
|
5
|
+
# One redaction pattern: a regex plus a label that classifies the
|
|
6
|
+
# kind of PII it matches.
|
|
7
|
+
class Pattern
|
|
8
|
+
attr_reader :name, :regex, :replacement, :description
|
|
9
|
+
|
|
10
|
+
# @param name [Symbol] pattern identifier (e.g. :ssn, :email)
|
|
11
|
+
# @param regex [Regexp] what to match
|
|
12
|
+
# @param replacement [String] replacement text (default "[REDACTED]")
|
|
13
|
+
# @param description [String] human-readable pattern description
|
|
14
|
+
def initialize(name:, regex:, replacement: "[REDACTED]",
|
|
15
|
+
description: nil)
|
|
16
|
+
@name = name
|
|
17
|
+
@regex = regex
|
|
18
|
+
@replacement = replacement
|
|
19
|
+
@description = description
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Redact
|
|
5
|
+
# Built-in library of common PII patterns. Open/closed: callers
|
|
6
|
+
# can register custom patterns via `PatternLibrary.register`.
|
|
7
|
+
class PatternLibrary
|
|
8
|
+
DEFAULT_PATTERNS = [
|
|
9
|
+
# US Social Security Number: AAA-GG-SSSS (no all-zeros groups)
|
|
10
|
+
Pattern.new(name: :ssn,
|
|
11
|
+
regex: /\b(?!000|666|9\d{2})\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/,
|
|
12
|
+
description: "US Social Security Number"),
|
|
13
|
+
# Email address
|
|
14
|
+
Pattern.new(name: :email,
|
|
15
|
+
regex: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i,
|
|
16
|
+
description: "Email address"),
|
|
17
|
+
# US phone: (555) 555-5555 or 555-555-5555
|
|
18
|
+
Pattern.new(name: :phone,
|
|
19
|
+
regex: /\b\(?\d{3}\)?[-.\s]\d{3}[-.\s]\d{4}\b/,
|
|
20
|
+
description: "US phone number"),
|
|
21
|
+
# Credit card number: 13-19 digits, optional separators
|
|
22
|
+
Pattern.new(name: :credit_card,
|
|
23
|
+
regex: /\b(?:\d[ -]*?){13,19}\b/,
|
|
24
|
+
description: "Credit card number"),
|
|
25
|
+
# IPv4 address
|
|
26
|
+
Pattern.new(name: :ipv4,
|
|
27
|
+
regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/,
|
|
28
|
+
description: "IPv4 address"),
|
|
29
|
+
].freeze
|
|
30
|
+
|
|
31
|
+
# All registered patterns, in registration order.
|
|
32
|
+
#
|
|
33
|
+
# @return [Array<Pattern>]
|
|
34
|
+
def self.all
|
|
35
|
+
DEFAULT_PATTERNS + @custom.to_a
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Select patterns by name.
|
|
39
|
+
#
|
|
40
|
+
# @param names [Array<Symbol>, :all] names to select, or :all
|
|
41
|
+
# @return [Array<Pattern>]
|
|
42
|
+
def self.select(names)
|
|
43
|
+
return all if names == :all
|
|
44
|
+
|
|
45
|
+
list = all
|
|
46
|
+
Array(names).filter_map { |n| list.find { |p| p.name == n } }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Register a custom pattern. Append-only.
|
|
50
|
+
#
|
|
51
|
+
# @param pattern [Pattern]
|
|
52
|
+
# @return [void]
|
|
53
|
+
def self.register(pattern)
|
|
54
|
+
(@custom ||= []) << pattern
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
@custom = []
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Redact
|
|
5
|
+
# Aggregated redaction result.
|
|
6
|
+
class Result
|
|
7
|
+
attr_reader :by_pattern
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@by_pattern = Hash.new { |h, k| h[k] = 0 }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @param name [Symbol] pattern name
|
|
14
|
+
# @param count [Integer] substitutions for this pattern
|
|
15
|
+
# @return [void]
|
|
16
|
+
def add(name, count)
|
|
17
|
+
@by_pattern[name] += count
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Total substitutions across all patterns.
|
|
21
|
+
#
|
|
22
|
+
# @return [Integer]
|
|
23
|
+
def count
|
|
24
|
+
@by_pattern.values.sum
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Patterns that matched at least once.
|
|
28
|
+
#
|
|
29
|
+
# @return [Array<Symbol>]
|
|
30
|
+
def patterns_matched
|
|
31
|
+
@by_pattern.select { |_, c| c.positive? }.keys
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# True when zero substitutions were made.
|
|
35
|
+
#
|
|
36
|
+
# @return [Boolean]
|
|
37
|
+
def empty?
|
|
38
|
+
count.zero?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
# Document redaction and anonymization.
|
|
5
|
+
#
|
|
6
|
+
# Built on FindReplace for content rewriting plus a metadata strip
|
|
7
|
+
# pass for identifying attributes (rsids, author info, revision
|
|
8
|
+
# metadata, hidden text). Compliance use case Word cannot serve.
|
|
9
|
+
module Redact
|
|
10
|
+
autoload :Engine, "#{__dir__}/redact/engine"
|
|
11
|
+
autoload :Pattern, "#{__dir__}/redact/pattern"
|
|
12
|
+
autoload :PatternLibrary, "#{__dir__}/redact/pattern_library"
|
|
13
|
+
autoload :Result, "#{__dir__}/redact/result"
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/uniword/version.rb
CHANGED
|
@@ -119,6 +119,122 @@ module Uniword
|
|
|
119
119
|
replacer.replace(self)
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
+
# Find and replace text across document parts.
|
|
123
|
+
#
|
|
124
|
+
# Mirrors Word's Home → Replace dialog (without the GUI).
|
|
125
|
+
# Replaces every non-overlapping match of `pattern` with
|
|
126
|
+
# `replacement` across the configured scopes. Returns a
|
|
127
|
+
# `FindReplace::Result` with per-scope counts.
|
|
128
|
+
#
|
|
129
|
+
# v1 limitation: matches inside a single run only. Matches
|
|
130
|
+
# that span run boundaries are silently skipped (Word does the
|
|
131
|
+
# same in default mode).
|
|
132
|
+
#
|
|
133
|
+
# @param pattern [String, Regexp] literal String or Regexp
|
|
134
|
+
# @param replacement [String] replacement text; for regex
|
|
135
|
+
# patterns, may reference captures via `\1`, `\2`, ...
|
|
136
|
+
# @param scope [Symbol, Array<Symbol>, :all] one or more of
|
|
137
|
+
# `:body`, `:headers`, `:footers`, `:footnotes`, `:endnotes`,
|
|
138
|
+
# `:comments`, `:styles`, or `:all` (default)
|
|
139
|
+
# @param ignore_case [Boolean] case-insensitive match
|
|
140
|
+
# @return [FindReplace::Result]
|
|
141
|
+
def find_replace(pattern, replacement, scope: :all, ignore_case: false)
|
|
142
|
+
matcher = build_find_replace_matcher(pattern, replacement, ignore_case)
|
|
143
|
+
FindReplace::Engine.new(document: self, matcher: matcher,
|
|
144
|
+
scopes: scope).run
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Turn change tracking on. Every subsequent edit is recorded as
|
|
148
|
+
# a tracked change. Mirrors Word's Review → Track Changes → On.
|
|
149
|
+
#
|
|
150
|
+
# @return [self]
|
|
151
|
+
def track_changes_on!
|
|
152
|
+
ensure_settings.track_changes = Wordprocessingml::TrackChanges.new
|
|
153
|
+
self
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Turn change tracking off. Existing tracked changes remain in
|
|
157
|
+
# the document; new edits are applied silently. Mirrors Word's
|
|
158
|
+
# Review → Track Changes → Off.
|
|
159
|
+
#
|
|
160
|
+
# @return [self]
|
|
161
|
+
def track_changes_off!
|
|
162
|
+
ensure_settings.track_changes = nil
|
|
163
|
+
self
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# True when change tracking is enabled.
|
|
167
|
+
#
|
|
168
|
+
# @return [Boolean]
|
|
169
|
+
def track_changes_enabled?
|
|
170
|
+
settings&.track_changes ? true : false
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Redact PII patterns and/or custom regex across the document.
|
|
174
|
+
#
|
|
175
|
+
# Built on FindReplace. Default pattern library matches US
|
|
176
|
+
# phone numbers, email, SSN, credit card numbers, IPv4
|
|
177
|
+
# addresses. Pass `patterns: :pii` for defaults, or an array
|
|
178
|
+
# of names (`[:ssn, :email]`) to select a subset.
|
|
179
|
+
#
|
|
180
|
+
# @param patterns [Symbol, Array<Symbol>, Array<Redact::Pattern>]
|
|
181
|
+
# `:pii` (default), or names/Pattern objects to apply
|
|
182
|
+
# @param scope [Symbol, Array<Symbol>, :all] find-replace scope
|
|
183
|
+
# @return [Redact::Result]
|
|
184
|
+
def redact(patterns: :pii, scope: :all)
|
|
185
|
+
Redact::Engine.new(document: self, patterns: patterns,
|
|
186
|
+
scope: scope).run
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Run a lint ruleset against the document.
|
|
190
|
+
#
|
|
191
|
+
# @param ruleset [Lint::Ruleset, Array<Lint::Rule>] rules to
|
|
192
|
+
# apply
|
|
193
|
+
# @return [Lint::Result]
|
|
194
|
+
def lint(ruleset:)
|
|
195
|
+
Lint::Engine.new(document: self, ruleset: ruleset).run
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Counter for auto-numbered captions. Persisted across the
|
|
199
|
+
# document's lifetime; reset on document load.
|
|
200
|
+
#
|
|
201
|
+
# @return [Caption::Counter]
|
|
202
|
+
def caption_counter
|
|
203
|
+
@caption_counter ||= Caption::Counter.new
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Add an auto-numbered caption paragraph to the body and
|
|
207
|
+
# return the bookmark name (for use in cross-references).
|
|
208
|
+
#
|
|
209
|
+
# The caption is appended as a new paragraph with style
|
|
210
|
+
# "Caption" and a SEQ field. The bookmark wraps the entire
|
|
211
|
+
# paragraph so cross-references resolve to the caption text.
|
|
212
|
+
#
|
|
213
|
+
# @param label [String] "Figure", "Table", "Equation", or any
|
|
214
|
+
# other category — each gets its own counter
|
|
215
|
+
# @param text [String] caption body
|
|
216
|
+
# @param separator [String] between the label/number and the
|
|
217
|
+
# body (default ": ")
|
|
218
|
+
# @return [String] bookmark name (e.g. "_Figure1")
|
|
219
|
+
def add_caption(label:, text:, separator: ": ")
|
|
220
|
+
builder = Caption::CaptionBuilder.new(caption_counter)
|
|
221
|
+
paragraph, bookmark_name = builder.build(label: label,
|
|
222
|
+
text: text,
|
|
223
|
+
separator: separator)
|
|
224
|
+
body.paragraphs << paragraph
|
|
225
|
+
bookmark_name
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Build a cross-reference run targeting a bookmark. Returns a
|
|
229
|
+
# Run containing a SimpleField with a REF instruction. The
|
|
230
|
+
# caller decides where to place it.
|
|
231
|
+
#
|
|
232
|
+
# @param bookmark_name [String] target bookmark
|
|
233
|
+
# @return [Wordprocessingml::SimpleField]
|
|
234
|
+
def cross_reference_to(bookmark_name)
|
|
235
|
+
Caption::CrossReference.new(bookmark_name).build
|
|
236
|
+
end
|
|
237
|
+
|
|
122
238
|
# Apply uniform page setup to every section of the document
|
|
123
239
|
#
|
|
124
240
|
# Mirrors Word's Layout dialog: named paper sizes, orientation
|
|
@@ -230,6 +346,21 @@ module Uniword
|
|
|
230
346
|
|
|
231
347
|
private
|
|
232
348
|
|
|
349
|
+
def build_find_replace_matcher(pattern, replacement, ignore_case)
|
|
350
|
+
if pattern.is_a?(Regexp)
|
|
351
|
+
FindReplace::RegexMatcher.new(pattern: pattern,
|
|
352
|
+
replacement: replacement)
|
|
353
|
+
else
|
|
354
|
+
FindReplace::StringMatcher.new(pattern: pattern,
|
|
355
|
+
replacement: replacement,
|
|
356
|
+
ignore_case: ignore_case)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def ensure_settings
|
|
361
|
+
self.settings ||= Wordprocessingml::Settings.new
|
|
362
|
+
end
|
|
363
|
+
|
|
233
364
|
# Ensure the document carries a theme part, creating it from a
|
|
234
365
|
# fresh parse of the bundled Office theme when absent (every
|
|
235
366
|
# document gets its own copy — no shared state).
|
|
@@ -37,6 +37,7 @@ module Uniword
|
|
|
37
37
|
attribute :hyphenation_zone, HyphenationZone
|
|
38
38
|
attribute :style_pane_sort_method, StylePaneSortMethod
|
|
39
39
|
attribute :doc_vars, DocVars
|
|
40
|
+
attribute :track_changes, TrackChanges
|
|
40
41
|
attribute :w14_doc_id, W14DocId
|
|
41
42
|
attribute :w15_chart_tracking_ref_based, W15ChartTrackingRefBased
|
|
42
43
|
attribute :w15_doc_id, W15DocId
|
|
@@ -106,6 +107,7 @@ module Uniword
|
|
|
106
107
|
map_element "endnotePr", to: :endnote_pr, render_nil: false
|
|
107
108
|
map_element "compat", to: :compat, render_nil: false
|
|
108
109
|
map_element "docVars", to: :doc_vars, render_nil: false
|
|
110
|
+
map_element "trackChanges", to: :track_changes, render_nil: false
|
|
109
111
|
map_element "rsids", to: :rsids, render_nil: false
|
|
110
112
|
map_element "mathPr", to: :math_pr, render_nil: false
|
|
111
113
|
map_element "themeFontLang", to: :theme_font_lang, render_nil: false
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Uniword
|
|
6
|
+
module Wordprocessingml
|
|
7
|
+
# Empty `<w:trackChanges/>` element in `<w:settings>` — Word's
|
|
8
|
+
# Review → Track Changes toggle.
|
|
9
|
+
#
|
|
10
|
+
# When present, Word records every edit as a tracked change. When
|
|
11
|
+
# absent, edits are applied silently.
|
|
12
|
+
class TrackChanges < Lutaml::Model::Serializable
|
|
13
|
+
xml do
|
|
14
|
+
element "trackChanges"
|
|
15
|
+
namespace Uniword::Ooxml::Namespaces::WordProcessingML
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -88,6 +88,7 @@ module Uniword
|
|
|
88
88
|
autoload :DefaultTabStop, "uniword/wordprocessingml/default_tab_stop"
|
|
89
89
|
autoload :CharacterSpacingControl, "uniword/wordprocessingml/character_spacing_control"
|
|
90
90
|
autoload :DoNotDisplayPageBoundaries, "uniword/wordprocessingml/do_not_display_page_boundaries"
|
|
91
|
+
autoload :TrackChanges, "uniword/wordprocessingml/track_changes"
|
|
91
92
|
autoload :Rsids, "uniword/wordprocessingml/rsids"
|
|
92
93
|
autoload :RsidRoot, "uniword/wordprocessingml/rsid_root"
|
|
93
94
|
autoload :Rsid, "uniword/wordprocessingml/rsid"
|
data/lib/uniword.rb
CHANGED
|
@@ -130,6 +130,22 @@ module Uniword
|
|
|
130
130
|
# Builder API (construction layer for OOXML models)
|
|
131
131
|
autoload :Builder, "uniword/builder"
|
|
132
132
|
|
|
133
|
+
# Find & replace over document parts (body, headers, footers,
|
|
134
|
+
# footnotes, endnotes, comments, styles).
|
|
135
|
+
autoload :FindReplace, "uniword/find_replace"
|
|
136
|
+
|
|
137
|
+
# Document redaction (PII patterns, custom regex).
|
|
138
|
+
autoload :Redact, "uniword/redact"
|
|
139
|
+
|
|
140
|
+
# Document lint (style-guide enforcement).
|
|
141
|
+
autoload :Lint, "uniword/lint"
|
|
142
|
+
|
|
143
|
+
# Auto-numbered captions + cross-references.
|
|
144
|
+
autoload :Caption, "uniword/caption"
|
|
145
|
+
|
|
146
|
+
# Plugin system (validators, transformers, CLI commands).
|
|
147
|
+
autoload :Plugin, "uniword/plugin"
|
|
148
|
+
|
|
133
149
|
# CLI
|
|
134
150
|
autoload :CLI, "uniword/cli/main"
|
|
135
151
|
autoload :GenerateCLI, "uniword/cli/generate_cli"
|
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.5.
|
|
4
|
+
version: 1.5.3
|
|
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-
|
|
11
|
+
date: 2026-08-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: logger
|
|
@@ -592,6 +592,13 @@ files:
|
|
|
592
592
|
- lib/uniword/batch.rb
|
|
593
593
|
- lib/uniword/batch/batch_result.rb
|
|
594
594
|
- lib/uniword/batch/document_processor.rb
|
|
595
|
+
- lib/uniword/batch/operation.rb
|
|
596
|
+
- lib/uniword/batch/operation/file_result.rb
|
|
597
|
+
- lib/uniword/batch/operation/repair_task.rb
|
|
598
|
+
- lib/uniword/batch/operation/report.rb
|
|
599
|
+
- lib/uniword/batch/operation/runner.rb
|
|
600
|
+
- lib/uniword/batch/operation/task.rb
|
|
601
|
+
- lib/uniword/batch/operation/verify_task.rb
|
|
595
602
|
- lib/uniword/batch/processing_stage.rb
|
|
596
603
|
- lib/uniword/batch/stages/compress_images_stage.rb
|
|
597
604
|
- lib/uniword/batch/stages/convert_format_stage.rb
|
|
@@ -656,6 +663,10 @@ files:
|
|
|
656
663
|
- lib/uniword/builder/theme_builder.rb
|
|
657
664
|
- lib/uniword/builder/toc_builder.rb
|
|
658
665
|
- lib/uniword/builder/watermark_builder.rb
|
|
666
|
+
- lib/uniword/caption.rb
|
|
667
|
+
- lib/uniword/caption/caption_builder.rb
|
|
668
|
+
- lib/uniword/caption/counter.rb
|
|
669
|
+
- lib/uniword/caption/cross_reference.rb
|
|
659
670
|
- lib/uniword/chart.rb
|
|
660
671
|
- lib/uniword/chart/area3_d_chart.rb
|
|
661
672
|
- lib/uniword/chart/area_chart.rb
|
|
@@ -800,6 +811,11 @@ files:
|
|
|
800
811
|
- lib/uniword/diff/formatter.rb
|
|
801
812
|
- lib/uniword/diff/package_diff_result.rb
|
|
802
813
|
- lib/uniword/diff/package_differ.rb
|
|
814
|
+
- lib/uniword/diff/semantic.rb
|
|
815
|
+
- lib/uniword/diff/semantic/change.rb
|
|
816
|
+
- lib/uniword/diff/semantic/engine.rb
|
|
817
|
+
- lib/uniword/diff/semantic/paragraph_comparator.rb
|
|
818
|
+
- lib/uniword/diff/semantic/result.rb
|
|
803
819
|
- lib/uniword/document_factory.rb
|
|
804
820
|
- lib/uniword/document_input.rb
|
|
805
821
|
- lib/uniword/document_variables.rb
|
|
@@ -817,6 +833,7 @@ files:
|
|
|
817
833
|
- lib/uniword/docx.rb
|
|
818
834
|
- lib/uniword/docx/chart_part.rb
|
|
819
835
|
- lib/uniword/docx/custom_xml_item.rb
|
|
836
|
+
- lib/uniword/docx/deterministic_output.rb
|
|
820
837
|
- lib/uniword/docx/document_statistics.rb
|
|
821
838
|
- lib/uniword/docx/header_footer_part.rb
|
|
822
839
|
- lib/uniword/docx/header_footer_part_collection.rb
|
|
@@ -1001,6 +1018,21 @@ files:
|
|
|
1001
1018
|
- lib/uniword/endnote.rb
|
|
1002
1019
|
- lib/uniword/errors.rb
|
|
1003
1020
|
- lib/uniword/field.rb
|
|
1021
|
+
- lib/uniword/find_replace.rb
|
|
1022
|
+
- lib/uniword/find_replace/body_scope.rb
|
|
1023
|
+
- lib/uniword/find_replace/comment_scope.rb
|
|
1024
|
+
- lib/uniword/find_replace/endnote_scope.rb
|
|
1025
|
+
- lib/uniword/find_replace/engine.rb
|
|
1026
|
+
- lib/uniword/find_replace/footer_scope.rb
|
|
1027
|
+
- lib/uniword/find_replace/footnote_scope.rb
|
|
1028
|
+
- lib/uniword/find_replace/header_scope.rb
|
|
1029
|
+
- lib/uniword/find_replace/matcher.rb
|
|
1030
|
+
- lib/uniword/find_replace/paragraph_walker.rb
|
|
1031
|
+
- lib/uniword/find_replace/regex_matcher.rb
|
|
1032
|
+
- lib/uniword/find_replace/result.rb
|
|
1033
|
+
- lib/uniword/find_replace/scope.rb
|
|
1034
|
+
- lib/uniword/find_replace/string_matcher.rb
|
|
1035
|
+
- lib/uniword/find_replace/styles_scope.rb
|
|
1004
1036
|
- lib/uniword/footer.rb
|
|
1005
1037
|
- lib/uniword/footnote.rb
|
|
1006
1038
|
- lib/uniword/format_converter.rb
|
|
@@ -1048,6 +1080,16 @@ files:
|
|
|
1048
1080
|
- lib/uniword/infrastructure/zip_packager.rb
|
|
1049
1081
|
- lib/uniword/lazy_loader.rb
|
|
1050
1082
|
- lib/uniword/line_numbering.rb
|
|
1083
|
+
- lib/uniword/lint.rb
|
|
1084
|
+
- lib/uniword/lint/builtin_rules.rb
|
|
1085
|
+
- lib/uniword/lint/builtin_rules/banned_words.rb
|
|
1086
|
+
- lib/uniword/lint/builtin_rules/max_paragraph_length.rb
|
|
1087
|
+
- lib/uniword/lint/builtin_rules/require_body.rb
|
|
1088
|
+
- lib/uniword/lint/builtin_rules/required_style.rb
|
|
1089
|
+
- lib/uniword/lint/engine.rb
|
|
1090
|
+
- lib/uniword/lint/result.rb
|
|
1091
|
+
- lib/uniword/lint/rule.rb
|
|
1092
|
+
- lib/uniword/lint/ruleset.rb
|
|
1051
1093
|
- lib/uniword/loggable.rb
|
|
1052
1094
|
- lib/uniword/logger.rb
|
|
1053
1095
|
- lib/uniword/math.rb
|
|
@@ -1179,6 +1221,12 @@ files:
|
|
|
1179
1221
|
- lib/uniword/picture/picture_source_rect.rb
|
|
1180
1222
|
- lib/uniword/picture/picture_stretch.rb
|
|
1181
1223
|
- lib/uniword/picture/tile.rb
|
|
1224
|
+
- lib/uniword/plugin.rb
|
|
1225
|
+
- lib/uniword/plugin/cli_command.rb
|
|
1226
|
+
- lib/uniword/plugin/loader.rb
|
|
1227
|
+
- lib/uniword/plugin/registry.rb
|
|
1228
|
+
- lib/uniword/plugin/transformer.rb
|
|
1229
|
+
- lib/uniword/plugin/validator.rb
|
|
1182
1230
|
- lib/uniword/presentationml.rb
|
|
1183
1231
|
- lib/uniword/presentationml/audio.rb
|
|
1184
1232
|
- lib/uniword/presentationml/body_properties.rb
|
|
@@ -1294,6 +1342,11 @@ files:
|
|
|
1294
1342
|
- lib/uniword/quality/rules/paragraph_length_rule.rb
|
|
1295
1343
|
- lib/uniword/quality/rules/style_consistency_rule.rb
|
|
1296
1344
|
- lib/uniword/quality/rules/table_header_rule.rb
|
|
1345
|
+
- lib/uniword/redact.rb
|
|
1346
|
+
- lib/uniword/redact/engine.rb
|
|
1347
|
+
- lib/uniword/redact/pattern.rb
|
|
1348
|
+
- lib/uniword/redact/pattern_library.rb
|
|
1349
|
+
- lib/uniword/redact/result.rb
|
|
1297
1350
|
- lib/uniword/resource.rb
|
|
1298
1351
|
- lib/uniword/resource/cache.rb
|
|
1299
1352
|
- lib/uniword/resource/cache_paths.rb
|
|
@@ -1849,6 +1902,7 @@ files:
|
|
|
1849
1902
|
- lib/uniword/wordprocessingml/theme_font_lang.rb
|
|
1850
1903
|
- lib/uniword/wordprocessingml/title_pg.rb
|
|
1851
1904
|
- lib/uniword/wordprocessingml/tr_height.rb
|
|
1905
|
+
- lib/uniword/wordprocessingml/track_changes.rb
|
|
1852
1906
|
- lib/uniword/wordprocessingml/ui_priority.rb
|
|
1853
1907
|
- lib/uniword/wordprocessingml/update_fields.rb
|
|
1854
1908
|
- lib/uniword/wordprocessingml/val_int.rb
|