{"record":{"id":"268629207da9ad63","repo":"jackwener/OpenCLI","slug":"targetcount-must-be-an-integer-between-1-and-100","errorCode":null,"errorMessage":"targetCount must be an integer between 1 and 100, got ${JSON.stringify(targetCount)}","messagePattern":"targetCount must be an integer between 1 and 100, got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/utils.js","lineNumber":463,"sourceCode":"          });\n        });\n        return rows;\n      })()\n    `;\n}\n\n/**\n * Build a scroll-until-enough IIFE for flights/hotels DOM-card pagination.\n *\n * Mirrors `clis/xiaohongshu/search.js#buildScrollUntilJs` (PR #1487) — counts a\n * caller-supplied row selector, scrolls until count >= target / DOM plateau /\n * maxScrolls. Returns final row count so the caller can decide whether to\n * surface an EmptyResultError. (xiaohongshu's helper hardcodes\n * `section.note-item`; this generic version takes a selector.)\n */\nexport function buildScrollUntilJs(rowSelector, targetCount, maxScrolls = 8) {\n    if (!Number.isInteger(targetCount) || targetCount < 1 || targetCount > 100) {\n        throw new ArgumentError(`targetCount must be an integer between 1 and 100, got ${JSON.stringify(targetCount)}`);\n    }\n    if (!Number.isInteger(maxScrolls) || maxScrolls < 1 || maxScrolls > 30) {\n        throw new ArgumentError(`maxScrolls must be an integer between 1 and 30, got ${JSON.stringify(maxScrolls)}`);\n    }\n    return `\n      (async () => {\n        const sel = ${JSON.stringify(rowSelector)};\n        const isVisible = (el) => {\n          const style = window.getComputedStyle(el);\n          if (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0) return false;\n          const rect = el.getBoundingClientRect();\n          return rect.width > 0 && rect.height > 0;\n        };\n        const countItems = () => Array.from(document.querySelectorAll(sel)).filter(isVisible).length;\n        let lastCount = countItems();\n        let plateauRounds = 0;\n        for (let i = 0; i < ${maxScrolls}; i++) {\n          if (countItems() >= ${targetCount}) break;","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/utils.js#L445-L481","documentation":"buildScrollUntilJs generates an in-page scroll-until-N-rows-appear script for browser scraping. Before emitting the JS, it validates that targetCount is an integer in the inclusive range 1-100; otherwise it throws ArgumentError. This guards the generated script from nonsensical or runaway scroll targets.","triggerScenarios":"Programmatically calling buildScrollUntilJs (used by renderedCardCount/js helpers) with targetCount = 0, negative values, non-integers like 2.5, NaN, undefined, strings like '10', or values above 100 such as 500.","commonSituations":"Library consumers computing the count from user flags without clamping, passing a string parsed from CLI args, or requesting 'scroll until everything is loaded' with an unbounded number.","solutions":["Pass an integer between 1 and 100 as targetCount (e.g. 10 or 20 rows).","Clamp user-supplied values: Math.min(100, Math.max(1, Math.floor(Number(x)))).","Parse CLI strings with Number()/parseInt before calling, and validate integer-ness first.","If you need more than 100 rows, call the scroll helper multiple times or paginate differently."],"exampleFix":"// before\nbuildScrollUntilJs('div.hotel-item', '500')\n// after\nbuildScrollUntilJs('div.hotel-item', Math.min(100, Math.max(1, parseInt(raw, 10))))","handlingStrategy":"validation","validationCode":"function clampTargetCount(v) {\n  const n = Number(v);\n  if (!Number.isInteger(n) || n < 1 || n > 100) throw new Error('targetCount must be an integer 1-100');\n  return n;\n}","typeGuard":"const isValidTargetCount = (v) => Number.isInteger(v) && v >= 1 && v <= 100;","tryCatchPattern":"try {\n  const js = buildScrollUntilJs(sel, count);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('targetCount')) {\n    return buildScrollUntilJs(sel, 20); // safe default\n  }\n  throw e;\n}","preventionTips":["Clamp user input with Math.min(100, Math.max(1, Math.floor(Number(v)))).","Parse CLI strings to numbers before passing them into helpers.","Treat >100 rows as a pagination problem, not a scroll target."],"tags":["validation","argument-error","browser-automation","integer-validation"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}