Parsers Contract strings, scoring and vulnerability aliases, and the engine.parse module that gathers every parser and type guard.
Import from @workspace/bridge/parsers. These parsers accept loosely formatted input from files and forms and return canonical domain values; the strict membership predicates (isScoringMode, isVulnerability…) live in Utils .
Function Signature Description parseContractString(contract: string) => DisplayContract | nullAccepts ^[1-7](S|H|D|C|NT)(X|XX)?$. Returns { level, suit, doubled } or null. buildContract(contract: string, declarer: Player) => Contract | nullSame parsing plus declarer and trump (the suit, or null for NT).
parseContractString ( "3NT" ); // => { level: 3, suit: "NT", doubled: "none" }
parseContractString ( "4SX" ); // => { level: 4, suit: "S", doubled: "X" }
parseContractString ( "6DXX" ); // => { level: 6, suit: "D", doubled: "XX" }
parseContractString ( "8S" ); // => null
buildContract ( "5HX" , "S" ); // => { level: 5, suit: "H", trump: "H", declarer: "S", doubled: "X" }
buildContract ( "3NT" , "N" ); // => { level: 3, suit: "NT", trump: null, declarer: "N", doubled: "none" }
Input is trimmed, upper-cased and stripped of spaces, hyphens and underscores before the alias lookup.
Function Signature Description parseScoring(candidate: string) => ScoringModeCanonical mode, "UNSET" when unknown. mapScoring<T>(value: string, mapping: Record<ScoringModeSet, T>) => T | undefinedLooks the parsed mode up in mapping; undefined when unknown.
Aliases Result IMP, IMPS, IMP PAIRS"IMP"TPP, TOTAL POINT(S), MATCHPOINT(S), MP"TPP"
parseScoring ( "IMP" ); // => "IMP"
parseScoring ( "match points" ); // => "TPP"
parseScoring ( "total_points" ); // => "TPP"
parseScoring ( "Butler" ); // => "UNSET"
mapScoring ( "imps" , { IMP: "International Match Points" , TPP: "Total points" }); // => "International Match Points"
mapScoring ( "Butler" , { IMP: 1 , TPP: 2 }); // => undefined
Input is trimmed, upper-cased and stripped of spaces, hyphens, underscores and slashes.
Function Signature Description parseVulnerability(vulnerability: string) => VulnerabilityCanonical value, "UNSET" when unknown. mapVulnerability<T>(value: string, mapping: Record<VulnerabilitySet, T>) => T | undefinedLooks the parsed value up in mapping; undefined when unknown.
Aliases Result NONE, LOVE"NONE"NS, N/S, N-S"NS"EW, E/W, E-W"EW"ALL, BOTH"ALL"
parseVulnerability ( "None" ); // => "NONE"
parseVulnerability ( "Love" ); // => "NONE"
parseVulnerability ( "N/S" ); // => "NS"
parseVulnerability ( "Both" ); // => "ALL"
parseVulnerability ( "Dealer" ); // => "UNSET"
mapVulnerability ( "Both" , { NONE: "o" , NS: "n" , EW: "e" , ALL: "b" }); // => "b"
mapVulnerability ( "??" , { NONE: 0 , NS: 1 , EW: 2 , ALL: 3 }); // => undefined
engine.parse has no configuration. It gathers the three parsers above with the card, bid and player parsers and guards that are otherwise reached through @workspace/bridge/card, @workspace/bridge/auction and @workspace/bridge/player.
Member Signature Description parseSuit(value: string) => Suit | nullS, H, D, C.parseRank(value: string) => Rank | nullSingle canonical character; "10" is not accepted. parseCard(value: string) => Card | nullUppercases and collapses "10" first, then validates. toCard(input: CardInput) => CardCanonical string from a Card or { suit, rank }; throws InvalidNotationError when it denotes no card. suitOf(card: Card) => SuitReader. rankOf(card: Card) => RankReader. isRank(value: string) => value is RankisCard(value: unknown) => value is CardDEFAULT_RANK_ORDERreadonly Rank[]13 ranks, highest first. sortRanksDefault(ranks: readonly Rank[]) => Rank[]Default order, highest first; unknown ranks sort last.
Member Signature Description parseBid(value: string) => Bid | nullRegular (1H, 3NT) or special (Pass, X, XX, Alert). splitBid(bid: Bid) => RegularBidParts | null{ level, suit }; null for special bids.toBid(input: BidInput) => BidCanonical string from a Bid or { level, suit }; throws InvalidNotationError when it denotes no bid. isBid(value: unknown) => value is Bid
Member Signature Description isPlayer(value: string) => value is PlayerCase-insensitive N, E, S, W. parseVulnerability, parseScoringas above parseContractString, buildContractas above
const engine = createBridgeEngine (
createBridgeContext ({ teachingMode: "auction" , locale: "en" }),
);
engine.parse. parseCard ( "SA" ); // => "SA"
engine.parse. parseCard ( "S1" ); // => null
engine.parse. parseRank ( "T" ); // => "T"
engine.parse. parseRank ( "10" ); // => null (strict single-character ranks)
engine.parse. suitOf ( "HQ" ); // => "H"
engine.parse. toCard ({ suit: "H" , rank: "Q" }); // => "HQ"
engine.parse. parseBid ( "3NT" ); // => "3NT"
engine.parse. toBid ({ level: 3 , suit: "NT" }); // => "3NT"
engine.parse. splitBid ( "3NT" ); // => { level: 3, suit: "NT" }
engine.parse. isPlayer ( "n" ); // => true
engine.parse. sortRanksDefault ([ "2" , "A" , "T" ]); // => ["A", "T", "2"]
engine.parse. parseVulnerability ( "Both" ); // => "ALL"
engine.parse. buildContract ( "4S" , "W" ); // => { level: 4, suit: "S", trump: "S", declarer: "W", doubled: "none" }