| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- import assert from 'node:assert/strict'
- import { readFile } from 'node:fs/promises'
- import ts from 'typescript'
- const sourceUrl = new URL(
- '../src/views/Editor/EnglishSpeaking/composables/articleAutoFormatRules.ts',
- import.meta.url,
- )
- const compiled = ts.transpileModule(await readFile(sourceUrl, 'utf8'), {
- compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 },
- }).outputText
- const {
- countWords,
- normalizeParagraphs,
- hasOverlongParagraph,
- shouldPromptOnPaste,
- MAX_PARAGRAPH_WORDS,
- PASTE_PROMPT_MIN_WORDS,
- } = await import(`data:text/javascript,${encodeURIComponent(compiled)}`)
- /** 生成 n 个单词的文本 */
- const words = n => Array.from({ length: n }, (_, i) => `w${i}`).join(' ')
- // ---------------- countWords ----------------
- assert.equal(countWords(''), 0)
- assert.equal(countWords(' \n\n '), 0)
- assert.equal(countWords('one two three'), 3)
- assert.equal(countWords(' leading and trailing '), 3)
- assert.equal(countWords(words(300)), 300)
- // ---------------- normalizeParagraphs ----------------
- // 与后端 split_paragraphs 同规则:单 \n 与空行皆为段界
- assert.equal(normalizeParagraphs('A one.\n\nB two.'), 'A one.\n\nB two.')
- assert.equal(normalizeParagraphs('A one.\nB two.'), 'A one.\n\nB two.')
- assert.equal(normalizeParagraphs('A one.\n\n\n\n \nB two.'), 'A one.\n\nB two.')
- assert.equal(normalizeParagraphs(' A one here. '), 'A one here.')
- assert.equal(normalizeParagraphs(''), '')
- assert.equal(normalizeParagraphs(' \n\n '), '')
- // 幂等:归一化结果再归一化不变(会回写 textarea,必须稳定)
- assert.equal(normalizeParagraphs(normalizeParagraphs('A.\nB.\n\n\nC.')), 'A.\n\nB.\n\nC.')
- // ---------------- hasOverlongParagraph(299 / 300 / 301 边界)----------------
- assert.equal(MAX_PARAGRAPH_WORDS, 300)
- assert.equal(hasOverlongParagraph(''), false)
- assert.equal(hasOverlongParagraph(words(299)), false)
- assert.equal(hasOverlongParagraph(words(300)), false)
- assert.equal(hasOverlongParagraph(words(301)), true)
- // 多段:只要有一段超标就 true
- assert.equal(hasOverlongParagraph(`${words(10)}\n\n${words(301)}`), true)
- assert.equal(hasOverlongParagraph(`${words(200)}\n\n${words(200)}`), false)
- // 单 \n 也是段界,故 200+200 不算一段 400
- assert.equal(hasOverlongParagraph(`${words(200)}\n${words(200)}`), false)
- // ---------------- shouldPromptOnPaste ----------------
- assert.equal(PASTE_PROMPT_MIN_WORDS, 50)
- // spec §3.2 step 1 只有两条:原内容 trim 后为空,且新内容 > 50 词。
- assert.equal(shouldPromptOnPaste('', words(60)), true) // 空框粘贴长文 → 弹
- assert.equal(shouldPromptOnPaste(' ', words(51)), true) // 纯空白算空框;51 词过阈值
- assert.equal(shouldPromptOnPaste('\n\n \n', words(60)), true) // 只剩换行的框同样算空
- assert.equal(shouldPromptOnPaste('', words(50)), false) // 恰好 50 词不弹(严格 >)
- assert.equal(shouldPromptOnPaste('', words(40)), false) // 短文不弹
- assert.equal(shouldPromptOnPaste(words(300), words(400)), false) // 原文非空 → 不打断编辑
- assert.equal(shouldPromptOnPaste('x', words(400)), false) // 哪怕只有一个字符也不算空框
- // 粘贴内容自带空行照样提示:带 \n\n ≠ 分得适合朗读(三段各 400 词就是反例)
- assert.equal(shouldPromptOnPaste('', `${words(30)}\n\n${words(30)}`), true)
- assert.equal(shouldPromptOnPaste('', `${words(400)}\n\n${words(400)}`), true)
- // enspeak 的 sentenceCount>=2 条件已弃用:无标点长文照样提示
- assert.equal(shouldPromptOnPaste('', words(60).replace(/\./g, '')), true)
- console.log('article auto-format rules OK')
|