Copy it 🚀

Copy it: Listen for mouse click events, combined with Alt, Shift, and Ctrl (Windows/Linux) or Command (macOS) keys, to copy the text content or title attribute of an element, supporting snake_case, kebab-case, and PascalCase format conversion.

  1. // ==UserScript==
  2. // @name Copy it 🚀
  3. // @name:zh-CN 便捷复制 🚀
  4. // @namespace https://github.com/xianghongai/Tampermonkey-UserScript
  5. // @version 1.5.1
  6. // @description Copy it: Listen for mouse click events, combined with Alt, Shift, and Ctrl (Windows/Linux) or Command (macOS) keys, to copy the text content or title attribute of an element, supporting snake_case, kebab-case, and PascalCase format conversion.
  7. // @description:zh-CN 一键复制元素文本内容:监听鼠标点击事件,结合 Alt、Shift 和 Ctrl(Windows/Linux)或 Command(macOS)键,复制元素的文本内容或 title 属性,支持 snake_case、kebab-case、PascalCase 格式转换。
  8. // @description:zh-TW 一键複製元素文本內容:監聽鼠標點擊事件,結合 Alt、Shift 和 Ctrl(Windows/Linux)或 Command(macOS)鍵,複製元素的文本內容或 title 屬性,支持 snake_case、kebab-case、PascalCase 格式轉換。
  9. // @description:ja-JP Copy it: マウスクリックイベントをリッスンし、Alt、Shift、Ctrl (Windows/Linux) または Command (macOS) キーと組み合わせて、要素のテキストコンテンツまたは title 属性をコピーします。snake_case、kebab-case、PascalCase 形式の変換をサポートします。
  10. // @description:ko-KR Copy it: マウスクリックイベントをリッスンし、Alt、Shift、Ctrl (Windows/Linux) または Command (macOS) キーと組み合わせて、要素のテキストコンテンツまたは title 属性をコピーします。snake_case、kebab-case、PascalCase 形式の変換をサポートします。
  11. // @description:fr-FR Copy it: Écoutez les événements de clic de la souris, combinés avec les touches Alt, Shift et Ctrl (Windows/Linux) ou Command (macOS), pour copier le contenu textuel ou l'attribut title d'un élément, en supportant la conversion de format en snake_case, kebab-case et PascalCase.
  12. // @description:es-ES Copy it: Escucha eventos de clic del ratón, combinados con las teclas Alt, Shift y Ctrl (Windows/Linux) o Command (macOS), para copiar el contenido de texto o el atributo title de un elemento, admitiendo la conversión de formato a snake_case, kebab-case y PascalCase.
  13. // @description:ru-RU Copy it: Слушайте события щелчка мыши, комбинируя клавиши Alt, Shift и Ctrl (Windows/Linux) или Command (macOS), чтобы скопировать текстовое содержимое или атрибут title элемента, поддерживающего преобразование формата в snake_case, kebab-case и PascalCase.
  14. // @description:de-DE Copy it: Lauschen Sie auf Mausklick-Ereignisse, kombinieren Sie die Alt-, Shift- und Ctrl-Tasten (Windows/Linux) oder die Command-Taste (macOS), um den Textinhalt oder das title-Attribut eines Elements zu kopieren, unterstützt die Formatkonvertierung in snake_case, kebab-case und PascalCase.
  15. // @description:it-IT Copy it: Ascolta gli eventi di clic del mouse, combinando le tasti Alt, Shift e Ctrl (Windows/Linux) o Command (macOS), per copiare il contenuto testuale o l'attributo title di un elemento, supportando la conversione del formato in snake_case, kebab-case e PascalCase.
  16. // @author Nicholas Hsiang
  17. // @icon https://xinlu.ink/favicon.ico
  18. // @match http*://*/*
  19. // @exclude *://*.github.dev
  20. // @grant GM_setClipboard
  21. // @license MIT
  22. // ==/UserScript==
  23.  
  24. function main() {
  25. 'use strict';
  26.  
  27. console.log(GM_info.script.name);
  28.  
  29. /**
  30. * EN:
  31. * | Command | Description |
  32. * | ---------------------------------------------------- | --------------------------------------------------- |
  33. * | Alt + Click | Copy the text content of the element |
  34. * | Right Alt + Click | Copy the text content of the element in snake_case |
  35. * | Alt + Shift + Click | Copy the text content of the element in kebab-case |
  36. * | Alt + Ctrl(Win/Linux)/Command(macOS) + Click | Copy the text content of the element in PascalCase |
  37. * | Alt + Shift + Ctrl(Win/Linux)/Command(macOS) + Click | Copy the title attribute of the element |
  38. *
  39. */
  40.  
  41. let leftAltPressed = false;
  42. let rightAltPressed = false;
  43.  
  44. // https://www.w3schools.com/js/tryit.asp?filename=tryjs_addeventlistener_usecapture
  45. // true: capturing, 当目标元素有添加事件,停止冒泡,以致无法生效,采用捕获模式
  46. // false: bubbling,当目标元素有添加事件,并有其它交互行为 (切换视图、打开弹窗...),以致无法额外触发,采用冒泡模式
  47. document.addEventListener('click', listener, true);
  48.  
  49. // camelCase,capitalize,kebabCase,snakeCase
  50.  
  51. function listener(event) {
  52. if (event.altKey) {
  53. event.preventDefault();
  54. event.stopPropagation();
  55. let target = event?.composedPath()[0] ?? event.target;
  56. // 获取元素的文本内容
  57. let text = getText(target);
  58. const isMac = isMacOS();
  59. const isCtrlOrMetaKey = isMac ? event.metaKey : event.ctrlKey;
  60. if (rightAltPressed) {
  61. // 1. 复制为 snake_case 风格,按键:右 Alt + Click
  62. return copyTextToClipboard(_.snakeCase(text));
  63. } else if (event.shiftKey && !isCtrlOrMetaKey) {
  64. // 2. 复制为 kebab-case 风格,按键:Alt + Shift + Click
  65. return copyTextToClipboard(_.kebabCase(text));
  66. } else if (!event.shiftKey && isCtrlOrMetaKey) {
  67. // 3. 复制为 PascalCase 风格,按键:Alt + Ctrl(Win/Linux)/Command(macOS) + Click
  68. return copyTextToClipboard(pascalCase(text));
  69. } else if (event.shiftKey && isCtrlOrMetaKey) {
  70. // 4. 复制元素的 title 属性,按键:Alt + Shift + Ctrl(Win/Linux)/Command(macOS) + Click
  71. text = event.target.title;
  72. return copyTextToClipboard(text);
  73. }
  74. // 0. 复制为纯文本,按键:Alt + Click
  75. return copyTextToClipboard(text);
  76. }
  77. }
  78.  
  79. const VALUE_CONTROLLER = ['INPUT', 'TEXTAREA'];
  80.  
  81. function getText(el) {
  82. let text = '';
  83. if (VALUE_CONTROLLER.includes(el.tagName)) {
  84. const value = `${el.value}`.trim();
  85. const placeholder = el.placeholder ?? '';
  86. text = value === '' ? placeholder : value;
  87. } else if (el.tagName === 'SELECT') {
  88. const selectedOption = el.options[el.selectedIndex];
  89. text = selectedOption.text;
  90. } else if (el.tagName === 'tspan') {
  91. // svg/text/tspan
  92. text = [...el.parentElement.querySelectorAll('tspan')].reduce((acc, cur) => `${acc} ${cur.textContent}`, '')
  93. } else {
  94.  
  95. text = el.innerText;
  96. }
  97. return text.trim();
  98. }
  99.  
  100. function copyTextToClipboard(text) {
  101. GM_setClipboard(text, 'text');
  102. }
  103.  
  104. function pascalCase(input) {
  105. return _.upperFirst(_.camelCase(input));
  106. }
  107.  
  108. // 监听 Alt 键状态
  109. document.addEventListener('keydown', (event) => {
  110. if (event.key === 'Alt') {
  111. event.preventDefault();
  112. if (event.location === 1) leftAltPressed = true;
  113. if (event.location === 2) rightAltPressed = true;
  114. }
  115. });
  116.  
  117. document.addEventListener('keyup', (event) => {
  118. if (event.key === 'Alt') {
  119. if (event.location === 1) leftAltPressed = false;
  120. if (event.location === 2) rightAltPressed = false;
  121. }
  122. });
  123.  
  124. // 浏览器兼容性处理
  125. function isAltPressed(event) {
  126. // 降级处理
  127. return event.altKey || event.keyCode === 18 || event.key === 'Alt';
  128. }
  129.  
  130. function keydown(event) {
  131. // 在 macOS 上,Option (ALT) 键有特殊功能,它用于输入特殊字符和符号。
  132. // 按下 Option+T 时,macOS 可能将其解释为一个特殊字符输入,而不是单纯的修饰键+字母组合,
  133. // 这就导致 JavaScript 事件系统接收到的不是标准的按键事件,而是 "Unidentified"。
  134. // event.code 表示物理按键的位置,与键盘布局无关。
  135. if (event.altKey && event.code === 'KeyT') {
  136. copyTextToClipboard(location.href);
  137. event.preventDefault();
  138. event.stopPropagation();
  139. }
  140. }
  141.  
  142. document.addEventListener('keydown', keydown, true);
  143. }
  144.  
  145. function isMacOS() {
  146. const userAgent = navigator.userAgent.toLowerCase();
  147. return userAgent.includes('mac') && !userAgent.includes('iphone') && !userAgent.includes('ipad');
  148. }
  149.  
  150. /**
  151. * @license
  152. * Lodash (Custom Build) <https://lodash.com/>
  153. * Build: `lodash include="camelCase,capitalize,kebabCase,snakeCase,"`
  154. * Copyright JS Foundation and other contributors <https://js.foundation/>
  155. * Released under MIT license <https://lodash.com/license>
  156. * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
  157. * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
  158. */
  159. ; (function () {
  160.  
  161. /** Used as a safe reference for `undefined` in pre-ES5 environments. */
  162. var undefined;
  163.  
  164. /** Used as the semantic version number. */
  165. var VERSION = '4.17.5';
  166.  
  167. /** Used as references for various `Number` constants. */
  168. var INFINITY = 1 / 0;
  169.  
  170. /** `Object#toString` result references. */
  171. var nullTag = '[object Null]',
  172. symbolTag = '[object Symbol]',
  173. undefinedTag = '[object Undefined]';
  174.  
  175. /** Used to match words composed of alphanumeric characters. */
  176. var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
  177.  
  178. /** Used to match Latin Unicode letters (excluding mathematical operators). */
  179. var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
  180.  
  181. /** Used to compose unicode character classes. */
  182. var rsAstralRange = '\\ud800-\\udfff',
  183. rsComboMarksRange = '\\u0300-\\u036f',
  184. reComboHalfMarksRange = '\\ufe20-\\ufe2f',
  185. rsComboSymbolsRange = '\\u20d0-\\u20ff',
  186. rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
  187. rsDingbatRange = '\\u2700-\\u27bf',
  188. rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
  189. rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
  190. rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
  191. rsPunctuationRange = '\\u2000-\\u206f',
  192. rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
  193. rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
  194. rsVarRange = '\\ufe0e\\ufe0f',
  195. rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
  196.  
  197. /** Used to compose unicode capture groups. */
  198. var rsApos = "['\u2019]",
  199. rsAstral = '[' + rsAstralRange + ']',
  200. rsBreak = '[' + rsBreakRange + ']',
  201. rsCombo = '[' + rsComboRange + ']',
  202. rsDigits = '\\d+',
  203. rsDingbat = '[' + rsDingbatRange + ']',
  204. rsLower = '[' + rsLowerRange + ']',
  205. rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
  206. rsFitz = '\\ud83c[\\udffb-\\udfff]',
  207. rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
  208. rsNonAstral = '[^' + rsAstralRange + ']',
  209. rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
  210. rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
  211. rsUpper = '[' + rsUpperRange + ']',
  212. rsZWJ = '\\u200d';
  213.  
  214. /** Used to compose unicode regexes. */
  215. var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
  216. rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
  217. rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
  218. rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
  219. reOptMod = rsModifier + '?',
  220. rsOptVar = '[' + rsVarRange + ']?',
  221. rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
  222. rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
  223. rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
  224. rsSeq = rsOptVar + reOptMod + rsOptJoin,
  225. rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
  226. rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
  227.  
  228. /** Used to match apostrophes. */
  229. var reApos = RegExp(rsApos, 'g');
  230.  
  231. /**
  232. * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
  233. * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
  234. */
  235. var reComboMark = RegExp(rsCombo, 'g');
  236.  
  237. /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
  238. var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
  239.  
  240. /** Used to match complex or compound words. */
  241. var reUnicodeWord = RegExp([
  242. rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
  243. rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
  244. rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
  245. rsUpper + '+' + rsOptContrUpper,
  246. rsOrdUpper,
  247. rsOrdLower,
  248. rsDigits,
  249. rsEmoji
  250. ].join('|'), 'g');
  251.  
  252. /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
  253. var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
  254.  
  255. /** Used to detect strings that need a more robust regexp to match words. */
  256. var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
  257.  
  258. /** Used to map Latin Unicode letters to basic Latin letters. */
  259. var deburredLetters = {
  260. // Latin-1 Supplement block.
  261. '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
  262. '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
  263. '\xc7': 'C', '\xe7': 'c',
  264. '\xd0': 'D', '\xf0': 'd',
  265. '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
  266. '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
  267. '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
  268. '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
  269. '\xd1': 'N', '\xf1': 'n',
  270. '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
  271. '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
  272. '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
  273. '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
  274. '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
  275. '\xc6': 'Ae', '\xe6': 'ae',
  276. '\xde': 'Th', '\xfe': 'th',
  277. '\xdf': 'ss',
  278. // Latin Extended-A block.
  279. '\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
  280. '\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
  281. '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
  282. '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
  283. '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
  284. '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
  285. '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
  286. '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
  287. '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
  288. '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
  289. '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
  290. '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
  291. '\u0134': 'J', '\u0135': 'j',
  292. '\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
  293. '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
  294. '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
  295. '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
  296. '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
  297. '\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
  298. '\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
  299. '\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
  300. '\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
  301. '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
  302. '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
  303. '\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
  304. '\u0163': 't', '\u0165': 't', '\u0167': 't',
  305. '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
  306. '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
  307. '\u0174': 'W', '\u0175': 'w',
  308. '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
  309. '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
  310. '\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
  311. '\u0132': 'IJ', '\u0133': 'ij',
  312. '\u0152': 'Oe', '\u0153': 'oe',
  313. '\u0149': "'n", '\u017f': 's'
  314. };
  315.  
  316. /** Detect free variable `global` from Node.js. */
  317. var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
  318.  
  319. /** Detect free variable `self`. */
  320. var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
  321.  
  322. /** Used as a reference to the global object. */
  323. var root = freeGlobal || freeSelf || Function('return this')();
  324.  
  325. /** Detect free variable `exports`. */
  326. var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
  327.  
  328. /** Detect free variable `module`. */
  329. var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
  330.  
  331. /*--------------------------------------------------------------------------*/
  332.  
  333. /**
  334. * A specialized version of `_.map` for arrays without support for iteratee
  335. * shorthands.
  336. *
  337. * @private
  338. * @param {Array} [array] The array to iterate over.
  339. * @param {Function} iteratee The function invoked per iteration.
  340. * @returns {Array} Returns the new mapped array.
  341. */
  342. function arrayMap(array, iteratee) {
  343. var index = -1,
  344. length = array == null ? 0 : array.length,
  345. result = Array(length);
  346.  
  347. while (++index < length) {
  348. result[index] = iteratee(array[index], index, array);
  349. }
  350. return result;
  351. }
  352.  
  353. /**
  354. * A specialized version of `_.reduce` for arrays without support for
  355. * iteratee shorthands.
  356. *
  357. * @private
  358. * @param {Array} [array] The array to iterate over.
  359. * @param {Function} iteratee The function invoked per iteration.
  360. * @param {*} [accumulator] The initial value.
  361. * @param {boolean} [initAccum] Specify using the first element of `array` as
  362. * the initial value.
  363. * @returns {*} Returns the accumulated value.
  364. */
  365. function arrayReduce(array, iteratee, accumulator, initAccum) {
  366. var index = -1,
  367. length = array == null ? 0 : array.length;
  368.  
  369. if (initAccum && length) {
  370. accumulator = array[++index];
  371. }
  372. while (++index < length) {
  373. accumulator = iteratee(accumulator, array[index], index, array);
  374. }
  375. return accumulator;
  376. }
  377.  
  378. /**
  379. * Converts an ASCII `string` to an array.
  380. *
  381. * @private
  382. * @param {string} string The string to convert.
  383. * @returns {Array} Returns the converted array.
  384. */
  385. function asciiToArray(string) {
  386. return string.split('');
  387. }
  388.  
  389. /**
  390. * Splits an ASCII `string` into an array of its words.
  391. *
  392. * @private
  393. * @param {string} The string to inspect.
  394. * @returns {Array} Returns the words of `string`.
  395. */
  396. function asciiWords(string) {
  397. return string.match(reAsciiWord) || [];
  398. }
  399.  
  400. /**
  401. * The base implementation of `_.propertyOf` without support for deep paths.
  402. *
  403. * @private
  404. * @param {Object} object The object to query.
  405. * @returns {Function} Returns the new accessor function.
  406. */
  407. function basePropertyOf(object) {
  408. return function (key) {
  409. return object == null ? undefined : object[key];
  410. };
  411. }
  412.  
  413. /**
  414. * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
  415. * letters to basic Latin letters.
  416. *
  417. * @private
  418. * @param {string} letter The matched letter to deburr.
  419. * @returns {string} Returns the deburred letter.
  420. */
  421. var deburrLetter = basePropertyOf(deburredLetters);
  422.  
  423. /**
  424. * Checks if `string` contains Unicode symbols.
  425. *
  426. * @private
  427. * @param {string} string The string to inspect.
  428. * @returns {boolean} Returns `true` if a symbol is found, else `false`.
  429. */
  430. function hasUnicode(string) {
  431. return reHasUnicode.test(string);
  432. }
  433.  
  434. /**
  435. * Checks if `string` contains a word composed of Unicode symbols.
  436. *
  437. * @private
  438. * @param {string} string The string to inspect.
  439. * @returns {boolean} Returns `true` if a word is found, else `false`.
  440. */
  441. function hasUnicodeWord(string) {
  442. return reHasUnicodeWord.test(string);
  443. }
  444.  
  445. /**
  446. * Converts `string` to an array.
  447. *
  448. * @private
  449. * @param {string} string The string to convert.
  450. * @returns {Array} Returns the converted array.
  451. */
  452. function stringToArray(string) {
  453. return hasUnicode(string)
  454. ? unicodeToArray(string)
  455. : asciiToArray(string);
  456. }
  457.  
  458. /**
  459. * Converts a Unicode `string` to an array.
  460. *
  461. * @private
  462. * @param {string} string The string to convert.
  463. * @returns {Array} Returns the converted array.
  464. */
  465. function unicodeToArray(string) {
  466. return string.match(reUnicode) || [];
  467. }
  468.  
  469. /**
  470. * Splits a Unicode `string` into an array of its words.
  471. *
  472. * @private
  473. * @param {string} The string to inspect.
  474. * @returns {Array} Returns the words of `string`.
  475. */
  476. function unicodeWords(string) {
  477. return string.match(reUnicodeWord) || [];
  478. }
  479.  
  480. /*--------------------------------------------------------------------------*/
  481.  
  482. /** Used for built-in method references. */
  483. var objectProto = Object.prototype;
  484.  
  485. /** Used to check objects for own properties. */
  486. var hasOwnProperty = objectProto.hasOwnProperty;
  487.  
  488. /**
  489. * Used to resolve the
  490. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  491. * of values.
  492. */
  493. var nativeObjectToString = objectProto.toString;
  494.  
  495. /** Built-in value references. */
  496. var Symbol = root.Symbol,
  497. symToStringTag = Symbol ? Symbol.toStringTag : undefined;
  498.  
  499. /** Used to lookup unminified function names. */
  500. var realNames = {};
  501.  
  502. /** Used to convert symbols to primitives and strings. */
  503. var symbolProto = Symbol ? Symbol.prototype : undefined,
  504. symbolToString = symbolProto ? symbolProto.toString : undefined;
  505.  
  506. /*------------------------------------------------------------------------*/
  507.  
  508. /**
  509. * Creates a `lodash` object which wraps `value` to enable implicit method
  510. * chain sequences. Methods that operate on and return arrays, collections,
  511. * and functions can be chained together. Methods that retrieve a single value
  512. * or may return a primitive value will automatically end the chain sequence
  513. * and return the unwrapped value. Otherwise, the value must be unwrapped
  514. * with `_#value`.
  515. *
  516. * Explicit chain sequences, which must be unwrapped with `_#value`, may be
  517. * enabled using `_.chain`.
  518. *
  519. * The execution of chained methods is lazy, that is, it's deferred until
  520. * `_#value` is implicitly or explicitly called.
  521. *
  522. * Lazy evaluation allows several methods to support shortcut fusion.
  523. * Shortcut fusion is an optimization to merge iteratee calls; this avoids
  524. * the creation of intermediate arrays and can greatly reduce the number of
  525. * iteratee executions. Sections of a chain sequence qualify for shortcut
  526. * fusion if the section is applied to an array and iteratees accept only
  527. * one argument. The heuristic for whether a section qualifies for shortcut
  528. * fusion is subject to change.
  529. *
  530. * Chaining is supported in custom builds as long as the `_#value` method is
  531. * directly or indirectly included in the build.
  532. *
  533. * In addition to lodash methods, wrappers have `Array` and `String` methods.
  534. *
  535. * The wrapper `Array` methods are:
  536. * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
  537. *
  538. * The wrapper `String` methods are:
  539. * `replace` and `split`
  540. *
  541. * The wrapper methods that support shortcut fusion are:
  542. * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
  543. * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
  544. * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
  545. *
  546. * The chainable wrapper methods are:
  547. * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
  548. * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
  549. * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
  550. * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
  551. * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
  552. * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
  553. * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
  554. * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
  555. * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
  556. * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
  557. * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
  558. * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
  559. * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
  560. * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
  561. * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
  562. * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
  563. * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
  564. * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
  565. * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
  566. * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
  567. * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
  568. * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
  569. * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
  570. * `zipObject`, `zipObjectDeep`, and `zipWith`
  571. *
  572. * The wrapper methods that are **not** chainable by default are:
  573. * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
  574. * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
  575. * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
  576. * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
  577. * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
  578. * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
  579. * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
  580. * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
  581. * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
  582. * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
  583. * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
  584. * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
  585. * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
  586. * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
  587. * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
  588. * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
  589. * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
  590. * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
  591. * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
  592. * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
  593. * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
  594. * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
  595. * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
  596. * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
  597. * `upperFirst`, `value`, and `words`
  598. *
  599. * @name _
  600. * @constructor
  601. * @category Seq
  602. * @param {*} value The value to wrap in a `lodash` instance.
  603. * @returns {Object} Returns the new `lodash` wrapper instance.
  604. * @example
  605. *
  606. * function square(n) {
  607. * return n * n;
  608. * }
  609. *
  610. * var wrapped = _([1, 2, 3]);
  611. *
  612. * // Returns an unwrapped value.
  613. * wrapped.reduce(_.add);
  614. * // => 6
  615. *
  616. * // Returns a wrapped value.
  617. * var squares = wrapped.map(square);
  618. *
  619. * _.isArray(squares);
  620. * // => false
  621. *
  622. * _.isArray(squares.value());
  623. * // => true
  624. */
  625. function lodash() {
  626. // No operation performed.
  627. }
  628.  
  629. /*------------------------------------------------------------------------*/
  630.  
  631. /**
  632. * The base implementation of `getTag` without fallbacks for buggy environments.
  633. *
  634. * @private
  635. * @param {*} value The value to query.
  636. * @returns {string} Returns the `toStringTag`.
  637. */
  638. function baseGetTag(value) {
  639. if (value == null) {
  640. return value === undefined ? undefinedTag : nullTag;
  641. }
  642. return (symToStringTag && symToStringTag in Object(value))
  643. ? getRawTag(value)
  644. : objectToString(value);
  645. }
  646.  
  647. /**
  648. * The base implementation of `_.slice` without an iteratee call guard.
  649. *
  650. * @private
  651. * @param {Array} array The array to slice.
  652. * @param {number} [start=0] The start position.
  653. * @param {number} [end=array.length] The end position.
  654. * @returns {Array} Returns the slice of `array`.
  655. */
  656. function baseSlice(array, start, end) {
  657. var index = -1,
  658. length = array.length;
  659.  
  660. if (start < 0) {
  661. start = -start > length ? 0 : (length + start);
  662. }
  663. end = end > length ? length : end;
  664. if (end < 0) {
  665. end += length;
  666. }
  667. length = start > end ? 0 : ((end - start) >>> 0);
  668. start >>>= 0;
  669.  
  670. var result = Array(length);
  671. while (++index < length) {
  672. result[index] = array[index + start];
  673. }
  674. return result;
  675. }
  676.  
  677. /**
  678. * The base implementation of `_.toString` which doesn't convert nullish
  679. * values to empty strings.
  680. *
  681. * @private
  682. * @param {*} value The value to process.
  683. * @returns {string} Returns the string.
  684. */
  685. function baseToString(value) {
  686. // Exit early for strings to avoid a performance hit in some environments.
  687. if (typeof value == 'string') {
  688. return value;
  689. }
  690. if (isArray(value)) {
  691. // Recursively convert values (susceptible to call stack limits).
  692. return arrayMap(value, baseToString) + '';
  693. }
  694. if (isSymbol(value)) {
  695. return symbolToString ? symbolToString.call(value) : '';
  696. }
  697. var result = (value + '');
  698. return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
  699. }
  700.  
  701. /**
  702. * Casts `array` to a slice if it's needed.
  703. *
  704. * @private
  705. * @param {Array} array The array to inspect.
  706. * @param {number} start The start position.
  707. * @param {number} [end=array.length] The end position.
  708. * @returns {Array} Returns the cast slice.
  709. */
  710. function castSlice(array, start, end) {
  711. var length = array.length;
  712. end = end === undefined ? length : end;
  713. return (!start && end >= length) ? array : baseSlice(array, start, end);
  714. }
  715.  
  716. /**
  717. * Creates a function like `_.lowerFirst`.
  718. *
  719. * @private
  720. * @param {string} methodName The name of the `String` case method to use.
  721. * @returns {Function} Returns the new case function.
  722. */
  723. function createCaseFirst(methodName) {
  724. return function (string) {
  725. string = toString(string);
  726.  
  727. var strSymbols = hasUnicode(string)
  728. ? stringToArray(string)
  729. : undefined;
  730.  
  731. var chr = strSymbols
  732. ? strSymbols[0]
  733. : string.charAt(0);
  734.  
  735. var trailing = strSymbols
  736. ? castSlice(strSymbols, 1).join('')
  737. : string.slice(1);
  738.  
  739. return chr[methodName]() + trailing;
  740. };
  741. }
  742.  
  743. /**
  744. * Creates a function like `_.camelCase`.
  745. *
  746. * @private
  747. * @param {Function} callback The function to combine each word.
  748. * @returns {Function} Returns the new compounder function.
  749. */
  750. function createCompounder(callback) {
  751. return function (string) {
  752. return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
  753. };
  754. }
  755.  
  756. /**
  757. * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
  758. *
  759. * @private
  760. * @param {*} value The value to query.
  761. * @returns {string} Returns the raw `toStringTag`.
  762. */
  763. function getRawTag(value) {
  764. var isOwn = hasOwnProperty.call(value, symToStringTag),
  765. tag = value[symToStringTag];
  766.  
  767. try {
  768. value[symToStringTag] = undefined;
  769. var unmasked = true;
  770. } catch (e) { }
  771.  
  772. var result = nativeObjectToString.call(value);
  773. if (unmasked) {
  774. if (isOwn) {
  775. value[symToStringTag] = tag;
  776. } else {
  777. delete value[symToStringTag];
  778. }
  779. }
  780. return result;
  781. }
  782.  
  783. /**
  784. * Converts `value` to a string using `Object.prototype.toString`.
  785. *
  786. * @private
  787. * @param {*} value The value to convert.
  788. * @returns {string} Returns the converted string.
  789. */
  790. function objectToString(value) {
  791. return nativeObjectToString.call(value);
  792. }
  793.  
  794. /*------------------------------------------------------------------------*/
  795.  
  796. /**
  797. * Checks if `value` is classified as an `Array` object.
  798. *
  799. * @static
  800. * @memberOf _
  801. * @since 0.1.0
  802. * @category Lang
  803. * @param {*} value The value to check.
  804. * @returns {boolean} Returns `true` if `value` is an array, else `false`.
  805. * @example
  806. *
  807. * _.isArray([1, 2, 3]);
  808. * // => true
  809. *
  810. * _.isArray(document.body.children);
  811. * // => false
  812. *
  813. * _.isArray('abc');
  814. * // => false
  815. *
  816. * _.isArray(_.noop);
  817. * // => false
  818. */
  819. var isArray = Array.isArray;
  820.  
  821. /**
  822. * Checks if `value` is object-like. A value is object-like if it's not `null`
  823. * and has a `typeof` result of "object".
  824. *
  825. * @static
  826. * @memberOf _
  827. * @since 4.0.0
  828. * @category Lang
  829. * @param {*} value The value to check.
  830. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  831. * @example
  832. *
  833. * _.isObjectLike({});
  834. * // => true
  835. *
  836. * _.isObjectLike([1, 2, 3]);
  837. * // => true
  838. *
  839. * _.isObjectLike(_.noop);
  840. * // => false
  841. *
  842. * _.isObjectLike(null);
  843. * // => false
  844. */
  845. function isObjectLike(value) {
  846. return value != null && typeof value == 'object';
  847. }
  848.  
  849. /**
  850. * Checks if `value` is classified as a `Symbol` primitive or object.
  851. *
  852. * @static
  853. * @memberOf _
  854. * @since 4.0.0
  855. * @category Lang
  856. * @param {*} value The value to check.
  857. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
  858. * @example
  859. *
  860. * _.isSymbol(Symbol.iterator);
  861. * // => true
  862. *
  863. * _.isSymbol('abc');
  864. * // => false
  865. */
  866. function isSymbol(value) {
  867. return typeof value == 'symbol' ||
  868. (isObjectLike(value) && baseGetTag(value) == symbolTag);
  869. }
  870.  
  871. /**
  872. * Converts `value` to a string. An empty string is returned for `null`
  873. * and `undefined` values. The sign of `-0` is preserved.
  874. *
  875. * @static
  876. * @memberOf _
  877. * @since 4.0.0
  878. * @category Lang
  879. * @param {*} value The value to convert.
  880. * @returns {string} Returns the converted string.
  881. * @example
  882. *
  883. * _.toString(null);
  884. * // => ''
  885. *
  886. * _.toString(-0);
  887. * // => '-0'
  888. *
  889. * _.toString([1, 2, 3]);
  890. * // => '1,2,3'
  891. */
  892. function toString(value) {
  893. return value == null ? '' : baseToString(value);
  894. }
  895.  
  896. /*------------------------------------------------------------------------*/
  897.  
  898. /**
  899. * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
  900. *
  901. * @static
  902. * @memberOf _
  903. * @since 3.0.0
  904. * @category String
  905. * @param {string} [string=''] The string to convert.
  906. * @returns {string} Returns the camel cased string.
  907. * @example
  908. *
  909. * _.camelCase('Foo Bar');
  910. * // => 'fooBar'
  911. *
  912. * _.camelCase('--foo-bar--');
  913. * // => 'fooBar'
  914. *
  915. * _.camelCase('__FOO_BAR__');
  916. * // => 'fooBar'
  917. */
  918. var camelCase = createCompounder(function (result, word, index) {
  919. word = word.toLowerCase();
  920. return result + (index ? capitalize(word) : word);
  921. });
  922.  
  923. /**
  924. * Converts the first character of `string` to upper case and the remaining
  925. * to lower case.
  926. *
  927. * @static
  928. * @memberOf _
  929. * @since 3.0.0
  930. * @category String
  931. * @param {string} [string=''] The string to capitalize.
  932. * @returns {string} Returns the capitalized string.
  933. * @example
  934. *
  935. * _.capitalize('FRED');
  936. * // => 'Fred'
  937. */
  938. function capitalize(string) {
  939. return upperFirst(toString(string).toLowerCase());
  940. }
  941.  
  942. /**
  943. * Deburrs `string` by converting
  944. * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
  945. * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
  946. * letters to basic Latin letters and removing
  947. * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
  948. *
  949. * @static
  950. * @memberOf _
  951. * @since 3.0.0
  952. * @category String
  953. * @param {string} [string=''] The string to deburr.
  954. * @returns {string} Returns the deburred string.
  955. * @example
  956. *
  957. * _.deburr('déjà vu');
  958. * // => 'deja vu'
  959. */
  960. function deburr(string) {
  961. string = toString(string);
  962. return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
  963. }
  964.  
  965. /**
  966. * Converts `string` to
  967. * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
  968. *
  969. * @static
  970. * @memberOf _
  971. * @since 3.0.0
  972. * @category String
  973. * @param {string} [string=''] The string to convert.
  974. * @returns {string} Returns the kebab cased string.
  975. * @example
  976. *
  977. * _.kebabCase('Foo Bar');
  978. * // => 'foo-bar'
  979. *
  980. * _.kebabCase('fooBar');
  981. * // => 'foo-bar'
  982. *
  983. * _.kebabCase('__FOO_BAR__');
  984. * // => 'foo-bar'
  985. */
  986. var kebabCase = createCompounder(function (result, word, index) {
  987. return result + (index ? '-' : '') + word.toLowerCase();
  988. });
  989.  
  990. /**
  991. * Converts `string` to
  992. * [snake case](https://en.wikipedia.org/wiki/Snake_case).
  993. *
  994. * @static
  995. * @memberOf _
  996. * @since 3.0.0
  997. * @category String
  998. * @param {string} [string=''] The string to convert.
  999. * @returns {string} Returns the snake cased string.
  1000. * @example
  1001. *
  1002. * _.snakeCase('Foo Bar');
  1003. * // => 'foo_bar'
  1004. *
  1005. * _.snakeCase('fooBar');
  1006. * // => 'foo_bar'
  1007. *
  1008. * _.snakeCase('--FOO-BAR--');
  1009. * // => 'foo_bar'
  1010. */
  1011. var snakeCase = createCompounder(function (result, word, index) {
  1012. return result + (index ? '_' : '') + word.toLowerCase();
  1013. });
  1014.  
  1015. /**
  1016. * Converts the first character of `string` to upper case.
  1017. *
  1018. * @static
  1019. * @memberOf _
  1020. * @since 4.0.0
  1021. * @category String
  1022. * @param {string} [string=''] The string to convert.
  1023. * @returns {string} Returns the converted string.
  1024. * @example
  1025. *
  1026. * _.upperFirst('fred');
  1027. * // => 'Fred'
  1028. *
  1029. * _.upperFirst('FRED');
  1030. * // => 'FRED'
  1031. */
  1032. var upperFirst = createCaseFirst('toUpperCase');
  1033.  
  1034. /**
  1035. * Splits `string` into an array of its words.
  1036. *
  1037. * @static
  1038. * @memberOf _
  1039. * @since 3.0.0
  1040. * @category String
  1041. * @param {string} [string=''] The string to inspect.
  1042. * @param {RegExp|string} [pattern] The pattern to match words.
  1043. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
  1044. * @returns {Array} Returns the words of `string`.
  1045. * @example
  1046. *
  1047. * _.words('fred, barney, & pebbles');
  1048. * // => ['fred', 'barney', 'pebbles']
  1049. *
  1050. * _.words('fred, barney, & pebbles', /[^, ]+/g);
  1051. * // => ['fred', 'barney', '&', 'pebbles']
  1052. */
  1053. function words(string, pattern, guard) {
  1054. string = toString(string);
  1055. pattern = guard ? undefined : pattern;
  1056.  
  1057. if (pattern === undefined) {
  1058. return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
  1059. }
  1060. return string.match(pattern) || [];
  1061. }
  1062.  
  1063. /*------------------------------------------------------------------------*/
  1064.  
  1065. // Add methods that return wrapped values in chain sequences.
  1066. lodash.words = words;
  1067.  
  1068. /*------------------------------------------------------------------------*/
  1069.  
  1070. // Add methods that return unwrapped values in chain sequences.
  1071. lodash.camelCase = camelCase;
  1072. lodash.capitalize = capitalize;
  1073. lodash.deburr = deburr;
  1074. lodash.isArray = isArray;
  1075. lodash.isObjectLike = isObjectLike;
  1076. lodash.isSymbol = isSymbol;
  1077. lodash.kebabCase = kebabCase;
  1078. lodash.snakeCase = snakeCase;
  1079. lodash.toString = toString;
  1080. lodash.upperFirst = upperFirst;
  1081.  
  1082. /*------------------------------------------------------------------------*/
  1083.  
  1084. /**
  1085. * The semantic version number.
  1086. *
  1087. * @static
  1088. * @memberOf _
  1089. * @type {string}
  1090. */
  1091. lodash.VERSION = VERSION;
  1092.  
  1093. /*--------------------------------------------------------------------------*/
  1094.  
  1095. // Some AMD build optimizers, like r.js, check for condition patterns like:
  1096. if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
  1097. // Expose Lodash on the global object to prevent errors when Lodash is
  1098. // loaded by a script tag in the presence of an AMD loader.
  1099. // See http://requirejs.org/docs/errors.html#mismatch for more details.
  1100. // Use `_.noConflict` to remove Lodash from the global object.
  1101. root._ = lodash;
  1102.  
  1103. // Define as an anonymous module so, through path mapping, it can be
  1104. // referenced as the "underscore" module.
  1105. define(function () {
  1106. return lodash;
  1107. });
  1108. }
  1109. // Check for `exports` after `define` in case a build optimizer adds it.
  1110. else if (freeModule) {
  1111. // Export for Node.js.
  1112. (freeModule.exports = lodash)._ = lodash;
  1113. // Export for CommonJS support.
  1114. freeExports._ = lodash;
  1115. }
  1116. else {
  1117. // Export to the global object.
  1118. root._ = lodash;
  1119. }
  1120. }.call(this));
  1121.  
  1122. (function () {
  1123. main();
  1124. })();