{"record":{"id":"98b944ab9ec92cd1","repo":"jackwener/OpenCLI","slug":"name-is-required-a-destination-or-attraction","errorCode":null,"errorMessage":"--${name} is required (a destination or attraction keyword)","messagePattern":"--(.+?) is required \\(a destination or attraction keyword\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/trip/utils.js","lineNumber":401,"sourceCode":"      if (/captcha|verify you are human|security check/i.test(document.body?.innerText || '')) return 'captcha';\n      const dr = window.__NEXT_DATA__?.props?.pageProps?.hotelDetailResponse;\n      if (dr && dr.hotelBaseInfo && dr.hotelBaseInfo.nameInfo) return 'content';\n      return null;\n    };\n    const found = detect();\n    if (found) return resolve(found);\n    const observer = new MutationObserver(() => {\n      const result = detect();\n      if (result) { observer.disconnect(); resolve(result); }\n    });\n    observer.observe(document.documentElement, { childList: true, subtree: true });\n    setTimeout(() => { observer.disconnect(); resolve('timeout'); }, 12000);\n  })\n`;\n\nexport function parseKeyword(name, raw) {\n    if (raw === undefined || raw === null || String(raw).trim() === '') {\n        throw new ArgumentError(`--${name} is required (a destination or attraction keyword)`);\n    }\n    const value = String(raw).trim();\n    if (value.length > 60) {\n        throw new ArgumentError(`--${name} is too long (max 60 chars): ${JSON.stringify(raw)}`);\n    }\n    return value;\n}\n\nexport function buildAttractionSearchUrl(keyword) {\n    const params = new URLSearchParams({ keyword, locale: 'en_US', curr: 'USD' });\n    return `https://www.trip.com/things-to-do/list?${params.toString()}`;\n}\n\n/**\n * Browser-context IIFE that extracts attraction / experience rows from Trip.com's\n * things-to-do results. The product cards use hashed CSS-module class names, so\n * this anchors on the one stable handle each card exposes, the\n * `things-to-do/detail/<id>` link (name is its text, `url` its href), and reads","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/utils.js#L383-L419","documentation":"parseKeyword enforces that keyword options (--query, --from, --to, --country, --city) are present and non-blank. If the value is undefined, null, or only whitespace, an ArgumentError is thrown with the option name embedded in the message. The library requires a search keyword because all attraction/destination searches are built from this string.","triggerScenarios":"Omitting a required --query/--from/--to/--country/--city flag; passing an empty string ('' or '   '); a shell variable that expands to nothing (e.g. --query \"$KEYWORD\" with KEYWORD unset); a config file key missing so the flag is dropped.","commonSituations":"Scripting with unset environment variables; YAML/JSON config typos where a keyword field is absent; CI pipelines where the search term comes from an empty secret or artifact; copy-paste commands with a placeholder left in and then deleted.","solutions":["Pass a non-empty keyword, e.g. --query \"Tokyo Tower\"","Echo the shell variable before the call to confirm it is set and non-blank","Add a default or guard in the calling script: [ -n \"$KEYWORD\" ] || { echo 'KEYWORD required'; exit 1; }","Fix the config file/CI variable so the keyword field is populated"],"exampleFix":"// before\ntripcli attractions-search --query \"$QUERY\"   # QUERY is empty\n// after\nexport QUERY=\"Santorini\"\ntripcli attractions-search --query \"$QUERY\"","handlingStrategy":"validation","validationCode":"if (keyword === undefined || keyword === null || String(keyword).trim() === '') {\n  throw new Error('keyword is required');\n}","typeGuard":"const hasKeyword = (v) => v !== undefined && v !== null && String(v).trim() !== '';","tryCatchPattern":"try {\n  await runCli(['attractions-search', '--query', keyword]);\n} catch (e) {\n  if (/is required \\(a destination or attraction keyword\\)/.test(e.message)) {\n    console.error(`Missing --query. Provide a search keyword.`);\n    process.exitCode = 2;\n    return;\n  }\n  throw e;\n}","preventionTips":["Use shell parameter expansion defaults: ${KEYWORD:?KEYWORD required}","Assert config fields exist before invoking the CLI","Echo/validate env-sourced values before the call","Keep required flags explicit in scripts rather than conditionally omitted"],"tags":["cli","missing-argument","argument-validation"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}