|
| 1 | +# Solution Summary for Issue #135 |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +The parser was treating documents with leading spaces differently than documents without leading spaces, even when the relative indentation was the same. |
| 6 | + |
| 7 | +### Example of the Bug: |
| 8 | +These two should parse identically, but didn't: |
| 9 | + |
| 10 | +```yaml |
| 11 | + TELEGRAM_BOT_TOKEN: 'value' |
| 12 | + TELEGRAM_ALLOWED_CHATS: |
| 13 | + item1 |
| 14 | + item2 |
| 15 | +``` |
| 16 | +
|
| 17 | +```yaml |
| 18 | +TELEGRAM_BOT_TOKEN: 'value' |
| 19 | +TELEGRAM_ALLOWED_CHATS: |
| 20 | + item1 |
| 21 | + item2 |
| 22 | +``` |
| 23 | +
|
| 24 | +In the first example, the parser incorrectly treated `TELEGRAM_ALLOWED_CHATS` as a child of `TELEGRAM_BOT_TOKEN` because both had 2 spaces, and the second line appeared to have the same indentation as the first. |
| 25 | + |
| 26 | +## Root Cause |
| 27 | + |
| 28 | +All parsers were counting **absolute** indentation (number of spaces from the start of the line) instead of **relative** indentation (increase/decrease compared to the parent level). |
| 29 | + |
| 30 | +## Solution |
| 31 | + |
| 32 | +The fix normalizes indentation by: |
| 33 | +1. Detecting the first content line's indentation and treating it as the baseline (level 0) |
| 34 | +2. Subtracting this baseline from all subsequent lines |
| 35 | +3. This makes the indentation **relative** to the first content line |
| 36 | + |
| 37 | +### Implementation Details |
| 38 | + |
| 39 | +#### Rust (`rust/src/parser.rs`) |
| 40 | +- Added `base_indentation` field to `ParserState` |
| 41 | +- Added `set_base_indentation()`, `get_base_indentation()`, and `normalize_indentation()` methods |
| 42 | +- Modified `first_line()` to capture and set the base indentation |
| 43 | +- Updated `push_indentation()` and `check_indentation()` to normalize values before comparison |
| 44 | + |
| 45 | +#### JavaScript (`js/src/grammar.pegjs`) |
| 46 | +- Added `baseIndentation` variable to track the first line's indentation |
| 47 | +- Added `setBaseIndentation()` and `normalizeIndentation()` functions |
| 48 | +- Updated `document` rule to skip only empty lines (not leading spaces on content lines) |
| 49 | +- Added `SET_BASE_INDENTATION` rule called from `firstLine` |
| 50 | +- Modified `PUSH_INDENTATION` and `CHECK_INDENTATION` to use normalized values |
| 51 | + |
| 52 | +#### C# (`csharp/Link.Foundation.Links.Notation/Parser.peg`) |
| 53 | +- Added `BaseIndentation` to parser state |
| 54 | +- Added `skipEmptyLines` rule to preserve leading spaces on first content line |
| 55 | +- Added `SET_BASE_INDENTATION` rule |
| 56 | +- Updated `PUSH_INDENTATION` and `CHECK_INDENTATION` to normalize indentation |
| 57 | + |
| 58 | +#### Python (TODO) |
| 59 | +- Needs similar changes to `python/links_notation/parser.py` |
| 60 | +- Should track `base_indentation` in the Parser class |
| 61 | +- Update `_parse_element()` to normalize indentation values |
| 62 | + |
| 63 | +## Test Coverage |
| 64 | + |
| 65 | +Added comprehensive test cases for all languages: |
| 66 | +- `rust/tests/indentation_consistency_tests.rs` |
| 67 | +- `js/tests/IndentationConsistency.test.js` |
| 68 | +- `csharp/Link.Foundation.Links.Notation.Tests/IndentationConsistencyTests.cs` |
| 69 | + |
| 70 | +Each test suite verifies: |
| 71 | +1. Documents with leading spaces vs no leading spaces produce identical results |
| 72 | +2. Different indentation sizes (2 vs 4 spaces) work correctly |
| 73 | +3. Multi-level nesting preserves structure regardless of indentation style |
| 74 | + |
| 75 | +## Results |
| 76 | + |
| 77 | +✅ **Rust**: All tests passing (106 tests) |
| 78 | +✅ **JavaScript**: All tests passing (106 tests) |
| 79 | +🔧 **C#**: Fixed, tests pending build verification |
| 80 | +⏳ **Python**: Implementation pending |
| 81 | + |
| 82 | +## Verification |
| 83 | + |
| 84 | +Run tests: |
| 85 | +```bash |
| 86 | +# Rust |
| 87 | +cd rust && cargo test |
| 88 | +
|
| 89 | +# JavaScript |
| 90 | +cd js && npm test |
| 91 | +
|
| 92 | +# C# |
| 93 | +cd csharp && dotnet test |
| 94 | +
|
| 95 | +# Python |
| 96 | +cd python && python -m pytest |
| 97 | +``` |
0 commit comments