Repository navigation
fix: patterns bug - #7872
fix: patterns bug#7872
Conversation
| label: '空行', | ||
| value: '(?<!\\n)\\n\\n(?!\\n)', | ||
| }, | ||
| ] |
There was a problem hiding this comment.
Here are the review findings:
Potential Issues
1. - list item regex is too broad
'(?<! )- .*'This only guards against a preceding space, so it will incorrectly match hyphen-minus in contexts like:
- Negative numbers:
value - 5,x - y - YAML-like text or inline math
- A
--flag with a following word
It also lacks a lookbehind for \n or start-of-line anchor pairing, unlike the heading patterns. Consider aligning it with the heading style (match line-start or after \n).
2. Missing anchor consistency
Heading patterns use (?<=^) but ^ in a lookbehind without the multiline flag only matches string start. If this regex runs on multi-line text without m flag, (?<=^) never fires except at position 0. The (?<=\n) branch covers most cases, but this is fragile — precompiled regexes should ideally use the m flag. Verify how the backend applies these patterns.
3. Heading negative lookaheads can mismatch across branches
For ##: (?<=\n)(?<!#)## (?!#).*|(?<=^)(?<!#)## (?!#).*. The (?<!#) before ## correctly prevents matching ###, but the two alternatives duplicate logic unnecessarily. Could be simplified to (?<=^|\n)(?<!#)## (?!#).* only if variable-length lookbehind is supported (it's not in JS), so keeping two branches is acceptable — just note the duplication.
4. Space pattern (?<! ) (?! ) is greedy on whitespace-normalized input
This matches any single space between non-spaces, including spaces inside markdown links, code, or English words. For CJK text splitting that may be intended, but confirm it won't break URLs/code blocks.
5. Labels are Chinese while the file mixes conventions
Existing labels are Chinese (模型优化, 直接回答) so this is consistent — no issue, just noting for reviewers.
Optimization Suggestions
- Deduplicate the heading generation with a small helper:
const headingPattern = (n: number) => {
const hashes = '#'.repeat(n);
const guard = `(?<!${'#'.repeat(n - 1) === '' ? '\\b' : '#'})`;
// simpler: build explicit lookarounds
};Or generate programmatically from a loop over 1–6 to reduce repetition and copy-paste risk.
- Add
as constto keep literal types, consistent with the constants block above:
] as const;-
Consider
mflag / documenting flags: export whether these strings are used withnew RegExp(value, 'gm')so consumers know expected behavior. -
Add a type/interface for the option shape (
{ label: string; value: string }[]) for reuse and clarity. -
Comment the lack of anchors for
-,空格, etc., since they behave differently from headings.
Summary
Main concerns: the - pattern over-matching and reliance on ^ without the multiline flag. The rest is stylistic/repetition cleanup.
| ] | ||
| // 分段策略展示文案,配置选项与执行详情共用。 | ||
| export const DOCUMENT_SPLIT_STRATEGY_LABELS: Readonly<Record<string, string>> = { | ||
| auto: '智能分段(推荐)', |
There was a problem hiding this comment.
Code Review
The diff removes splitPatternOptions while leaving a comment above DOCUMENT_SPLIT_STRATEGY_LABELS that references shared usage. Please check the following:
-
Dangling References / Broken Imports
splitPatternOptionswas exported. Any other module importing it (e.g., a splitter UI config, tests, or the backend-alignment layer) will now break. Search the repo forsplitPatternOptionsbefore merging.- The removed block's leading comment ("与后端 DocumentSerializers.SplitPattern 的固定标识保持一致;顺序由用户选择决定。") is deleted too, so the backend-coupling contract is now undocumented. If the data moved elsewhere, make sure that contract note moved with it.
-
Backend/Frontend Contract Drift
- These regex values must stay in sync with
DocumentSerializers.SplitPattern. Removing them here without a replacement risks divergence if any consumer still relies on client-side values.
- These regex values must stay in sync with
-
Regex Concerns (if reused elsewhere)
- Patterns like
(?<=^)and variable-length lookbehind ((?<=^)# .*) are not supported in all JS engines (Safari/JSC historically rejected variable-length lookbehind). Verify browser support requirements. - Header patterns only exclude immediately preceding
#, so#######(7 hashes) could match at level 6. Consider a more robust anchor (^#{n}with word-boundary or(?!\s*#)). - The
-list pattern(?<! )- .*doesn't anchor to line start, so mid-line-occurrences can match. - Non-ASCII full-width punctuation patterns (
;,。) are fine but document encoding expectations.
- Patterns like
-
Duplicate/Redundant Alternatives
(?<=\n)...|(?<=^)...alternatives repeat identical bodies; could factor as(?:(?<=\n)|^)# .*. Minor readability/size gain (avoid for perf-critical paths — no real gain, just DRY).
-
Case:
label: '空格'uses(?<! ) (?! )— matches single spaces not adjacent to another space, but will also match leading/trailing spaces; confirm intended behavior. -
Typing
- Consider
as const+ explicit type instead of untyped array, e.g.:export const splitPatternOptions = [...] as const satisfies ReadonlyArray<{ label: string; value: string }>
- Consider
Recommendation: Confirm whether the removal is intentional relocation. If yes, update imports and port the contract comment. If accidental, revert this hunk.
| } | ||
| }) | ||
| return i18n | ||
| } |
There was a problem hiding this comment.
Code Review
Potential Issues
-
Event listener leak – The
storageevent listener onwindowis never removed. Every call tocreateAppI18n()adds a new listener (one per app entry: Admin, Chat, etc.), causing memory leaks and duplicate handlers that all calluser.setLanguage. Consider returning a cleanup function or usingonScopeDispose/onUnmounted. -
flush: 'sync'inwatch– Synchronous flush can cause bugs when the watched value changes during render/component setup, and disables Vue's batching. Only use it if truly required.'pre'(default) or'post'is usually safer. -
event.storageArea === localStorage–storageAreamay benullin some browsers/tests. Safer check:event.key === ... && (event.storageArea == null || event.storageArea === localStorage). Also consider guarding for SSR (typeof window !== 'undefined'). -
Initial
document.documentElement.langside-effect – Settingdocument.documentElement.langinside a composable couples i18n logic to the DOM. IfcreateAppI18nis called multiple times (Admin + Chat simultaneously), both will writelang. That's acceptable but worth documenting; alternatively, expose a setter. -
Cross-tab
newValuefallback – Whenevent.key === null(clear), you fall back tonavigator.language, ignoringLANGUAGE_STORAGE_KEYremoval semantics. Confirm this is intentional; otherwise read fromlocalStorage.getItem(LANGUAGE_STORAGE_KEY)first. -
No guard against non-browser env – Module-level imports of
vue-i18nare fine, but the function directly toucheswindow,localStorage,navigator,document. If ever used in SSR/SSG or tests (jsdom without storage), this will throw. -
MessageSchema['common']forenUS/hantCommontype assertion – Type inference assumes other locales match zh-CN shape. If a translation file diverges (missing/extra keys), TypeScript won't catch it unless you explicitly type each import asMessageSchema['common']. Worth adding:import enCommonRaw from './en-US/common.json' const enCommon = enCommonRaw satisfies typeof zhCommon
-
Listener added after watch with
immediate: true– Order is fine, but note the initial language sync relies onuser.languagebeing set before mount ("bound before mount" comment acknowledges this). Consider asserting/warning ifuser.languageis empty. -
Missing error feedback –
normalizeLocalesilently falls back; no logging when an unknown locale is persisted. Minor.
Optimization Suggestions
- Extract the storage listener into a returned cleanup:
Or wrap in
function createAppI18n(user: LanguageState) { // ... const onStorage = (event: StorageEvent) => { /* ... */ } window.addEventListener('storage', onStorage) return { i18n, dispose: () => window.removeEventListener('storage', onStorage), } }
effectScope()so consumers can callscope.stop(). - Cache
normalizeLocale(language)result to skip redundant watcher writes (if (i18n.global.locale.value === locale) return). - Use
import.meta.env.SSR/typeof windowguard for portability. - Consider lazy-loading
zh-Hantmessages (or splitting common translations) to reduce initial bundle — three JSON blobs load eagerly now. - Add JSDoc noting that
user.setLanguagemust persist toLANGUAGE_STORAGE_KEY, otherwise cross-tab sync breaks silently.
Minor
- No blank-line/formatting issue. Comments and typing look clean.
globalInjection: falseis good; ensure templates useuseI18n()composition API consistently.
fix: patterns bug