From 6ba513c530bc730576eba08d36f6c9685069d3f4 Mon Sep 17 00:00:00 2001 From: Lucas 'Paperboy' Rose-Winters Date: Mon, 20 Oct 2025 07:07:21 +1100 Subject: [PATCH] fix(inventory): handle commas inside parentheses and strip brackets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes two parsing issues with inventory items: 1. Items with commas in parenthetical descriptions were incorrectly split into multiple items. For example: "Potato (Cursed, Sexy, Your Mum & Dick, Etc)" would become 3-4 separate items instead of one. 2. AI sometimes wraps item lists in square brackets, which should be stripped. For example: "[Sword, Shield]" should parse as ["Sword", "Shield"] Solution: - Enhanced parseItems() to track parenthesis depth during parsing - Only split on commas that are OUTSIDE parentheses - Strip wrapping square brackets before parsing - Commas inside parentheses are now preserved as part of the item name - Maintains backward compatibility with existing items Implementation: - Pre-processing: strip wrapping brackets if present - Two-pass parsing: first collapses newlines in parentheses (existing), then smart comma splitting (new) - Similar approach to existing newline handling logic Examples: - "Sword, Shield" → ["Sword", "Shield"] (unchanged) - "Item (tag1, tag2), Sword" → ["Item (tag1, tag2)", "Sword"] (fixed) - "[Sword, Shield]" → ["Sword", "Shield"] (fixed) Fixes: Items with commas split into multiple items --- src/utils/itemParser.js | 58 +++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/src/utils/itemParser.js b/src/utils/itemParser.js index edf82a1..e35a901 100644 --- a/src/utils/itemParser.js +++ b/src/utils/itemParser.js @@ -6,7 +6,10 @@ /** * Parses a comma-separated item string into an array of trimmed item names. * Filters out empty strings and handles "None" gracefully. - * Smart handling: collapses newlines inside parentheses, preserves them outside. + * Smart handling: + * - Strips wrapping square brackets that AI sometimes adds + * - Collapses newlines inside parentheses to spaces + * - Only splits on commas OUTSIDE parentheses (commas inside parentheses are preserved) * * @param {string} itemString - Comma-separated items (e.g., "Sword, Shield, 3x Potions") * @returns {string[]} Array of item names, or empty array if none @@ -14,6 +17,8 @@ * @example * parseItems("Sword, Shield, 3x Potions") // ["Sword", "Shield", "3x Potions"] * parseItems("Books (magical\ntomes), Sword") // ["Books (magical tomes)", "Sword"] + * parseItems("Potato (Cursed, Sexy, Your Mum & Dick, Etc), Sword") // ["Potato (Cursed, Sexy, Your Mum & Dick, Etc)", "Sword"] + * parseItems("[Sword, Shield]") // ["Sword", "Shield"] * parseItems("None") // [] * parseItems("") // [] * parseItems(null) // [] @@ -25,12 +30,21 @@ export function parseItems(itemString) { } // Trim and check for "None" (case-insensitive) - const trimmed = itemString.trim(); + let trimmed = itemString.trim(); if (trimmed === '' || trimmed.toLowerCase() === 'none') { return []; } - // Collapse newlines inside parentheses + // Strip wrapping square brackets if present (AI sometimes adds these) + if (trimmed.startsWith('[') && trimmed.endsWith(']')) { + trimmed = trimmed.slice(1, -1).trim(); + // Check again for empty after stripping brackets + if (trimmed === '' || trimmed.toLowerCase() === 'none') { + return []; + } + } + + // First pass: Collapse newlines inside parentheses let processed = ''; let parenDepth = 0; @@ -57,11 +71,39 @@ export function parseItems(itemString) { // Clean up multiple consecutive spaces processed = processed.replace(/\s+/g, ' '); - // Split by comma, trim each item, filter empties - return processed - .split(',') - .map(item => item.trim()) - .filter(item => item !== '' && item.toLowerCase() !== 'none'); + // Second pass: Smart comma splitting (only split on commas outside parentheses) + const items = []; + let currentItem = ''; + parenDepth = 0; + + for (let i = 0; i < processed.length; i++) { + const char = processed[i]; + + if (char === '(') { + parenDepth++; + currentItem += char; + } else if (char === ')') { + parenDepth--; + currentItem += char; + } else if (char === ',' && parenDepth === 0) { + // Comma outside parentheses - this is a separator + const trimmedItem = currentItem.trim(); + if (trimmedItem !== '' && trimmedItem.toLowerCase() !== 'none') { + items.push(trimmedItem); + } + currentItem = ''; // Start new item + } else { + currentItem += char; + } + } + + // Don't forget the last item + const trimmedItem = currentItem.trim(); + if (trimmedItem !== '' && trimmedItem.toLowerCase() !== 'none') { + items.push(trimmedItem); + } + + return items; } /**