{"record":{"id":"81ac52c77d0837cb","repo":"jackwener/OpenCLI","slug":"name-is-required-e-g","errorCode":null,"errorMessage":"--${name} is required (e.g. 北京 / 上海)","messagePattern":"--(.+?) is required \\(e\\.g\\. 北京 / 上海\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/utils.js","lineNumber":518,"sourceCode":"          } else {\n            plateauRounds = 0;\n            lastCount = newCount;\n          }\n        }\n        return countItems();\n      })()\n    `;\n}\n\n/** Validate a 1-50 result limit shared by the browser-mode list commands (default 20). */\nexport function parseListLimit(raw, fallback = 20) {\n    return parseStrictIntegerRange('limit', raw, fallback);\n}\n\n/** Validate a Chinese place keyword (station, city, port, or destination) for the browser list queries. */\nexport function parsePlaceName(name, raw) {\n    if (raw === undefined || raw === null || String(raw).trim() === '') {\n        throw new ArgumentError(`--${name} is required (e.g. 北京 / 上海)`);\n    }\n    const value = String(raw).trim();\n    // These list pages key on the raw Chinese place name; reject control\n    // characters and over-long input rather than passing them through.\n    if (value.length > 20 || /[\\x00-\\x1f]/.test(value)) {\n        throw new ArgumentError(`--${name} is not a valid place name: ${JSON.stringify(raw)}`);\n    }\n    return value;\n}\n\nexport function buildTrainListUrl(fromName, toName, date) {\n    const params = new URLSearchParams({\n        dStationName: fromName,\n        aStationName: toName,\n        dDate: date,\n        ticketType: '1',\n    });\n    return `https://trains.ctrip.com/webapp/train/list?${params.toString()}`;","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/utils.js#L500-L536","documentation":"parsePlaceName validates Chinese place keywords (station, city, port, destination) used to build Ctrip train list query URLs. undefined, null, or blank-after-trim input is rejected with ArgumentError '--<name> is required (e.g. 北京 / 上海)'. These list pages key on the raw Chinese place name, so it must be supplied.","triggerScenarios":"Omitting --from-city/--to-city/--port/--destination (or --from-name/--to-name) on train list commands, or passing empty strings/whitespace-only values.","commonSituations":"Users pass an English/pinyin name ('Shanghai' or 'shanghai') thinking it is optional validation, or forget one leg of a from/to pair; unset shell variables expanding to empty also trigger this.","solutions":["Provide the Chinese place name, e.g. --from-city 北京 --to-city 上海.","Ensure the flag is present and not an empty shell variable expansion.","Use the same name form the Ctrip list pages accept (raw Chinese keyword); convert pinyin/English names to Chinese first."],"exampleFix":"// before\nctrip trains --from-city \"Shanghai\" --to-city 北京\n// after\nctrip trains --from-city 上海 --to-city 北京","handlingStrategy":"validation","validationCode":"if (fromCity === undefined || fromCity === null || String(fromCity).trim() === '') {\n  throw new Error('--from-city is required (e.g. 北京 / 上海)');\n}","typeGuard":"const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try {\n  const name = parsePlaceName('from-city', raw);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('is required')) {\n    console.error('Usage: --from-city 北京 --to-city 上海');\n  } else throw e;\n}","preventionTips":["Use Chinese place names exactly as Ctrip expects (e.g. 上海, not Shanghai).","Guard shell variables: ${FROM_CITY:?must be set}.","Validate both legs (from/to) before invoking train list commands."],"tags":["cli","validation","argument-error","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}