Browse Source

Perf: tweaked typorgapher checks

pull/14/head
Vitaly Puzrin 10 years ago
parent
commit
94871401b8
  1. 46
      lib/rules_text/replace.js
  2. 116
      lib/rules_text/smartquotes.js

46
lib/rules_text/replace.js

@ -3,6 +3,9 @@
'use strict';
var COPY_RE = /\((c|tm|r|p)\)/i;
var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/;
module.exports = function replace(t, state) {
var i, token, text,
tokens = state.tokens,
@ -13,7 +16,7 @@ module.exports = function replace(t, state) {
if (token.type === 'text') {
text = token.content;
if (text.indexOf('(') >= 0) {
if (COPY_RE.test(text)) {
if (options.copyright) {
text = text.replace(/\(c\)/gi, '©');
}
@ -28,27 +31,26 @@ module.exports = function replace(t, state) {
}
}
if (options.plusminus && text.indexOf('+-') >= 0) {
text = text.replace(/\+-/g, '±');
}
if (options.ellipsis && text.indexOf('..') >= 0) {
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
text = text.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..');
}
if (options.dupes &&
(text.indexOf('????') >= 0 ||
text.indexOf('!!!!') >= 0 ||
text.indexOf(',,') >= 0)) {
text = text.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',');
}
if (options.dashes && text.indexOf('--') >= 0) {
text = text
// em-dash
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2')
// en-dash
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2')
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2');
if (RARE_RE.test(text)) {
if (options.plusminus) {
text = text.replace(/\+-/g, '±');
}
if (options.ellipsis) {
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
text = text.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..');
}
if (options.dupes) {
text = text.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',');
}
if (options.dashes) {
text = text
// em-dash
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2')
// en-dash
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2')
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2');
}
}
token.content = text;

116
lib/rules_text/smartquotes.js

@ -3,20 +3,21 @@
'use strict';
var quoteReg = /['"]/g;
var punctReg = /[-\s()\[\]]/;
var apostrophe = '’';
var QUOTE_TEST_RE = /['"]/;
var QUOTE_RE = /['"]/g;
var PUNCT_RE = /[-\s()\[\]]/;
var APOSTROPHE = '’';
// This function returns true if the character at `pos`
// could be inside a word.
function isLetter(str, pos) {
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) {
if (!obj[tokenId]) { obj[tokenId] = {}; }
if (typeof obj[tokenId] === 'undefined') { obj[tokenId] = {}; }
obj[tokenId][posId] = str;
}
@ -31,6 +32,9 @@ module.exports = function smartquotes(typographer, state) {
for (i = 0; i < tokens.length; i++) {
token = tokens[i];
if (token.type !== 'text' || QUOTE_TEST_RE.test(token.text)) { continue; }
thisLevel = tokens[i].level;
for (j = stack.length - 1; j >= 0; j--) {
@ -38,74 +42,72 @@ module.exports = function smartquotes(typographer, state) {
}
stack.length = j + 1;
if (token.type === 'text') {
text = token.content;
pos = 0;
max = text.length;
while (pos < max) {
quoteReg.lastIndex = pos;
t = quoteReg.exec(text);
if (!t) { break; }
lastSpace = !isLetter(text, t.index - 1);
pos = t.index + t[0].length;
isSingle = t[0] === "'";
nextSpace = !isLetter(text, pos);
if (!nextSpace && !lastSpace) {
// middle word
if (isSingle) {
addQuote(replace, i, t.index, apostrophe);
}
continue;
text = token.content;
pos = 0;
max = text.length;
while (pos < max) {
QUOTE_RE.lastIndex = pos;
t = QUOTE_RE.exec(text);
if (!t) { break; }
lastSpace = !isLetter(text, t.index - 1);
pos = t.index + t[0].length;
isSingle = t[0] === "'";
nextSpace = !isLetter(text, pos);
if (!nextSpace && !lastSpace) {
// middle word
if (isSingle) {
addQuote(replace, i, t.index, APOSTROPHE);
}
continue;
}
canOpen = !nextSpace;
canClose = !lastSpace;
canOpen = !nextSpace;
canClose = !lastSpace;
if (canClose) {
// this could be a closing quote, rewind the stack to get a match
for (j = stack.length - 1; j >= 0; j--) {
if (canClose) {
// this could be a closing quote, rewind the stack to get a match
for (j = stack.length - 1; j >= 0; j--) {
item = stack[j];
if (stack[j].level < thisLevel) { break; }
if (item.single === isSingle && stack[j].level === thisLevel) {
item = stack[j];
if (stack[j].level < thisLevel) { break; }
if (item.single === isSingle && stack[j].level === thisLevel) {
item = stack[j];
chars = isSingle ? options.singleQuotes : options.doubleQuotes;
if (chars) {
addQuote(replace, item.token, item.start, chars[0]);
addQuote(replace, i, t.index, chars[1]);
}
stack.length = j;
canOpen = false; // should be "continue OUTER;", but eslint refuses labels :(
break;
chars = isSingle ? options.singleQuotes : options.doubleQuotes;
if (chars) {
addQuote(replace, item.token, item.start, chars[0]);
addQuote(replace, i, t.index, chars[1]);
}
stack.length = j;
canOpen = false; // should be "continue OUTER;", but eslint refuses labels :(
break;
}
}
}
if (canOpen) {
stack.push({
token: i,
start: t.index,
end: pos,
single: isSingle,
level: thisLevel
});
} else if (canClose && isSingle) {
addQuote(replace, i, t.index, apostrophe);
}
if (canOpen) {
stack.push({
token: i,
start: t.index,
end: pos,
single: isSingle,
level: thisLevel
});
} else if (canClose && isSingle) {
addQuote(replace, i, t.index, APOSTROPHE);
}
}
}
fn = function(str, pos) {
if (!replace[i][pos]) { return str; }
if (typeof replace[i][pos] === 'undefined') { return str; }
return replace[i][pos];
};
for (i = 0; i < tokens.length; i++) {
if (!replace[i]) { continue; }
quoteReg.lastIndex = 0;
tokens[i].content = tokens[i].content.replace(quoteReg, fn);
if (typeof replace[i] === 'undefined') { continue; }
QUOTE_RE.lastIndex = 0;
tokens[i].content = tokens[i].content.replace(QUOTE_RE, fn);
}
};

Loading…
Cancel
Save