pangu
Version:
Paranoid text spacing for good readability, to automatically insert whitespace between CJK (Chinese, Japanese, Korean) and half-width characters (alphabetical letters, numerical digits and symbols).
1 lines • 33.2 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../../src/shared/index.ts"],"sourcesContent":["// CJK is short for Chinese, Japanese, and Korean:\n// \\u2e80-\\u2eff CJK Radicals Supplement\n// \\u2f00-\\u2fdf Kangxi Radicals\n// \\u3040-\\u309f Hiragana\n// \\u30a0-\\u30ff Katakana\n// \\u3100-\\u312f Bopomofo\n// \\u3200-\\u32ff Enclosed CJK Letters and Months\n// \\u3400-\\u4dbf CJK Unified Ideographs Extension A\n// \\u4e00-\\u9fff CJK Unified Ideographs\n// \\uf900-\\ufaff CJK Compatibility Ideographs\n//\n// ANS is short for Alphabets, Numbers, and Symbols:\n// A includes A-Za-z\\u0370-\\u03ff\n// N includes 0-9\n// S includes `~!@#$%^&*()-_=+[]{}\\|;:'\",<.>/?\n//\n// All J below does not include \\u30fb\n// Some S below does not include all symbols\n//\n// For more information about Unicode blocks, see\n// https://symbl.cc/en/unicode-table/\n\nconst CJK = '\\u2e80-\\u2eff\\u2f00-\\u2fdf\\u3040-\\u309f\\u30a0-\\u30fa\\u30fc-\\u30ff\\u3100-\\u312f\\u3200-\\u32ff\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff';\n\n// Basic character classes\nconst AN = 'A-Za-z0-9';\nconst A = 'A-Za-z';\nconst UPPER_AN = 'A-Z0-9'; // For FIX_CJK_COLON_ANS\n\n// Operators - note the different sets!\nconst OPERATORS_BASE = '\\\\+\\\\*=&';\nconst OPERATORS_WITH_HYPHEN = `${OPERATORS_BASE}\\\\-`; // For CJK patterns\nconst OPERATORS_NO_HYPHEN = OPERATORS_BASE; // For ANS_OPERATOR_ANS only\nconst GRADE_OPERATORS = '\\\\+\\\\-\\\\*'; // For single letter grades\n\n// Quotes\nconst QUOTES = '\\`\"\\u05f4'; // Backtick, straight quote, Hebrew punctuation\n\n// Brackets - different sets!\nconst LEFT_BRACKETS_BASIC = '\\\\(\\\\[\\\\{'; // For AN_LEFT_BRACKET\nconst RIGHT_BRACKETS_BASIC = '\\\\)\\\\]\\\\}'; // For RIGHT_BRACKET_AN\nconst LEFT_BRACKETS_EXTENDED = '\\\\(\\\\[\\\\{<>\\u201c'; // For CJK_LEFT_BRACKET (includes angle brackets + curly quote)\nconst RIGHT_BRACKETS_EXTENDED = '\\\\)\\\\]\\\\}<>\\u201d'; // For RIGHT_BRACKET_CJK\n\n// ANS extended sets - CAREFUL: different symbols!\nconst ANS_CJK_AFTER = `${A}\\u0370-\\u03ff0-9@\\\\$%\\\\^&\\\\*\\\\-\\\\+\\\\\\\\=\\u00a1-\\u00ff\\u2150-\\u218f\\u2700—\\u27bf`; // Has @, no punctuation\nconst ANS_BEFORE_CJK = `${A}\\u0370-\\u03ff0-9\\\\$%\\\\^&\\\\*\\\\-\\\\+\\\\\\\\=\\u00a1-\\u00ff\\u2150-\\u218f\\u2700—\\u27bf`; // No @ symbol\n\n// File path components - common directories in Unix/project paths\n// prettier-ignore\nconst FILE_PATH_DIRS = 'home|root|usr|etc|var|opt|tmp|dev|mnt|proc|sys|bin|boot|lib|media|run|sbin|srv|node_modules|path|project|src|dist|test|tests|docs|templates|assets|public|static|config|scripts|tools|build|out|target|your|\\\\.claude|\\\\.git|\\\\.vscode';\nconst FILE_PATH_CHARS = '[A-Za-z0-9_\\\\-\\\\.@\\\\+\\\\*]+';\n\n// Unix absolute paths: system dirs + common project paths\n// Examples: /home, /usr/bin, /etc/nginx.conf, /.bashrc, /node_modules/@babel/core, /path/to/your/project\nconst UNIX_ABSOLUTE_FILE_PATH = new RegExp(`/(?:\\\\.?(?:${FILE_PATH_DIRS})|\\\\.(?:[A-Za-z0-9_\\\\-]+))(?:/${FILE_PATH_CHARS})*`);\n\n// Unix relative paths common in documentation and blog posts\n// Examples: src/main.py, dist/index.js, test/spec.js, ./.claude/CLAUDE.md, templates/*.html\nconst UNIX_RELATIVE_FILE_PATH = new RegExp(`(?:\\\\./)?(?:${FILE_PATH_DIRS})(?:/${FILE_PATH_CHARS})+`);\n\n// Windows paths: C:\\Users\\name\\, D:\\Program Files\\, C:\\Windows\\System32\nconst WINDOWS_FILE_PATH = /[A-Z]:\\\\(?:[A-Za-z0-9_\\-\\. ]+\\\\?)+/;\n\nconst ANY_CJK = new RegExp(`[${CJK}]`);\n\n// Handle punctuation after CJK - add space but don't convert to full-width\n// Support multiple consecutive punctuation marks\n// Only add space if followed by CJK, letters, or numbers (not at end of text or before same punctuation)\nconst CJK_PUNCTUATION = new RegExp(`([${CJK}])([!;,\\\\?:]+)(?=[${CJK}${AN}])`, 'g');\n// Handle punctuation between AN and CJK - add space after punctuation\nconst AN_PUNCTUATION_CJK = new RegExp(`([${AN}])([!;,\\\\?]+)([${CJK}])`, 'g');\n// Handle tilde separately for special cases like ~=\n// Only add space if followed by CJK, letters, or numbers (not at end of text)\nconst CJK_TILDE = new RegExp(`([${CJK}])(~+)(?!=)(?=[${CJK}${AN}])`, 'g');\nconst CJK_TILDE_EQUALS = new RegExp(`([${CJK}])(~=)`, 'g');\n// Handle period separately to avoid matching file extensions, multiple dots, and file paths\n// Note: Multiple dots are handled by DOTS_CJK pattern first\n// Only add space if followed by CJK, letters, or numbers (not at end of text)\nconst CJK_PERIOD = new RegExp(`([${CJK}])(\\\\.)(?![${AN}\\\\./])(?=[${CJK}${AN}])`, 'g');\n// Handle period between AN and CJK - avoid file extensions\nconst AN_PERIOD_CJK = new RegExp(`([${AN}])(\\\\.)([${CJK}])`, 'g');\n// Handle colon between AN and CJK\nconst AN_COLON_CJK = new RegExp(`([${AN}])(:)([${CJK}])`, 'g');\nconst DOTS_CJK = new RegExp(`([\\\\.]{2,}|\\u2026)([${CJK}])`, 'g');\n// Special case for colon before uppercase letters/parentheses (convert to full-width)\nconst FIX_CJK_COLON_ANS = new RegExp(`([${CJK}])\\\\:([${UPPER_AN}\\\\(\\\\)])`, 'g');\n\n// The symbol part does not include '\nconst CJK_QUOTE = new RegExp(`([${CJK}])([${QUOTES}])`, 'g');\nconst QUOTE_CJK = new RegExp(`([${QUOTES}])([${CJK}])`, 'g');\nconst FIX_QUOTE_ANY_QUOTE = new RegExp(`([${QUOTES}]+)[ ]*(.+?)[ ]*([${QUOTES}]+)`, 'g');\n\n// Handle curly quotes with alphanumeric characters\n// These patterns should only apply to curly quotes, not straight quotes\n// Straight quotes are already handled by CJK_QUOTE, QUOTE_CJK and FIX_QUOTE_ANY_QUOTE\nconst QUOTE_AN = new RegExp(`([\\u201d])([${AN}])`, 'g'); // Only closing curly quotes + AN\n\n// Special handling for straight quotes followed by alphanumeric after CJK\n// This catches patterns like: 中文\"ABC where the quote appears to be closing a quoted CJK phrase\nconst CJK_QUOTE_AN = new RegExp(`([${CJK}])(\")([${AN}])`, 'g');\n\nconst CJK_SINGLE_QUOTE_BUT_POSSESSIVE = new RegExp(`([${CJK}])('[^s])`, 'g');\nconst SINGLE_QUOTE_CJK = new RegExp(`(')([${CJK}])`, 'g');\nconst FIX_POSSESSIVE_SINGLE_QUOTE = new RegExp(`([${AN}${CJK}])( )('s)`, 'g');\n\nconst HASH_ANS_CJK_HASH = new RegExp(`([${CJK}])(#)([${CJK}]+)(#)([${CJK}])`, 'g');\nconst CJK_HASH = new RegExp(`([${CJK}])(#([^ ]))`, 'g');\nconst HASH_CJK = new RegExp(`(([^ ])#)([${CJK}])`, 'g');\n\n// The symbol part only includes + - * = & (excluding | / < >)\nconst CJK_OPERATOR_ANS = new RegExp(`([${CJK}])([${OPERATORS_WITH_HYPHEN}])([${AN}])`, 'g');\nconst ANS_OPERATOR_CJK = new RegExp(`([${AN}])([${OPERATORS_WITH_HYPHEN}])([${CJK}])`, 'g');\n// Handle operators between alphanumeric characters when CJK is present in text\n// Note: This pattern excludes hyphens entirely (only + * = &) to avoid conflicts with compound words\nconst ANS_OPERATOR_ANS = new RegExp(`([${AN}])([${OPERATORS_NO_HYPHEN}])([${AN}])`, 'g');\n\n// Hyphens that should be treated as operators (with spaces) rather than word connectors\n// This regex has 3 patterns to catch different cases while preserving compound words:\n// 1. Letter-Letter/Number: A-B, X-5 (spaces added) BUT NOT co-author, X-ray, GPT-5 (preserved)\n// 2. Mixed alphanumeric-number patterns that aren't already protected as compound words\n// 3. Number-Letter: 5-A, 3-B (spaces added) BUT NOT 5-year, 2016-12-26 (preserved)\n// Note: Patterns like GPT4-5, v1-2 are protected by COMPOUND_WORD_PATTERN and won't get spaces\n// The negative lookahead (?![a-z]) prevents matching hyphens followed by lowercase letters\nconst ANS_HYPHEN_ANS_NOT_COMPOUND = new RegExp(`([A-Za-z])(-(?![a-z]))([A-Za-z0-9])|([A-Za-z]+[0-9]+)(-(?![a-z]))([0-9])|([0-9])(-(?![a-z0-9]))([A-Za-z])`, 'g');\n\n// Slash patterns for operator vs separator behavior\nconst CJK_SLASH_CJK = new RegExp(`([${CJK}])([/])([${CJK}])`, 'g');\nconst CJK_SLASH_ANS = new RegExp(`([${CJK}])([/])([${AN}])`, 'g');\nconst ANS_SLASH_CJK = new RegExp(`([${AN}])([/])([${CJK}])`, 'g');\nconst ANS_SLASH_ANS = new RegExp(`([${AN}])([/])([${AN}])`, 'g');\n\n// Special handling for single letter grades/ratings (A+, B-, C*) before CJK\n// These should have space after the operator, not before\n// Use word boundary to ensure it's a single letter, not part of a longer word\nconst SINGLE_LETTER_GRADE_CJK = new RegExp(`\\\\b([${A}])([${GRADE_OPERATORS}])([${CJK}])`, 'g');\n\n// Special handling for < and > as comparison operators (not brackets)\nconst CJK_LESS_THAN = new RegExp(`([${CJK}])(<)([${AN}])`, 'g');\nconst LESS_THAN_CJK = new RegExp(`([${AN}])(<)([${CJK}])`, 'g');\nconst CJK_GREATER_THAN = new RegExp(`([${CJK}])(>)([${AN}])`, 'g');\nconst GREATER_THAN_CJK = new RegExp(`([${AN}])(>)([${CJK}])`, 'g');\n// Handle < and > between alphanumeric characters when CJK is present in text\nconst ANS_LESS_THAN_ANS = new RegExp(`([${AN}])(<)([${AN}])`, 'g');\nconst ANS_GREATER_THAN_ANS = new RegExp(`([${AN}])(>)([${AN}])`, 'g');\n\n// Bracket patterns: ( ) [ ] { } and also < > (though < > are also handled as operators separately)\n// Note: The curly quotes “ ” (\\u201c \\u201d) appear in CJK_LEFT_BRACKET/RIGHT_BRACKET_CJK but are primarily handled in the patterns below\nconst CJK_LEFT_BRACKET = new RegExp(`([${CJK}])([${LEFT_BRACKETS_EXTENDED}])`, 'g');\nconst RIGHT_BRACKET_CJK = new RegExp(`([${RIGHT_BRACKETS_EXTENDED}])([${CJK}])`, 'g');\nconst ANS_CJK_LEFT_BRACKET_ANY_RIGHT_BRACKET = new RegExp(`([${AN}${CJK}])[ ]*([\\u201c])([${AN}${CJK}\\\\-_ ]+)([\\u201d])`, 'g');\nconst LEFT_BRACKET_ANY_RIGHT_BRACKET_ANS_CJK = new RegExp(`([\\u201c])([${AN}${CJK}\\\\-_ ]+)([\\u201d])[ ]*([${AN}${CJK}])`, 'g');\n\nconst AN_LEFT_BRACKET = new RegExp(`([${AN}])(?<!\\\\.[${AN}]*)([${LEFT_BRACKETS_BASIC}])`, 'g');\nconst RIGHT_BRACKET_AN = new RegExp(`([${RIGHT_BRACKETS_BASIC}])([${AN}])`, 'g');\n\n// Special patterns for filesystem paths after CJK\nconst CJK_UNIX_ABSOLUTE_FILE_PATH = new RegExp(`([${CJK}])(${UNIX_ABSOLUTE_FILE_PATH.source})`, 'g');\nconst CJK_UNIX_RELATIVE_FILE_PATH = new RegExp(`([${CJK}])(${UNIX_RELATIVE_FILE_PATH.source})`, 'g');\nconst CJK_WINDOWS_PATH = new RegExp(`([${CJK}])(${WINDOWS_FILE_PATH.source})`, 'g');\n\n// Pattern for Unix paths ending with / followed by CJK\nconst UNIX_ABSOLUTE_FILE_PATH_SLASH_CJK = new RegExp(`(${UNIX_ABSOLUTE_FILE_PATH.source}/)([${CJK}])`, 'g');\nconst UNIX_RELATIVE_FILE_PATH_SLASH_CJK = new RegExp(`(${UNIX_RELATIVE_FILE_PATH.source}/)([${CJK}])`, 'g');\n\nconst CJK_ANS = new RegExp(`([${CJK}])([${ANS_CJK_AFTER}])`, 'g');\nconst ANS_CJK = new RegExp(`([${ANS_BEFORE_CJK}])([${CJK}])`, 'g');\n\nconst S_A = new RegExp(`(%)([${A}])`, 'g');\n\nconst MIDDLE_DOT = /([ ]*)([\\u00b7\\u2022\\u2027])([ ]*)/g;\n\nclass PlaceholderReplacer {\n private items: string[] = [];\n private index = 0;\n private pattern: RegExp;\n\n constructor(\n private placeholder: string,\n private startDelimiter: string,\n private endDelimiter: string,\n ) {\n const escapedStart = this.startDelimiter.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const escapedEnd = this.endDelimiter.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n this.pattern = new RegExp(`${escapedStart}${this.placeholder}(\\\\d+)${escapedEnd}`, 'g');\n }\n\n store(item: string) {\n this.items[this.index] = item;\n return `${this.startDelimiter}${this.placeholder}${this.index++}${this.endDelimiter}`;\n }\n\n restore(text: string) {\n return text.replace(this.pattern, (_match, index) => {\n return this.items[parseInt(index, 10)] || '';\n });\n }\n\n reset() {\n this.items = [];\n this.index = 0;\n }\n}\n\nexport class Pangu {\n version: string;\n\n constructor() {\n this.version = '7.2.0';\n }\n\n public spacingText(text: string) {\n if (typeof text !== 'string') {\n console.warn(`spacingText(text) only accepts string but got ${typeof text}`);\n return text;\n }\n\n if (text.length <= 1 || !ANY_CJK.test(text)) {\n return text;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n let newText = text;\n\n // Protect backtick content from quote processing but allow spacing around backticks\n const backtickManager = new PlaceholderReplacer('BACKTICK_CONTENT_', '\\uE004', '\\uE005');\n newText = newText.replace(/`([^`]+)`/g, (_match, content) => {\n return `\\`${backtickManager.store(content)}\\``;\n });\n\n // Initialize placeholder managers\n const htmlTagManager = new PlaceholderReplacer('HTML_TAG_PLACEHOLDER_', '\\uE000', '\\uE001');\n let hasHtmlTags = false;\n\n // Early return for HTML processing if no HTML tags present\n if (newText.includes('<')) {\n hasHtmlTags = true;\n // More specific HTML tag pattern:\n // - Opening tags: <tagname ...> or <tagname>\n // - Closing tags: </tagname>\n // - Self-closing tags: <tagname ... />\n // This pattern ensures we only match actual HTML tags, not just any < > content\n const HTML_TAG_PATTERN = /<\\/?[a-zA-Z][a-zA-Z0-9]*(?:\\s+[^>]*)?>/g;\n\n // Replace all HTML tags with placeholders, but process attribute values\n newText = newText.replace(HTML_TAG_PATTERN, (match) => {\n // Process attribute values inside the tag\n const processedTag = match.replace(/(\\w+)=\"([^\"]*)\"/g, (_attrMatch, attrName, attrValue) => {\n // Process the attribute value with spacing\n const processedValue = self.spacingText(attrValue);\n return `${attrName}=\"${processedValue}\"`;\n });\n\n return htmlTagManager.store(processedTag);\n });\n }\n\n // Handle multiple dots first (before single period)\n newText = newText.replace(DOTS_CJK, '$1 $2');\n\n // Handle punctuation after CJK - add space but don't convert to full-width\n newText = newText.replace(CJK_PUNCTUATION, '$1$2 ');\n // Handle punctuation between AN and CJK\n newText = newText.replace(AN_PUNCTUATION_CJK, '$1$2 $3');\n // Handle tilde separately for special cases\n newText = newText.replace(CJK_TILDE, '$1$2 ');\n newText = newText.replace(CJK_TILDE_EQUALS, '$1 $2 ');\n // Handle period separately to avoid file extensions\n newText = newText.replace(CJK_PERIOD, '$1$2 ');\n newText = newText.replace(AN_PERIOD_CJK, '$1$2 $3');\n // Handle colon between AN and CJK\n newText = newText.replace(AN_COLON_CJK, '$1$2 $3');\n // Only convert colon to full-width in specific cases (before uppercase/parentheses)\n newText = newText.replace(FIX_CJK_COLON_ANS, '$1:$2');\n\n newText = newText.replace(CJK_QUOTE, '$1 $2');\n newText = newText.replace(QUOTE_CJK, '$1 $2');\n newText = newText.replace(FIX_QUOTE_ANY_QUOTE, '$1$2$3');\n\n // Handle quotes with alphanumeric - closing quotes followed by AN need space\n newText = newText.replace(QUOTE_AN, '$1 $2');\n // Opening quotes preceded by AN don't need space (they're handled by other patterns)\n\n // Handle CJK followed by closing quote followed by alphanumeric\n newText = newText.replace(CJK_QUOTE_AN, '$1$2 $3');\n\n // Handle single quotes more intelligently\n // First, handle possessive case\n newText = newText.replace(FIX_POSSESSIVE_SINGLE_QUOTE, \"$1's\");\n\n // Process single quotes around pure CJK text differently from mixed content\n const singleQuoteCJKManager = new PlaceholderReplacer('SINGLE_QUOTE_CJK_PLACEHOLDER_', '\\uE030', '\\uE031');\n\n // Pattern to match single quotes around pure CJK text (no spaces, no other characters)\n const SINGLE_QUOTE_PURE_CJK = new RegExp(`(')([${CJK}]+)(')`, 'g');\n\n // Protect pure CJK content in single quotes\n newText = newText.replace(SINGLE_QUOTE_PURE_CJK, (match) => {\n return singleQuoteCJKManager.store(match);\n });\n\n // Now process other single quote patterns\n newText = newText.replace(CJK_SINGLE_QUOTE_BUT_POSSESSIVE, '$1 $2');\n newText = newText.replace(SINGLE_QUOTE_CJK, '$1 $2');\n\n // Restore protected pure CJK content\n newText = singleQuoteCJKManager.restore(newText);\n\n // Early return for complex patterns that need longer text\n const textLength = newText.length;\n\n // Check slash count early to determine hashtag behavior\n const slashCount = (newText.match(/\\//g) || []).length;\n\n // Early return for slash processing if no slashes present\n if (slashCount === 0) {\n // Apply normal hashtag spacing without slash considerations\n // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n if (textLength >= 5) {\n newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n }\n newText = newText.replace(CJK_HASH, '$1 $2');\n newText = newText.replace(HASH_CJK, '$1 $3');\n } else if (slashCount <= 1) {\n // Single or no slash - apply normal hashtag spacing\n // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n if (textLength >= 5) {\n newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n }\n newText = newText.replace(CJK_HASH, '$1 $2');\n newText = newText.replace(HASH_CJK, '$1 $3');\n } else {\n // Multiple slashes - skip hashtag processing to preserve path structure\n // But add space before final hashtag if it's not preceded by a slash\n // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n if (textLength >= 5) {\n newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n }\n newText = newText.replace(new RegExp(`([^/])([${CJK}])(#[A-Za-z0-9]+)$`), '$1$2 $3');\n }\n\n // Protect compound words from operator spacing\n const compoundWordManager = new PlaceholderReplacer('COMPOUND_WORD_PLACEHOLDER_', '\\uE010', '\\uE011');\n\n // Pattern to detect compound words: alphanumeric-alphanumeric combinations that look like compound words/product names\n // Examples: state-of-the-art, machine-learning, GPT-4o, real-time, end-to-end, gpt-4o, GPT-5, claude-4-opus\n // Match: word-word(s) where at least one part contains lowercase letters OR contains mix of letters and numbers (like GPT-5)\n const COMPOUND_WORD_PATTERN = /\\b(?:[A-Za-z0-9]*[a-z][A-Za-z0-9]*-[A-Za-z0-9]+|[A-Za-z0-9]+-[A-Za-z0-9]*[a-z][A-Za-z0-9]*|[A-Za-z]+-[0-9]+|[A-Za-z]+[0-9]+-[A-Za-z0-9]+)(?:-[A-Za-z0-9]+)*\\b/g;\n\n // Store compound words and replace with placeholders\n newText = newText.replace(COMPOUND_WORD_PATTERN, (match) => {\n return compoundWordManager.store(match);\n });\n\n // Handle single letter grades (A+, B-, etc.) before general operator rules\n // This ensures \"A+的\" becomes \"A+ 的\" not \"A + 的\"\n newText = newText.replace(SINGLE_LETTER_GRADE_CJK, '$1$2 $3');\n\n newText = newText.replace(CJK_OPERATOR_ANS, '$1 $2 $3');\n newText = newText.replace(ANS_OPERATOR_CJK, '$1 $2 $3');\n newText = newText.replace(ANS_OPERATOR_ANS, '$1 $2 $3');\n newText = newText.replace(ANS_HYPHEN_ANS_NOT_COMPOUND, (match, ...groups) => {\n // Handle all patterns in the alternation\n if (groups[0] && groups[1] && groups[2]) {\n // First pattern: letter-alphanumeric\n return `${groups[0]} ${groups[1]} ${groups[2]}`;\n } else if (groups[3] && groups[4] && groups[5]) {\n // Second pattern: version range (letter+number-number)\n return `${groups[3]} ${groups[4]} ${groups[5]}`;\n } else if (groups[6] && groups[7] && groups[8]) {\n // Third pattern: number-letter\n return `${groups[6]} ${groups[7]} ${groups[8]}`;\n }\n return match;\n });\n\n // Handle < and > as comparison operators\n newText = newText.replace(CJK_LESS_THAN, '$1 $2 $3');\n newText = newText.replace(LESS_THAN_CJK, '$1 $2 $3');\n newText = newText.replace(ANS_LESS_THAN_ANS, '$1 $2 $3');\n newText = newText.replace(CJK_GREATER_THAN, '$1 $2 $3');\n newText = newText.replace(GREATER_THAN_CJK, '$1 $2 $3');\n newText = newText.replace(ANS_GREATER_THAN_ANS, '$1 $2 $3');\n\n // Add space before filesystem paths after CJK\n newText = newText.replace(CJK_UNIX_ABSOLUTE_FILE_PATH, '$1 $2');\n newText = newText.replace(CJK_UNIX_RELATIVE_FILE_PATH, '$1 $2');\n newText = newText.replace(CJK_WINDOWS_PATH, '$1 $2');\n\n // Add space after Unix paths ending with / before CJK\n newText = newText.replace(UNIX_ABSOLUTE_FILE_PATH_SLASH_CJK, '$1 $2');\n newText = newText.replace(UNIX_RELATIVE_FILE_PATH_SLASH_CJK, '$1 $2');\n\n // Context-aware slash handling: single slash = operator, multiple slashes = separator\n // But exclude slashes that are part of file paths by protecting them first\n if (slashCount === 1) {\n // Temporarily protect file paths from slash operator processing\n const filePathManager = new PlaceholderReplacer('FILE_PATH_PLACEHOLDER_', '\\uE020', '\\uE021');\n\n // Store all file paths and replace with placeholders\n const allFilePathPattern = new RegExp(`(${UNIX_ABSOLUTE_FILE_PATH.source}|${UNIX_RELATIVE_FILE_PATH.source})`, 'g');\n newText = newText.replace(allFilePathPattern, (match) => {\n return filePathManager.store(match);\n });\n\n // Now apply slash operator spacing\n newText = newText.replace(CJK_SLASH_CJK, '$1 $2 $3');\n newText = newText.replace(CJK_SLASH_ANS, '$1 $2 $3');\n newText = newText.replace(ANS_SLASH_CJK, '$1 $2 $3');\n newText = newText.replace(ANS_SLASH_ANS, '$1 $2 $3');\n\n // Restore file paths\n newText = filePathManager.restore(newText);\n }\n // If multiple slashes, treat as separator - do nothing (no spaces)\n\n // Restore compound words from placeholders\n newText = compoundWordManager.restore(newText);\n\n newText = newText.replace(CJK_LEFT_BRACKET, '$1 $2');\n newText = newText.replace(RIGHT_BRACKET_CJK, '$1 $2');\n newText = newText.replace(ANS_CJK_LEFT_BRACKET_ANY_RIGHT_BRACKET, '$1 $2$3$4');\n newText = newText.replace(LEFT_BRACKET_ANY_RIGHT_BRACKET_ANS_CJK, '$1$2$3 $4');\n\n newText = newText.replace(AN_LEFT_BRACKET, '$1 $2');\n newText = newText.replace(RIGHT_BRACKET_AN, '$1 $2');\n\n newText = newText.replace(CJK_ANS, '$1 $2');\n newText = newText.replace(ANS_CJK, '$1 $2');\n\n newText = newText.replace(S_A, '$1 $2');\n\n newText = newText.replace(MIDDLE_DOT, '・');\n\n // Brackets: <fcontentl> (fcontentl) [fcontentl] {fcontentl}\n // f: the first character inside the brackets\n // l: the last character inside the brackets\n // content: the content inside the brackets but exclude the first and last characters\n // DO NOT change the first and last characters inside brackets AT ALL\n // ONLY spacing the content between them\n\n // Fix spacing inside brackets according to the above rules:\n // Ensure no unwanted spaces immediately after opening or before closing brackets\n const fixBracketSpacing = (text: string) => {\n // Process all bracket types at once\n const bracketPatterns = [\n { pattern: /<([^<>]*)>/g, open: '<', close: '>' },\n { pattern: /\\(([^()]*)\\)/g, open: '(', close: ')' },\n { pattern: /\\[([^\\[\\]]*)\\]/g, open: '[', close: ']' },\n { pattern: /\\{([^{}]*)\\}/g, open: '{', close: '}' },\n ];\n\n for (const { pattern, open, close } of bracketPatterns) {\n text = text.replace(pattern, (_match, innerContent) => {\n if (!innerContent) {\n return `${open}${close}`;\n }\n // Remove spaces at the very beginning and end of content\n const trimmedContent = innerContent.replace(/^ +| +$/g, '');\n return `${open}${trimmedContent}${close}`;\n });\n }\n\n return text;\n };\n\n newText = fixBracketSpacing(newText);\n\n // Restore HTML tags from placeholders (only if HTML processing occurred)\n if (hasHtmlTags) {\n newText = htmlTagManager.restore(newText);\n }\n\n // Restore backtick content\n newText = backtickManager.restore(newText);\n\n // TODO:\n // Final fix for HTML comments: ensure no space after <!--\n // This is needed because <!-- is not protected as an HTML tag\n // and the ! character gets spaced by ANS_CJK pattern\n // newText = newText.replace(/<!--\\s+/g, '<!--');\n\n return newText;\n }\n\n public hasProperSpacing(text: string) {\n return this.spacingText(text) === text;\n }\n}\n\nexport const pangu = new Pangu();\n\nexport { ANY_CJK };\n\nexport default pangu;\n"],"names":["text"],"mappings":"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"}