fix(inventory): handle commas inside parentheses and strip brackets
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
This commit is contained in:
+50
-8
@@ -6,7 +6,10 @@
|
|||||||
/**
|
/**
|
||||||
* Parses a comma-separated item string into an array of trimmed item names.
|
* Parses a comma-separated item string into an array of trimmed item names.
|
||||||
* Filters out empty strings and handles "None" gracefully.
|
* 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")
|
* @param {string} itemString - Comma-separated items (e.g., "Sword, Shield, 3x Potions")
|
||||||
* @returns {string[]} Array of item names, or empty array if none
|
* @returns {string[]} Array of item names, or empty array if none
|
||||||
@@ -14,6 +17,8 @@
|
|||||||
* @example
|
* @example
|
||||||
* parseItems("Sword, Shield, 3x Potions") // ["Sword", "Shield", "3x Potions"]
|
* parseItems("Sword, Shield, 3x Potions") // ["Sword", "Shield", "3x Potions"]
|
||||||
* parseItems("Books (magical\ntomes), Sword") // ["Books (magical tomes)", "Sword"]
|
* 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("None") // []
|
||||||
* parseItems("") // []
|
* parseItems("") // []
|
||||||
* parseItems(null) // []
|
* parseItems(null) // []
|
||||||
@@ -25,12 +30,21 @@ export function parseItems(itemString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trim and check for "None" (case-insensitive)
|
// Trim and check for "None" (case-insensitive)
|
||||||
const trimmed = itemString.trim();
|
let trimmed = itemString.trim();
|
||||||
if (trimmed === '' || trimmed.toLowerCase() === 'none') {
|
if (trimmed === '' || trimmed.toLowerCase() === 'none') {
|
||||||
return [];
|
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 processed = '';
|
||||||
let parenDepth = 0;
|
let parenDepth = 0;
|
||||||
|
|
||||||
@@ -57,11 +71,39 @@ export function parseItems(itemString) {
|
|||||||
// Clean up multiple consecutive spaces
|
// Clean up multiple consecutive spaces
|
||||||
processed = processed.replace(/\s+/g, ' ');
|
processed = processed.replace(/\s+/g, ' ');
|
||||||
|
|
||||||
// Split by comma, trim each item, filter empties
|
// Second pass: Smart comma splitting (only split on commas outside parentheses)
|
||||||
return processed
|
const items = [];
|
||||||
.split(',')
|
let currentItem = '';
|
||||||
.map(item => item.trim())
|
parenDepth = 0;
|
||||||
.filter(item => item !== '' && item.toLowerCase() !== 'none');
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user