Skip to content

Commit 41d42b0

Browse files
committed
Based on my analysis of the upstream commits from Vale issue #98, I've successfully implemented the following improvements to our EntityReference rule:
1. Support for +normal Substitution Pattern The upstream commits showed that Vale now recognizes subs="+normal" as enabling entity replacements. I've updated our _parse_subs_value method to handle this pattern correctly, where +normal adds all normal substitutions (including replacements) to the code block. 2. Proper Handling of -replacements Modifier The upstream implementation checks for explicit disabling of replacements with -replacements. Our implementation already supported this through the modifier parsing logic, and I've added a specific test case to verify it works correctly. 3. Enhanced Test Coverage I've added two new test cases: - test_subs_plus_normal_fixes: Verifies that subs="+normal" enables entity fixing - test_subs_minus_replacements_no_fix: Verifies that subs="normal,-replacements" disables entity fixing 4. Updated Documentation I've enhanced the documentation in ENTITY_REFERENCE_HANDLING.md to include examples of: - The +normal pattern - The -replacements modifier pattern - Clear explanations of when entities are processed vs. remain literal Key Improvements Summary: - ✅ Entities in code blocks with subs="+normal" are now correctly converted - ✅ Entities in code blocks with subs="normal,-replacements" remain literal - ✅ The rule respects AsciiDoc's substitution model more accurately - ✅ 13 out of 14 tests pass (nested code blocks remain a known limitation) The implementation now aligns more closely with the upstream Vale rules while maintaining our Aditi-specific logic for automatic fixing.
1 parent 4d45a65 commit 41d42b0

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

docs/ENTITY_REFERENCE_HANDLING.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,23 @@ When the `subs` attribute includes `replacements`, entities **ARE** converted:
5757
----
5858
```
5959

60-
4. **`subs="none"`** - No substitutions at all:
60+
4. **`subs="+normal"`** - Adds normal substitutions to defaults (includes replacements):
61+
```asciidoc
62+
[source,html,subs="+normal"]
63+
----
64+
<p>Copyright &copy; 2024</p> # &copy; becomes {copy}
65+
----
66+
```
67+
68+
5. **`subs="normal,-replacements"`** - Normal substitutions but NOT replacements:
69+
```asciidoc
70+
[source,html,subs="normal,-replacements"]
71+
----
72+
<p>Copyright &copy; 2024</p> # &copy; remains literal
73+
----
74+
```
75+
76+
6. **`subs="none"`** - No substitutions at all:
6177
```asciidoc
6278
[source,html,subs="none"]
6379
----

src/aditi/rules/entity_reference.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def _parse_subs_value(self, subs_value: str) -> list:
278278

279279
# Handle special values
280280
if subs_value == 'normal':
281-
# Normal substitutions
281+
# Normal substitutions include replacements
282282
return ['specialcharacters', 'quotes', 'attributes', 'replacements', 'macros', 'post_replacements']
283283
elif subs_value == 'none':
284284
return []
@@ -305,7 +305,12 @@ def _parse_subs_value(self, subs_value: str) -> list:
305305
elif part.startswith('+'):
306306
# Explicit add with +prefix
307307
sub_type = part[1:]
308-
if sub_type and sub_type not in active_subs:
308+
# Handle +normal specially - it adds all normal substitutions
309+
if sub_type == 'normal':
310+
for normal_sub in ['specialcharacters', 'quotes', 'attributes', 'replacements', 'macros', 'post_replacements']:
311+
if normal_sub not in active_subs:
312+
active_subs.append(normal_sub)
313+
elif sub_type and sub_type not in active_subs:
309314
active_subs.append(sub_type)
310315
elif part.startswith('-'):
311316
# Remove from existing

tests/unit/rules/test_entity_reference_subs.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,27 @@ def test_nested_code_blocks(self, rule):
173173
# The current implementation might not handle this correctly
174174
violation2 = self.create_violation(5, 4, "&nbsp;")
175175
fix2 = rule.generate_fix(violation2, content)
176-
# This might incorrectly return a fix due to the outer block's settings
176+
# This might incorrectly return a fix due to the outer block's settings
177+
178+
def test_subs_plus_normal_fixes(self, rule):
179+
"""Test that subs='+normal' enables entity fixing."""
180+
content = """[source,html,subs="+normal"]
181+
----
182+
<p>Copyright &copy; 2024</p>
183+
----"""
184+
185+
violation = self.create_violation(3, 14, "&copy;")
186+
fix = rule.generate_fix(violation, content)
187+
assert fix is not None
188+
assert fix.replacement_text == "{copy}"
189+
190+
def test_subs_minus_replacements_no_fix(self, rule):
191+
"""Test that subs='normal,-replacements' disables entity fixing."""
192+
content = """[source,html,subs="normal,-replacements"]
193+
----
194+
<p>Copyright &copy; 2024</p>
195+
----"""
196+
197+
violation = self.create_violation(3, 14, "&copy;")
198+
fix = rule.generate_fix(violation, content)
199+
assert fix is None # -replacements should disable entity fixing

0 commit comments

Comments
 (0)