Skip to content

fix(12306): accept lowercase letters in train_no regex#1734

Open
dusty-cjh wants to merge 1 commit into
jackwener:mainfrom
dusty-cjh:fix/12306-train-no-allow-lowercase
Open

fix(12306): accept lowercase letters in train_no regex#1734
dusty-cjh wants to merge 1 commit into
jackwener:mainfrom
dusty-cjh:fix/12306-train-no-allow-lowercase

Conversation

@dusty-cjh
Copy link
Copy Markdown

Problem

The 12306 leftTicket API sometimes returns train_no values that contain lowercase letters. For example, querying 上海 → 宝鸡 on 2026-05-25 returns this for G1970:

train_no: 5l000G1970A3   # note the lowercase "l"
code: G1970
from_station: 上海虹桥
to_station: 宝鸡南

12306 trains outputs the value verbatim, but feeding it back into the documented next step fails locally before ever hitting 12306:

$ opencli 12306 price 5l000G1970A3 --from AOH --to BBY --date 2026-05-25
ok: false
error:
  code: ARGUMENT
  message: <train-no> "5l000G1970A3" does not look like a 12306 internal train_no
  help: Use the train_no field from `12306 trains` output (e.g. 24000000G10L), not the public code (G1).
  exitCode: 2

Same failure on 12306 train. Root cause: TRAIN_NO_RE = /^[0-9A-Z]{8,18}$/ in both price.js and train.js is stricter than what 12306 actually emits. Capitalising the l to L passes the regex but then returns EMPTY_RESULT from 12306 — confirming the canonical id really is lowercase.

The error help text is also misleading: it tells the user to use the value from 12306 trains output, which is exactly what they did.

Fix

Widen the regex to /^[0-9A-Za-z]{8,18}$/ in both adapters. Verified end-to-end after the change:

$ opencli 12306 price 5l000G1970A3 --from AOH --to BBY --date 2026-05-25
- seat_code: A9
  seat_name: 商务座
  price: '2611.0'
- seat_code: M
  seat_name: 一等座
  price: '1252.0'
- seat_code: O
  seat_name: 二等座
  price: '768.0'
  ...

Tests

Added a parameterised describe block in clis/12306/utils.test.js that pins both regexes (price + train) against:

  • the historical uppercase example 24000000G10L (must accept)
  • the lowercase real-world value 5l000G1970A3 (must accept — regression)
  • public codes like G1970 (must reject)
  • values containing punctuation 5l000-G1970A3 (must reject)
Test Files  1 passed (1)
     Tests  39 passed (39)

npx tsc --noEmit clean.

Notes

  • Only the format regex changed; everything downstream (URL building, 12306 API contract) already round-trips the value as an opaque string.
  • SEAT_TYPES_RE is intentionally left untouched — seat-type letters are a small, well-known uppercase set defined by 12306.

The 12306 leftTicket API sometimes emits train_no values containing
lowercase letters (e.g. "5l000G1970A3" for G1970 上海虹桥 -> 宝鸡南,
real payload as of 2026-05). `12306 trains` returns this value
verbatim, but `12306 price` and `12306 train` reject it with an
ARGUMENT error because TRAIN_NO_RE only allows [0-9A-Z]. This makes
the recommended workflow

  opencli 12306 trains <from> <to> --date <d>     # pick train_no
  opencli 12306 price <train_no> --from ... --to ... --date <d>

silently broken for any train whose internal id happens to contain a
lowercase character — the user has no way to discover that the value
is being rejected by a local regex rather than 12306 itself.

Widen both regexes to [0-9A-Za-z]{8,18} and add regression coverage
that pins both: the historical uppercase example (24000000G10L) and
the lowercase real-world value (5l000G1970A3).
Copilot AI review requested due to automatic review settings May 23, 2026 17:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns OpenCLI’s 12306 adapters with real-world leftTicket payloads by relaxing the internal train_no validation to accept lowercase letters, preventing local ARGUMENT failures when users paste values emitted by 12306.

Changes:

  • Widened TRAIN_NO_RE in both clis/12306/price.js and clis/12306/train.js to allow [A-Za-z].
  • Exposed TRAIN_NO_RE in price.js test exports and added parameterized tests to pin behavior for both adapters.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
clis/12306/utils.test.js Adds regression coverage ensuring both adapters accept lowercase-containing train_no values and still reject public codes/invalid chars.
clis/12306/train.js Updates TRAIN_NO_RE to accept lowercase letters for real 12306 train_no values.
clis/12306/price.js Updates TRAIN_NO_RE to accept lowercase letters and exports it via __test__ for validation tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants