Skip to content

Commit 719aa65

Browse files
authored
fix: skip impossible TypeScript type offset scans (#445)
1 parent 4d222d7 commit 719aa65

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

‎src/tokenizeTypeScript.js‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,9 @@ const addTypeOffsets = (offsets, type, typeOffset) => {
483483

484484
const getFunctionParameterTypeOffsets = (line) => {
485485
const offsets = new Map()
486+
if (!line.includes(':')) {
487+
return offsets
488+
}
486489
for (const match of line.matchAll(RE_FUNCTION_PARAMETER_TYPE)) {
487490
const type = match[1]
488491
const typeOffset = match.index + match[0].lastIndexOf(type)
@@ -536,6 +539,9 @@ const getArrowFunctionTypeOffsets = (line) => {
536539

537540
const getGenericTypeArgumentOffsets = (line) => {
538541
const offsets = new Map()
542+
if (!line.includes('<') || !line.includes(',')) {
543+
return offsets
544+
}
539545
for (const match of line.matchAll(RE_GENERIC_TYPE_ARGUMENTS)) {
540546
for (const argumentIndex of [1, 2]) {
541547
const typeArguments = match[argumentIndex]

‎test/offsetScans.test.js‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import assert from 'node:assert/strict'
2+
import { test } from 'node:test'
3+
import {
4+
initialLineState,
5+
TokenMap,
6+
tokenizeLine,
7+
} from '../src/tokenizeTypeScript.js'
8+
9+
const tokenize = (source) => {
10+
let state = structuredClone(initialLineState)
11+
const result = []
12+
for (const line of source.split('\n')) {
13+
state = tokenizeLine(line, state)
14+
let offset = 0
15+
for (let index = 0; index < state.tokens.length; index += 2) {
16+
const length = state.tokens[index + 1]
17+
result.push([
18+
TokenMap[state.tokens[index]],
19+
line.slice(offset, offset + length),
20+
])
21+
offset += length
22+
}
23+
assert.equal(offset, line.length)
24+
}
25+
return result
26+
}
27+
28+
test('preserves parameter and generic type classifications across scan fast paths', () => {
29+
const tokens = tokenize(`const value = 1
30+
function first(value: number) {}
31+
const plain = value
32+
const table: Map<string, User> = new Map()
33+
const identity = (value: User): User => value
34+
/* open
35+
comment */
36+
function last(value: boolean) {}`)
37+
assert.ok(
38+
tokens.some(([type, text]) => type === 'TypePrimitive' && text === 'number')
39+
)
40+
assert.ok(
41+
tokens.some(
42+
([type, text]) => type === 'TypePrimitive' && text === 'boolean'
43+
)
44+
)
45+
assert.ok(tokens.some(([type, text]) => type === 'Type' && text === 'User'))
46+
assert.ok(
47+
tokens.some(
48+
([type, text]) => type === 'Comment' && text.includes('comment')
49+
)
50+
)
51+
})

0 commit comments

Comments
 (0)