electron-text-substitutions
Version:
Substitute text in an input field based on OS X System Preferences
140 lines (118 loc) • 7.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ellipsis = exports.emDash = exports.closingDoubleQuote = exports.openingDoubleQuote = exports.closingSingleQuote = exports.openingSingleQuote = undefined;
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
exports.getSubstitutionRegExp = getSubstitutionRegExp;
exports.getSmartQuotesRegExp = getSmartQuotesRegExp;
exports.getSmartDashesRegExp = getSmartDashesRegExp;
exports.scrubInputString = scrubInputString;
exports.formatReplacement = formatReplacement;
exports.regExpReplacer = regExpReplacer;
exports.regExpReviver = regExpReviver;
var _lodash = require('lodash');
var openingSingleQuote = exports.openingSingleQuote = '\u2018'; // ‘
var closingSingleQuote = exports.closingSingleQuote = '\u2019'; // ’
var openingDoubleQuote = exports.openingDoubleQuote = '\u201C'; // “
var closingDoubleQuote = exports.closingDoubleQuote = '\u201D'; // ”
var emDash = exports.emDash = '\u2014'; // —
var ellipsis = exports.ellipsis = '\u2026'; // …
/**
* Recreate something like \b; we don't want to use \b because no Unicode support.
*/
var wordBoundary = /[ \n\r\t.,:;|{}()<>'"`+!?«»“”‘’‹›—–−-]/;
var startsWithWordBoundary = new RegExp('^' + wordBoundary.source);
var endsWithWordBoundary = new RegExp(wordBoundary.source + '$');
/**
* @typedef {Object} ReplacementItem
* @property {String} match The text to replace
* @property {RegExp} regExp A regular expression that matches the text to replace
* @property {String} replacement The replacement text
*/
/**
* Creates a regular expression that will match a word and its boundaries– that
* is, some surrounding whitespace or separator character.
*
* @param {String} match The string to match
* @return {ReplacementItem} A replacement item; contains a `RegExp` and its replacement
*/
function getSubstitutionRegExp(match, replacement) {
// Require the start of input or a word boundary, unless the string to match
// already starts with a boundary (e.g., `(tm)`) in which case we want to
// match text like `BigCompany(tm)`.
var startOfInputOrBoundary = startsWithWordBoundary.test(match) ? '' : '^|' + wordBoundary.source;
// Require a terminating word boundary, unless the string to match already
// ends with a boundary (e.g., `<br>`) in which case we will also accept word
// characters, to match something like `<br>content`.
var wordCharacterOrBoundary = endsWithWordBoundary.test(match) ? '\\w|' + wordBoundary.source : wordBoundary.source;
// Capture the left and right boundaries as groups $1 and $2, to align with
// `formatReplacement`. Be sure to escape special characters in the string
// to match.
var regExp = new RegExp('(' + startOfInputOrBoundary + ')' + ('' + (0, _lodash.escapeRegExp)(match)) + ('(' + wordCharacterOrBoundary + ')'), 'u');
return { match: match, regExp: regExp, replacement: replacement };
}
/**
* Returns an array of regular expressions that will progressively replace
* straight quotes with curly quotes.
*
* @return {Array<ReplacementItem>} An array of replacement items
*/
function getSmartQuotesRegExp() {
return [{ regExp: /((?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))"((?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: closingDoubleQuote }, { regExp: /()"((?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: openingDoubleQuote }, { regExp: /((?:[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))'((?:[\0-/:-@\[-\^`\{-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: closingSingleQuote }, { regExp: /((?:[\0-/:-@\[-\^`\{-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])|^)'([\t-\r 0-9A-Z_a-z\xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF])/, replacement: openingSingleQuote }, { regExp: /([0-9A-Z_a-z])'([0-9A-Z_a-z]+(?:[\0-/:-@\[-\^`\{-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: closingSingleQuote }];
}
/**
* Returns an array of regular expressions that will replace hypens with
* em-dashes (and ellipsis, as a bonus).
*
* @return {Array<ReplacementItem>} An array of replacement items
*/
function getSmartDashesRegExp() {
return [{ regExp: /(^|(?:[\0-,\.-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))\-\-\-((?:[\0-,\.-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: emDash }, { regExp: /(^|(?:[\0-,\.-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))\-\-((?:[\0-,\.-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: emDash }, { regExp: /(^|(?:[\0-\-/-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))\.\.\.((?:[\0-\-/-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))/, replacement: ellipsis }];
}
/**
* Replaces text in an input string using the given replacement items.
*
* @param {String} input The input string
* @param {Array<ReplacementItem>} items An array of replacement items
* @return {String} The output string
*/
function scrubInputString(input, items) {
return (0, _lodash.reduce)(items, function (output, _ref) {
var regExp = _ref.regExp,
replacement = _ref.replacement;
return output.replace(regExp, '$1' + replacement + '$2');
}, input);
}
/**
* Preserves whitespace around the match. These expressions match the text
* being substituted along with boundaries on the left ($1) and right ($2).
*/
function formatReplacement(match, replacement) {
var _match = _slicedToArray(match, 3),
left = _match[1],
right = _match[2];
return '' + left + replacement + right;
}
/**
* Can be used as the replacer parameter in `JSON.stringify` to serialize
* replacement items.
*/
function regExpReplacer(key, value) {
if (value instanceof RegExp) return value.toString();
return value;
}
/**
* Can be used as the reviver parameter in `JSON.parse` to deserialize
* replacement items.
*/
function regExpReviver(key, value) {
if (key === 'regExp') {
var _value$match = value.match(/\/(.*)\/(.*)?/),
_value$match2 = _slicedToArray(_value$match, 3),
regExp = _value$match2[1],
flags = _value$match2[2];
return new RegExp(regExp, flags || '');
}
return value;
}