escaper.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*!
  2. * Escaper v2.5.3
  3. * https://github.com/kobezzza/Escaper
  4. *
  5. * Released under the MIT license
  6. * https://github.com/kobezzza/Escaper/blob/master/LICENSE
  7. *
  8. * Date: Tue, 23 Jan 2018 15:58:45 GMT
  9. */
  10. (function (global, factory) {
  11. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  12. typeof define === 'function' && define.amd ? define('Escaper', ['exports'], factory) :
  13. (factory((global.Escaper = {})));
  14. }(this, (function (exports) { 'use strict';
  15. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  16. return typeof obj;
  17. } : function (obj) {
  18. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  19. };
  20. var Escaper = void 0;
  21. var escaper = Escaper = {
  22. VERSION: [2, 5, 3],
  23. content: [],
  24. cache: {},
  25. snakeskinRgxp: null,
  26. symbols: null,
  27. replace: replace,
  28. paste: paste
  29. };
  30. var stringLiterals = {
  31. '"': true,
  32. '\'': true,
  33. '`': true
  34. };
  35. var literals = {
  36. '/': true
  37. };
  38. for (var key in stringLiterals) {
  39. if (!stringLiterals.hasOwnProperty(key)) {
  40. break;
  41. }
  42. literals[key] = true;
  43. }
  44. var singleComments = {
  45. '//': true,
  46. '//*': true,
  47. '//!': true,
  48. '//#': true,
  49. '//@': true,
  50. '//$': true
  51. };
  52. var multComments = {
  53. '/*': true,
  54. '/**': true,
  55. '/*!': true,
  56. '/*#': true,
  57. '/*@': true,
  58. '/*$': true
  59. };
  60. var keyArr = [];
  61. var finalMap = {};
  62. for (var _key in literals) {
  63. if (!literals.hasOwnProperty(_key)) {
  64. break;
  65. }
  66. keyArr.push(_key);
  67. finalMap[_key] = true;
  68. }
  69. for (var _key2 in singleComments) {
  70. if (!singleComments.hasOwnProperty(_key2)) {
  71. break;
  72. }
  73. keyArr.push(_key2);
  74. finalMap[_key2] = true;
  75. }
  76. for (var _key3 in multComments) {
  77. if (!multComments.hasOwnProperty(_key3)) {
  78. break;
  79. }
  80. keyArr.push(_key3);
  81. finalMap[_key3] = true;
  82. }
  83. var rgxpFlags = [];
  84. var rgxpFlagsMap = {
  85. 'g': true,
  86. 'm': true,
  87. 'i': true,
  88. 'y': true,
  89. 'u': true
  90. };
  91. for (var _key4 in rgxpFlagsMap) {
  92. if (!rgxpFlagsMap.hasOwnProperty(_key4)) {
  93. break;
  94. }
  95. rgxpFlags.push(_key4);
  96. }
  97. var escapeEndMap = {
  98. '-': true,
  99. '+': true,
  100. '*': true,
  101. '%': true,
  102. '~': true,
  103. '>': true,
  104. '<': true,
  105. '^': true,
  106. ',': true,
  107. ';': true,
  108. '=': true,
  109. '|': true,
  110. '&': true,
  111. '!': true,
  112. '?': true,
  113. ':': true,
  114. '(': true,
  115. '{': true,
  116. '[': true
  117. };
  118. var escapeEndWordMap = {
  119. 'return': true,
  120. 'yield': true,
  121. 'await': true,
  122. 'typeof': true,
  123. 'void': true,
  124. 'instanceof': true,
  125. 'delete': true,
  126. 'in': true,
  127. 'new': true,
  128. 'of': true
  129. };
  130. /**
  131. * @param {!Object} obj
  132. * @param {!Object} p
  133. * @param {(boolean|number)} val
  134. */
  135. function mix(obj, p, val) {
  136. for (var _key5 in obj) {
  137. if (!obj.hasOwnProperty(_key5)) {
  138. break;
  139. }
  140. if (_key5 in p === false) {
  141. p[_key5] = val;
  142. }
  143. }
  144. }
  145. var symbols = void 0;
  146. var snakeskinRgxp = void 0;
  147. var uSRgxp = /[^\s/]/;
  148. var wRgxp = /[a-z]/;
  149. var sRgxp = /\s/;
  150. var nRgxp = /[\r\n]/;
  151. var posRgxp = /\${pos}/g;
  152. var objMap = {
  153. 'object': true,
  154. 'function': true
  155. };
  156. /**
  157. * Replaces all found blocks ' ... ', " ... ", ` ... `, / ... /, // ..., /* ... *\/ to
  158. * __ESCAPER_QUOT__number_ in a string and returns a new string
  159. *
  160. * @param {string} str - source string
  161. * @param {(Object<string, boolean>|boolean)=} [opt_withCommentsOrParams=false] - parameters:
  162. *
  163. * (if a parameter value is set to -1, then all found matches will be removed from the final string,
  164. * or if the value will be set to true/false they will be included/excluded)
  165. *
  166. * *) @label - template for replacement, e.g. __ESCAPER_QUOT__${pos}_
  167. * *) @all - replaces all found matches
  168. * *) @comments - replaces all kinds of comments
  169. * *) @strings - replaces all kinds of string literals
  170. * *) @literals - replaces all kinds of string literals and regular expressions
  171. * *) `
  172. * *) '
  173. * *) "
  174. * *) /
  175. * *) //
  176. * *) //*
  177. * *) //!
  178. * *) //#
  179. * *) //@
  180. * *) //$
  181. * *) /*
  182. * *) /**
  183. * *) /*!
  184. * *) /*#
  185. * *) /*@
  186. * *) /*$
  187. *
  188. * OR if the value is boolean, then will be replaced all found comments (true) / literals (false)
  189. *
  190. * @param {Array=} [opt_content=Escaper.content] - array for matches
  191. * @param {?boolean=} [opt_snakeskin] - private parameter for using with Snakeskin
  192. * @return {string}
  193. */
  194. function replace(str, opt_withCommentsOrParams, opt_content, opt_snakeskin) {
  195. symbols = symbols || Escaper.symbols || 'a-z';
  196. snakeskinRgxp = snakeskinRgxp || Escaper.snakeskinRgxp || new RegExp('[!$' + symbols + '_]', 'i');
  197. var _Escaper = Escaper,
  198. cache = _Escaper.cache,
  199. content = _Escaper.content;
  200. var isObj = Boolean(opt_withCommentsOrParams && objMap[typeof opt_withCommentsOrParams === 'undefined' ? 'undefined' : _typeof(opt_withCommentsOrParams)]);
  201. var p = isObj ? Object(opt_withCommentsOrParams) : {};
  202. function mark(pos) {
  203. if (p['@label']) {
  204. return p['@label'].replace(posRgxp, pos);
  205. }
  206. return '__ESCAPER_QUOT__' + pos + '_';
  207. }
  208. var withComments = false;
  209. if (typeof opt_withCommentsOrParams === 'boolean') {
  210. withComments = Boolean(opt_withCommentsOrParams);
  211. }
  212. if ('@comments' in p) {
  213. mix(multComments, p, p['@comments']);
  214. mix(singleComments, p, p['@comments']);
  215. delete p['@comments'];
  216. }
  217. if ('@strings' in p) {
  218. mix(stringLiterals, p, p['@strings']);
  219. delete p['@strings'];
  220. }
  221. if ('@literals' in p) {
  222. mix(literals, p, p['@literals']);
  223. delete p['@literals'];
  224. }
  225. if ('@all' in p) {
  226. mix(finalMap, p, p['@all']);
  227. delete p['@all'];
  228. }
  229. var cacheKey = '';
  230. for (var i = -1; ++i < keyArr.length;) {
  231. var el = keyArr[i];
  232. if (multComments[el] || singleComments[el]) {
  233. p[el] = withComments || p[el];
  234. } else {
  235. p[el] = p[el] || !isObj;
  236. }
  237. cacheKey += p[el] + ',';
  238. }
  239. var initStr = str,
  240. stack = opt_content || content;
  241. if (stack === content && cache[cacheKey] && cache[cacheKey][initStr]) {
  242. return cache[cacheKey][initStr];
  243. }
  244. var begin = false,
  245. end = true;
  246. var escape = false,
  247. comment = false;
  248. var selectionStart = 0,
  249. block = false;
  250. var templateVar = 0,
  251. filterStart = false;
  252. var cut = void 0,
  253. label = void 0;
  254. var part = '',
  255. rPart = '';
  256. for (var _i = -1; ++_i < str.length;) {
  257. var _el = str.charAt(_i);
  258. var next = str.charAt(_i + 1),
  259. word = str.substr(_i, 2),
  260. extWord = str.substr(_i, 3);
  261. if (!comment) {
  262. if (!begin) {
  263. if (_el === '/') {
  264. if (singleComments[word] || multComments[word]) {
  265. if (singleComments[extWord] || multComments[extWord]) {
  266. comment = extWord;
  267. } else {
  268. comment = word;
  269. }
  270. }
  271. if (comment) {
  272. selectionStart = _i;
  273. continue;
  274. }
  275. }
  276. if (escapeEndMap[_el] || escapeEndWordMap[rPart]) {
  277. end = true;
  278. rPart = '';
  279. } else if (uSRgxp.test(_el)) {
  280. end = false;
  281. }
  282. if (wRgxp.test(_el)) {
  283. part += _el;
  284. } else {
  285. rPart = part;
  286. part = '';
  287. }
  288. var skip = false;
  289. if (opt_snakeskin) {
  290. if (_el === '|' && snakeskinRgxp.test(next)) {
  291. filterStart = true;
  292. end = false;
  293. skip = true;
  294. } else if (filterStart && sRgxp.test(_el)) {
  295. filterStart = false;
  296. end = true;
  297. skip = true;
  298. }
  299. }
  300. if (!skip) {
  301. if (escapeEndMap[_el]) {
  302. end = true;
  303. } else if (uSRgxp.test(_el)) {
  304. end = false;
  305. }
  306. }
  307. }
  308. // [] inside RegExp
  309. if (begin === '/' && !escape) {
  310. if (_el === '[') {
  311. block = true;
  312. } else if (_el === ']') {
  313. block = false;
  314. }
  315. }
  316. if (!begin && templateVar) {
  317. if (_el === '}') {
  318. templateVar--;
  319. } else if (_el === '{') {
  320. templateVar++;
  321. }
  322. if (!templateVar) {
  323. _el = '`';
  324. }
  325. }
  326. if (begin === '`' && !escape && word === '${') {
  327. _el = '`';
  328. _i++;
  329. templateVar++;
  330. }
  331. if (finalMap[_el] && (_el !== '/' || end) && !begin) {
  332. begin = _el;
  333. selectionStart = _i;
  334. } else if (begin && (_el === '\\' || escape)) {
  335. escape = !escape;
  336. } else if (finalMap[_el] && begin === _el && !escape && (begin !== '/' || !block)) {
  337. if (_el === '/') {
  338. for (var j = -1; ++j < rgxpFlags.length;) {
  339. if (rgxpFlagsMap[str.charAt(_i + 1)]) {
  340. _i++;
  341. }
  342. }
  343. }
  344. begin = false;
  345. end = false;
  346. if (p[_el]) {
  347. cut = str.substring(selectionStart, _i + 1);
  348. if (p[_el] === -1) {
  349. label = '';
  350. } else {
  351. label = mark(stack.length);
  352. stack.push(cut);
  353. }
  354. str = str.substring(0, selectionStart) + label + str.substring(_i + 1);
  355. _i += label.length - cut.length;
  356. }
  357. }
  358. } else if (nRgxp.test(next) && singleComments[comment] || multComments[_el + str.charAt(_i - 1)] && _i - selectionStart > 2 && multComments[comment]) {
  359. if (p[comment]) {
  360. cut = str.substring(selectionStart, _i + 1);
  361. if (p[comment] === -1) {
  362. label = '';
  363. } else {
  364. label = mark(stack.length);
  365. stack.push(cut);
  366. }
  367. str = str.substring(0, selectionStart) + label + str.substring(_i + 1);
  368. _i += label.length - cut.length;
  369. }
  370. comment = false;
  371. }
  372. }
  373. if (stack === content) {
  374. cache[cacheKey] = cache[cacheKey] || {};
  375. cache[cacheKey][initStr] = str;
  376. }
  377. return str;
  378. }
  379. var pasteRgxp = /__ESCAPER_QUOT__(\d+)_/g;
  380. /**
  381. * Replaces all found blocks __ESCAPER_QUOT__number_ to real content in a string
  382. * and returns a new string
  383. *
  384. * @param {string} str - source string
  385. * @param {Array=} [opt_content=Escaper.content] - array of matches
  386. * @param {RegExp=} [opt_rgxp] - RegExp for searching, e.g. /__ESCAPER_QUOT__(\d+)_/g
  387. * @return {string}
  388. */
  389. function paste(str, opt_content, opt_rgxp) {
  390. return str.replace(opt_rgxp || pasteRgxp, function (str, pos) {
  391. return (opt_content || Escaper.content)[pos];
  392. });
  393. }
  394. exports['default'] = escaper;
  395. exports.replace = replace;
  396. exports.paste = paste;
  397. Object.defineProperty(exports, '__esModule', { value: true });
  398. })));