this repo has no description
at main 734 lines 26 kB view raw
1/** 2 * Example usage of TaggedStringParser 3 * Demonstrates basic usage, schema definition, formatters, and type inference 4 * 5 * Run with: node src/examples.ts 6 */ 7 8import { TaggedStringParser } from './TaggedStringParser.ts' 9import type { EntitySchema } from './types.ts' 10 11// ============================================================================ 12// Example 1: Basic Usage with Schema and Simple String Formatters 13// ============================================================================ 14 15console.log('=== Example 1: Basic Usage with String Formatters ===\n') 16 17const basicSchema: EntitySchema = { 18 operation: { type: 'string', format: (v) => String(v).toUpperCase() }, 19 stack: { type: 'string', format: (v) => String(v).trim() }, 20 changes: { type: 'number', format: (n) => `${n} changes` }, 21 status: 'string', // Shorthand without formatter 22} 23 24const basicParser = new TaggedStringParser({ schema: basicSchema }) 25const result1 = basicParser.parse( 26 '[operation:deploy] started with [changes:5] to [stack: prod-stack ]', 27) 28 29console.log('Original message:', result1.originalMessage) 30console.log('Formatted message:', result1.format()) 31console.log('\nParsed entities:') 32result1.entities.forEach((entity) => { 33 console.log(` - Type: ${entity.type}`) 34 console.log(` Raw value: "${entity.value}"`) 35 console.log( 36 ` Parsed value: ${entity.parsedValue} (${entity.inferredType})`, 37 ) 38 console.log(` Formatted value: "${entity.formattedValue}"`) 39 console.log(` Position: ${entity.position}`) 40}) 41 42// ============================================================================ 43// Example 2: Automatic Type Inference for Unknown Entities 44// ============================================================================ 45 46console.log('\n\n=== Example 2: Automatic Type Inference ===\n') 47 48const inferenceParser = new TaggedStringParser() // No schema 49const result2 = inferenceParser.parse( 50 '[count:42] items processed, [enabled:true] flag set, [name:test-service]', 51) 52 53console.log('Message:', result2.originalMessage) 54console.log('\nInferred types:') 55result2.entities.forEach((entity) => { 56 console.log( 57 ` - [${entity.type}:${entity.value}] → ${entity.inferredType} (${typeof entity.parsedValue})`, 58 ) 59 console.log(` Parsed value: ${JSON.stringify(entity.parsedValue)}`) 60}) 61 62// ============================================================================ 63// Example 3: Entity Filtering by Type 64// ============================================================================ 65 66console.log('\n\n=== Example 3: Entity Filtering ===\n') 67 68const filterSchema: EntitySchema = { 69 resource: 'string', 70 action: 'string', 71 count: 'number', 72} 73 74const filterParser = new TaggedStringParser({ schema: filterSchema }) 75const result3 = filterParser.parse( 76 '[action:create] [resource:function] with [count:3] instances, [action:update] [resource:database]', 77) 78 79console.log('All entity types:', result3.getAllTypes()) 80console.log( 81 '\nActions:', 82 result3.getEntitiesByType('action').map((e) => e.parsedValue), 83) 84console.log( 85 'Resources:', 86 result3.getEntitiesByType('resource').map((e) => e.parsedValue), 87) 88console.log( 89 'Counts:', 90 result3.getEntitiesByType('count').map((e) => e.parsedValue), 91) 92console.log('Non-existent type:', result3.getEntitiesByType('missing')) 93 94// ============================================================================ 95// Example 4: IaC Logging Examples (from design document) 96// ============================================================================ 97 98console.log('\n\n=== Example 4: IaC Logging Examples ===\n') 99 100const iacSchema: EntitySchema = { 101 operation: { type: 'string', format: (v) => `OP:${v}` }, 102 stack: { type: 'string', format: (v) => `Stack(${v})` }, 103 changes: { type: 'number', format: (n) => `${n} change(s)` }, 104 blueprint: { type: 'string', format: (v) => `BP:${v}` }, 105 create: 'number', 106 update: 'number', 107 destroy: 'number', 108 action: 'string', 109 resource: 'string', 110 resourceName: 'string', 111 type: 'string', 112 externalId: 'string', 113 reason: 'string', 114 error: 'string', 115} 116 117const iacParser = new TaggedStringParser({ schema: iacSchema }) 118 119// Operation lifecycle 120console.log('Operation Lifecycle:') 121const op1 = iacParser.parse( 122 '[operation:OP-123] started with [changes:5] to [stack:ST-456]', 123) 124console.log(' ', op1.format()) 125 126const op2 = iacParser.parse( 127 '[operation:OP-123] completed [changes:5] to [stack:ST-456]', 128) 129console.log(' ', op2.format()) 130 131const op3 = iacParser.parse('[operation:OP-123] failed: [reason:Timeout error]') 132console.log(' ', op3.format()) 133 134// Planning 135console.log('\nPlanning:') 136const plan1 = iacParser.parse('[blueprint:BP-123] planning for [stack:ST-456]') 137console.log(' ', plan1.format()) 138 139const plan2 = iacParser.parse( 140 '[blueprint:BP-123] plan complete with [create:2] [update:3] [destroy:1] for [stack:ST-456]', 141) 142console.log(' ', plan2.format()) 143console.log(' Plan summary:', { 144 create: plan2.getEntitiesByType('create')[0]?.parsedValue, 145 update: plan2.getEntitiesByType('update')[0]?.parsedValue, 146 destroy: plan2.getEntitiesByType('destroy')[0]?.parsedValue, 147}) 148 149// Resource commands 150console.log('\nResource Commands:') 151const res1 = iacParser.parse( 152 '[action:create] executing for [resource:RS-123] [resourceName:my-function] [type:function]', 153) 154console.log(' ', res1.format()) 155 156const res2 = iacParser.parse( 157 '[action:create] completed for [resource:RS-123] [externalId:EXT-789]', 158) 159console.log(' ', res2.format()) 160 161const res3 = iacParser.parse( 162 '[action:create] failed for [resource:RS-123]: [error:Connection timeout]', 163) 164console.log(' ', res3.format()) 165 166// ============================================================================ 167// Example 5: Custom Configuration (Delimiters with Formatting) 168// ============================================================================ 169 170console.log('\n\n=== Example 5: Custom Delimiters with Formatting ===\n') 171 172// This example demonstrates the fix for custom delimiter formatting 173// Previously, format() was hardcoded to use ']' and wouldn't work with custom delimiters 174// Now it correctly uses the configured delimiters to reconstruct messages 175 176const customParser = new TaggedStringParser({ 177 openDelimiter: '{{', 178 closeDelimiter: '}}', 179 typeSeparator: '=', 180 schema: { 181 user: { type: 'string', format: (v) => `@${v}` }, 182 count: { type: 'number', format: (v) => String(v) }, 183 }, 184}) 185 186const result5 = customParser.parse( 187 'User {{user=john}} performed {{count=10}} actions', 188) 189console.log('Original message:', result5.originalMessage) 190console.log('Formatted message:', result5.format()) 191console.log(' ✓ Custom delimiters {{}} work correctly with format()') 192console.log(' ✓ Formatters applied: user → @john, count → 10') 193 194console.log('\nParsed entities:') 195result5.entities.forEach((entity) => { 196 console.log( 197 ` - {{${entity.type}=${entity.value}}} at position ${entity.position}-${entity.endPosition}`, 198 ) 199 console.log(` Formatted as: "${entity.formattedValue}"`) 200}) 201 202// Additional custom delimiter examples 203console.log('\nOther custom delimiter configurations:') 204 205const angleParser = new TaggedStringParser({ 206 openDelimiter: '<<', 207 closeDelimiter: '>>', 208 typeSeparator: ':', 209 schema: { 210 status: { type: 'string', format: (v) => String(v).toUpperCase() }, 211 }, 212}) 213const angleResult = angleParser.parse('Operation <<status:success>> completed') 214console.log(' Angle brackets:', angleResult.format()) 215 216const parenParser = new TaggedStringParser({ 217 openDelimiter: '(', 218 closeDelimiter: ')', 219 typeSeparator: ':', 220 schema: { 221 code: { type: 'number', format: (n) => `#${n}` }, 222 }, 223}) 224const parenResult = parenParser.parse('Error (code:404) occurred') 225console.log(' Parentheses:', parenResult.format()) 226 227// ============================================================================ 228// Example 6: Mixed Known and Unknown Entities 229// ============================================================================ 230 231console.log('\n\n=== Example 6: Mixed Known and Unknown Entities ===\n') 232 233const mixedSchema: EntitySchema = { 234 operation: { type: 'string', format: (v) => `[OP: ${v}]` }, 235 // Other entity types will be inferred 236} 237 238const mixedParser = new TaggedStringParser({ schema: mixedSchema }) 239const result6 = mixedParser.parse( 240 '[operation:deploy] with [timeout:30] seconds and [retry:true] flag', 241) 242 243console.log('Formatted:', result6.format()) 244console.log('\nEntity details:') 245result6.entities.forEach((entity) => { 246 const source = mixedSchema[entity.type] ? 'schema' : 'inferred' 247 console.log( 248 ` - ${entity.type}: ${entity.parsedValue} (${entity.inferredType}, ${source})`, 249 ) 250}) 251 252// ============================================================================ 253// Example 7: Accessing Entity Properties 254// ============================================================================ 255 256console.log('\n\n=== Example 7: Accessing Entity Properties ===\n') 257 258const propsSchema: EntitySchema = { 259 price: { type: 'number', format: (n) => `$${Number(n).toFixed(2)}` }, 260 available: { type: 'boolean', format: (b) => (b ? '✓' : '✗') }, 261 product: 'string', 262} 263 264const propsParser = new TaggedStringParser({ schema: propsSchema }) 265const result7 = propsParser.parse( 266 '[product:Widget] is [available:true] at [price:29.99]', 267) 268 269console.log('Original message:', result7.originalMessage) 270console.log('Formatted message:', result7.format()) 271console.log('\nDetailed entity properties:') 272result7.entities.forEach((entity) => { 273 console.log(`\n Entity: ${entity.type}`) 274 console.log(` value (raw string): "${entity.value}"`) 275 console.log( 276 ` parsedValue (typed): ${JSON.stringify(entity.parsedValue)} (${typeof entity.parsedValue})`, 277 ) 278 console.log(` formattedValue (display): "${entity.formattedValue}"`) 279 console.log(` inferredType: ${entity.inferredType}`) 280 console.log(` position: ${entity.position}`) 281}) 282 283// ============================================================================ 284// Example 8: Handling Quoted Values 285// ============================================================================ 286 287console.log('\n\n=== Example 8: Handling Quoted Values ===\n') 288 289const quotedParser = new TaggedStringParser({ 290 schema: { 291 resourceName: 'string', 292 error: 'string', 293 }, 294}) 295 296const result8 = quotedParser.parse( 297 '[resourceName:"my-function"] failed with [error:"Connection timeout"]', 298) 299console.log('Original:', result8.originalMessage) 300console.log('\nEntity values (quotes preserved):') 301result8.entities.forEach((entity) => { 302 console.log(` ${entity.type}: ${entity.value}`) 303}) 304 305console.log('\n=== Examples Complete ===\n') 306// ============================================================================ 307// Example 9: Producer-Consumer Pattern with Generator 308// ============================================================================ 309 310console.log('\n\n=== Example 9: Producer-Consumer Pattern ===\n') 311 312import { TaggedStringGenerator } from './TaggedStringGenerator.ts' 313 314// Producer: Generate tagged strings 315const generator = new TaggedStringGenerator() 316 317console.log('Producer generating tagged strings:') 318const generatedMessage1 = generator.embed('Starting ', 'operation', 'deploy') 319console.log(' ', generatedMessage1) 320 321const generatedMessage2 = generator.embed('Processing ', 'stack', 'prod-stack') 322console.log(' ', generatedMessage2) 323 324const generatedMessage3 = `${generator.tag('operation', 'deploy')} completed with ${generator.tag('changes', 5)} to ${generator.tag('stack', 'prod-stack')}` 325console.log(' ', generatedMessage3) 326 327// Consumer: Parse the generated strings 328const consumerSchema: EntitySchema = { 329 operation: { type: 'string', format: (v) => String(v).toUpperCase() }, 330 stack: { type: 'string', format: (v) => `Stack(${v})` }, 331 changes: { type: 'number', format: (n) => `${n} change(s)` }, 332} 333 334const consumerParser = new TaggedStringParser({ schema: consumerSchema }) 335 336console.log('\nConsumer parsing generated strings:') 337const parsed1 = consumerParser.parse(generatedMessage1) 338console.log(' Original:', parsed1.originalMessage) 339console.log(' Formatted:', parsed1.format()) 340console.log( 341 ' Entities:', 342 parsed1.entities.map((e) => `${e.type}=${e.parsedValue}`), 343) 344 345const parsed3 = consumerParser.parse(generatedMessage3) 346console.log('\n Original:', parsed3.originalMessage) 347console.log(' Formatted:', parsed3.format()) 348console.log( 349 ' Entities:', 350 parsed3.entities.map((e) => `${e.type}=${e.parsedValue}`), 351) 352 353// Demonstrate matching configurations 354console.log('\n✓ Producer and consumer use matching default configuration') 355console.log('✓ Generated tags are correctly parsed and formatted') 356 357// ============================================================================ 358// Example 10: Custom Delimiters with Generator and Parser 359// ============================================================================ 360 361console.log('\n\n=== Example 10: Custom Delimiters with Generator ===\n') 362 363// Producer with custom delimiters 364const customConfig = { 365 openDelimiter: '{{', 366 closeDelimiter: '}}', 367 typeSeparator: '=', 368} 369 370const customGenerator = new TaggedStringGenerator(customConfig) 371 372console.log('Producer generating with custom delimiters {{}}:') 373const customMessage1 = customGenerator.embed('User ', 'user', 'alice') 374console.log(' ', customMessage1) 375 376const customMessage2 = `${customGenerator.tag('action', 'login')} by ${customGenerator.tag('user', 'alice')} at ${customGenerator.tag('timestamp', 1699999999)}` 377console.log(' ', customMessage2) 378 379// Consumer with matching custom delimiters 380const customConsumerParser = new TaggedStringParser({ 381 ...customConfig, 382 schema: { 383 user: { type: 'string', format: (v) => `@${v}` }, 384 action: { type: 'string', format: (v) => String(v).toUpperCase() }, 385 timestamp: { 386 type: 'number', 387 format: (n) => new Date(Number(n) * 1000).toISOString(), 388 }, 389 }, 390}) 391 392console.log('\nConsumer parsing with matching custom delimiters:') 393const customParsed1 = customConsumerParser.parse(customMessage1) 394console.log(' Original:', customParsed1.originalMessage) 395console.log(' Formatted:', customParsed1.format()) 396 397const customParsed2 = customConsumerParser.parse(customMessage2) 398console.log('\n Original:', customParsed2.originalMessage) 399console.log(' Formatted:', customParsed2.format()) 400console.log( 401 ' Entities:', 402 customParsed2.entities.map((e) => `${e.type}=${e.parsedValue}`), 403) 404 405console.log('\n✓ Custom delimiters work correctly with generator and parser') 406console.log('✓ Configuration consistency ensures proper round-trip') 407 408// ============================================================================ 409// Example 11: Delimiter-Free Mode - Basic Usage 410// ============================================================================ 411 412console.log('\n\n=== Example 11: Delimiter-Free Mode - Basic Usage ===\n') 413 414const delimiterFreeParser = new TaggedStringParser({ 415 delimiters: false, 416 typeSeparator: '=', 417 schema: { 418 order: 'number', 419 status: 'string', 420 user: 'string', 421 }, 422}) 423 424const result11 = delimiterFreeParser.parse( 425 'Processing order=1337 with status=pending for user=alice', 426) 427 428console.log('Original message:', result11.originalMessage) 429console.log('Formatted message:', result11.format()) 430console.log('\nExtracted entities:') 431result11.entities.forEach((entity) => { 432 console.log( 433 ` - ${entity.type}=${entity.value} (${entity.inferredType}) at position ${entity.position}`, 434 ) 435}) 436 437// ============================================================================ 438// Example 12: Delimiter-Free Mode - Natural Language 439// ============================================================================ 440 441console.log('\n\n=== Example 12: Delimiter-Free Mode - Natural Language ===\n') 442 443const naturalParser = new TaggedStringParser({ 444 delimiters: [], 445 typeSeparator: '=', 446 schema: { 447 order: { type: 'number', format: (n) => `Order #${n}` }, 448 status: { type: 'string', format: (v) => String(v).toUpperCase() }, 449 }, 450}) 451 452const result12 = naturalParser.parse( 453 'An order=1337 was placed and status=confirmed', 454) 455 456console.log('Original:', result12.originalMessage) 457console.log('Formatted:', result12.format()) 458console.log( 459 '\nEntities:', 460 result12.entities.map((e) => `${e.type}=${e.parsedValue}`), 461) 462 463// ============================================================================ 464// Example 13: Quoted Values with Spaces 465// ============================================================================ 466 467console.log('\n\n=== Example 13: Quoted Values with Spaces ===\n') 468 469const quotedValuesParser = new TaggedStringParser({ 470 delimiters: false, 471 typeSeparator: '=', 472}) 473 474const result13a = quotedValuesParser.parse( 475 'description="high priority task" created', 476) 477console.log('Quoted value:', result13a.entities[0].value) 478console.log(' ✓ Spaces preserved in quoted value') 479 480const result13b = quotedValuesParser.parse('order="number 42" was processed') 481console.log('\nQuoted value with number:', result13b.entities[0].value) 482console.log(' ✓ Type separator preserved in quoted value') 483 484const result13c = quotedValuesParser.parse( 485 'Multiple entities: name="John Doe" age=30 city="New York"', 486) 487console.log('\nMultiple entities with quoted values:') 488result13c.entities.forEach((entity) => { 489 console.log(` - ${entity.type}: "${entity.value}"`) 490}) 491 492// ============================================================================ 493// Example 14: Quoted Keys with Spaces 494// ============================================================================ 495 496console.log('\n\n=== Example 14: Quoted Keys with Spaces ===\n') 497 498const quotedKeysParser = new TaggedStringParser({ 499 delimiters: false, 500 typeSeparator: '=', 501}) 502 503const result14a = quotedKeysParser.parse('"user name"=alice logged in') 504console.log('Quoted key:', result14a.entities[0].type) 505console.log(' ✓ Spaces preserved in quoted key') 506 507const result14b = quotedKeysParser.parse( 508 '"store order"=1337 and "customer id"=42 recorded', 509) 510console.log('\nMultiple quoted keys:') 511result14b.entities.forEach((entity) => { 512 console.log(` - "${entity.type}" = ${entity.value}`) 513}) 514 515// Both key and value quoted 516const result14c = quotedKeysParser.parse( 517 '"order type"="express delivery" selected', 518) 519console.log('\nBoth key and value quoted:') 520console.log( 521 ` - "${result14c.entities[0].type}" = "${result14c.entities[0].value}"`, 522) 523 524// ============================================================================ 525// Example 15: Escape Sequences 526// ============================================================================ 527 528console.log('\n\n=== Example 15: Escape Sequences ===\n') 529 530const escapeParser = new TaggedStringParser({ 531 delimiters: false, 532 typeSeparator: '=', 533}) 534 535// Escaped quotes 536const result15a = escapeParser.parse('message="She said \\"hello\\"" sent') 537console.log('Escaped quotes:', result15a.entities[0].value) 538console.log(' ✓ Literal quotes preserved: She said "hello"') 539 540// Escaped backslashes 541const result15b = escapeParser.parse( 542 'path="C:\\\\Program Files\\\\app.exe" opened', 543) 544console.log('\nEscaped backslashes:', result15b.entities[0].value) 545console.log(' ✓ Literal backslashes preserved: C:\\Program Files\\app.exe') 546 547// Mixed escapes 548const result15c = escapeParser.parse('text="Line 1\\nLine 2" contains \\n') 549console.log('\nMixed escapes:', result15c.entities[0].value) 550console.log(' ✓ Escape sequences processed: Line 1\\nLine 2') 551 552// Escape at end 553const result15d = escapeParser.parse('note="ends with backslash\\\\" saved') 554console.log('\nBackslash at end:', result15d.entities[0].value) 555console.log(' ✓ Trailing backslash preserved: ends with backslash\\') 556 557// ============================================================================ 558// Example 16: Quoted Strings in Delimited Mode 559// ============================================================================ 560 561console.log('\n\n=== Example 16: Quoted Strings in Delimited Mode ===\n') 562 563const delimitedQuotedParser = new TaggedStringParser({ 564 delimiters: ['[', ']'], 565 typeSeparator: '=', 566}) 567 568const result16a = delimitedQuotedParser.parse( 569 'Server ["linux server"=home] is running', 570) 571if (result16a.entities.length > 0) { 572 console.log('Quoted key in delimited mode:', result16a.entities[0].type) 573 console.log(' ✓ Spaces in type name: "linux server"') 574} else { 575 console.log('Note: Quoted keys in delimited mode require implementation') 576} 577 578const result16b = delimitedQuotedParser.parse('[server="web server"] is active') 579if (result16b.entities.length > 0) { 580 console.log('\nQuoted value in delimited mode:', result16b.entities[0].value) 581 console.log(' ✓ Spaces in value: "web server"') 582} else { 583 console.log('\nNote: Quoted values in delimited mode require implementation') 584} 585 586const result16c = delimitedQuotedParser.parse( 587 '["linux server"="production server"] configured', 588) 589if (result16c.entities.length > 0) { 590 console.log('\nBoth quoted in delimited mode:') 591 console.log(` - Type: "${result16c.entities[0].type}"`) 592 console.log(` - Value: "${result16c.entities[0].value}"`) 593} else { 594 console.log('\nNote: Both quoted in delimited mode requires implementation') 595} 596 597// ============================================================================ 598// Example 17: Delimiter-Free vs Delimited Mode Comparison 599// ============================================================================ 600 601console.log('\n\n=== Example 17: Mode Comparison ===\n') 602 603const message = 'order=1337 was placed' 604 605// Delimiter-free mode extracts the pattern 606const freeParser = new TaggedStringParser({ 607 delimiters: false, 608 typeSeparator: '=', 609}) 610const freeResult = freeParser.parse(message) 611console.log('Delimiter-free mode:') 612console.log(' Input:', message) 613console.log(' Entities found:', freeResult.entities.length) 614console.log( 615 ' Extracted:', 616 freeResult.entities.map((e) => `${e.type}=${e.value}`), 617) 618 619// Delimited mode ignores the pattern 620const delimitedParser = new TaggedStringParser({ delimiters: ['[', ']'] }) 621const delimitedResult = delimitedParser.parse(message) 622console.log('\nDelimited mode:') 623console.log(' Input:', message) 624console.log(' Entities found:', delimitedResult.entities.length) 625console.log(' ✓ Delimiter-free patterns ignored in delimited mode') 626 627// Delimited mode with proper tags 628const delimitedMessage = '[order:1337] was placed' 629const delimitedResult2 = delimitedParser.parse(delimitedMessage) 630console.log('\nDelimited mode with tags:') 631console.log(' Input:', delimitedMessage) 632console.log(' Entities found:', delimitedResult2.entities.length) 633console.log( 634 ' Extracted:', 635 delimitedResult2.entities.map((e) => `${e.type}:${e.value}`), 636) 637 638// ============================================================================ 639// Example 18: Delimiter-Free with Custom Type Separator 640// ============================================================================ 641 642console.log('\n\n=== Example 18: Custom Type Separator ===\n') 643 644const colonParser = new TaggedStringParser({ 645 delimiters: false, 646 typeSeparator: ':', 647}) 648 649const result18 = colonParser.parse('Processing order:1337 with status:pending') 650console.log('Using colon separator:') 651console.log(' Input:', result18.originalMessage) 652console.log( 653 ' Entities:', 654 result18.entities.map((e) => `${e.type}:${e.value}`), 655) 656 657// ============================================================================ 658// Example 19: Error Handling in Delimiter-Free Mode 659// ============================================================================ 660 661console.log('\n\n=== Example 19: Error Handling ===\n') 662 663const errorParser = new TaggedStringParser({ 664 delimiters: false, 665 typeSeparator: '=', 666}) 667 668// Unclosed quote - entity skipped 669const result19a = errorParser.parse('order="unclosed value was placed') 670console.log('Unclosed quote:') 671console.log(' Input: order="unclosed value was placed') 672console.log(' Entities found:', result19a.entities.length) 673console.log(' ✓ Malformed entity skipped, parsing continues') 674 675// Key without value - skipped 676const result19b = errorParser.parse('order= status=pending') 677console.log('\nEmpty value:') 678console.log(' Input: order= status=pending') 679console.log(' Entities found:', result19b.entities.length) 680console.log( 681 ' Extracted:', 682 result19b.entities.map((e) => `${e.type}=${e.value}`), 683) 684console.log(' ✓ Empty value skipped, valid entity extracted') 685 686// Mixed valid and invalid 687const result19c = errorParser.parse('valid=123 invalid="unclosed another=456') 688console.log('\nMixed valid and invalid:') 689console.log(' Input: valid=123 invalid="unclosed another=456') 690console.log( 691 ' Entities:', 692 result19c.entities.map((e) => `${e.type}=${e.value}`), 693) 694console.log(' ✓ Parser continues after errors') 695 696// ============================================================================ 697// Example 20: Real-World Use Case - Log Parsing 698// ============================================================================ 699 700console.log('\n\n=== Example 20: Real-World Log Parsing ===\n') 701 702const logParser = new TaggedStringParser({ 703 delimiters: false, 704 typeSeparator: '=', 705 schema: { 706 user: { type: 'string', format: (v) => `@${v}` }, 707 order: { type: 'number', format: (n) => `Order #${n}` }, 708 status: { type: 'string', format: (v) => String(v).toUpperCase() }, 709 amount: { type: 'number', format: (n) => `$${Number(n).toFixed(2)}` }, 710 }, 711}) 712 713const logs = [ 714 'User user=alice placed order=1337 with amount=99.99', 715 'Order order=1337 status=confirmed for user=alice', 716 'Payment amount=99.99 processed for order=1337', 717 'Order order=1337 status=shipped to user=alice', 718] 719 720console.log('Parsing application logs:') 721logs.forEach((log, i) => { 722 const result = logParser.parse(log) 723 console.log(`\n Log ${i + 1}:`, log) 724 console.log(' Formatted:', result.format()) 725 console.log( 726 ' Entities:', 727 result.entities.map((e) => `${e.type}=${e.parsedValue}`).join(', '), 728 ) 729}) 730 731console.log('\n✓ Delimiter-free mode ideal for natural language logs') 732console.log('✓ Schema formatters enhance readability') 733 734console.log('\n=== All Examples Complete ===\n')