fix(parameterization): word-boundary check prevents over-eager value match
ParameterizationPreview.tokenize() matched highlight values via raw seg.text.startsWith(value, cursor) with no word-boundary check and no minimum length. A param value like "D" (e.g. a drive letter) lit up every capital D in the script body — Get-ADUser, Add-Type, Disable- all rendered as proposed-parameter pills. Add a word-boundary guard: a candidate match is only accepted if either side of the match either falls at start/end of the segment, OR the adjacent character is non-alphanumeric. The guard is conditional on whether the value itself starts/ends with a word char, so values that begin or end in punctuation (e.g. "D:\\Folder") still match cleanly when they sit next to whitespace or punctuation. Surfaced 2026-05-01 while testing the suggested-fix flow with a real PowerShell script. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -80,10 +80,27 @@ function tokenize(body: string, highlightValues: Record<string, string> | undefi
|
||||
while (cursor < seg.text.length) {
|
||||
let matched: { key: string; value: string } | null = null
|
||||
for (const [key, value] of valueEntries) {
|
||||
if (seg.text.startsWith(value, cursor)) {
|
||||
matched = { key, value }
|
||||
break
|
||||
}
|
||||
if (!seg.text.startsWith(value, cursor)) continue
|
||||
// Word-boundary guard: a single-char value like "D" (drive letter)
|
||||
// would otherwise light up every capital D in identifiers like
|
||||
// `Get-ADUser`. We only require a boundary on a side of the value
|
||||
// that itself starts/ends with a word char, so values that begin or
|
||||
// end in punctuation (e.g. "D:\\Folder") still match cleanly.
|
||||
const valueStartsWithWordChar = /^\w/.test(value)
|
||||
const valueEndsWithWordChar = /\w$/.test(value)
|
||||
const before = cursor > 0 ? seg.text[cursor - 1] : undefined
|
||||
const after = cursor + value.length < seg.text.length
|
||||
? seg.text[cursor + value.length]
|
||||
: undefined
|
||||
const startBounded = !valueStartsWithWordChar
|
||||
|| before === undefined
|
||||
|| !/\w/.test(before)
|
||||
const endBounded = !valueEndsWithWordChar
|
||||
|| after === undefined
|
||||
|| !/\w/.test(after)
|
||||
if (!startBounded || !endBounded) continue
|
||||
matched = { key, value }
|
||||
break
|
||||
}
|
||||
if (matched) {
|
||||
flushPending()
|
||||
|
||||
Reference in New Issue
Block a user