UNPKG

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 38.8 kB
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/shared/index.ts","../../src/node/index.ts","../../src/node/index.cts"],"sourcesContent":["// CJK is short for Chinese, Japanese, and Korean\n//\n// ANS is short for Alphabets, Numbers, and Symbols:\n// A includes A-Za-z plus Greek and Coptic\n// N includes 0-9\n// S varies per rule, see the symbol sets below\n//\n// For more about Unicode blocks, see https://symbl.cc/en/unicode-table/\n\n// Unicode blocks. A name that ends in a carve-out marks a range that is deliberately smaller than its whole block, so widening it back to the block boundary is a wrong edit, not a tidy-up\nexport const CJK_RADICALS_SUPPLEMENT = '\\u2e80-\\u2eff';\nexport const KANGXI_RADICALS = '\\u2f00-\\u2fdf';\nexport const HIRAGANA = '\\u3040-\\u309f';\nexport const KATAKANA_NO_MIDDLE_DOT = '\\u30a0-\\u30fa\\u30fc-\\u30ff'; // The Katakana block ends at \\u30ff, but \\u30fb is the character that MIDDLE_DOT normalizes to, so it must not read as CJK itself\nexport const BOPOMOFO = '\\u3100-\\u312f';\nexport const ENCLOSED_CJK_LETTERS_AND_MONTHS = '\\u3200-\\u32ff';\nexport const CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A = '\\u3400-\\u4dbf';\nexport const CJK_UNIFIED_IDEOGRAPHS = '\\u4e00-\\u9fff';\nexport const CJK_COMPATIBILITY_IDEOGRAPHS = '\\uf900-\\ufaff';\nexport const GREEK_AND_COPTIC = '\\u0370-\\u03ff';\nexport const LATIN_1_SUPPLEMENT_AFTER_NBSP = '\\u00a1-\\u00ff'; // The Latin-1 Supplement block starts at \\u0080, but this range starts one past NBSP (\\u00a0) so an NBSP lands in no character class at all. See ADR 0009\nexport const NUMBER_FORMS = '\\u2150-\\u218f';\nexport const DINGBATS = '\\u2700-\\u27bf';\n\nexport const CJK = `${CJK_RADICALS_SUPPLEMENT}${KANGXI_RADICALS}${HIRAGANA}${KATAKANA_NO_MIDDLE_DOT}${BOPOMOFO}${ENCLOSED_CJK_LETTERS_AND_MONTHS}${CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A}${CJK_UNIFIED_IDEOGRAPHS}${CJK_COMPATIBILITY_IDEOGRAPHS}`;\n\n// Basic character classes\nexport const AN = 'A-Za-z0-9';\nexport const A = 'A-Za-z';\nexport const UPPER_AN = 'A-Z0-9'; // For FIX_CJK_COLON_ANS\n\n// Operators. Each rule uses a different set\nexport const OPERATORS_BASE = '\\\\+\\\\*=&';\nexport const OPERATORS_WITH_HYPHEN = `${OPERATORS_BASE}\\\\-`; // For CJK_OPERATOR_ANS\nexport const OPERATORS_NO_PLUS = '\\\\*=&\\\\-'; // For ANS_OPERATOR_CJK only. No + because + attaches to the preceding half-width run as a suffix (Disney+, 18+)\nexport const GRADE_OPERATORS = '\\\\+\\\\-\\\\*'; // For single letter grades\n\nexport const QUOTES = '\\`\"\\u05f4'; // Backtick, straight quote, Hebrew punctuation\n\n// Brackets. Each rule uses a different set\nexport const LEFT_BRACKETS_BASIC = '\\\\(\\\\[\\\\{'; // For AN_LEFT_BRACKET\nexport const RIGHT_BRACKETS_BASIC = '\\\\)\\\\]\\\\}'; // For RIGHT_BRACKET_AN\nexport const LEFT_BRACKETS_EXTENDED = '\\\\(\\\\[\\\\{<>\\u201c'; // For CJK_LEFT_BRACKET (includes angle brackets + curly quote)\nexport const RIGHT_BRACKETS_EXTENDED = '\\\\)\\\\]\\\\}<>\\u201d'; // For RIGHT_BRACKET_CJK\n\n// ANS extended sets. The two sets are not identical, see the inline notes\n// Both ranges start at \\u00a1, one past NBSP (\\u00a0), so an NBSP is in no character class at all. That inertness is load-bearing: an NBSP already separates the runs it sits between,\n// so no rule matches across it and none fires. pangu therefore never rewrites an author's NBSP, it only inserts a space where one is genuinely missing. See ADR 0009\nexport const ANS_CJK_AFTER = `${A}${GREEK_AND_COPTIC}0-9@\\\\$%\\\\^&\\\\*\\\\-\\\\+\\\\\\\\=${LATIN_1_SUPPLEMENT_AFTER_NBSP}${NUMBER_FORMS}${DINGBATS}`; // Has @, no punctuation\nexport const ANS_BEFORE_CJK = `${A}${GREEK_AND_COPTIC}0-9\\\\$%\\\\^&\\\\*\\\\-\\\\+\\\\\\\\=${LATIN_1_SUPPLEMENT_AFTER_NBSP}${NUMBER_FORMS}${DINGBATS}`; // No @ symbol\n\n// Common directory names in Unix and project paths\n// prettier-ignore\nexport const 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';\nexport const FILE_PATH_CHARS = '[A-Za-z0-9_\\\\-\\\\.@\\\\+\\\\*]+';\n\n// Unix absolute paths: system directories and common project paths, for example /home, /usr/bin, /etc/nginx.conf, /.bashrc, /node_modules/@babel/core, /path/to/your/project\nexport const UNIX_ABSOLUTE_FILE_PATH = new RegExp(`/(?:\\\\.?(?:${FILE_PATH_DIRS})|\\\\.(?:[A-Za-z0-9_\\\\-]+))(?:/${FILE_PATH_CHARS})*`);\n\n// Unix relative paths that are common in documentation and blog posts, for example src/main.py, dist/index.js, test/spec.js, ./.claude/CLAUDE.md, templates/*.html\nexport const 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\nexport const WINDOWS_FILE_PATH = /[A-Z]:\\\\(?:[A-Za-z0-9_\\-\\. ]+\\\\?)+/;\n\nexport const ANY_CJK = new RegExp(`[${CJK}]`);\n\n// A punctuation run after CJK gets a trailing space and never converts to full-width. Space only when CJK, a letter, or a digit follows, so nothing changes at the end of the text\nexport const CJK_PUNCTUATION = new RegExp(`([${CJK}])([!;,\\\\?:]+)(?=[${CJK}${AN}])`, 'g');\n// A punctuation run directly before CJK gets a space after it, whatever sits on its left (no left anchor). An already-typed 'CJK ,CJK' shape is a typo, not preserved. See ADR 0007\n// CJK_PUNCTUATION still owns colon and punctuation before letters and digits\nexport const PUNCTUATION_CJK = new RegExp(`([!;,\\\\?]+)(?=[${CJK}])`, 'g');\n// Tilde has its own rule so ~= stays intact. Space only when CJK, a letter, or a digit follows\nexport const CJK_TILDE = new RegExp(`([${CJK}])(~+)(?!=)(?=[${CJK}${AN}])`, 'g');\nexport const CJK_TILDE_EQUALS = new RegExp(`([${CJK}])(~=)`, 'g');\n// Period has its own rule so file extensions, dot runs, and file paths stay intact; DOTS_CJK handles runs of dots first. Space only when CJK, a letter, or a digit follows\nexport const CJK_PERIOD = new RegExp(`([${CJK}])(\\\\.)(?![${AN}\\\\./])(?=[${CJK}${AN}])`, 'g');\nexport const AN_PERIOD_CJK = new RegExp(`([${AN}])(\\\\.)([${CJK}])`, 'g');\nexport const AN_COLON_CJK = new RegExp(`([${AN}])(:)([${CJK}])`, 'g');\nexport const DOTS_CJK = new RegExp(`([\\\\.]{2,}|\\u2026)([${CJK}])`, 'g');\n// The only case where a colon converts to full-width: after CJK, before an uppercase letter, a digit, or a parenthesis\nexport const FIX_CJK_COLON_ANS = new RegExp(`([${CJK}])\\\\:([${UPPER_AN}\\\\(\\\\)])`, 'g');\n\n// The quote class deliberately excludes ' because single quotes have their own rules\nexport const CJK_QUOTE = new RegExp(`([${CJK}])([${QUOTES}])`, 'g');\nexport const QUOTE_CJK = new RegExp(`([${QUOTES}])([${CJK}])`, 'g');\n// The content class is [\\s\\S] rather than . so a quoted segment that spans a line break still pairs with its own closing quote. HTML source wrapping puts newlines mid-sentence, and with . that\n// closing quote is unreachable, so the scan resyncs on the next quote, pairs closing-to-opening and strips the spaces outside the quotes instead of inside\nexport const FIX_QUOTE_ANY_QUOTE = new RegExp(`([${QUOTES}]+)[ ]*([\\\\s\\\\S]+?)[ ]*([${QUOTES}]+)`, 'g');\n\n// Curly quotes only: CJK_QUOTE, QUOTE_CJK, and FIX_QUOTE_ANY_QUOTE already handle straight quotes\nexport const QUOTE_AN = new RegExp(`([\\u201d])([${AN}])`, 'g');\n\n// A straight quote between CJK and AN (CJK\"AN) reads as closing a quoted CJK phrase, so the space goes after the quote\nexport const CJK_QUOTE_AN = new RegExp(`([${CJK}])(\")([${AN}])`, 'g');\n\nexport const CJK_SINGLE_QUOTE_BUT_POSSESSIVE = new RegExp(`([${CJK}])('[^s])`, 'g');\nexport const SINGLE_QUOTE_CJK = new RegExp(`(')([${CJK}])`, 'g');\nexport const FIX_POSSESSIVE_SINGLE_QUOTE = new RegExp(`([${AN}${CJK}])( )('s)`, 'g');\n// Single quotes whose content is only CJK characters\nexport const SINGLE_QUOTE_PURE_CJK = new RegExp(`(')([${CJK}]+)(')`, 'g');\n\nexport const HASH_ANS_CJK_HASH = new RegExp(`([${CJK}])(#)([${CJK}]+)(#)([${CJK}])`, 'g');\n// The negated class is the \"something is glued to this #, so it is a hashtag\" guard, so it has to reject an NBSP the same way it rejects a space. It stays a literal pair rather than \\S because \\S\n// also excludes zero-width characters like U+FEFF, and treating those as a gap would drop the space entirely and leave the runs flush\nexport const CJK_HASH = new RegExp(`([${CJK}])(#([^ \\\\u00a0]))`, 'g');\nexport const HASH_CJK = new RegExp(`(([^ \\\\u00a0])#)([${CJK}])`, 'g');\n// In file path context (multiple slashes), only a final hashtag not preceded by a slash gets a space\nexport const CJK_FINAL_HASHTAG = new RegExp(`([^/])([${CJK}])(#[A-Za-z0-9]+)$`);\n\n// The operator set is + - * = & only (no | / < >). Only direct CJK contact makes a symbol an operator: a symbol between two half-width characters binds them into a joiner token (A+B, a=1, S&P)\n// and never gets spaces, so there is deliberately no between-half-width rule here\nexport const CJK_OPERATOR_ANS = new RegExp(`([${CJK}])([${OPERATORS_WITH_HYPHEN}])([${AN}])`, 'g');\nexport const ANS_OPERATOR_CJK = new RegExp(`([${AN}])([${OPERATORS_NO_PLUS}])([${CJK}])`, 'g');\n\n// Slash patterns for operator vs separator behavior\nexport const CJK_SLASH_CJK = new RegExp(`([${CJK}])([/])([${CJK}])`, 'g');\nexport const CJK_SLASH_ANS = new RegExp(`([${CJK}])([/])([${AN}])`, 'g');\nexport const ANS_SLASH_CJK = new RegExp(`([${AN}])([/])([${CJK}])`, 'g');\n\n// Pipe patterns for separator vs joiner-token behavior, decided per line\nexport const PIPE_CJK_CONTACT = new RegExp(`[${CJK}]\\\\||\\\\|[${CJK}]`);\nexport const PIPE_SEPARATOR = /([^\\s|])[ ]*(\\|+)[ ]*(?=[^\\s|])/g;\n\n// Plus patterns for separator vs joiner-token behavior, decided per line like the pipe. The separator matches a solitary plus only: a space-adjacent plus is settled and a ++ run is a preserved\n// pattern (C++, i++)\nexport const PLUS_CJK_CONTACT = new RegExp(`[${CJK}]\\\\+|\\\\+[${CJK}]`);\nexport const PLUS_SEPARATOR = /(?<=[^\\s+])\\+(?=[^\\s+])/g;\n\n// Single-letter grades (A+, B-, C*) before CJK get the space after the symbol, not before. The \\b keeps the letter single, not the tail of a longer word\nexport const SINGLE_LETTER_GRADE_CJK = new RegExp(`\\\\b([${A}])([${GRADE_OPERATORS}])([${CJK}])`, 'g');\n\n// Affix readings attach a symbol to its half-width side at a CJK boundary, overriding the operator reading\n// Sign: + or - attaches to following digits (+886, -5)\nexport const CJK_SIGN_DIGIT = new RegExp(`([${CJK}])([\\\\+\\\\-])([0-9])`, 'g');\n// Flag: - attaches to a following single lowercase letter (-m). [a-z] keeps a capitalized word on the operator reading, and the trailing \\b keeps a longer lowercase word there too\nexport const CJK_HYPHEN_FLAG = new RegExp(`([${CJK}])(\\\\-)([a-z])\\\\b`, 'g');\n// Suffix: + attaches to a preceding half-width run (Disney+, 18+)\nexport const AN_PLUS_CJK = new RegExp(`([${AN}])(\\\\+)([${CJK}])`, 'g');\n\n// < and > as comparison operators, not brackets\nexport const CJK_LESS_THAN = new RegExp(`([${CJK}])(<)([${AN}])`, 'g');\nexport const LESS_THAN_CJK = new RegExp(`([${AN}])(<)([${CJK}])`, 'g');\nexport const CJK_GREATER_THAN = new RegExp(`([${CJK}])(>)([${AN}])`, 'g');\nexport const GREATER_THAN_CJK = new RegExp(`([${AN}])(>)([${CJK}])`, 'g');\n\n// Bracket patterns: ( ) [ ] { } plus < >, which also act as comparison operators\n// The curly quotes \\u201c and \\u201d appear in CJK_LEFT_BRACKET/RIGHT_BRACKET_CJK, but the paired-quote patterns handle them primarily\nexport const CJK_LEFT_BRACKET = new RegExp(`([${CJK}])([${LEFT_BRACKETS_EXTENDED}])`, 'g');\nexport const RIGHT_BRACKET_CJK = new RegExp(`([${RIGHT_BRACKETS_EXTENDED}])([${CJK}])`, 'g');\nexport const ANS_CJK_LEFT_BRACKET_ANY_RIGHT_BRACKET = new RegExp(`([${AN}${CJK}])[ ]*([\\u201c])([${AN}${CJK}\\\\-_ ]+)([\\u201d])`, 'g');\nexport const LEFT_BRACKET_ANY_RIGHT_BRACKET_ANS_CJK = new RegExp(`([\\u201c])([${AN}${CJK}\\\\-_ ]+)([\\u201d])[ ]*([${AN}${CJK}])`, 'g');\n// Some input habits type both quotes of a pair as closing curly quotes (\\u201d): the shape CJK\\u201dCJK\\u201d appears where CJK\\u201cCJK\\u201d was meant\n// A \\u201d only opens a \\u201d...\\u201d pair when no unclosed \\u201c precedes it on the line (the lookbehind), otherwise it closes that \\u201c\n// Runs after RIGHT_BRACKET_CJK, so the [ ]* after the opener strips the space that rule just added inside the pair\n// Not portable as a plain regex: the lookbehind is variable-length, which Python `re` and Go `regexp` reject. A port to those engines has to track the unclosed \\u201c in code instead\nexport const ANS_CJK_RIGHT_QUOTE_ANY_RIGHT_QUOTE = new RegExp(`([${AN}${CJK}])[ ]*(?<![\\u201c][^\\u201c\\u201d\\n]*)([\\u201d])[ ]*([${AN}${CJK}\\\\-_ ]+?)[ ]*([\\u201d])`, 'g');\n\n// A dotted name keeps its call parenthesis tight (`Math.floor(x)`, `array.map(fn)`), a bare name does not (`foo (x)`)\n// Not portable as a plain regex: the lookbehind is variable-length, which Python `re` and Go `regexp` reject. A port to those engines has to detect the preceding dot in code instead\nexport const AN_LEFT_BRACKET = new RegExp(`([${AN}])(?<!\\\\.[${AN}]*)([${LEFT_BRACKETS_BASIC}])`, 'g');\nexport const RIGHT_BRACKET_AN = new RegExp(`([${RIGHT_BRACKETS_BASIC}])([${AN}])`, 'g');\n\nexport const CJK_UNIX_ABSOLUTE_FILE_PATH = new RegExp(`([${CJK}])(${UNIX_ABSOLUTE_FILE_PATH.source})`, 'g');\nexport const CJK_UNIX_RELATIVE_FILE_PATH = new RegExp(`([${CJK}])(${UNIX_RELATIVE_FILE_PATH.source})`, 'g');\nexport const CJK_WINDOWS_PATH = new RegExp(`([${CJK}])(${WINDOWS_FILE_PATH.source})`, 'g');\n\nexport const UNIX_ABSOLUTE_FILE_PATH_SLASH_CJK = new RegExp(`(${UNIX_ABSOLUTE_FILE_PATH.source}/)([${CJK}])`, 'g');\nexport const UNIX_RELATIVE_FILE_PATH_SLASH_CJK = new RegExp(`(${UNIX_RELATIVE_FILE_PATH.source}/)([${CJK}])`, 'g');\n\nexport const CJK_ANS = new RegExp(`([${CJK}])([${ANS_CJK_AFTER}])`, 'g');\nexport const ANS_CJK = new RegExp(`([${ANS_BEFORE_CJK}])([${CJK}])`, 'g');\n\nexport const S_A = new RegExp(`(%)([${A}])`, 'g');\n\nexport const MIDDLE_DOT = /([ ]*)([\\u00b7\\u2022\\u2027])([ ]*)/g;\n\n// A bare unpaired non-void tag amid prose is a tag mention, not markup: it reads as one unit and is spaced from CJK it directly touches\n// A trailing self-closing slash is still bare, but void elements render on their own (<br> or <hr>), so they stay markup even unpaired\nexport const VOID_HTML_TAGS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);\nexport const BARE_HTML_TAG = /^<([a-zA-Z][a-zA-Z0-9]*)\\s*\\/?>$/;\nexport const CLOSING_HTML_TAG = /<\\/([a-zA-Z][a-zA-Z0-9]*)/g;\n\n// Spacing at direct CJK contact with a tag mention placeholder (\\uE002...\\uE003)\nexport const CJK_HTML_TAG_MENTION = new RegExp(`([${CJK}])(?=\\uE002)`, 'g');\nexport const HTML_TAG_MENTION_CJK = new RegExp(`(?<=\\uE003)([${CJK}])`, 'g');\n\n// Used by fixBracketSpacing to strip the spaces just inside a bracket pair; everything else between the brackets stays unchanged\nexport const BRACKET_PATTERNS = [\n { pattern: /<([^<>]*)>/g, open: '<', close: '>' },\n { pattern: /\\(([^()]*)\\)/g, open: '(', close: ')' },\n { pattern: /\\[([^\\[\\]]*)\\]/g, open: '[', close: ']' },\n { pattern: /\\{([^{}]*)\\}/g, open: '{', close: '}' },\n];\n\nexport class PlaceholderReplacer {\n // Every spacingText() call creates instances from the same few fixed configs, so compiled patterns are cached and shared across instances\n private static patternCache = new Map<string, RegExp>();\n\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 cacheKey = `${startDelimiter}${placeholder}${endDelimiter}`;\n let pattern = PlaceholderReplacer.patternCache.get(cacheKey);\n if (!pattern) {\n const escapedStart = this.startDelimiter.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const escapedEnd = this.endDelimiter.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n pattern = new RegExp(`${escapedStart}${this.placeholder}(\\\\d+)${escapedEnd}`, 'g');\n PlaceholderReplacer.patternCache.set(cacheKey, pattern);\n }\n this.pattern = pattern;\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 if (this.index === 0) {\n return text;\n }\n return text.replace(this.pattern, (_match, index) => {\n return this.items[parseInt(index, 10)] || '';\n });\n }\n}\n\nexport class Pangu {\n version: string;\n\n constructor() {\n this.version = '9.1.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 let newText = text;\n\n // Hide backtick content from the quote rules; the backticks themselves still get spacing\n const backtickManager = new PlaceholderReplacer('BACKTICK_CONTENT_', '\\uE004', '\\uE005');\n newText = newText.replace(/`([^`]+)`/g, (_match, content) => {\n return `\\`${backtickManager.store(content)}\\``;\n });\n\n const htmlTagManager = new PlaceholderReplacer('HTML_TAG_PLACEHOLDER_', '\\uE000', '\\uE001');\n const mentionedTagManager = new PlaceholderReplacer('HTML_TAG_MENTION_', '\\uE002', '\\uE003');\n let hasHtmlTags = false;\n\n if (newText.includes('<')) {\n hasHtmlTags = true;\n // Matches only opening, closing, and self-closing tags with a real tag name, so stray < > content is not read as a tag\n const HTML_TAG_PATTERN = /<\\/?[a-zA-Z][a-zA-Z0-9]*(?:\\s+[^>]*)?>/g;\n\n // Tag names whose closing tag appears anywhere in the text: their opening tags are paired markup\n const closedTagNames = new Set<string>();\n for (const closingTag of newText.matchAll(CLOSING_HTML_TAG)) {\n closedTagNames.add(closingTag[1]!.toLowerCase());\n }\n\n // Hide every real tag behind a placeholder; attribute values get spacing first\n newText = newText.replace(HTML_TAG_PATTERN, (match) => {\n const bareTag = match.match(BARE_HTML_TAG);\n if (bareTag) {\n const tagName = bareTag[1]!.toLowerCase();\n if (!VOID_HTML_TAGS.has(tagName) && !closedTagNames.has(tagName)) {\n return mentionedTagManager.store(match);\n }\n }\n const processedTag = match.replace(/(\\w+)=\"([^\"]*)\"/g, (_attrMatch, attrName, attrValue) => {\n const processedValue = this.spacingText(attrValue);\n return `${attrName}=\"${processedValue}\"`;\n });\n\n return htmlTagManager.store(processedTag);\n });\n }\n\n // Dot runs go first, before the single-period rule\n newText = newText.replace(DOTS_CJK, '$1 $2');\n\n newText = newText.replace(CJK_PUNCTUATION, '$1$2 ');\n newText = newText.replace(PUNCTUATION_CJK, '$1 ');\n newText = newText.replace(CJK_TILDE, '$1$2 ');\n newText = newText.replace(CJK_TILDE_EQUALS, '$1 $2 ');\n newText = newText.replace(CJK_PERIOD, '$1$2 ');\n newText = newText.replace(AN_PERIOD_CJK, '$1$2 $3');\n newText = newText.replace(AN_COLON_CJK, '$1$2 $3');\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 newText = newText.replace(QUOTE_AN, '$1 $2');\n newText = newText.replace(CJK_QUOTE_AN, '$1$2 $3');\n\n newText = newText.replace(FIX_POSSESSIVE_SINGLE_QUOTE, \"$1's\");\n\n // Quoted pure-CJK content keeps its quotes tight, so hide it before the single-quote rules run\n const singleQuoteCJKManager = new PlaceholderReplacer('SINGLE_QUOTE_CJK_PLACEHOLDER_', '\\uE030', '\\uE031');\n\n newText = newText.replace(SINGLE_QUOTE_PURE_CJK, (match) => {\n return singleQuoteCJKManager.store(match);\n });\n\n newText = newText.replace(CJK_SINGLE_QUOTE_BUT_POSSESSIVE, '$1 $2');\n newText = newText.replace(SINGLE_QUOTE_CJK, '$1 $2');\n\n newText = singleQuoteCJKManager.restore(newText);\n\n // HASH_ANS_CJK_HASH pattern needs at least 5 characters\n if (newText.length >= 5) {\n newText = newText.replace(HASH_ANS_CJK_HASH, '$1 $2$3$4 $5');\n }\n // Slash reading is per line, so each line's slash count decides its own hashtag behavior\n newText = newText\n .split('\\n')\n .map((line) => {\n if ((line.match(/\\//g) || []).length <= 1) {\n line = line.replace(CJK_HASH, '$1 $2');\n line = line.replace(HASH_CJK, '$1 $3');\n } else {\n // Multiple slashes read as a path: no hashtag spacing except a final hashtag not preceded by a slash\n line = line.replace(CJK_FINAL_HASHTAG, '$1$2 $3');\n }\n return line;\n })\n .join('\\n');\n\n // Protect compound words from operator spacing\n const compoundWordManager = new PlaceholderReplacer('COMPOUND_WORD_PLACEHOLDER_', '\\uE010', '\\uE011');\n\n // Hyphen-joined alphanumeric runs that read as one name, for example state-of-the-art, GPT-4o, claude-4-opus. At least one part must contain a lowercase letter or mix letters with digits (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 newText = newText.replace(COMPOUND_WORD_PATTERN, (match) => {\n return compoundWordManager.store(match);\n });\n\n // Single-letter grades run before the general operator rules so A+CJK becomes A+ CJK, not A + CJK\n newText = newText.replace(SINGLE_LETTER_GRADE_CJK, '$1$2 $3');\n\n // Affix readings run before the operator rules so the symbol stays attached to its half-width side\n newText = newText.replace(CJK_SIGN_DIGIT, '$1 $2$3');\n newText = newText.replace(CJK_HYPHEN_FLAG, '$1 $2$3');\n newText = newText.replace(AN_PLUS_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\n newText = newText.replace(CJK_LESS_THAN, '$1 $2 $3');\n newText = newText.replace(LESS_THAN_CJK, '$1 $2 $3');\n newText = newText.replace(CJK_GREATER_THAN, '$1 $2 $3');\n newText = newText.replace(GREATER_THAN_CJK, '$1 $2 $3');\n\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 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 // Slash reading is per line: the line's only slash acts as an operator when CJK touches it. Repeated slashes read as a file path or a list and get no spaces\n // A slash between half-width characters binds tight as a slash token, so no rule fires on it; file paths need no extra protection because the path rules already spaced their CJK edges\n newText = newText\n .split('\\n')\n .map((line) => {\n if ((line.match(/\\//g) || []).length !== 1) {\n return line;\n }\n line = line.replace(CJK_SLASH_CJK, '$1 $2 $3');\n line = line.replace(CJK_SLASH_ANS, '$1 $2 $3');\n line = line.replace(ANS_SLASH_CJK, '$1 $2 $3');\n return line;\n })\n .join('\\n');\n\n // Pipe reading is per line: a pipe in direct CJK contact makes every pipe on the line a separator with spaces on both sides (CJK | CJK, as in concatenated page titles)\n // A line whose pipes touch no CJK keeps them tight as joiner tokens (x|y, ps aux|grep node)\n newText = newText\n .split('\\n')\n .map((line) => {\n if (!PIPE_CJK_CONTACT.test(line)) {\n return line;\n }\n return line.replace(PIPE_SEPARATOR, '$1 $2 ');\n })\n .join('\\n');\n\n // Plus reading is per line: a plus in direct contact with CJK makes every unsettled plus on the line a separator with spaces on both sides, as in telecom bundle plans that chain products with +\n // A settled plus keeps its reading: space-adjacent, affix-attached (Disney+, +886), or in a ++ run (C++). A line with no CJK contact keeps its joiner tokens tight (A+B, 5+5)\n newText = newText\n .split('\\n')\n .map((line) => {\n if (!PLUS_CJK_CONTACT.test(line)) {\n return line;\n }\n return line.replace(PLUS_SEPARATOR, ' + ');\n })\n .join('\\n');\n\n // A pipe/plus separator space can land just inside a closing quote; re-strip so the first pass already emits what a second pass would (idempotency)\n newText = newText.replace(FIX_QUOTE_ANY_QUOTE, '$1$2$3');\n\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 newText = newText.replace(ANS_CJK_RIGHT_QUOTE_ANY_RIGHT_QUOTE, '$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 newText = this.fixBracketSpacing(newText);\n\n if (hasHtmlTags) {\n // A tag mention reads as one unit: space it from CJK it directly touches\n newText = newText.replace(CJK_HTML_TAG_MENTION, '$1 ');\n newText = newText.replace(HTML_TAG_MENTION_CJK, ' $1');\n newText = mentionedTagManager.restore(newText);\n newText = htmlTagManager.restore(newText);\n }\n\n newText = backtickManager.restore(newText);\n\n return newText;\n }\n\n public hasProperSpacing(text: string) {\n return this.spacingText(text) === text;\n }\n\n // Strip the spaces that earlier rules left just inside a bracket pair: no space after an opening bracket or before a closing bracket\n private fixBracketSpacing(text: string) {\n for (const { pattern, open, close } of BRACKET_PATTERNS) {\n text = text.replace(pattern, (_match, innerContent) => {\n if (!innerContent) {\n return `${open}${close}`;\n }\n const trimmedContent = innerContent.replace(/^ +| +$/g, '');\n return `${open}${trimmedContent}${close}`;\n });\n }\n return text;\n }\n}\n\nexport const pangu = new Pangu();\n","import { readFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { Pangu } from '../shared/index.js';\n\nexport class NodePangu extends Pangu {\n async spacingFile(path: string) {\n const data = await readFile(path, 'utf8');\n return this.spacingText(data);\n }\n\n spacingFileSync(path: string) {\n return this.spacingText(readFileSync(path, 'utf8'));\n }\n}\n\nexport const pangu = new NodePangu();\n\nexport default pangu;\n","// TypeScript 5.8+ under NodeNext models Node's require(esm) and resolves the ESM entry's types directly. Runtime never performs the require either way, since Rolldown inlines the ESM entry into this bundle.\n\n// `import =` rather than `import from` because `verbatimModuleSyntax` rejects ESM syntax in a CommonJS file (TS1286), and this file has to emit CommonJS for the `export =` at the bottom to be legal\n// at all. Unlike a bare `require()` call, this form is typed by the compiler.\n// The namespace access below (`index.NodePangu`) is also load-bearing: a top-level `NodePangu` binding would collide with the inlined `class NodePangu`, and Rolldown would rename the class to `NodePangu$1`,\n// which is observable through `constructor.name` and in stack traces\nimport index = require('./index.js');\n\n// The module is a NodePangu instance carrying the named exports as class fields, so the object is complete at construction and no cast is needed anywhere. The class declaration is also what puts the\n// properties in the emitted .d.cts, so the published types show the same surface the runtime has instead of hiding it from every require() consumer\nclass PanguModule extends index.NodePangu {\n // Allows both: const pangu = require('pangu') AND const { NodePangu } = require('pangu')\n NodePangu = index.NodePangu;\n pangu: PanguModule = this;\n // Pure surface parity, not interop. `export =` sets no `__esModule` flag, so a default import already receives the whole module and does not need this. What needs it is explicit `.default` access\n // from a require() consumer, which is undefined without it.\n default: PanguModule = this;\n}\n\nconst pangu = new PanguModule();\n\n// `export =` is not a preference here, it is the only spelling that both runs and types. `export default` and `export const` are ESM syntax, which `verbatimModuleSyntax` rejects in a CommonJS file.\n// A plain `module.exports = pangu` assignment compiles and behaves identically at runtime, but TypeScript models export assignment only in .js files, so the emitted .d.cts collapses to `export {}`\n// and every property access in a consumer becomes TS2339.\nexport = pangu;\n"],"mappings":"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"}