(source: string)
| 1268 | const C_TYPE_ARG_OPENER_RE = /^(struct|union|enum)([ \t\r\n]+)([A-Za-z_]\w*)([ \t\r\n]*\*+)?(?=[ \t\r\n]*[,)])/; |
| 1269 | const C_TYPE_ARG_SCAN_CAP = 600; |
| 1270 | export function blankCTypeKeywordArgs(source: string): string { |
| 1271 | if (!/\b(?:struct|union|enum)[ \t\r\n]/.test(source)) return source; |
| 1272 | let chars: string[] | null = null; |
| 1273 | C_TYPE_ARG_HEAD_RE.lastIndex = 0; |
| 1274 | let m: RegExpExecArray | null; |
| 1275 | while ((m = C_TYPE_ARG_HEAD_RE.exec(source)) !== null) { |
| 1276 | const head = m[1] as string; |
| 1277 | if (C_TYPE_ARG_HEAD_EXCLUSIONS.has(head)) continue; |
| 1278 | // Reject declaration shapes: an identifier or `*` (a return/field type) |
| 1279 | // immediately before the head — unless that word is `return`. |
| 1280 | let j = m.index - 1; |
| 1281 | while (j >= 0 && (source[j] === ' ' || source[j] === '\t')) j--; |
| 1282 | const prev = j >= 0 ? (source[j] as string) : ''; |
| 1283 | if (/[\w*]/.test(prev)) { |
| 1284 | let w = j; |
| 1285 | while (w >= 0 && /\w/.test(source[w] as string)) w--; |
| 1286 | if (source.slice(w + 1, j + 1) !== 'return') continue; |
| 1287 | } |
| 1288 | const open = m.index + (m[0] as string).length - 1; |
| 1289 | let depth = 1; |
| 1290 | let atArgStart = true; |
| 1291 | for (let k = open + 1; k < source.length && k - open <= C_TYPE_ARG_SCAN_CAP; k++) { |
| 1292 | const ch = source[k] as string; |
| 1293 | if (ch === '"' || ch === "'") { |
| 1294 | const quote = ch; |
| 1295 | k++; |
| 1296 | while (k < source.length && source[k] !== quote) { |
| 1297 | if (source[k] === '\\') k++; |
| 1298 | k++; |
| 1299 | } |
| 1300 | atArgStart = false; |
| 1301 | continue; |
| 1302 | } |
| 1303 | if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r') continue; |
| 1304 | if (ch === '(') { |
| 1305 | depth++; |
| 1306 | atArgStart = false; |
| 1307 | continue; |
| 1308 | } |
| 1309 | if (ch === ')') { |
| 1310 | depth--; |
| 1311 | if (depth === 0) break; |
| 1312 | atArgStart = false; |
| 1313 | continue; |
| 1314 | } |
| 1315 | if (ch === ';' || ch === '{' || ch === '}') break; // not an argument list |
| 1316 | if (ch === ',') { |
| 1317 | if (depth === 1) atArgStart = true; |
| 1318 | continue; |
| 1319 | } |
| 1320 | if (depth === 1 && atArgStart) { |
| 1321 | const opener = C_TYPE_ARG_OPENER_RE.exec(source.slice(k, k + 160)); |
| 1322 | if (opener) { |
| 1323 | chars ??= [...source]; |
| 1324 | const kw = opener[1] as string; |
| 1325 | for (let b = k; b < k + kw.length; b++) chars[b] = ' '; |
| 1326 | if (opener[4]) { |
| 1327 | const tail = opener[4] as string; |
no test coverage detected