UNPKG

chat-bet-parse

Version:

TypeScript package for parsing sports betting contract text into structured data types compatible with SQL Server stored procedures

640 lines (464 loc) โ€ข 27.1 kB
# chat-bet-parse ## 0.6.11 ### Patch Changes - **Support for letter-first quarter/period formats in single-team game totals**: Fixed parser to recognize `q1`, `q2`, `q3`, `q4`, `p1`, `p2`, `p3` period formats when no league prefix is provided. ### ๐ŸŽฏ Problem Solved Previously, single-team game totals with letter-first period notation (e.g., `q1` instead of `1q`) required a league prefix to parse correctly. **Before:** ```typescript const result = parseChat('YG pacers q1 u61 @ -111 = risk 3300'); // โŒ InvalidContractTypeError: Unable to determine contract type from: "pacers q1 u61" ``` **After:** ```typescript const result = parseChat('YG pacers q1 u61 @ -111 = risk 3300'); // โœ… Successfully parses as TotalPoints contract console.log(result.contract.Match.Team1); // "pacers" console.log(result.contract.Line); // 61 console.log(result.contract.Period); // { PeriodTypeCode: 'Q', PeriodNumber: 1 } ``` ### ๐Ÿ”ง Technical Details Updated the contract type detection regex for single-team game totals to include letter-first period formats (`q1|q2|q3|q4|p1|p2|p3`), matching the pattern already used for two-team game totals. ### โœ… Impact - All 510 tests passing - 2 new tests added for quarter period totals with and without league prefix - Both `YG pacers q1 u61 @ -111 = risk 3300` and `YG NBA pacers q1 u61 @ -111 = risk 3300` now parse correctly ## 0.6.10 ### Patch Changes - **Comma-Thousands Syntax Support**: Added support for American thousands formatting in bet sizes with strict validation. ### ๐ŸŽฏ Problem Solved Previously, the parser only accepted sizes without commas. Users couldn't input sizes like `20,000` or `$15,550` - they had to write `20000` or use k-notation like `$15.55k`. **Before:** ```typescript const result = parseChat('YG Lakers @ +120 = $1,500'); // โŒ InvalidSizeFormatError: Invalid size format: "= $1,500" ``` **After:** ```typescript const result = parseChat('YG Lakers @ +120 = $1,500'); // โœ… Successfully parses as $1,500 console.log(result.bet.Size); // 1500 // Works in all size contexts parseChat('YG Lakers @ +120 = risk 20,000'); parseChat('YGP Lakers @ +120 & Warriors @ -110 = $5k tw $15,550'); ``` ### ๐Ÿ”ง Technical Details **Valid comma-thousands formats:** - `1,234` - four digits - `12,345` - five digits - `1,234,567` - multiple comma groups - `$15,550` - with dollar sign - Works with: `risk 20,000`, `tw $15,550`, `= $1,500` **Validation enforces American thousands formatting:** - โœ… Valid: Groups of exactly 3 digits after first 1-3 digits - โŒ Invalid: `20,30` (only 2 digits after comma) - โŒ Invalid: `1,2345` (4 digits after comma) - โŒ Invalid: `123,45` (2 digits after comma) **Additional fix:** Parser now handles missing spaces around `@` symbol (e.g., `o39.5@-122` now works correctly). ### โœ… Impact - All 508 tests passing - Supports comma-thousands in all size contexts (risk, towin, size) - Strict validation prevents invalid comma placement - 7 new tests covering valid and invalid comma patterns ## 0.6.9 ### Patch Changes - **Support for Team Names Starting with Numbers (49ers, 76ers)**: Fixed parser regex patterns to correctly handle team names that start with "49" or "76", such as "49ers" and "76ers". ### ๐ŸŽฏ Problem Solved Previously, the parser failed to recognize team names starting with digits in single-team game total formats, causing parse errors. **Before:** ```typescript const result = parseChat('YG NBA 11/28/2025 76ers u226.5 @ -115 = 1k'); // โŒ InvalidContractTypeError: Unable to determine contract type ``` **After:** ```typescript const result = parseChat('YG NBA 11/28/2025 76ers u226.5 @ -115 = 1k'); // โœ… Successfully parses as TotalPoints contract console.log(result.contract.Match.Contestant1_RawName); // "76ers" console.log(result.contract.Line); // 226.5 ``` ### ๐Ÿ”ง Technical Details Updated 5 regex patterns in the parser to allow optional "49" or "76" numeric prefixes: - Single team game total shorthand (`76ers u226.5`) - Single team with period (`76ers 1H u110`) - Period extraction for spreads, team totals, and game totals Pattern format: `(?:49|76)?[a-zA-Z\s&.-]+` allows optional "49" or "76" prefix followed by standard team name characters, preventing unintended matches while supporting these specific NFL/NBA teams. ### โœ… Impact - All 499 tests passing - Supports both "49ers" (NFL) and "76ers" (NBA) in all bet formats - Precise regex ensures no false positives with other numeric patterns ## 0.6.8 ### Patch Changes - **Automatic ToWin Calculation for Parlays and Round Robins**: When parsing parlays (YGP) and round robins (YGRR) with fair odds (`useFair: true`), the library now automatically calculates `bet.ToWin` from leg prices using fair parlay odds mathematics. ### ๐ŸŽฏ Problem Solved Previously, `bet.ToWin` was `undefined` for parlays and round robins when no explicit `tw` override was provided. This caused downstream errors in systems that expected both `Risk` and `ToWin` to be populated. **Before:** ```typescript const result = parseChat('YGP Lakers @ +120 & Warriors @ -110 = $100'); console.log(result.bet.ToWin); // undefined โŒ ``` **After:** ```typescript const result = parseChat('YGP Lakers @ +120 & Warriors @ -110 = $100'); console.log(result.bet.ToWin); // 320.00 โœ… console.log(result.useFair); // true ``` ### ๐Ÿš€ How It Works **Parlay Calculation:** 1. Convert each leg's American odds to decimal odds (+120 โ†’ 2.20, -110 โ†’ 1.909090...) 2. Multiply all decimal odds together to get parlay multiplier 3. Calculate `ToWin = Risk ร— (multiplier - 1)` **Round Robin Calculation:** 1. Generate all nCr combinations (or at-most combinations for notation like 4c3-) 2. Calculate fair ToWin for each parlay combination 3. Sum all ToWins for total expected payout ### ๐Ÿ“š Examples ```typescript // 2-leg parlay parseChat('YGP Lakers @ +120 & Warriors @ -110 = $100') // โ†’ { bet: { Risk: 100, ToWin: 320 }, useFair: true } // 3-leg parlay parseChat('YGP Lakers @ +120 & Warriors @ -110 & Celtics @ +105 = $100') // โ†’ { bet: { Risk: 100, ToWin: 761 }, useFair: true } // Round robin with per-selection risk parseChat('YGRR 4c2 Lakers @ +120 & Warriors @ -110 & Celtics @ +105 & Nets @ +115 = $100 per') // โ†’ { bet: { Risk: 600, ToWin: 1986.56 }, useFair: true, riskType: 'perSelection' } // With explicit tw override (not fair odds) parseChat('YGP Lakers @ +120 & Warriors @ -110 = $100 tw $500') // โ†’ { bet: { Risk: 100, ToWin: 500 }, useFair: false } ``` ### โœ… Impact - `bet.ToWin` is now always populated for fills with fair odds - Use `useFair: true` to distinguish calculated ToWin from explicit overrides - All 497 tests passing - **Correct Total Risk Calculation for Round Robins**: When parsing round robins with per-selection risk mode (e.g., `$100 per`), the library now correctly calculates total risk as `per-parlay risk ร— number of parlays`. ### ๐ŸŽฏ Problem Solved Previously, the library only returned the per-parlay risk amount instead of calculating the total risk across all parlays. **Before:** ```typescript const result = parseChat('YGRR 4c2 ... = $100 per'); console.log(result.bet.Risk); // 100 โŒ (only per-parlay amount) ``` **After:** ```typescript const result = parseChat('YGRR 4c2 ... = $100 per'); console.log(result.bet.Risk); // 600 โœ… ($100 per ร— 6 parlays) ``` ### ๐Ÿ“š Examples ```typescript // 4c2 = C(4,2) = 6 parlays parseChat('YGRR 4c2 Lakers @ +120 & Warriors @ -110 & Celtics @ +105 & Nets @ +115 = $100 per') // โ†’ { bet: { Risk: 600 }, riskType: 'perSelection' } // 4c3- (at-most) = C(4,2) + C(4,3) = 6 + 4 = 10 parlays parseChat('YGRR 4c3- Lakers @ +120 & Warriors @ -110 & Celtics @ +105 & Nets @ +115 = $100 per') // โ†’ { bet: { Risk: 1000 }, riskType: 'perSelection' } // Total risk mode (unchanged behavior) parseChat('YGRR 4c2 ... = $600 total') // โ†’ { bet: { Risk: 600 }, riskType: 'total' } ``` ### ๐Ÿ”ง New Helper Functions - `calculateCombination(n, r)`: Calculates C(n,r) = "n choose r" - `calculateTotalParlays(totalLegs, parlaySize, isAtMost)`: Calculates total number of parlays - `americanToDecimalOdds(odds)`: Converts American odds to decimal - `calculateParlayFairToWin(legPrices, risk)`: Calculates fair ToWin for a single parlay - `calculateRoundRobinFairToWin(legPrices, risk, riskType, parlaySize, isAtMost)`: Calculates fair ToWin for all round robin combinations ### ๐Ÿ“„ Migration Guide See `RECENT_CHANGES_FOR_UI.md` for detailed migration instructions for UI developers. ## 0.6.3 ### Patch Changes - **Timezone-Agnostic Date Handling**: All date parsing and creation now uses UTC to ensure consistent behavior across different server timezones ### ๐ŸŽฏ Problem Solved Previously, dates were created using local timezone (e.g., `new Date(year, month, day)`), which caused test failures when running in different timezones: - **Local (Eastern timezone)**: `2025-10-26T04:00:00.000Z` (midnight Eastern = 4am UTC) - **CI/CD (UTC timezone)**: `2025-10-26T00:00:00.000Z` (midnight UTC) ### ๐Ÿš€ Solution All date creation now uses `Date.UTC()` to produce timezone-agnostic dates at midnight UTC: ```typescript // Before (timezone-dependent) new Date(2025, 9, 26) // Different results in different timezones // After (timezone-agnostic) new Date(Date.UTC(2025, 9, 26)) // Always 2025-10-26T00:00:00.000Z ``` ### ๐Ÿ“š Files Modified - `src/parsers/utils.ts`: Updated date creation and validation to use UTC - `src/tracking/mappers.ts`: Updated ExecutionDtm extraction and fallback logic to use UTC - Test files: Updated expectations to use `Date.UTC()` and UTC getter methods - Test fixtures: Updated all date expectations from local time to UTC midnight ### โœ… Impact - Tests now pass consistently in any timezone (Eastern, UTC, PST, etc.) - Parser produces identical results regardless of server location - All 485 tests passing in both local and CI/CD environments ## 0.6.2 ### Patch Changes - **Tracking Mapper EventDate Priority Enhancement**: The tracking mapper now prioritizes dates embedded in bet text (`contract.Match.Date`) over execution timestamps when determining `EventDate` ### ๐ŸŽฏ EventDate Priority Order 1. Writein contracts' explicit `EventDate` 2. Caller-provided `options.eventDate` 3. **Date parsed from bet text (`contract.Match.Date`)** โ† NEW 4. Date extracted from `ExecutionDtm` timestamp 5. Today's date (fallback) ### ๐Ÿš€ What Changed Before this fix, when parsing a bet like `"YG NBA 10/26/2025 Pacers u230 @ -110 = 1k"` executed on 10/25/2025, the mapper would use the execution date (10/25) instead of the date specified in the bet text (10/26). **Before:** ```typescript const result = parseChat('YG NBA 10/26/2025 Pacers u230 @ -110 = 1k'); const spec = mapParseResultToContractLegSpec(result); // EventDate = 2025-10-25 (from ExecutionDtm) โŒ ``` **After:** ```typescript const result = parseChat('YG NBA 10/26/2025 Pacers u230 @ -110 = 1k'); const spec = mapParseResultToContractLegSpec(result); // EventDate = 2025-10-26 (from bet text) โœ… ``` ### ๐Ÿงช Test Coverage - Added 11 new Date Handling tests covering: - Full date formats (MM/DD/YYYY) - Partial date formats (MM/DD) with referenceDate inference - Priority ordering verification (options.eventDate > Match.Date > ExecutionDtm) - All 485 tests passing ### ๐Ÿ“š Files Modified - `src/tracking/mappers.ts`: Added `contract.Match.Date` check in EventDate determination - `tests/unit/tracking.test.ts`: Added 7 new comprehensive Date Handling tests - `tests/fixtures/game-totals.fixtures.ts`: Added 4 NBA date parsing test cases ## 0.6.0 ### Minor Changes - **DEPRECATION: Grading Mapper Functions**: The grading mapper module (`src/grading/mappers.ts`) is now deprecated in favor of the tracking mapper module. The grading mapper now wraps the tracking mapper for backward compatibility. **Deprecated Functions:** - `mapParseResultToSqlParameters` โ†’ Use `mapParseResultToContractLegSpec` instead - `validateGradingParameters` โ†’ Use `validateContractLegSpec` instead **Migration:** ```typescript // Before (DEPRECATED) import { mapParseResultToSqlParameters } from 'chat-bet-parse/grading'; const params = mapParseResultToSqlParameters(result, { matchScheduledDate: date }); // After (RECOMMENDED) import { mapParseResultToContractLegSpec } from 'chat-bet-parse/tracking'; const spec = mapParseResultToContractLegSpec(result, { eventDate: date }); ``` **Why?** Both mappers were doing the same conceptual work with 95% duplicate code. Consolidating to the tracking mapper eliminates duplication and provides a single source of truth. The `ChatBetGradingClient` continues to work unchanged. - **Individual Player Props with Match.Player Field**: Add dedicated fields for individual player props to properly distinguish them from team-based props ### ๐ŸŽฏ New Match Fields - **`Match.Player`** - Player name for individual props (e.g., "Cooper Flagg", "B. Falter") ```typescript // Before (WRONG): Player stored in Team1 { Match: { Team1: "Cooper Flagg" }, ContestantType: "Individual" } // After (CORRECT): Player stored in dedicated field { Match: { Player: "Cooper Flagg", PlayerTeam: "DAL" }, ContestantType: "Individual" } ``` - **`Match.PlayerTeam`** - Optional team affiliation from "(TEAM)" syntax ``` YG NBA Cooper Flagg (DAL) pts o16.5 @ +100 = 2k โ†’ Match.Player = "Cooper Flagg" โ†’ Match.PlayerTeam = "DAL" ``` ### ๐Ÿ”„ Breaking Changes - **`Match.Team1` is now optional** (was previously required) - Individual player props now use `Match.Player` instead of `Match.Team1` - SQL mapper returns `undefined` (not `null`) for missing `Contestant1_RawName` on individual props ### ๐Ÿš€ Parser Enhancements - **Smart contestant type detection**: Automatically determines Individual vs TeamLeague based on prop keywords - **Multi-word player name support**: New `extractContestantAndProp()` utility handles names like "Cooper Flagg pts" - **Team affiliation parsing**: `parsePlayerWithTeam()` extracts player and team from "(TEAM)" syntax - **Team prop differentiation**: Use "team passing yards" keyword to distinguish team-level props from player props ### ๐Ÿ“ฆ SQL Mapping Updates - **Individual props**: `Contestant1_RawName = PlayerTeam || undefined`, `SelectedContestant_RawName = Player` - **Team props**: `Contestant1_RawName = Team1` (unchanged) - No SQL schema changes required - existing `ContractLegSpecTableType` handles both cases ### ๐Ÿงช Test Coverage - Updated 9 test files with individual player prop test cases - Added support for "Cooper Flagg", "B. Falter", and Player123/Team123 patterns - All 441 tests passing ### ๐Ÿ“š Files Modified - `src/types/index.ts`: Extended Match interface with Player and PlayerTeam fields - `src/parsers/utils.ts`: Added parsePlayerWithTeam() and extractContestantAndProp() - `src/parsers/index.ts`: Updated parsePropOU() and parsePropYN() for individual props - `src/tracking/mappers.ts`: Updated extractMatchInfo() for correct SQL mapping - Test fixtures updated to use "team passing yards" syntax for team-level props - **Parlay/Round Robin Support in Mappers**: Grading and tracking mappers now handle parlay and round robin bets by returning arrays of mapped parameters ### ๐ŸŽฏ Mapper Updates - **`mapParseResultToSqlParameters()`** - Returns array for parlay/round robin ```typescript // Straight bet (backward compatible) const params = mapParseResultToSqlParameters(straightBet, options); // โ†’ Single GradingSqlParameters object // Parlay/Round Robin (new) const params = mapParseResultToSqlParameters(parlayBet, options); // โ†’ Array of GradingSqlParameters (one per leg) ``` - **`mapParseResultToContractLegSpec()`** - Returns array for parlay/round robin ```typescript // Straight bet (backward compatible) const spec = mapParseResultToContractLegSpec(straightBet, options); // โ†’ Single ContractLegSpec object // Parlay/Round Robin (new) const specs = mapParseResultToContractLegSpec(parlayBet, options); // โ†’ Array of ContractLegSpec (one per leg with LegSequence and Price) ``` ### ๐Ÿš€ Features - **Recursive leg mapping**: Each parlay/round robin leg is mapped individually using the same logic as straight bets - **Automatic LegSequence**: Combo legs automatically get assigned proper 1-based LegSequence values - **Price handling**: Combo legs include Price field (null for straight bets per SQL spec) - **Validation updates**: Allow `undefined` Contestant1 for individual props (PropOU/PropYN with Individual type) ### ๐Ÿ”„ Breaking Changes - Return type changed from `GradingSqlParameters` to `GradingSqlParameters | GradingSqlParameters[]` - Return type changed from `ContractLegSpec` to `ContractLegSpec | ContractLegSpec[]` - Code using these mappers must handle both single and array return types ### ๐Ÿงช Test Coverage - New test suite `tests/unit/mappers.test.ts` with 31 comprehensive tests - Covers all contract types, parlay/round robin mapping, validation - Updated individual prop tests to expect correct Contestant1 mapping - All 472 tests passing ### ๐Ÿ“š Files Modified - `src/grading/mappers.ts`: Updated mapParseResultToSqlParameters() to handle combos - `src/tracking/mappers.ts`: Updated mapParseResultToContractLegSpec() to handle combos - `tests/unit/mappers.test.ts`: New comprehensive test suite for grading mappers ## 0.5.0 ### Minor Changes - **Extended Size Syntax for Straight Bets**: Add new size specification formats that allow explicit control over risk and to-win amounts ### ๐ŸŽฏ New Size Formats - **`tw` / `to win`** - Specify risk and to-win explicitly ``` YG Lakers ML @ -110 = $110 tw $100 ``` Perfect for tickets that show risk amount even with negative odds, or when dealing with short-pay due to rounded odds. - **`tp` / `to pay`** - Specify risk and total payout (parser calculates to-win) ``` YG Warriors ML @ -120 = $120 tp $220 ``` Useful when ticket shows total payout instead of profit. - **`risk`** - Specify only risk amount (parser calculates to-win from price) ``` YG Knicks -2.5 @ -110 = risk $110 ``` - **`towin`** - Specify only to-win amount (parser calculates risk from price) ``` YG Bulls ML @ +150 = towin $150 ``` ### ๐Ÿš€ Automatic Risk/ToWin Calculation - **Parser now always populates `bet.Risk` and `bet.ToWin`** for all straight bets - Clients **no longer need** their own `calculateRiskAndToWin()` utility functions - Moved calculation logic into parser library for single source of truth - Smart inference: fills in missing Risk or ToWin based on Price when only one value specified - Full backward compatibility: existing `Size` syntax still works and auto-calculates both values ### ๐Ÿ“ฆ Type Updates - `Bet` interface now includes `Risk?: number` and `ToWin?: number` - `ParsedTokens` and `WriteInTokens` interfaces updated to support new fields - New `ParsedStraightSize` interface for size parsing results ### ๐Ÿ”ง Implementation Details - Added `calculateRiskAndToWin()`, `calculateToWinFromRisk()`, `calculateRiskFromToWin()` to utils - New `parseStraightSize()` function handles all size formats (DRY implementation) - Updated `parseChatOrder()` and `parseChatFill()` to always populate Risk/ToWin - 7 new tests for extended syntax, all existing 437 tests still passing - **Changed**: +311 lines, -17 lines across 5 files ### ๐Ÿ“š Migration Guide See [MIGRATION_GUIDE_v0.5.0.md](./MIGRATION_GUIDE_v0.5.0.md) for detailed instructions on: - Removing client-side `calculateRiskAndToWin()` utilities - Updating components to use `result.bet.Risk` and `result.bet.ToWin` directly - Testing recommendations ## 0.4.3 ### Patch Changes - **Case-insensitive league detection**: Support league codes in any case (NBA, nba, Nba, etc.) - **CBB alias support**: Add CBB as alias for CBK (College Basketball), similar to existing FCS โ†’ CFB mapping - **Expanded prop keywords**: Add 120+ prop betting keywords across baseball, football, and basketball with automatic Individual/TeamLeague classification - Keywords are matched longest-first and include contestantType metadata that flows through to ContractLegSpec - Examples: player stats (Individual), team props (TeamLeague) - Backward compatible: existing API unchanged, sim-dash gets PropContestantType automatically - **Fix dollar+k-notation parsing**: Correctly parse `$11k` โ†’ `$11,000` (previously incorrectly parsed as `$11`) - **Writein legs in parlays/round robins**: Add test coverage for writein contracts as legs in YGP/IWP/YGRR/IWRR bets - Syntax: `YGP writein 12/25/2024 Event description @ +200 & Lakers @ +120 = $100` - Known limitation: Writein descriptions cannot contain ampersand character ## 0.4.2 ### Patch Changes - **DRY refactoring**: Consolidate duplicated parsing and validation logic - Merged size parsing functions into shared helper - Consolidated keyword parsing with `extractAndValidateKeywords` helper - Extracted contract validation to `shared/contractValidation.ts` module - Replaced duplicate switch statements with contract parser factory pattern - Fixed parlay/round robin size parsing to support k-notation and decimal formats - Reduced codebase by ~410 lines while maintaining 100% test coverage - **Timezone-independent testing**: Fix ExecutionDtm date handling test to work across all timezones (was failing in CI/CD) ## 0.4.1 ### Patch Changes - **Documentation update**: Update README and archive implementation guides - Add parlay (YGP/IWP) and round robin (YGRR/IWRR) support to features - Document two-discriminator type system (chatType + betType) - Add comprehensive EBNF grammar for parlays and round robins - Add 60+ new syntax examples for parlays and round robins - Update API documentation with type guards and result structures ## 0.4.0 ### Minor Changes - **Parlay betting support**: Implement YGP/IWP parlay parsing - 2-10 leg parlays with `&` separator - Fair odds calculation or explicit to-win override (`tw` keyword) - Support for `pusheslose`/`tieslose` and `freebet` flags - Leg-level rotation numbers, game numbers, dates, leagues, and periods - Multiline format support - Size formats: decimal thousands, k-notation, dollar+k (`$11k`) - All contract types supported in parlay legs (including writein) - **Round robin betting support**: Implement YGRR/IWRR round robin parsing with nCr notation - nCr notation: `4c2` (4 teams, 2-team parlays), `5c3`, `6c4`, etc. - At-most modifier with trailing dash: `4c3-` (at most 3: creates 2s and 3s) - Per-selection vs total risk types: `= $100 per` or `= $600 total` - Same parlay features: to-win override, flags, leg properties - Multiline format support - **Event dates for straight bets**: Add date support for YG/IW bets - Multiple date formats: YYYY-MM-DD, MM/DD/YYYY, YYYY/MM/DD, MM-DD-YYYY - Positional dates: `YG 12/25/2024 Lakers @ +150 = 2.5` - Keyword dates: `YG date:12/25/2024 Lakers @ +150 = 2.5` - Smart year inference for MM/DD format - Calendar date validation - **League keywords for writeins**: Add league support for YGW/IWW - Syntax: `YGW league:NBA 12/25/2024 Custom event @ +200 = 1.5` - Works with both positional and keyword date formats - **ParseOptions**: New options object for parser configuration - `referenceDate?: Date` - for date parsing context - Passed to all parse functions: `parseChat(message, options)` - **Type system refactor**: Implement two-discriminator type system - `chatType`: 'order' | 'fill' - `betType`: 'straight' | 'parlay' | 'roundRobin' - Type guards: `isParlay()`, `isRoundRobin()`, `isStraightBet()` - Discriminated unions for type-safe result handling ## 0.3.7 ### Minor Changes - Add Writein contract support for custom betting events ### ๐Ÿ—๏ธ New Features - **Writein Contracts**: New contract type for custom betting events not tied to specific sports matches - Support for format: `IW/YG writein DATE DESCRIPTION [@ price] [= size]` - Multiple date format support: YYYY-MM-DD, MM/DD/YYYY, YYYY/MM/DD, MM-DD-YYYY, and equivalents without year - Smart year inference (current year if future/today, next year if past) - Calendar date validation (rejects invalid dates like Feb 30th) - Description validation (10-255 characters, no newlines) - Full price and size parsing support (@ +150, = 3.0, k-notation, etc.) - Case-insensitive "writein" detection - **Enhanced Type System**: New `ContractWritein` interface with `EventDate` and `Description` properties - **Comprehensive Error Handling**: - `InvalidWriteinFormatError` for format issues - `InvalidWriteinDateError` for date parsing failures - `InvalidWriteinDescriptionError` for description validation - **Grading System Integration**: Updated SQL Server grading support for Writein contracts - **Extensive Testing**: 18 new tests covering positive and error scenarios ## 0.3.0 ### Minor Changes - 354c740: Add SQL Server grading client and expand parser support ### ๐Ÿ—๏ธ New Features - **SQL Server Grading Client**: New `ChatBetGradingClient` for automated contract grading against SQL Server databases - Support for all major contract types: TotalPoints, TotalPointsContestant, HandicapContestantML, HandicapContestantLine - Comprehensive error handling with `GradingConnectionError` and `GradingDataError` - Flexible configuration with connection pooling options - Factory functions for easy client creation - **Enhanced Parser Support**: Extended parsing capabilities for F3 periods and individual player props - F3 (first three innings) period parsing for baseball games - Individual player detection for props (e.g., "B. Name Ks o1.5") - Improved team name handling with special characters ## 0.2.0 ### Minor Changes - 744258e: Initial release of chat-bet-parse - ๐Ÿˆ Multi-sport support (MLB, NBA) with extensible framework - ๐Ÿ“ Rich parsing for chat orders (IW) and fills (YG) with different size interpretations - ๐Ÿ”’ Full TypeScript support with discriminated unions - ๐Ÿ—ƒ๏ธ SQL Server ready types for stored procedure integration - โšก Zero runtime dependencies - ๐Ÿงช Comprehensive test suite with 141 tests and 100% coverage - ๐Ÿ“– Complete EBNF grammar documentation - โœ… README validation tests to ensure documentation accuracy