canon 0.1.23 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +155 -30
  3. data/docs/INDEX.adoc +4 -0
  4. data/docs/advanced/diff-classification.adoc +3 -2
  5. data/docs/advanced/verbose-mode-architecture.adoc +23 -0
  6. data/docs/features/configuration-profiles.adoc +288 -0
  7. data/docs/features/diff-formatting/character-visualization.adoc +153 -454
  8. data/docs/features/diff-formatting/display-filtering.adoc +44 -0
  9. data/docs/features/diff-formatting/display-preprocessing.adoc +656 -0
  10. data/docs/features/diff-formatting/index.adoc +47 -0
  11. data/docs/features/diff-formatting/pretty-diff-mode.adoc +154 -0
  12. data/docs/features/environment-configuration/override-system.adoc +10 -3
  13. data/docs/features/index.adoc +9 -0
  14. data/docs/features/match-options/html-policies.adoc +3 -0
  15. data/docs/features/match-options/index.adoc +32 -42
  16. data/docs/features/match-options/pretty-printed-fixtures.adoc +270 -0
  17. data/docs/guides/choosing-configuration.adoc +22 -0
  18. data/docs/reference/environment-variables.adoc +121 -1
  19. data/docs/reference/options-across-interfaces.adoc +182 -2
  20. data/lib/canon/cli.rb +20 -0
  21. data/lib/canon/commands/diff_command.rb +7 -2
  22. data/lib/canon/commands/format_command.rb +1 -1
  23. data/lib/canon/comparison/html_comparator.rb +29 -19
  24. data/lib/canon/comparison/html_compare_profile.rb +4 -4
  25. data/lib/canon/comparison/markup_comparator.rb +12 -3
  26. data/lib/canon/comparison/match_options/base_resolver.rb +29 -7
  27. data/lib/canon/comparison/match_options/json_resolver.rb +9 -0
  28. data/lib/canon/comparison/match_options/xml_resolver.rb +16 -2
  29. data/lib/canon/comparison/match_options/yaml_resolver.rb +10 -0
  30. data/lib/canon/comparison/match_options.rb +4 -1
  31. data/lib/canon/comparison/whitespace_sensitivity.rb +189 -137
  32. data/lib/canon/comparison/xml_comparator/child_comparison.rb +21 -4
  33. data/lib/canon/comparison/xml_comparator.rb +14 -12
  34. data/lib/canon/comparison/xml_node_comparison.rb +51 -6
  35. data/lib/canon/comparison.rb +52 -9
  36. data/lib/canon/config/env_schema.rb +32 -4
  37. data/lib/canon/config/override_resolver.rb +16 -3
  38. data/lib/canon/config/profile_loader.rb +135 -0
  39. data/lib/canon/config/profiles/metanorma.yml +74 -0
  40. data/lib/canon/config/profiles/metanorma_debug.yml +8 -0
  41. data/lib/canon/config/type_converter.rb +8 -0
  42. data/lib/canon/config.rb +469 -5
  43. data/lib/canon/diff/diff_classifier.rb +41 -11
  44. data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +48 -17
  45. data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +58 -0
  46. data/lib/canon/diff_formatter/diff_detail_formatter.rb +73 -17
  47. data/lib/canon/diff_formatter.rb +493 -36
  48. data/lib/canon/pretty_printer/xml_normalized.rb +395 -0
  49. data/lib/canon/rspec_matchers.rb +36 -0
  50. data/lib/canon/version.rb +1 -1
  51. data/lib/canon/xml/nodes/namespace_node.rb +4 -0
  52. data/lib/canon/xml/nodes/processing_instruction_node.rb +4 -0
  53. data/lib/canon/xml/nodes/root_node.rb +4 -0
  54. data/lib/canon/xml/nodes/text_node.rb +4 -0
  55. data/lib/tasks/performance_helpers.rb +2 -2
  56. metadata +24 -2
@@ -72,6 +72,19 @@ Make invisible characters visible in diff output:
72
72
  * Non-ASCII character detection
73
73
  * CJK-safe Unicode symbols
74
74
 
75
+ Controlled via `Canon::Config`:
76
+
77
+ * `true` — (default) apply the full visualization map; spaces → `░`, tabs → `⇥`, NBSP → `␣`
78
+ * `false` — disable all substitution; useful for copying output or CI tooling that cannot render Unicode symbols
79
+ * `:content_only` — reserved; currently behaves as `true`
80
+
81
+ [source,ruby]
82
+ ----
83
+ Canon::Config.configure do |cfg|
84
+ cfg.xml.diff.character_visualization = false
85
+ end
86
+ ----
87
+
75
88
  See link:character-visualization.adoc[Character visualization] for details.
76
89
 
77
90
  === Context and grouping
@@ -83,6 +96,40 @@ Control how much surrounding context to show:
83
96
 
84
97
  See link:context-and-grouping.adoc[Context and grouping] for details.
85
98
 
99
+ === Display preprocessing
100
+
101
+ Normalize both documents through the same formatter before the line diff, so
102
+ that formatting differences between expected and actual do not confuse the LCS
103
+ algorithm:
104
+
105
+ * `:none` — use documents as-is (default)
106
+ * `:pretty_print` — run through `Canon::PrettyPrinter::Xml` (one tag per line)
107
+ * `:c14n` — run through XML C14N normalization
108
+
109
+ See link:display-preprocessing.adoc[Display preprocessing] for details,
110
+ including the character-visualization constraint for future extensibility.
111
+
112
+ === Pretty-diff mode
113
+
114
+ `:pretty_diff` is a text-LCS diff mode that bypasses DiffNodeMapper entirely.
115
+ It applies `display_preprocessing` to both sides and runs `Diff::LCS.sdiff`
116
+ on the resulting plain-text lines, guaranteeing that every line-level change
117
+ is visible — even when DiffNodeMapper's DOM-address correlation is unreliable.
118
+
119
+ Use it as a reliable fallback when `:by_line` shows no output for changes you
120
+ know are present (issue #85).
121
+
122
+ [source,ruby]
123
+ ----
124
+ formatter = Canon::DiffFormatter.new(
125
+ mode: :pretty_diff,
126
+ display_preprocessing: :pretty_print,
127
+ context_lines: 3,
128
+ )
129
+ ----
130
+
131
+ See link:pretty-diff-mode.adoc[Pretty-diff mode] for details and limitations.
132
+
86
133
  === Algorithm-specific output
87
134
 
88
135
  Different diff algorithms produce different output styles:
@@ -0,0 +1,154 @@
1
+ ---
2
+ title: Pretty-diff mode
3
+ parent: Diff Formatting
4
+ grand_parent: Features
5
+ nav_order: 9
6
+ ---
7
+ = Pretty-diff mode
8
+ :toc:
9
+ :toclevels: 2
10
+
11
+ == Purpose
12
+
13
+ `:pretty_diff` is a text-LCS diff mode that bypasses DiffNodeMapper entirely.
14
+ It applies `display_preprocessing` to both sides, then runs
15
+ `Diff::LCS.sdiff` on the resulting plain-text lines.
16
+
17
+ This guarantees that every line-level change is visible, regardless of whether
18
+ DiffNodeMapper's DOM-address correlation is accurate.
19
+
20
+ == When to use
21
+
22
+ Use `:pretty_diff` when:
23
+
24
+ * `:by_line` mode shows no diff output for changes you *know* are present
25
+ (the issue #85 class of bug where DiffNodeMapper maps DiffNodes to the
26
+ wrong post-preprocessing line numbers)
27
+ * You want a quick human-readable text diff and do not need inline
28
+ character-level highlighting
29
+
30
+ Use `:by_line` when:
31
+
32
+ * Inline character highlighting within a line matters
33
+ * `show_diffs: :normative` / `:informative` filtering is required (these
34
+ filters rely on DiffNodes that `:pretty_diff` does not use)
35
+
36
+ == Usage
37
+
38
+ === Basic usage
39
+
40
+ [source,ruby]
41
+ ----
42
+ formatter = Canon::DiffFormatter.new(
43
+ mode: :pretty_diff,
44
+ display_preprocessing: :normalize_pretty_print, # recommended for mixed-content XML
45
+ context_lines: 3,
46
+ use_color: true,
47
+ )
48
+ output = formatter.format(differences, :xml, doc1: expected, doc2: actual)
49
+ ----
50
+
51
+ Combining with `display_preprocessing: :normalize_pretty_print` is strongly
52
+ recommended for XML with inline markup (Metanorma, DocBook, DITA). It breaks
53
+ every mixed-content element onto separate lines and visualizes inter-element
54
+ whitespace, so the LCS diff can pinpoint changes inside `<p>`, `<formattedref>`,
55
+ and similar elements.
56
+
57
+ `display_preprocessing: :pretty_print` is sufficient for element-only XML
58
+ (no mixed content).
59
+
60
+ === Controlling per-element whitespace visualization
61
+
62
+ By default, `:normalize_pretty_print` treats all inter-element whitespace as
63
+ structural formatting noise and drops it silently — both compact XML and
64
+ indented XML serialize to identical lines. This is the correct default for
65
+ purely structural elements such as `<formattedref>` or `<bibdata>`.
66
+
67
+ For mixed-content elements where whitespace *presence* is meaningful (e.g. the
68
+ word-boundary space in `<p>See <xref/>`), opt in with
69
+ `collapse_whitespace_elements`:
70
+
71
+ [source,ruby]
72
+ ----
73
+ formatter = Canon::DiffFormatter.new(
74
+ mode: :pretty_diff,
75
+ display_preprocessing: :normalize_pretty_print,
76
+ collapse_whitespace_elements: %w[p li td th],
77
+ context_lines: 3,
78
+ use_color: true,
79
+ )
80
+ ----
81
+
82
+ Or via `Canon::Config` (recommended in `spec_helper.rb`):
83
+
84
+ [source,ruby]
85
+ ----
86
+ Canon::Config.configure do |cfg|
87
+ cfg.xml.diff.mode = :pretty_diff
88
+ cfg.xml.diff.display_preprocessing = :normalize_pretty_print
89
+ cfg.xml.diff.collapse_whitespace_elements = %w[p li td th]
90
+ end
91
+ ----
92
+
93
+ For preformatted elements where every whitespace character is significant, use
94
+ `preserve_whitespace_elements` instead (e.g. `%w[pre code]`).
95
+
96
+ See
97
+ link:display-preprocessing.adoc#_controlling_whitespace_visualization_with_element_classification[display-preprocessing:
98
+ element classification] for the full three-way classification system and HTML
99
+ format defaults.
100
+
101
+ == Output format
102
+
103
+ The output uses the same header/context/separator conventions as `:by_line`:
104
+
105
+ [source]
106
+ ----
107
+ Pretty diff (XML mode):
108
+ <section>
109
+ <title>Introduction</title>
110
+ - <para>This describes the <strong>old</strong> behaviour.</para>
111
+ + <para>This describes the <strong>new</strong> behaviour.</para>
112
+ <note>See also: Appendix A.</note>
113
+ </section>
114
+ ----
115
+
116
+ * Lines prefixed `- ` are removals (present in `doc1`, absent in `doc2`)
117
+ * Lines prefixed `+ ` are additions (absent in `doc1`, present in `doc2`)
118
+ * Lines prefixed ` ` are context (unchanged)
119
+ * `--- ---` separates non-adjacent change blocks
120
+
121
+ == Context windowing
122
+
123
+ `context_lines` (default 3) controls how many unchanged lines are shown around
124
+ each change. Nearby windows whose expanded ranges overlap or are adjacent are
125
+ merged into a single block. A `--- ---` separator is emitted between blocks
126
+ that are not adjacent.
127
+
128
+ Setting `context_lines: 0` shows only the changed lines with no surrounding
129
+ context.
130
+
131
+ == Limitations
132
+
133
+ `:pretty_diff` trades DiffNode integration for reliability:
134
+
135
+ * `show_diffs: :normative` / `:informative` filtering is **not supported**.
136
+ All line differences are shown regardless of their classification.
137
+ * Inline character-level highlighting (e.g. highlighting the changed word
138
+ within a changed line) is **not available**; granularity is whole-line only.
139
+ * The `differences` array passed to `DiffFormatter#format` is **ignored**;
140
+ the diff is computed purely from `doc1` and `doc2` via LCS.
141
+
142
+ == Implementation note
143
+
144
+ `Diff::LCS.sdiff` is invoked with `::Diff::LCS` (absolute constant path)
145
+ to avoid resolving against `Canon::Diff` which is an unrelated internal module.
146
+
147
+ == See also
148
+
149
+ * link:display-preprocessing.adoc[Display preprocessing] — normalising input
150
+ before the diff
151
+ * link:context-and-grouping.adoc[Context and grouping] — context_lines and
152
+ diff grouping
153
+ * link:display-filtering.adoc[Display filtering] — normative/informative
154
+ filtering (`:by_line` only)
@@ -16,7 +16,7 @@ This page explains how the priority chain works, when overrides apply, and how t
16
16
 
17
17
  == Priority chain
18
18
 
19
- Configuration values are resolved using a strict three-level priority:
19
+ Configuration values are resolved using a strict four-level priority:
20
20
 
21
21
  [source]
22
22
  ----
@@ -26,18 +26,25 @@ Configuration values are resolved using a strict three-level priority:
26
26
  └──────────────┬──────────────────┘
27
27
  ↓ overrides
28
28
  ┌─────────────────────────────────┐
29
- │ 2. Programmatic Configuration │ ← Medium Priority
29
+ │ 2. Programmatic Configuration │
30
30
  │ (config.xml.diff.algorithm) │
31
31
  └──────────────┬──────────────────┘
32
32
  ↓ overrides
33
33
  ┌─────────────────────────────────┐
34
- │ 3. Default Values │ ← Lowest Priority
34
+ │ 3. Profile Values │
35
+ │ (from YAML config profile) │
36
+ └──────────────┬──────────────────┘
37
+ ↓ overrides
38
+ ┌─────────────────────────────────┐
39
+ │ 4. Default Values │ ← Lowest Priority
35
40
  │ (defined in Canon::Config) │
36
41
  └─────────────────────────────────┘
37
42
  ----
38
43
 
39
44
  **Rule**: Higher priority always wins, regardless of when values are set.
40
45
 
46
+ See link:../configuration-profiles.adoc[Configuration Profiles] for details on the profile layer.
47
+
41
48
  == How overrides work
42
49
 
43
50
  === Environment variables override programmatic settings
@@ -77,6 +77,15 @@ Customize how differences are displayed.
77
77
  * link:diff-formatting/context-and-grouping[Context and Grouping] - Surrounding lines
78
78
  * link:diff-formatting/character-visualization[Character Visualization] - Whitespace visibility
79
79
 
80
+ === Configuration Profiles
81
+
82
+ link:configuration-profiles.adoc[**Configuration Profiles**]::
83
+ Bundle all settings into named presets defined in YAML.
84
+ +
85
+ * Built-in profiles (metanorma, metanorma_debug)
86
+ * Custom profiles from local YAML files
87
+ * Profile inheritance
88
+
80
89
  === System Configuration
81
90
 
82
91
  link:environment-configuration/[**Environment Configuration**]::
@@ -226,6 +226,9 @@ Canon::Comparison.equivalent?(html1, html2, preprocessing: :rendered)
226
226
  Pretty-prints before comparison:
227
227
  - Consistent indentation
228
228
  - One element per line
229
+ - Whitespace-only text nodes in strip-context elements (e.g. `<div>`) are
230
+ removed after formatting, so differences in structural whitespace between
231
+ elements do not produce false normative differences
229
232
  - Good for visual diffs
230
233
 
231
234
  [source,ruby]
@@ -30,6 +30,7 @@ Match options control which aspects of documents are compared and how strictly t
30
30
  * link:profiles.adoc[Match Profiles] - Predefined configurations
31
31
  * link:algorithm-specific-behavior.adoc[Algorithm-Specific Behavior] - How DOM and Semantic algorithms interpret options differently
32
32
  * link:html-policies.adoc[HTML-Specific Policies] - HTML format-specific comparison policies
33
+ * link:pretty-printed-fixtures.adoc[Pretty-Printed Fixture Support] - Comparing compact generated XML against hand-indented fixture heredocs without spurious whitespace differences
33
34
 
34
35
  == Match dimensions overview
35
36
 
@@ -188,34 +189,25 @@ Canon::Comparison.equivalent?(xml1, xml2,
188
189
  ----
189
190
  ====
190
191
 
191
- ==== Whitelist and blacklist options
192
+ ==== Element classification options
192
193
 
193
- You can explicitly specify which elements are whitespace-sensitive using either short or long option names:
194
+ You can explicitly classify elements for whitespace handling:
194
195
 
195
196
  [source,ruby]
196
197
  ----
197
- # Short names (preferred)
198
198
  Canon::Comparison.equivalent?(xml1, xml2,
199
199
  match: {
200
200
  structural_whitespace: :strict,
201
- sensitive_elements: ["pre", "code", "sample"],
202
- insensitive_elements: ["div", "span"]
203
- }
204
- )
205
-
206
- # Long names (backward-compatible)
207
- Canon::Comparison.equivalent?(xml1, xml2,
208
- match: {
209
- structural_whitespace: :strict,
210
- whitespace_sensitive_elements: ["pre", "code", "sample"],
211
- whitespace_insensitive_elements: ["div", "span"]
201
+ preserve_whitespace_elements: ["pre", "code", "sample"],
202
+ collapse_whitespace_elements: ["p", "li", "td"],
203
+ strip_whitespace_elements: ["div", "span"]
212
204
  }
213
205
  )
214
206
  ----
215
207
 
216
208
  **Element names are strings** (not symbols) for consistency with XML/HTML conventions.
217
209
 
218
- **Blacklist takes precedence over whitelist** if an element appears in both lists, whitespace is stripped.
210
+ **Priority order**: strip > preserve > collapse > format defaults.
219
211
 
220
212
  ==== respect_xml_space option
221
213
 
@@ -248,21 +240,19 @@ When determining if an element is whitespace-sensitive, Canon uses this priority
248
240
  ----
249
241
  1. respect_xml_space: false → User config only (ignore xml:space)
250
242
 
251
- 2. User whitelist Use whitelist (user explicitly declared)
243
+ 2. Ancestor walk (strip wins; then preserve; then collapse)
252
244
 
253
- 3. Format defaults HTML: [:pre, :textarea, :script, :style], XML: []
245
+ 3. xml:space="preserve"Element classified as :preserve
254
246
 
255
- 4. User blacklist Remove from defaults/whitelist
247
+ 4. xml:space="default"Use configured behaviour
256
248
 
257
- 5. xml:space="preserve" Element is sensitive
258
-
259
- 6. xml:space="default" → Use steps 1-4
260
- ----
249
+ 5. Format defaults (HTML: preserve + collapse; XML: strip)
261
250
 
262
251
  ==== Format-specific defaults
263
252
 
264
- **HTML**:: `["pre", "textarea", "script", "style"]` - These elements preserve whitespace by HTML specification
265
- **XML**:: `[]` - No default whitespace-sensitive elements, purely user-controlled
253
+ **HTML preserve**:: `["pre", "textarea", "script", "style"]` - Every whitespace character significant
254
+ **HTML collapse**:: `["p", "li", "td", "th", "dt", "dd", "h1"-"h6", ...]` - Whitespace collapsed
255
+ **XML**:: No defaults — all elements are :strip unless explicitly configured
266
256
 
267
257
  ==== Two types of whitespace sensitivity
268
258
 
@@ -272,28 +262,28 @@ Canon handles two distinct whitespace concerns:
272
262
 
273
263
  **2. Text content comparison** — how non-whitespace text content is compared. Controlled by `structural_whitespace` and `text_content` dimension behaviors (`:strict`, `:normalize`, `:ignore`).
274
264
 
275
- The `sensitive_elements` / `insensitive_elements` options control both concerns:
265
+ The `preserve_whitespace_elements`, `collapse_whitespace_elements`, and `strip_whitespace_elements` options control both concerns:
276
266
 
277
267
  [source,ruby]
278
268
  ----
279
269
  # For XML: structural whitespace is stripped by default
280
- # Use sensitive_elements to preserve whitespace in specific elements
270
+ # Use preserve_whitespace_elements to preserve whitespace in specific elements
281
271
  xml1 = "<root><item>Test</item></root>"
282
272
  xml2 = "<root>\n <item>Test</item>\n</root>"
283
273
 
284
- # With sensitive_elements, whitespace inside <item> is preserved
274
+ # With preserve_whitespace_elements, whitespace inside <item> is preserved
285
275
  Canon::Comparison.equivalent?(xml1, xml2,
286
276
  match: {
287
277
  structural_whitespace: :strict,
288
- sensitive_elements: ["item"]
278
+ preserve_whitespace_elements: ["item"]
289
279
  }
290
280
  )
291
281
  # => true
292
282
  ----
293
283
 
294
- **Precedence**: blacklist (`insensitive_elements`) > whitelist (`sensitive_elements`) > format defaults
284
+ **Precedence**: `strip_whitespace_elements` > `preserve_whitespace_elements` > `collapse_whitespace_elements` > format defaults
295
285
 
296
- **No inheritance**: Only the immediate parent element's name is checked — not ancestor elements.
286
+ **Ancestor-based**: The closest matching ancestor determines classification.
297
287
 
298
288
  ==== Examples
299
289
 
@@ -321,17 +311,17 @@ Canon::Comparison.equivalent?(xml1, xml2,
321
311
  # => false
322
312
  ----
323
313
 
324
- .Using sensitive_elements whitelist
314
+ .Using preserve_whitespace_elements
325
315
  [source,ruby]
326
316
  ----
327
- # Make <sample> elements whitespace-sensitive (strings, not symbols)
317
+ # Make <sample> elements preserve whitespace exactly (strings, not symbols)
328
318
  xml1 = "<sample>\n content\n</sample>"
329
319
  xml2 = "<sample>content</sample>"
330
320
 
331
321
  Canon::Comparison.equivalent?(xml1, xml2,
332
322
  match: {
333
323
  structural_whitespace: :strict,
334
- sensitive_elements: ["sample"]
324
+ preserve_whitespace_elements: ["sample"]
335
325
  }
336
326
  )
337
327
  # => false (structural whitespace differs in <sample>)
@@ -340,30 +330,30 @@ Canon::Comparison.equivalent?(xml1, xml2,
340
330
  .Overriding HTML defaults
341
331
  [source,ruby]
342
332
  ----
343
- # Make <script> NOT whitespace-sensitive (override HTML default)
333
+ # Make <script> NOT whitespace-preserved (override HTML default)
344
334
  Canon::Comparison.equivalent?(html1, html2,
345
335
  format: :html,
346
336
  match: {
347
337
  structural_whitespace: :strict,
348
- insensitive_elements: ["script"]
338
+ strip_whitespace_elements: ["script"]
349
339
  }
350
340
  )
351
341
  ----
352
342
 
353
- .Using text_content: :normalize with whitespace_insensitive_elements
343
+ .Using text_content: :normalize with strip_whitespace_elements
354
344
  [source,ruby]
355
345
  ----
356
- # HTML defaults: [:pre, :code, :textarea, :script, :style]
357
- # Excluding :code means it's no longer whitespace-sensitive
346
+ # HTML defaults: pre, code, textarea, script, style are :preserve
347
+ # Adding code to strip list removes it from preserve
358
348
  html1 = '<root><pre> indented </pre><code> code </code></root>'
359
349
  html2 = '<root><pre> indented </pre><code>code</code></root>'
360
350
 
361
- # With :code blacklisted, whitespace in <code> is normalized (formatting-only)
351
+ # With :code in strip list, whitespace in <code> is normalized (formatting-only)
362
352
  # HTML uses text_content: :normalize by default
363
353
  Canon::Comparison.equivalent?(html1, html2,
364
354
  format: :html,
365
355
  match: {
366
- whitespace_insensitive_elements: [:code],
356
+ strip_whitespace_elements: [:code],
367
357
  }
368
358
  )
369
359
  # => true (whitespace differences in <code> are formatting-only)
@@ -737,7 +727,7 @@ expect(actual).to be_xml_equivalent_to(expected,
737
727
  match: { structural_whitespace: :strict }
738
728
  )
739
729
  .with_options(
740
- sensitive_elements: ["pre", "code", "sample"],
730
+ preserve_whitespace_elements: ["pre", "code", "sample"],
741
731
  respect_xml_space: true
742
732
  )
743
733
 
@@ -746,7 +736,7 @@ expect(html).to be_html_equivalent_to(expected,
746
736
  match: { structural_whitespace: :strict }
747
737
  )
748
738
  .with_options(
749
- insensitive_elements: ["script", "style"]
739
+ strip_whitespace_elements: ["script", "style"]
750
740
  )
751
741
  ====
752
742