fix(12306): accept lowercase letters in train_no regex#1734
Open
dusty-cjh wants to merge 1 commit into
Open
Conversation
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).
There was a problem hiding this comment.
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_REin bothclis/12306/price.jsandclis/12306/train.jsto allow[A-Za-z]. - Exposed
TRAIN_NO_REinprice.jstest 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The 12306
leftTicketAPI sometimes returnstrain_novalues that contain lowercase letters. For example, querying 上海 → 宝鸡 on 2026-05-25 returns this for G1970:12306 trainsoutputs the value verbatim, but feeding it back into the documented next step fails locally before ever hitting 12306:Same failure on
12306 train. Root cause:TRAIN_NO_RE = /^[0-9A-Z]{8,18}$/in bothprice.jsandtrain.jsis stricter than what 12306 actually emits. Capitalising theltoLpasses the regex but then returnsEMPTY_RESULTfrom 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 trainsoutput, 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:Tests
Added a parameterised
describeblock inclis/12306/utils.test.jsthat pins both regexes (price+train) against:24000000G10L(must accept)5l000G1970A3(must accept — regression)G1970(must reject)5l000-G1970A3(must reject)npx tsc --noEmitclean.Notes
SEAT_TYPES_REis intentionally left untouched — seat-type letters are a small, well-known uppercase set defined by 12306.