Skip to content

Fix Node#rangeBy() ignoring index 0#2091

Open
sarathfrancis90 wants to merge 1 commit into
postcss:mainfrom
sarathfrancis90:fix-rangeby-index-zero
Open

Fix Node#rangeBy() ignoring index 0#2091
sarathfrancis90 wants to merge 1 commit into
postcss:mainfrom
sarathfrancis90:fix-rangeby-index-zero

Conversation

@sarathfrancis90
Copy link
Copy Markdown

What

Node#rangeBy() ignored an index of 0, returning a range that spanned the entire node instead of a single character at offset 0. This also affected Node#error() and Node#warn(), which build their positions through rangeBy().

const root = postcss.parse('a b{}')

// before this PR
root.first.rangeBy({ index: 0 })
// => { start: { column: 1, ... }, end: { column: 6, offset: 5 } }  // whole "a b{}"

// any other index works correctly
root.first.rangeBy({ index: 1 })
// => { start: { column: 2, ... }, end: { column: 3, ... } }  // single character

Root cause

In lib/node.js, the end-of-range branch used a truthy check on opts.index:

} else if (opts.index) {
  end = this.positionInside(opts.index + 1)
}

With index === 0 the condition is falsy, so the branch is skipped and end keeps the node's end position, producing a whole-node range. The start branch had the same truthy check, though for the start position positionInside(0) happens to equal the node start, so only the end was observably wrong.

This is the same off-by-zero that was previously fixed for endIndex in #1932 (else if (opts.endIndex)typeof opts.endIndex === 'number'); the two opts.index branches were left unchanged at that time.

Fix

Switch both opts.index checks to a numeric type check, matching the existing endIndex handling:

} else if (typeof opts.index === 'number') {

index: 0 now yields a single-character range, consistent with every other index value.

Tests

Added regression tests (both confirmed failing before the fix, passing after):

  • test/node.test.tsrangeBy() returns a single-character range for index: 0.
  • test/warning.test.ts — a warning created with index: 0 reports endColumn one past the start rather than the node end.

Full suite locally:

  • pnpm unit — 654/654 passing
  • pnpm test:lint — clean
  • pnpm test:types — clean

When calling Node#rangeBy() (and therefore Node#error() and
Node#warn()) with index 0, the resulting range covered the whole node
instead of a single character at offset 0.

The end-of-range branch used a truthy check on opts.index, so an index
of 0 fell through and left the end position at the node's end. This is
the same off-by-zero issue that was previously fixed for endIndex; the
index branches were missed. Switch both index checks to a numeric type
check, matching the existing endIndex handling.

index 0 now produces a single-character range, consistent with every
other index value.
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