* Parse properties from a const definition, resolving nested const references.
( content: string, toolPrefix: string, typesContent: string, depth: number )
| 1438 | * Parse properties from a const definition, resolving nested const references. |
| 1439 | */ |
| 1440 | function parseConstProperties( |
| 1441 | content: string, |
| 1442 | toolPrefix: string, |
| 1443 | typesContent: string, |
| 1444 | depth: number |
| 1445 | ): Record<string, any> { |
| 1446 | const properties: Record<string, any> = {} |
| 1447 | |
| 1448 | // First, handle spread operators (e.g., "...COMMENT_OUTPUT_PROPERTIES,") |
| 1449 | const spreadRegex = /\.\.\.([A-Z][A-Z_0-9]+)\s*(?:,|$)/g |
| 1450 | let spreadMatch |
| 1451 | while ((spreadMatch = spreadRegex.exec(content)) !== null) { |
| 1452 | const constName = spreadMatch[1] |
| 1453 | |
| 1454 | // Check if at depth 0 |
| 1455 | const beforeMatch = content.substring(0, spreadMatch.index) |
| 1456 | const openBraces = (beforeMatch.match(/\{/g) || []).length |
| 1457 | const closeBraces = (beforeMatch.match(/\}/g) || []).length |
| 1458 | if (openBraces !== closeBraces) { |
| 1459 | continue |
| 1460 | } |
| 1461 | |
| 1462 | const resolvedConst = resolveConstFromTypesContent(constName, typesContent, toolPrefix, depth) |
| 1463 | if (resolvedConst && typeof resolvedConst === 'object') { |
| 1464 | // Spread all properties from the resolved const |
| 1465 | Object.assign(properties, resolvedConst) |
| 1466 | } |
| 1467 | } |
| 1468 | |
| 1469 | // Find all top-level property definitions |
| 1470 | const propRegex = /(\w+)\s*:\s*(?:\{|([A-Z][A-Z_0-9]+)(?:\s*,|\s*$))/g |
| 1471 | let match |
| 1472 | |
| 1473 | while ((match = propRegex.exec(content)) !== null) { |
| 1474 | const propName = match[1] |
| 1475 | const constRef = match[2] |
| 1476 | |
| 1477 | // Skip 'items' keyword (always a nested structure, never a field name) |
| 1478 | if (propName === 'items') { |
| 1479 | continue |
| 1480 | } |
| 1481 | |
| 1482 | // Check if this match is at depth 0 (not inside nested braces) |
| 1483 | const beforeMatch = content.substring(0, match.index) |
| 1484 | const openBraces = (beforeMatch.match(/\{/g) || []).length |
| 1485 | const closeBraces = (beforeMatch.match(/\}/g) || []).length |
| 1486 | if (openBraces !== closeBraces) { |
| 1487 | continue // Skip - this is a nested property |
| 1488 | } |
| 1489 | |
| 1490 | // For 'properties' or 'type', check if it's an output field definition vs a keyword |
| 1491 | // Output field definitions have 'type:' inside (e.g., { type: 'string', description: '...' }) |
| 1492 | if ((propName === 'properties' || propName === 'type') && !constRef) { |
| 1493 | // Peek at what's inside the braces |
| 1494 | const startPos = match.index + match[0].length - 1 |
| 1495 | const endPos = findMatchingClose(content, startPos) |
| 1496 | if (endPos !== -1) { |
| 1497 | const propContent = content.substring(startPos + 1, endPos - 1).trim() |
no test coverage detected