Skip to content

Conversation

@sethconvex
Copy link

Problem

The getMappedLocation function was creating inverted text ranges when source maps contained negative VLQ (Variable Length Quantity) offsets. Negative offsets are legal and valid in the source map specification - they occur when declarations in the generated .d.ts file are out of order relative to the source file (non-monotonic mappings).

When VSCode received these inverted ranges in LSP location responses, it mis-interpreted them, causing jump to definition to fail or navigate to incorrect locations. This was particularly problematic for projects like Convex, which generate api.d.ts files with potentially out-of-order references that result in negative VLQ offsets in their source maps.

Root cause:

  • Source maps use relative VLQ encoding where positions are stored as deltas
  • When declaration order differs from source order, these deltas can be negative (going backwards)
  • Example: Position 100 in .d.ts maps to position 800 in source, but position 200 in .d.ts maps to position 200 in source
  • When mapping a range from position 100-200 in .d.ts, the end position (200) would be before the start position (800) in the source, creating an invalid inverted range
  • VSCode cannot handle inverted ranges, breaking jump to definition functionality

Solution

Added validation logic in getMappedLocation to ensure the end position is always valid:

  • Clamps the end position to the start position when:
    • The end position is before the start position (inverted range)
    • The end position is in a different file than the start position
  • This results in a zero-length range when clamping occurs, which is a valid and safe fallback

Changes

  • internal/ls/source_map.go: Added validation and clamping logic to prevent inverted ranges
  • internal/ls/source_map_test.go: Added comprehensive test suite (219 lines) covering:
    • Inverted ranges being clamped correctly
    • Valid ranges not being modified
    • Different file scenarios being handled
    • Zero-length ranges being valid

Testing

The fix includes extensive test coverage with multiple test cases:

  • TestGetMappedLocation_NonMonotonicMappings: Tests the core fix for non-monotonic mappings
  • TestGetMappedLocation_ZeroLengthRange: Verifies zero-length ranges are handled correctly
  • TestValidateAndClampSpanLogic: Directly tests the validation logic

All tests pass and verify that:

  1. Inverted ranges are clamped to prevent negative-length ranges
  2. Valid ranges remain unchanged
  3. Cross-file scenarios are handled safely

Impact

  • Fixes: Restores jump to definition functionality in VSCode when source maps contain negative VLQ offsets
  • Real-world impact: Resolves issues for Convex projects and other codebases that generate .d.ts files with out-of-order declarations
  • Backward compatible: No breaking changes; only adds validation for edge cases
  • Safe fallback: Zero-length ranges are valid and prevent VSCode from mis-interpreting the location
  • Standards compliant: Properly handles negative VLQ offsets as specified in the source map specification

…suring it remains within bounds and avoids inverted ranges.
@sethconvex
Copy link
Author

sethconvex commented Dec 22, 2025

@microsoft-github-policy-service agree company="Convex, Inc"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant