From 94871401b85b7b4e91d8237901a8d66e3609ed52 Mon Sep 17 00:00:00 2001 From: Vitaly Puzrin Date: Sun, 26 Oct 2014 15:37:56 +0300 Subject: [PATCH] Perf: tweaked typorgapher checks --- lib/rules_text/replace.js | 46 +++++++------- lib/rules_text/smartquotes.js | 116 +++++++++++++++++----------------- 2 files changed, 83 insertions(+), 79 deletions(-) diff --git a/lib/rules_text/replace.js b/lib/rules_text/replace.js index b895f47..f311631 100644 --- a/lib/rules_text/replace.js +++ b/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; diff --git a/lib/rules_text/smartquotes.js b/lib/rules_text/smartquotes.js index 5e8ed39..02bcbd0 100644 --- a/lib/rules_text/smartquotes.js +++ b/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); } };