diff options
| author | altaf-creator <dev@altafcreator.com> | 2026-04-30 22:01:53 +0800 |
|---|---|---|
| committer | altaf-creator <dev@altafcreator.com> | 2026-04-30 22:01:53 +0800 |
| commit | db1c6676a13798ee57dbac429a1d5045b60356fb (patch) | |
| tree | 5ff305c09686de50bbcac404c1954e42c26ba494 /packages/markdown-it-14.1.0/lib/rules_core/smartquotes.mjs | |
| parent | 97fa8f57fbefcbfa6b3e56c31a1e5b60ef1a9e37 (diff) | |
quite a big commit
Diffstat (limited to 'packages/markdown-it-14.1.0/lib/rules_core/smartquotes.mjs')
| -rw-r--r-- | packages/markdown-it-14.1.0/lib/rules_core/smartquotes.mjs | 193 |
1 files changed, 0 insertions, 193 deletions
diff --git a/packages/markdown-it-14.1.0/lib/rules_core/smartquotes.mjs b/packages/markdown-it-14.1.0/lib/rules_core/smartquotes.mjs deleted file mode 100644 index 3b990ed..0000000 --- a/packages/markdown-it-14.1.0/lib/rules_core/smartquotes.mjs +++ /dev/null @@ -1,193 +0,0 @@ -// Convert straight quotation marks to typographic ones -// - -import { isWhiteSpace, isPunctChar, isMdAsciiPunct } from '../common/utils.mjs' - -const QUOTE_TEST_RE = /['"]/ -const QUOTE_RE = /['"]/g -const APOSTROPHE = '\u2019' /* ’ */ - -function replaceAt (str, index, ch) { - return str.slice(0, index) + ch + str.slice(index + 1) -} - -function process_inlines (tokens, state) { - let j - - const stack = [] - - for (let i = 0; i < tokens.length; i++) { - const token = tokens[i] - - const thisLevel = tokens[i].level - - for (j = stack.length - 1; j >= 0; j--) { - if (stack[j].level <= thisLevel) { break } - } - stack.length = j + 1 - - if (token.type !== 'text') { continue } - - let text = token.content - let pos = 0 - let max = text.length - - /* eslint no-labels:0,block-scoped-var:0 */ - OUTER: - while (pos < max) { - QUOTE_RE.lastIndex = pos - const t = QUOTE_RE.exec(text) - if (!t) { break } - - let canOpen = true - let canClose = true - pos = t.index + 1 - const isSingle = (t[0] === "'") - - // Find previous character, - // default to space if it's the beginning of the line - // - let lastChar = 0x20 - - if (t.index - 1 >= 0) { - lastChar = text.charCodeAt(t.index - 1) - } else { - for (j = i - 1; j >= 0; j--) { - if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // lastChar defaults to 0x20 - if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline' - - lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1) - break - } - } - - // Find next character, - // default to space if it's the end of the line - // - let nextChar = 0x20 - - if (pos < max) { - nextChar = text.charCodeAt(pos) - } else { - for (j = i + 1; j < tokens.length; j++) { - if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // nextChar defaults to 0x20 - if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline' - - nextChar = tokens[j].content.charCodeAt(0) - break - } - } - - const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctChar(String.fromCharCode(lastChar)) - const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctChar(String.fromCharCode(nextChar)) - - const isLastWhiteSpace = isWhiteSpace(lastChar) - const isNextWhiteSpace = isWhiteSpace(nextChar) - - if (isNextWhiteSpace) { - canOpen = false - } else if (isNextPunctChar) { - if (!(isLastWhiteSpace || isLastPunctChar)) { - canOpen = false - } - } - - if (isLastWhiteSpace) { - canClose = false - } else if (isLastPunctChar) { - if (!(isNextWhiteSpace || isNextPunctChar)) { - canClose = false - } - } - - if (nextChar === 0x22 /* " */ && t[0] === '"') { - if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) { - // special case: 1"" - count first quote as an inch - canClose = canOpen = false - } - } - - if (canOpen && canClose) { - // Replace quotes in the middle of punctuation sequence, but not - // in the middle of the words, i.e.: - // - // 1. foo " bar " baz - not replaced - // 2. foo-"-bar-"-baz - replaced - // 3. foo"bar"baz - not replaced - // - canOpen = isLastPunctChar - canClose = isNextPunctChar - } - - if (!canOpen && !canClose) { - // middle of word - if (isSingle) { - token.content = replaceAt(token.content, t.index, APOSTROPHE) - } - continue - } - - if (canClose) { - // this could be a closing quote, rewind the stack to get a match - for (j = stack.length - 1; j >= 0; j--) { - let item = stack[j] - if (stack[j].level < thisLevel) { break } - if (item.single === isSingle && stack[j].level === thisLevel) { - item = stack[j] - - let openQuote - let closeQuote - if (isSingle) { - openQuote = state.md.options.quotes[2] - closeQuote = state.md.options.quotes[3] - } else { - openQuote = state.md.options.quotes[0] - closeQuote = state.md.options.quotes[1] - } - - // replace token.content *before* tokens[item.token].content, - // because, if they are pointing at the same token, replaceAt - // could mess up indices when quote length != 1 - token.content = replaceAt(token.content, t.index, closeQuote) - tokens[item.token].content = replaceAt( - tokens[item.token].content, item.pos, openQuote) - - pos += closeQuote.length - 1 - if (item.token === i) { pos += openQuote.length - 1 } - - text = token.content - max = text.length - - stack.length = j - continue OUTER - } - } - } - - if (canOpen) { - stack.push({ - token: i, - pos: t.index, - single: isSingle, - level: thisLevel - }) - } else if (canClose && isSingle) { - token.content = replaceAt(token.content, t.index, APOSTROPHE) - } - } - } -} - -export default function smartquotes (state) { - /* eslint max-depth:0 */ - if (!state.md.options.typographer) { return } - - for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { - if (state.tokens[blkIdx].type !== 'inline' || - !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) { - continue - } - - process_inlines(state.tokens[blkIdx].children, state) - } -} |
