|
@ -3,20 +3,21 @@ |
|
|
'use strict'; |
|
|
'use strict'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var quoteReg = /['"]/g; |
|
|
var QUOTE_TEST_RE = /['"]/; |
|
|
var punctReg = /[-\s()\[\]]/; |
|
|
var QUOTE_RE = /['"]/g; |
|
|
var apostrophe = '’'; |
|
|
var PUNCT_RE = /[-\s()\[\]]/; |
|
|
|
|
|
var APOSTROPHE = '’'; |
|
|
|
|
|
|
|
|
// This function returns true if the character at `pos`
|
|
|
// This function returns true if the character at `pos`
|
|
|
// could be inside a word.
|
|
|
// could be inside a word.
|
|
|
function isLetter(str, pos) { |
|
|
function isLetter(str, pos) { |
|
|
if (pos < 0 || pos >= str.length) { return false; } |
|
|
if (pos < 0 || pos >= str.length) { return false; } |
|
|
return !punctReg.test(str[pos]); |
|
|
return !PUNCT_RE.test(str[pos]); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function addQuote(obj, tokenId, posId, str) { |
|
|
function addQuote(obj, tokenId, posId, str) { |
|
|
if (!obj[tokenId]) { obj[tokenId] = {}; } |
|
|
if (typeof obj[tokenId] === 'undefined') { obj[tokenId] = {}; } |
|
|
obj[tokenId][posId] = str; |
|
|
obj[tokenId][posId] = str; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -31,6 +32,9 @@ module.exports = function smartquotes(typographer, state) { |
|
|
|
|
|
|
|
|
for (i = 0; i < tokens.length; i++) { |
|
|
for (i = 0; i < tokens.length; i++) { |
|
|
token = tokens[i]; |
|
|
token = tokens[i]; |
|
|
|
|
|
|
|
|
|
|
|
if (token.type !== 'text' || QUOTE_TEST_RE.test(token.text)) { continue; } |
|
|
|
|
|
|
|
|
thisLevel = tokens[i].level; |
|
|
thisLevel = tokens[i].level; |
|
|
|
|
|
|
|
|
for (j = stack.length - 1; j >= 0; j--) { |
|
|
for (j = stack.length - 1; j >= 0; j--) { |
|
@ -38,14 +42,13 @@ module.exports = function smartquotes(typographer, state) { |
|
|
} |
|
|
} |
|
|
stack.length = j + 1; |
|
|
stack.length = j + 1; |
|
|
|
|
|
|
|
|
if (token.type === 'text') { |
|
|
|
|
|
text = token.content; |
|
|
text = token.content; |
|
|
pos = 0; |
|
|
pos = 0; |
|
|
max = text.length; |
|
|
max = text.length; |
|
|
|
|
|
|
|
|
while (pos < max) { |
|
|
while (pos < max) { |
|
|
quoteReg.lastIndex = pos; |
|
|
QUOTE_RE.lastIndex = pos; |
|
|
t = quoteReg.exec(text); |
|
|
t = QUOTE_RE.exec(text); |
|
|
if (!t) { break; } |
|
|
if (!t) { break; } |
|
|
|
|
|
|
|
|
lastSpace = !isLetter(text, t.index - 1); |
|
|
lastSpace = !isLetter(text, t.index - 1); |
|
@ -56,7 +59,7 @@ module.exports = function smartquotes(typographer, state) { |
|
|
if (!nextSpace && !lastSpace) { |
|
|
if (!nextSpace && !lastSpace) { |
|
|
// middle word
|
|
|
// middle word
|
|
|
if (isSingle) { |
|
|
if (isSingle) { |
|
|
addQuote(replace, i, t.index, apostrophe); |
|
|
addQuote(replace, i, t.index, APOSTROPHE); |
|
|
} |
|
|
} |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
@ -92,20 +95,19 @@ module.exports = function smartquotes(typographer, state) { |
|
|
level: thisLevel |
|
|
level: thisLevel |
|
|
}); |
|
|
}); |
|
|
} else if (canClose && isSingle) { |
|
|
} else if (canClose && isSingle) { |
|
|
addQuote(replace, i, t.index, apostrophe); |
|
|
addQuote(replace, i, t.index, APOSTROPHE); |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fn = function(str, pos) { |
|
|
fn = function(str, pos) { |
|
|
if (!replace[i][pos]) { return str; } |
|
|
if (typeof replace[i][pos] === 'undefined') { return str; } |
|
|
return replace[i][pos]; |
|
|
return replace[i][pos]; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
for (i = 0; i < tokens.length; i++) { |
|
|
for (i = 0; i < tokens.length; i++) { |
|
|
if (!replace[i]) { continue; } |
|
|
if (typeof replace[i] === 'undefined') { continue; } |
|
|
quoteReg.lastIndex = 0; |
|
|
QUOTE_RE.lastIndex = 0; |
|
|
tokens[i].content = tokens[i].content.replace(quoteReg, fn); |
|
|
tokens[i].content = tokens[i].content.replace(QUOTE_RE, fn); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|