fix: handle multi-line param() attributes in parameter detection
Switch from single multiline regex to line-by-line scanning that skips PowerShell attribute decorators like [Parameter(Mandatory=$true)] and [ValidateSet(...)]. This correctly detects parameters with attribute lines above them (the most common real-world pattern). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -178,27 +178,36 @@ function extractParamBlockCandidates(
|
|||||||
block: { start: number; end: number }
|
block: { start: number; end: number }
|
||||||
): ParameterCandidate[] {
|
): ParameterCandidate[] {
|
||||||
const lines = script.split('\n')
|
const lines = script.split('\n')
|
||||||
const blockText = lines.slice(block.start, block.end + 1).join('\n')
|
|
||||||
const candidates: ParameterCandidate[] = []
|
const candidates: ParameterCandidate[] = []
|
||||||
|
|
||||||
const paramRegex = /(?:\[(\w+)\])?\s*\$(\w+)(?:\s*=\s*(.+?))?(?:\s*,\s*$|\s*$|\s*\))/gm
|
// Scan each line in the param block for $VarName patterns.
|
||||||
let match: RegExpExecArray | null
|
// Lines with [Parameter(...)], [ValidateSet(...)], etc. don't contain $VarName
|
||||||
|
// so they are naturally skipped. The type annotation [string], [int], etc.
|
||||||
|
// appears on the same line as $VarName.
|
||||||
|
const varLineRegex = /(?:\[(\w+)\])?\s*\$(\w+)(?:\s*=\s*(.+?))?(?:\s*,?\s*$)/
|
||||||
|
|
||||||
|
for (let i = block.start; i <= block.end; i++) {
|
||||||
|
const trimmed = lines[i].trim()
|
||||||
|
|
||||||
|
// Skip attribute lines like [Parameter(...)], [ValidateSet(...)], etc.
|
||||||
|
if (/^\[(?:Parameter|ValidateSet|ValidateRange|ValidatePattern|ValidateScript|ValidateLength|ValidateCount|Alias|AllowNull|AllowEmptyString|AllowEmptyCollection)\s*\(/i.test(trimmed)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = trimmed.match(varLineRegex)
|
||||||
|
if (!match) continue
|
||||||
|
|
||||||
while ((match = paramRegex.exec(blockText)) !== null) {
|
|
||||||
const typeAnnotation = match[1] || null
|
const typeAnnotation = match[1] || null
|
||||||
const varName = match[2]
|
const varName = match[2]
|
||||||
const rawDefault = match[3]?.trim() ?? null
|
const rawDefault = match[3]?.trim() ?? null
|
||||||
|
|
||||||
|
// Skip if type looks like an attribute we didn't catch above
|
||||||
if (typeAnnotation && /^Parameter$/i.test(typeAnnotation)) continue
|
if (typeAnnotation && /^Parameter$/i.test(typeAnnotation)) continue
|
||||||
|
|
||||||
const key = toSnakeCase(varName)
|
const key = toSnakeCase(varName)
|
||||||
const { type, sensitive, reason } = inferType(typeAnnotation, rawDefault, varName)
|
const { type, sensitive, reason } = inferType(typeAnnotation, rawDefault, varName)
|
||||||
const defaultValue = parseDefault(rawDefault, type)
|
const defaultValue = parseDefault(rawDefault, type)
|
||||||
|
|
||||||
const lineIndex = lines.findIndex((line, idx) =>
|
|
||||||
idx >= block.start && idx <= block.end && line.includes(`$${varName}`)
|
|
||||||
)
|
|
||||||
|
|
||||||
candidates.push({
|
candidates.push({
|
||||||
variableName: `$${varName}`,
|
variableName: `$${varName}`,
|
||||||
suggestedKey: key,
|
suggestedKey: key,
|
||||||
@@ -207,8 +216,8 @@ function extractParamBlockCandidates(
|
|||||||
sensitive,
|
sensitive,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
source: 'param_block',
|
source: 'param_block',
|
||||||
lineNumber: lineIndex !== -1 ? lineIndex + 1 : block.start + 1,
|
lineNumber: i + 1,
|
||||||
matchedLine: lineIndex !== -1 ? lines[lineIndex].trim() : `$${varName}`,
|
matchedLine: trimmed,
|
||||||
inferenceReason: reason,
|
inferenceReason: reason,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user