Skip to content

Commit

Permalink
Refactor to improve performance w/ lazy indexing
Browse files Browse the repository at this point in the history
Closes GH-15.
  • Loading branch information
wooorm committed Jul 15, 2024
1 parent 1bddad2 commit 6da1222
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 14 deletions.
35 changes: 22 additions & 13 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,32 @@ export function location(file) {
* @type {Array<number>}
*/
const indices = []
let lastIndex = next(value, 0)

while (lastIndex !== -1) {
indices.push(lastIndex + 1)
lastIndex = next(value, lastIndex + 1)
}

indices.push(value.length + 1)

return {toOffset, toPoint}

/** @type {Location['toPoint']} */
function toPoint(offset) {
if (typeof offset === 'number' && offset > -1 && offset <= value.length) {
let index = -1
let index = 0

while (++index < indices.length) {
if (indices[index] > offset) {
while (true) {
let end = indices[index]

if (end === undefined) {
const eol = next(value, indices[index - 1])
end = eol === -1 ? value.length + 1 : eol + 1
indices[index] = end
}

if (end > offset) {
return {
line: index + 1,
column: offset - (index > 0 ? indices[index - 1] : 0) + 1,
offset
}
}

index++
}
}
}
Expand All @@ -60,9 +62,16 @@ export function location(file) {
typeof point.line === 'number' &&
typeof point.column === 'number' &&
!Number.isNaN(point.line) &&
!Number.isNaN(point.column) &&
point.line <= indices.length
!Number.isNaN(point.column)
) {
while (indices.length < point.line) {
const from = indices[indices.length - 1]
const eol = next(value, from)
const end = eol === -1 ? value.length + 1 : eol + 1
if (from === end) break
indices.push(end)
}

const offset =
(point.line > 1 ? indices[point.line - 2] : 0) + point.column - 1
// The given `column` could not exist on this line.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
],
"prettier": true,
"rules": {
"no-constant-condition": "off",
"unicorn/prefer-at": "off"
}
}
Expand Down
38 changes: 37 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test('toOffset(point)', async function (t) {
assert.equal(place.toOffset({line: 2, column: 4}), 7)
})

await t.test('should return an offset (#3)', async function () {
await t.test('should return an offset (#4)', async function () {
assert.equal(place.toOffset({line: 3, column: 4}), 11)
})

Expand Down Expand Up @@ -264,3 +264,39 @@ test('mixed carriage returns, carriage return + line feeds, and line feeds', asy
)
})
})

test('mixed line endings, *only* line endings', async function (t) {
const place = location('\r\r\n\n')

await t.test('should return points', async function () {
assert.deepEqual(
[
place.toPoint(0), // `\r` (alone)
place.toPoint(1), // `\r` (combined w/ next)
place.toPoint(2), // `\n` (combined w/ previous)
place.toPoint(3), // `\n` (alone)
place.toPoint(4) // EOF
],
[
{line: 1, column: 1, offset: 0},
{line: 2, column: 1, offset: 1},
{line: 2, column: 2, offset: 2},
{line: 3, column: 1, offset: 3},
{line: 4, column: 1, offset: 4}
]
)
})

await t.test('should return offsets', async function () {
assert.deepEqual(
[
place.toOffset({line: 1, column: 1}), // `\r` (alone)
place.toOffset({line: 2, column: 1}), // `\r` (combined w/ next)
place.toOffset({line: 2, column: 2}), // `\n` (combined w/ previous)
place.toOffset({line: 3, column: 1}), // `\n` (alone)
place.toOffset({line: 4, column: 1}) // EOF
],
[0, 1, 2, 3, 4]
)
})
})

0 comments on commit 6da1222

Please sign in to comment.