PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/grunt/node_modules/findup-sync/node_modules/lodash/build.js

https://bitbucket.org/biojazzard/gantry-eboracast
JavaScript | 2509 lines | 1975 code | 107 blank | 427 comment | 61 complexity | e1448a92e58938cdb14eaa98aebe80a4 MD5 | raw file
Possible License(s): MIT, JSON, BSD-2-Clause, Unlicense, GPL-2.0, WTFPL, LGPL-3.0, Apache-2.0, 0BSD, BSD-3-Clause, CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env node
  2. ;(function() {
  3. 'use strict';
  4. /** Load modules */
  5. var fs = require('fs'),
  6. path = require('path'),
  7. vm = require('vm'),
  8. minify = require(path.join(__dirname, 'build', 'minify.js')),
  9. _ = require(path.join(__dirname, 'lodash.js'));
  10. /** The current working directory */
  11. var cwd = process.cwd();
  12. /** Used for array method references */
  13. var arrayRef = [];
  14. /** Shortcut used to push arrays of values to an array */
  15. var push = arrayRef.push;
  16. /** Shortcut used to convert array-like objects to arrays */
  17. var slice = arrayRef.slice;
  18. /** Shortcut to the `stdout` object */
  19. var stdout = process.stdout;
  20. /** Used to associate aliases with their real names */
  21. var aliasToRealMap = {
  22. 'all': 'every',
  23. 'any': 'some',
  24. 'collect': 'map',
  25. 'detect': 'find',
  26. 'drop': 'rest',
  27. 'each': 'forEach',
  28. 'extend': 'assign',
  29. 'foldl': 'reduce',
  30. 'foldr': 'reduceRight',
  31. 'head': 'first',
  32. 'include': 'contains',
  33. 'inject': 'reduce',
  34. 'methods': 'functions',
  35. 'select': 'filter',
  36. 'tail': 'rest',
  37. 'take': 'first',
  38. 'unique': 'uniq'
  39. };
  40. /** Used to associate real names with their aliases */
  41. var realToAliasMap = {
  42. 'assign': ['extend'],
  43. 'contains': ['include'],
  44. 'every': ['all'],
  45. 'filter': ['select'],
  46. 'find': ['detect'],
  47. 'first': ['head', 'take'],
  48. 'forEach': ['each'],
  49. 'functions': ['methods'],
  50. 'map': ['collect'],
  51. 'reduce': ['foldl', 'inject'],
  52. 'reduceRight': ['foldr'],
  53. 'rest': ['drop', 'tail'],
  54. 'some': ['any'],
  55. 'uniq': ['unique']
  56. };
  57. /** Used to track function dependencies */
  58. var dependencyMap = {
  59. 'after': [],
  60. 'assign': ['isArray', 'forEach', 'forOwn'],
  61. 'at': ['isString'],
  62. 'bind': ['isFunction', 'isObject'],
  63. 'bindAll': ['bind', 'functions'],
  64. 'bindKey': ['isFunction', 'isObject'],
  65. 'clone': ['assign', 'forEach', 'forOwn', 'isArray', 'isObject'],
  66. 'cloneDeep': ['clone'],
  67. 'compact': [],
  68. 'compose': [],
  69. 'contains': ['indexOf', 'isString'],
  70. 'countBy': ['forEach', 'identity', 'isEqual', 'keys'],
  71. 'debounce': [],
  72. 'defaults': ['isArray', 'forEach', 'forOwn'],
  73. 'defer': ['bind'],
  74. 'delay': [],
  75. 'difference': ['indexOf'],
  76. 'escape': [],
  77. 'every': ['identity', 'isArray', 'isEqual', 'keys'],
  78. 'filter': ['identity', 'isArray', 'isEqual', 'keys'],
  79. 'find': ['forEach', 'identity', 'isEqual', 'keys'],
  80. 'first': [],
  81. 'flatten': ['isArray'],
  82. 'forEach': ['identity', 'isArguments', 'isArray', 'isString'],
  83. 'forIn': ['identity', 'isArguments'],
  84. 'forOwn': ['identity', 'isArguments'],
  85. 'functions': ['forIn', 'isFunction'],
  86. 'groupBy': ['forEach', 'identity', 'isEqual', 'keys'],
  87. 'has': [],
  88. 'identity': [],
  89. 'indexOf': ['sortedIndex'],
  90. 'initial': [],
  91. 'intersection': ['indexOf'],
  92. 'invert': ['keys'],
  93. 'invoke': ['forEach'],
  94. 'isArguments': [],
  95. 'isArray': [],
  96. 'isBoolean': [],
  97. 'isDate': [],
  98. 'isElement': [],
  99. 'isEmpty': ['forOwn', 'isArguments', 'isFunction'],
  100. 'isEqual': ['forIn', 'isArguments', 'isFunction'],
  101. 'isFinite': [],
  102. 'isFunction': [],
  103. 'isNaN': ['isNumber'],
  104. 'isNull': [],
  105. 'isNumber': [],
  106. 'isObject': [],
  107. 'isPlainObject': ['forIn', 'isArguments', 'isFunction'],
  108. 'isRegExp': [],
  109. 'isString': [],
  110. 'isUndefined': [],
  111. 'keys': ['forOwn', 'isArguments', 'isObject'],
  112. 'last': [],
  113. 'lastIndexOf': [],
  114. 'map': ['identity', 'isArray', 'isEqual', 'keys'],
  115. 'max': ['isArray', 'isEqual', 'isString', 'keys'],
  116. 'memoize': [],
  117. 'merge': ['forEach', 'forOwn', 'isArray', 'isObject', 'isPlainObject'],
  118. 'min': ['isArray', 'isEqual', 'isString', 'keys'],
  119. 'mixin': ['forEach', 'forOwn', 'functions'],
  120. 'noConflict': [],
  121. 'object': [],
  122. 'omit': ['forIn', 'indexOf'],
  123. 'once': [],
  124. 'pairs': ['keys'],
  125. 'partial': ['isFunction', 'isObject'],
  126. 'partialRight': ['isFunction', 'isObject'],
  127. 'pick': ['forIn', 'isObject'],
  128. 'pluck': ['map'],
  129. 'random': [],
  130. 'range': [],
  131. 'reduce': ['identity', 'isArray', 'isEqual', 'keys'],
  132. 'reduceRight': ['forEach', 'identity', 'isEqual', 'isString', 'keys'],
  133. 'reject': ['filter', 'identity', 'isEqual', 'keys'],
  134. 'rest': [],
  135. 'result': ['isFunction'],
  136. 'shuffle': ['forEach'],
  137. 'size': ['keys'],
  138. 'some': ['identity', 'isArray', 'isEqual', 'keys'],
  139. 'sortBy': ['forEach', 'identity', 'isEqual', 'keys'],
  140. 'sortedIndex': ['identity', 'isEqual', 'keys'],
  141. 'tap': ['mixin'],
  142. 'template': ['defaults', 'escape', 'keys', 'values'],
  143. 'throttle': [],
  144. 'times': [],
  145. 'toArray': ['isString', 'values'],
  146. 'unescape': [],
  147. 'union': ['uniq'],
  148. 'uniq': ['indexOf', 'isEqual', 'keys'],
  149. 'uniqueId': [],
  150. 'value': ['mixin'],
  151. 'values': ['keys'],
  152. 'where': ['filter'],
  153. 'without': ['indexOf'],
  154. 'wrap': [],
  155. 'zip': ['max', 'pluck'],
  156. // method used by the `backbone` and `underscore` builds
  157. 'chain': ['mixin'],
  158. 'findWhere': ['where']
  159. };
  160. /** Used to inline `iteratorTemplate` */
  161. var iteratorOptions = [
  162. 'args',
  163. 'arrays',
  164. 'bottom',
  165. 'firstArg',
  166. 'hasDontEnumBug',
  167. 'hasEnumPrototype',
  168. 'isKeysFast',
  169. 'loop',
  170. 'nonEnumArgs',
  171. 'noCharByIndex',
  172. 'shadowed',
  173. 'top',
  174. 'useHas'
  175. ];
  176. /** List of all Lo-Dash methods */
  177. var allMethods = _.keys(dependencyMap);
  178. /** List of Backbone's Lo-Dash dependencies */
  179. var backboneDependencies = [
  180. 'bind',
  181. 'bindAll',
  182. 'chain',
  183. 'clone',
  184. 'contains',
  185. 'countBy',
  186. 'defaults',
  187. 'escape',
  188. 'every',
  189. 'extend',
  190. 'filter',
  191. 'find',
  192. 'first',
  193. 'forEach',
  194. 'groupBy',
  195. 'has',
  196. 'indexOf',
  197. 'initial',
  198. 'invoke',
  199. 'isArray',
  200. 'isEmpty',
  201. 'isEqual',
  202. 'isFunction',
  203. 'isObject',
  204. 'isRegExp',
  205. 'isString',
  206. 'keys',
  207. 'last',
  208. 'lastIndexOf',
  209. 'map',
  210. 'max',
  211. 'min',
  212. 'mixin',
  213. 'once',
  214. 'pick',
  215. 'reduce',
  216. 'reduceRight',
  217. 'reject',
  218. 'rest',
  219. 'result',
  220. 'shuffle',
  221. 'size',
  222. 'some',
  223. 'sortBy',
  224. 'sortedIndex',
  225. 'toArray',
  226. 'uniqueId',
  227. 'value',
  228. 'without'
  229. ];
  230. /** List of methods used by Underscore */
  231. var underscoreMethods = _.without.apply(_, [allMethods].concat([
  232. 'at',
  233. 'bindKey',
  234. 'cloneDeep',
  235. 'forIn',
  236. 'forOwn',
  237. 'isPlainObject',
  238. 'merge',
  239. 'partialRight'
  240. ]));
  241. /** List of ways to export the `lodash` function */
  242. var exportsAll = [
  243. 'amd',
  244. 'commonjs',
  245. 'global',
  246. 'node'
  247. ];
  248. /*--------------------------------------------------------------------------*/
  249. /**
  250. * Adds support for Underscore style chaining to the `source`.
  251. *
  252. * @private
  253. * @param {String} source The source to process.
  254. * @returns {String} Returns the modified source.
  255. */
  256. function addChainMethods(source) {
  257. // add `_.chain`
  258. source = source.replace(matchFunction(source, 'tap'), function(match) {
  259. return [
  260. '',
  261. ' /**',
  262. ' * Creates a `lodash` object that wraps the given `value`.',
  263. ' *',
  264. ' * @static',
  265. ' * @memberOf _',
  266. ' * @category Chaining',
  267. ' * @param {Mixed} value The value to wrap.',
  268. ' * @returns {Object} Returns the wrapper object.',
  269. ' * @example',
  270. ' *',
  271. ' * var stooges = [',
  272. " * { 'name': 'moe', 'age': 40 },",
  273. " * { 'name': 'larry', 'age': 50 },",
  274. " * { 'name': 'curly', 'age': 60 }",
  275. ' * ];',
  276. ' *',
  277. ' * var youngest = _.chain(stooges)',
  278. ' * .sortBy(function(stooge) { return stooge.age; })',
  279. " * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })",
  280. ' * .first();',
  281. " * // => 'moe is 40'",
  282. ' */',
  283. ' function chain(value) {',
  284. ' value = new lodash(value);',
  285. ' value.__chain__ = true;',
  286. ' return value;',
  287. ' }',
  288. '',
  289. match
  290. ].join('\n');
  291. });
  292. // add `wrapperChain`
  293. source = source.replace(matchFunction(source, 'wrapperToString'), function(match) {
  294. return [
  295. '',
  296. ' /**',
  297. ' * Enables method chaining on the wrapper object.',
  298. ' *',
  299. ' * @name chain',
  300. ' * @memberOf _',
  301. ' * @category Chaining',
  302. ' * @returns {Mixed} Returns the wrapper object.',
  303. ' * @example',
  304. ' *',
  305. ' * var sum = _([1, 2, 3])',
  306. ' * .chain()',
  307. ' * .reduce(function(sum, num) { return sum + num; })',
  308. ' * .value()',
  309. ' * // => 6`',
  310. ' */',
  311. ' function wrapperChain() {',
  312. ' this.__chain__ = true;',
  313. ' return this;',
  314. ' }',
  315. '',
  316. match
  317. ].join('\n');
  318. });
  319. // add `lodash.chain` assignment
  320. source = source.replace(getMethodAssignments(source), function(match) {
  321. return match.replace(/^(?: *\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/\n)?( *)lodash\.VERSION *=/m, '$1lodash.chain = chain;\n\n$&');
  322. });
  323. // add `lodash.prototype.chain` assignment
  324. source = source.replace(/^( *)lodash\.prototype\.value *=.+\n/m, '$1lodash.prototype.chain = wrapperChain;\n$&');
  325. // remove `lodash.prototype.toString` and `lodash.prototype.valueOf` assignments
  326. source = source.replace(/^ *lodash\.prototype\.(?:toString|valueOf) *=.+\n/gm, '');
  327. // remove `lodash.prototype` batch method assignments
  328. source = source.replace(/(?:\s*\/\/.*)*\n( *)forOwn\(lodash, *function\(func, *methodName\)[\s\S]+?\n\1}.+/g, '');
  329. // move `mixin(lodash)` to after the method assignments
  330. source = source.replace(/(?:\s*\/\/.*)*\s*mixin\(lodash\).+/, '');
  331. source = source.replace(getMethodAssignments(source), function(match) {
  332. return match + [
  333. '',
  334. '',
  335. ' // add functions to `lodash.prototype`',
  336. ' mixin(lodash);'
  337. ].join('\n');
  338. });
  339. // add `__chain__` checks to `_.mixin`
  340. source = source.replace(matchFunction(source, 'mixin'), function(match) {
  341. return match.replace(/^( *)return new lodash.+/m, function() {
  342. var indent = arguments[1];
  343. return indent + [
  344. '',
  345. 'var result = func.apply(lodash, args);',
  346. 'if (this.__chain__) {',
  347. ' result = new lodash(result);',
  348. ' result.__chain__ = true;',
  349. '}',
  350. 'return result;'
  351. ].join('\n' + indent);
  352. });
  353. });
  354. // replace wrapper `Array` method assignments
  355. source = source.replace(/^(?: *\/\/.*\n)*( *)each\(\['[\s\S]+?\n\1}$/m, function() {
  356. return [
  357. ' // add `Array` mutator functions to the wrapper',
  358. " each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {",
  359. ' var func = arrayRef[methodName];',
  360. ' lodash.prototype[methodName] = function() {',
  361. ' var value = this.__wrapped__;',
  362. ' func.apply(value, arguments);',
  363. '',
  364. ' // avoid array-like object bugs with `Array#shift` and `Array#splice`',
  365. ' // in Firefox < 10 and IE < 9',
  366. ' if (hasObjectSpliceBug && value.length === 0) {',
  367. ' delete value[0];',
  368. ' }',
  369. ' return this;',
  370. ' };',
  371. ' });',
  372. '',
  373. ' // add `Array` accessor functions to the wrapper',
  374. " each(['concat', 'join', 'slice'], function(methodName) {",
  375. ' var func = arrayRef[methodName];',
  376. ' lodash.prototype[methodName] = function() {',
  377. ' var value = this.__wrapped__,',
  378. ' result = func.apply(value, arguments);',
  379. '',
  380. ' if (this.__chain__) {',
  381. ' result = new lodash(result);',
  382. ' result.__chain__ = true;',
  383. ' }',
  384. ' return result;',
  385. ' };',
  386. ' });'
  387. ].join('\n');
  388. });
  389. return source;
  390. }
  391. /**
  392. * Adds build `commands` to the copyright/license header of the `source`.
  393. *
  394. * @private
  395. * @param {String} source The source to process.
  396. * @param {Array} [commands=[]] An array of commands.
  397. * @returns {String} Returns the modified source.
  398. */
  399. function addCommandsToHeader(source, commands) {
  400. return source.replace(/(\/\**\n)( \*)( *@license[\s*]+)( *Lo-Dash [\w.-]+)(.*)/, function() {
  401. // remove `node path/to/build.js` from `commands`
  402. if (commands[0] == 'node') {
  403. commands.splice(0, 2);
  404. }
  405. // add quotes to commands with spaces or equals signs
  406. commands = _.map(commands, function(command) {
  407. var separator = (command.match(/[= ]/) || [''])[0];
  408. if (separator) {
  409. var pair = command.split(separator);
  410. command = pair[0] + separator + '"' + pair[1] + '"';
  411. }
  412. // escape newlines, carriage returns, multi-line comment end tokens
  413. command = command
  414. .replace(/\n/g, '\\n')
  415. .replace(/\r/g, '\\r')
  416. .replace(/\*\//g, '*\\/');
  417. return command;
  418. });
  419. // add build commands to copyright/license header
  420. var parts = slice.call(arguments, 1);
  421. return (
  422. parts[0] +
  423. parts[1] +
  424. parts[2] + parts[3] + ' (Custom Build)' + parts[4] + '\n' +
  425. parts[1] + ' Build: `lodash ' + commands.join(' ') + '`'
  426. );
  427. });
  428. }
  429. /**
  430. * Compiles template files matched by the given file path `pattern` into a
  431. * single source, extending `_.templates` with precompiled templates named after
  432. * each template file's basename.
  433. *
  434. * @private
  435. * @param {String} [pattern='<cwd>/*.jst'] The file path pattern.
  436. * @param {Object} options The options object.
  437. * @returns {String} Returns the compiled source.
  438. */
  439. function buildTemplate(pattern, options) {
  440. pattern || (pattern = path.join(cwd, '*.jst'));
  441. var directory = path.dirname(pattern);
  442. var source = [
  443. ';(function(window) {',
  444. " var freeExports = typeof exports == 'object' && exports;",
  445. '',
  446. " var freeModule = typeof module == 'object' && module && module.exports == freeExports && module;",
  447. '',
  448. " var freeGlobal = typeof global == 'object' && global;",
  449. ' if (freeGlobal.global === freeGlobal) {',
  450. ' window = freeGlobal;',
  451. ' }',
  452. '',
  453. ' var templates = {},',
  454. ' _ = window._;',
  455. ''
  456. ];
  457. // convert to a regexp
  458. pattern = RegExp(
  459. path.basename(pattern)
  460. .replace(/[.+?^=!:${}()|[\]\/\\]/g, '\\$&')
  461. .replace(/\*/g, '.*?') + '$'
  462. );
  463. fs.readdirSync(directory).forEach(function(filename) {
  464. var filePath = path.join(directory, filename);
  465. if (pattern.test(filename)) {
  466. var text = fs.readFileSync(filePath, 'utf8'),
  467. precompiled = getFunctionSource(_.template(text, null, options)),
  468. prop = filename.replace(/\..*$/, '');
  469. source.push(" templates['" + prop.replace(/['\n\r\t]/g, '\\$&') + "'] = " + precompiled + ';', '');
  470. }
  471. });
  472. source.push(
  473. " if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {",
  474. " define(['" + options.moduleId + "'], function(lodash) {",
  475. ' _ = lodash;',
  476. ' lodash.templates = lodash.extend(lodash.templates || {}, templates);',
  477. ' });',
  478. " } else if (freeExports) {",
  479. " if (freeModule) {",
  480. ' (freeModule.exports = templates).templates = templates;',
  481. ' } else {',
  482. ' freeExports.templates = templates;',
  483. ' }',
  484. ' } else if (_) {',
  485. ' _.templates = _.extend(_.templates || {}, templates);',
  486. ' }',
  487. '}(this));'
  488. );
  489. return source.join('\n');
  490. }
  491. /**
  492. * Capitalizes a given string.
  493. *
  494. * @private
  495. * @param {String} string The string to capitalize.
  496. * @returns {String} Returns the capitalized string.
  497. */
  498. function capitalize(string) {
  499. return string[0].toUpperCase() + string.toLowerCase().slice(1);
  500. }
  501. /**
  502. * Removes unnecessary comments, whitespace, and pseudo private properties.
  503. *
  504. * @private
  505. * @param {String} source The source to process.
  506. * @returns {String} Returns the modified source.
  507. */
  508. function cleanupSource(source) {
  509. return source
  510. // remove pseudo private properties
  511. .replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n')
  512. // remove lines with just whitespace and semicolons
  513. .replace(/^ *;\n/gm, '')
  514. // consolidate multiple newlines
  515. .replace(/\n{3,}/g, '\n\n')
  516. // consolidate consecutive horizontal rule comment separators
  517. .replace(/(?:\s*\/\*-+\*\/\s*){2,}/g, function(separators) {
  518. return separators.match(/^\s*/)[0] + separators.slice(separators.lastIndexOf('/*'));
  519. });
  520. }
  521. /**
  522. * Writes the help message to standard output.
  523. *
  524. * @private
  525. */
  526. function displayHelp() {
  527. console.log([
  528. '',
  529. ' Commands:',
  530. '',
  531. ' lodash backbone Build with only methods required by Backbone',
  532. ' lodash csp Build supporting default Content Security Policy restrictions',
  533. ' lodash legacy Build tailored for older environments without ES5 support',
  534. ' lodash modern Build tailored for newer environments with ES5 support',
  535. ' lodash mobile Build without method compilation and most bug fixes for old browsers',
  536. ' lodash strict Build with `_.assign`, `_.bindAll`, & `_.defaults` in strict mode',
  537. ' lodash underscore Build tailored for projects already using Underscore',
  538. ' lodash include=... Comma separated method/category names to include in the build',
  539. ' lodash minus=... Comma separated method/category names to remove from those included in the build',
  540. ' lodash plus=... Comma separated method/category names to add to those included in the build',
  541. ' lodash category=... Comma separated categories of methods to include in the build (case-insensitive)',
  542. ' (i.e. “arrays”, “chaining”, “collections”, “functions”, “objects”, and “utilities”)',
  543. ' lodash exports=... Comma separated names of ways to export the `lodash` function',
  544. ' (i.e. “amd”, “commonjs”, “global”, “node”, and “none”)',
  545. ' lodash iife=... Code to replace the immediately-invoked function expression that wraps Lo-Dash',
  546. ' (e.g. `lodash iife="!function(window,undefined){%output%}(this)"`)',
  547. '',
  548. ' lodash template=... File path pattern used to match template files to precompile',
  549. ' (e.g. `lodash template=./*.jst`)',
  550. ' lodash settings=... Template settings used when precompiling templates',
  551. ' (e.g. `lodash settings="{interpolate:/{{([\\s\\S]+?)}}/g}"`)',
  552. ' lodash moduleId=... The AMD module ID of Lo-Dash, which defaults to “lodash”, used by precompiled templates',
  553. '',
  554. ' All arguments, except `legacy` with `csp`, `mobile`, `modern`, or `underscore`, may be combined.',
  555. ' Unless specified by `-o` or `--output`, all files created are saved to the current working directory.',
  556. '',
  557. ' Options:',
  558. '',
  559. ' -c, --stdout Write output to standard output',
  560. ' -d, --debug Write only the non-minified development output',
  561. ' -h, --help Display help information',
  562. ' -m, --minify Write only the minified production output',
  563. ' -o, --output Write output to a given path/filename',
  564. ' -p, --source-map Generate a source map for the minified output, using an optional source map URL',
  565. ' -s, --silent Skip status updates normally logged to the console',
  566. ' -V, --version Output current version of Lo-Dash',
  567. ''
  568. ].join('\n'));
  569. }
  570. /**
  571. * Gets the aliases associated with a given function name.
  572. *
  573. * @private
  574. * @param {String} methodName The name of the method to get aliases for.
  575. * @returns {Array} Returns an array of aliases.
  576. */
  577. function getAliases(methodName) {
  578. return realToAliasMap[methodName] || [];
  579. }
  580. /**
  581. * Gets the category of the given method name.
  582. *
  583. * @private
  584. * @param {String} source The source to inspect.
  585. * @param {String} methodName The method name.
  586. * @returns {String} Returns the method name's category.
  587. */
  588. function getCategory(source, methodName) {
  589. var result = /@category +(\w+)/.exec(matchFunction(source, methodName));
  590. return result ? result[1] : '';
  591. }
  592. /**
  593. * Gets an array of category dependencies for a given category.
  594. *
  595. * @private
  596. * @param {String} source The source to inspect.
  597. * @param {String} category The category.
  598. * @returns {Array} Returns an array of cetegory dependants.
  599. */
  600. function getCategoryDependencies(source, category) {
  601. var methods = _.uniq(getMethodsByCategory(source, category).reduce(function(result, methodName) {
  602. push.apply(result, getDependencies(methodName));
  603. return result;
  604. }, []));
  605. var categories = _.uniq(methods.map(function(methodName) {
  606. return getCategory(source, methodName);
  607. }));
  608. return categories.filter(function(other) {
  609. return other != category;
  610. });
  611. }
  612. /**
  613. * Gets an array of depenants for a method by a given name.
  614. *
  615. * @private
  616. * @param {String} methodName The method name.
  617. * @returns {Array} Returns an array of method dependants.
  618. */
  619. function getDependants(methodName) {
  620. // iterate over the `dependencyMap`, adding the names of methods that
  621. // have `methodName` as a dependency
  622. return _.reduce(dependencyMap, function(result, dependencies, otherName) {
  623. if (_.contains(dependencies, methodName)) {
  624. result.push(otherName);
  625. }
  626. return result;
  627. }, []);
  628. }
  629. /**
  630. * Gets an array of dependencies for a given method name. If passed an array
  631. * of dependencies it will return an array containing the given dependencies
  632. * plus any additional detected sub-dependencies.
  633. *
  634. * @private
  635. * @param {Array|String} methodName A single method name or array of
  636. * dependencies to query.
  637. * @returns {Array} Returns an array of method dependencies.
  638. */
  639. function getDependencies(methodName) {
  640. var dependencies = Array.isArray(methodName) ? methodName : dependencyMap[methodName];
  641. if (!dependencies) {
  642. return [];
  643. }
  644. // recursively accumulate the dependencies of the `methodName` function, and
  645. // the dependencies of its dependencies, and so on
  646. return _.uniq(dependencies.reduce(function(result, otherName) {
  647. result.push.apply(result, getDependencies(otherName).concat(otherName));
  648. return result;
  649. }, []));
  650. }
  651. /**
  652. * Gets the formatted source of the given function.
  653. *
  654. * @private
  655. * @param {Function} func The function to process.
  656. * @returns {String} Returns the formatted source.
  657. */
  658. function getFunctionSource(func) {
  659. var source = func.source || (func + '');
  660. // format leading whitespace
  661. return source.replace(/\n(?:.*)/g, function(match, index) {
  662. match = match.slice(1);
  663. return (
  664. match == '}' && source.indexOf('}', index + 2) < 0 ? '\n ' : '\n '
  665. ) + match;
  666. });
  667. }
  668. /**
  669. * Gets the `_.isArguments` fallback from `source`.
  670. *
  671. * @private
  672. * @param {String} source The source to inspect.
  673. * @returns {String} Returns the `isArguments` fallback.
  674. */
  675. function getIsArgumentsFallback(source) {
  676. return (source.match(/(?:\s*\/\/.*)*\n( *)if *\((?:noArgsClass|!isArguments)[\s\S]+?};\n\1}/) || [''])[0];
  677. }
  678. /**
  679. * Gets the `_.isFunction` fallback from `source`.
  680. *
  681. * @private
  682. * @param {String} source The source to inspect.
  683. * @returns {String} Returns the `isFunction` fallback.
  684. */
  685. function getIsFunctionFallback(source) {
  686. return (source.match(/(?:\s*\/\/.*)*\n( *)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/) || [''])[0];
  687. }
  688. /**
  689. * Gets the `iteratorTemplate` from `source`.
  690. *
  691. * @private
  692. * @param {String} source The source to inspect.
  693. * @returns {String} Returns the `iteratorTemplate`.
  694. */
  695. function getIteratorTemplate(source) {
  696. return (source.match(/^( *)var iteratorTemplate *= *[\s\S]+?\n\1.+?;\n/m) || [''])[0];
  697. }
  698. /**
  699. * Gets the Lo-Dash method assignments snippet from `source`.
  700. *
  701. * @private
  702. * @param {String} source The source to inspect.
  703. * @returns {String} Returns the method assignments snippet.
  704. */
  705. function getMethodAssignments(source) {
  706. return (source.match(/\/\*-+\*\/\n(?:\s*\/\/.*)*\s*lodash\.\w+ *=[\s\S]+?lodash\.VERSION *=.+/) || [''])[0];
  707. }
  708. /**
  709. * Gets the names of methods in `source` belonging to the given `category`.
  710. *
  711. * @private
  712. * @param {String} source The source to inspect.
  713. * @param {String} category The category to filter by.
  714. * @returns {Array} Returns a new array of method names belonging to the given category.
  715. */
  716. function getMethodsByCategory(source, category) {
  717. return allMethods.filter(function(methodName) {
  718. return getCategory(source, methodName) == category;
  719. });
  720. }
  721. /**
  722. * Gets the real name, not alias, of a given method name.
  723. *
  724. * @private
  725. * @param {String} methodName The name of the method to resolve.
  726. * @returns {String} Returns the real method name.
  727. */
  728. function getRealName(methodName) {
  729. return aliasToRealMap[methodName] || methodName;
  730. }
  731. /**
  732. * Determines if all functions of the given names have been removed from `source`.
  733. *
  734. * @private
  735. * @param {String} source The source to inspect.
  736. * @param {String} [funcName1, funcName2, ...] The names of functions to check.
  737. * @returns {Boolean} Returns `true` if all functions have been removed, else `false`.
  738. */
  739. function isRemoved(source) {
  740. return slice.call(arguments, 1).every(function(funcName) {
  741. return !matchFunction(source, funcName);
  742. });
  743. }
  744. /**
  745. * Searches `source` for a `funcName` function declaration, expression, or
  746. * assignment and returns the matched snippet.
  747. *
  748. * @private
  749. * @param {String} source The source to inspect.
  750. * @param {String} funcName The name of the function to match.
  751. * @returns {String} Returns the matched function snippet.
  752. */
  753. function matchFunction(source, funcName) {
  754. var result = source.match(RegExp(
  755. // match multi-line comment block (could be on a single line)
  756. '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n)?' +
  757. // begin non-capturing group
  758. '( *)(?:' +
  759. // match a function declaration
  760. 'function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' +
  761. // match a variable declaration with function expression
  762. 'var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\1};' +
  763. // end non-capturing group
  764. ')\\n'
  765. ));
  766. // match variables that are explicitly defined as functions
  767. result || (result = source.match(RegExp(
  768. // match multi-line comment block
  769. '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' +
  770. // match simple variable declarations and those with `createIterator`
  771. ' *var ' + funcName + ' *=(?:.+?|.*?createIterator\\([\\s\\S]+?\\));\\n'
  772. )));
  773. return /@type +Function|function\s*\w*\(/.test(result) ? result[0] : '';
  774. }
  775. /**
  776. * Converts a comma separated options string into an array.
  777. *
  778. * @private
  779. * @param {String} value The option to convert.
  780. * @returns {Array} Returns the new converted array.
  781. */
  782. function optionToArray(value) {
  783. return value.match(/\w+=(.*)$/)[1].split(/, */);
  784. }
  785. /**
  786. * Converts a comma separated options string into an array containing
  787. * only real method names.
  788. *
  789. * @private
  790. * @param {String} source The source to inspect.
  791. * @param {String} value The option to convert.
  792. * @returns {Array} Returns the new converted array.
  793. */
  794. function optionToMethodsArray(source, value) {
  795. var methodNames = optionToArray(value);
  796. // convert categories to method names
  797. methodNames.forEach(function(category) {
  798. push.apply(methodNames, getMethodsByCategory(source, category));
  799. });
  800. // convert aliases to real method names
  801. methodNames = methodNames.map(getRealName);
  802. // remove nonexistent and duplicate method names
  803. return _.uniq(_.intersection(allMethods, methodNames));
  804. }
  805. /**
  806. * Removes all `argsAreObjects` references from `source`.
  807. *
  808. * @private
  809. * @param {String} source The source to process.
  810. * @returns {String} Returns the modified source.
  811. */
  812. function removeArgsAreObjects(source) {
  813. source = removeVar(source, 'argsAreObjects');
  814. // remove `argsAreObjects` from `_.isArray`
  815. source = source.replace(matchFunction(source, 'isArray'), function(match) {
  816. return match.replace(/\(argsAreObjects && *([^)]+)\)/g, '$1');
  817. });
  818. // remove `argsAreObjects` from `_.isEqual`
  819. source = source.replace(matchFunction(source, 'isEqual'), function(match) {
  820. return match.replace(/!argsAreObjects[^:]+:\s*/g, '');
  821. });
  822. return source;
  823. }
  824. /**
  825. * Removes the all references to `varName` from `createIterator` in `source`.
  826. *
  827. * @private
  828. * @param {String} source The source to process.
  829. * @param {String} varName The name of the variable to remove.
  830. * @returns {String} Returns the modified source.
  831. */
  832. function removeFromCreateIterator(source, varName) {
  833. var snippet = matchFunction(source, 'createIterator');
  834. if ( snippet) {
  835. // remove data object property assignment
  836. var modified = snippet.replace(RegExp("^ *'" + varName + "': *" + varName + '.+\\n', 'm'), '');
  837. source = source.replace(snippet, modified);
  838. // clip at the `factory` assignment
  839. snippet = modified.match(/Function\([\s\S]+$/)[0];
  840. modified = snippet
  841. .replace(RegExp('\\b' + varName + '\\b,? *', 'g'), '')
  842. .replace(/, *',/, "',")
  843. .replace(/,\s*\)/, ')')
  844. source = source.replace(snippet, modified);
  845. }
  846. return source;
  847. }
  848. /**
  849. * Removes the `funcName` function declaration, expression, or assignment and
  850. * associated code from `source`.
  851. *
  852. * @private
  853. * @param {String} source The source to process.
  854. * @param {String} funcName The name of the function to remove.
  855. * @returns {String} Returns the modified source.
  856. */
  857. function removeFunction(source, funcName) {
  858. // remove function
  859. var snippet = matchFunction(source, funcName);
  860. if (snippet) {
  861. source = source.replace(snippet, '');
  862. }
  863. // grab the method assignments snippet
  864. snippet = getMethodAssignments(source);
  865. // remove assignment and aliases
  866. var modified = getAliases(funcName).concat(funcName).reduce(function(result, otherName) {
  867. return result.replace(RegExp('(?:\\n *//.*\\s*)* *lodash\\.' + otherName + ' *= *.+\\n'), '');
  868. }, snippet);
  869. // replace with the modified snippet
  870. source = source.replace(snippet, modified);
  871. return removeFromCreateIterator(source, funcName);
  872. }
  873. /**
  874. * Removes all `hasDontEnumBug` references from `source`.
  875. *
  876. * @private
  877. * @param {String} source The source to process.
  878. * @returns {String} Returns the modified source.
  879. */
  880. function removeHasDontEnumBug(source) {
  881. source = removeFromCreateIterator(source, 'hasDontEnumBug');
  882. source = removeFromCreateIterator(source, 'shadowed');
  883. // remove `hasDontEnumBug` declaration and assignment
  884. source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b.*|.+?hasDontEnumBug *=.+/g, '');
  885. // remove `shadowed` variable
  886. source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var shadowed[\s\S]+?;\n/, '');
  887. // remove `hasDontEnumBug` from `iteratorTemplate`
  888. source = source.replace(getIteratorTemplate(source), function(match) {
  889. return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(hasDontEnumBug[\s\S]+?["']\1<% *} *%>.+/, '');
  890. });
  891. return source;
  892. }
  893. /**
  894. * Removes all `hasEnumPrototype` references from `source`.
  895. *
  896. * @private
  897. * @param {String} source The source to process.
  898. * @returns {String} Returns the modified source.
  899. */
  900. function removeHasEnumPrototype(source) {
  901. source = removeFromCreateIterator(source, 'hasEnumPrototype');
  902. // remove `hasEnumPrototype` declaration and assignment
  903. source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasEnumPrototype\b.*|.+?hasEnumPrototype *=.+/g, '');
  904. // remove `hasEnumPrototype` from `_.keys`
  905. source = source.replace(matchFunction(source, 'keys'), function(match) {
  906. return match
  907. .replace(/\(hasEnumPrototype[^)]+\)(?:\s*\|\|\s*)?/, '')
  908. .replace(/\s*if *\(\s*\)[^}]+}/, '');
  909. });
  910. // remove `hasEnumPrototype` from `iteratorTemplate`
  911. source = source.replace(getIteratorTemplate(source), function(match) {
  912. return match
  913. .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(hasEnumPrototype *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '')
  914. .replace(/hasEnumPrototype *\|\|\s*/g, '');
  915. });
  916. return source;
  917. }
  918. /**
  919. * Removes the `_.isArguments` fallback from `source`.
  920. *
  921. * @private
  922. * @param {String} source The source to process.
  923. * @returns {String} Returns the modified source.
  924. */
  925. function removeIsArgumentsFallback(source) {
  926. return source.replace(getIsArgumentsFallback(source), '');
  927. }
  928. /**
  929. * Removes the `_.isFunction` fallback from `source`.
  930. *
  931. * @private
  932. * @param {String} source The source to process.
  933. * @returns {String} Returns the modified source.
  934. */
  935. function removeIsFunctionFallback(source) {
  936. return source.replace(getIsFunctionFallback(source), '');
  937. }
  938. /**
  939. * Removes all `iteratesOwnLast` references from `source`.
  940. *
  941. * @private
  942. * @param {String} source The source to process.
  943. * @returns {String} Returns the modified source.
  944. */
  945. function removeIteratesOwnLast(source) {
  946. // remove `iteratesOwnLast` declaration and assignment
  947. source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast\b.*|.+?iteratesOwnLast *=.+/g, '');
  948. // remove `iteratesOwnLast` from `shimIsPlainObject`
  949. source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) {
  950. return match.replace(/(?:\s*\/\/.*)*\n( *)if *\(iteratesOwnLast[\s\S]+?\n\1}/, '');
  951. });
  952. return source;
  953. }
  954. /**
  955. * Removes the `Object.keys` object iteration optimization from `source`.
  956. *
  957. * @private
  958. * @param {String} source The source to process.
  959. * @returns {String} Returns the modified source.
  960. */
  961. function removeKeysOptimization(source) {
  962. source = removeVar(source, 'isKeysFast');
  963. // remove optimized branch in `iteratorTemplate`
  964. source = source.replace(getIteratorTemplate(source), function(match) {
  965. return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(isKeysFast[\s\S]+?["']\1<% *} *else *{ *%>.+\n([\s\S]+?) *["']\1<% *} *%>.+/, "'\\n' +\n$2");
  966. });
  967. return source;
  968. }
  969. /**
  970. * Removes all `noArgsClass` references from `source`.
  971. *
  972. * @private
  973. * @param {String} source The source to process.
  974. * @returns {String} Returns the modified source.
  975. */
  976. function removeNoArgsClass(source) {
  977. source = removeVar(source, 'noArgsClass');
  978. // replace `noArgsClass` in the `_.isArguments` fallback
  979. source = source.replace(getIsArgumentsFallback(source), function(match) {
  980. return match.replace(/noArgsClass/g, '!isArguments(arguments)');
  981. });
  982. // remove `noArgsClass` from `_.isEmpty`
  983. source = source.replace(matchFunction(source, 'isEmpty'), function(match) {
  984. return match.replace(/ *\|\|\s*\(noArgsClass *&&[^)]+?\)\)/g, '');
  985. });
  986. return source;
  987. }
  988. /**
  989. * Removes all `noCharByIndex` references from `source`.
  990. *
  991. * @private
  992. * @param {String} source The source to process.
  993. * @returns {String} Returns the modified source.
  994. */
  995. function removeNoCharByIndex(source) {
  996. source = removeVar(source, 'noCharByIndex');
  997. // remove `noCharByIndex` from `_.at`
  998. source = source.replace(matchFunction(source, 'at'), function(match) {
  999. return match.replace(/^ *if *\(noCharByIndex[^}]+}\n/m, '');
  1000. });
  1001. // remove `noCharByIndex` from `_.reduceRight`
  1002. source = source.replace(matchFunction(source, 'reduceRight'), function(match) {
  1003. return match.replace(/}\s*else if *\(noCharByIndex[^}]+/, '');
  1004. });
  1005. // remove `noCharByIndex` from `_.toArray`
  1006. source = source.replace(matchFunction(source, 'toArray'), function(match) {
  1007. return match.replace(/noCharByIndex[^:]+:/, '');
  1008. });
  1009. // `noCharByIndex` from `iteratorTemplate`
  1010. source = source.replace(getIteratorTemplate(source), function(match) {
  1011. return match
  1012. .replace(/'if *\(<%= *arrays *%>[^']*/, '$&\\n')
  1013. .replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(noCharByIndex[\s\S]+?["']\1<% *} *%>.+/, '');
  1014. });
  1015. return source;
  1016. }
  1017. /**
  1018. * Removes all `nonEnumArgs` references from `source`.
  1019. *
  1020. * @private
  1021. * @param {String} source The source to process.
  1022. * @returns {String} Returns the modified source.
  1023. */
  1024. function removeNonEnumArgs(source) {
  1025. source = removeFromCreateIterator(source, 'nonEnumArgs');
  1026. // remove `nonEnumArgs` declaration and assignment
  1027. source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var nonEnumArgs\b.*|.+?nonEnumArgs *=.+/g, '');
  1028. // remove `nonEnumArgs` from `_.keys`
  1029. source = source.replace(matchFunction(source, 'keys'), function(match) {
  1030. return match
  1031. .replace(/(?:\s*\|\|\s*)?\(nonEnumArgs[^)]+\)\)/, '')
  1032. .replace(/\s*if *\(\s*\)[^}]+}/, '');
  1033. });
  1034. // remove `nonEnumArgs` from `iteratorTemplate`
  1035. source = source.replace(getIteratorTemplate(source), function(match) {
  1036. return match
  1037. .replace(/(?: *\/\/.*\n)*( *["'] *)<% *} *else *if *\(nonEnumArgs[\s\S]+?(\1<% *} *%>.+)/, '$2')
  1038. .replace(/ *\|\|\s*nonEnumArgs/, '');
  1039. });
  1040. return source;
  1041. }
  1042. /**
  1043. * Removes all `noNodeClass` references from `source`.
  1044. *
  1045. * @private
  1046. * @param {String} source The source to process.
  1047. * @returns {String} Returns the modified source.
  1048. */
  1049. function removeNoNodeClass(source) {
  1050. // remove `noNodeClass` assignment
  1051. source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *try *{(?:\s*\/\/.*)*\n *var noNodeClass[\s\S]+?catch[^}]+}\n/, '');
  1052. // remove `noNodeClass` from `shimIsPlainObject`
  1053. source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) {
  1054. return match.replace(/ *&& *\(!noNodeClass[\s\S]+?\)\)/, '');
  1055. });
  1056. // remove `noNodeClass` from `_.clone`
  1057. source = source.replace(matchFunction(source, 'clone'), function(match) {
  1058. return match.replace(/ *\|\|\s*\(noNodeClass[\s\S]+?\)\)/, '');
  1059. });
  1060. // remove `noNodeClass` from `_.isEqual`
  1061. source = source.replace(matchFunction(source, 'isEqual'), function(match) {
  1062. return match.replace(/ *\|\|\s*\(noNodeClass[\s\S]+?\)\)\)/, '');
  1063. });
  1064. return source;
  1065. }
  1066. /**
  1067. * Removes all `hasObjectSpliceByg` references from `source`.
  1068. *
  1069. * @private
  1070. * @param {String} source The source to process.
  1071. * @returns {String} Returns the modified source.
  1072. */
  1073. function removeHasObjectSpliceBug(source) {
  1074. return removeVar(source, 'hasObjectSpliceBug')
  1075. // remove `hasObjectSpliceBug` fix from the `Array` function mixins
  1076. .replace(/(?:\s*\/\/.*)*\n( *)if *\(hasObjectSpliceBug[\s\S]+?(?:{\s*}|\n\1})/, '');
  1077. }
  1078. /**
  1079. * Removes the `setImmediate` fork of `_.defer`.
  1080. *
  1081. * @private
  1082. * @param {String} source The source to process.
  1083. * @returns {String} Returns the modified source.
  1084. */
  1085. function removeSetImmediate(source) {
  1086. return source.replace(/(?:\s*\/\/.*)*\n( *)if *\(isV8 *&& *freeModule[\s\S]+?\n\1}/, '');
  1087. }
  1088. /**
  1089. * Removes a given variable from `source`.
  1090. *
  1091. * @private
  1092. * @param {String} source The source to process.
  1093. * @param {String} varName The name of the variable to remove.
  1094. * @returns {String} Returns the modified source.
  1095. */
  1096. function removeVar(source, varName) {
  1097. // simplify `cloneableClasses`, `ctorByClass`, or `hasObjectSpliceBug`
  1098. if (/^(?:cloneableClasses|ctorByClass|hasObjectSpliceBug)$/.test(varName)) {
  1099. source = source.replace(RegExp('(var ' + varName + ' *=)[\\s\\S]+?\\n\\n'), '$1=null;\n\n');
  1100. }
  1101. source = source.replace(RegExp(
  1102. // match multi-line comment block
  1103. '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' +
  1104. // match a variable declaration that's not part of a declaration list
  1105. '( *)var ' + varName + ' *= *(?:.+?(?:;|&&\\n[^;]+;)|(?:\\w+\\(|{)[\\s\\S]+?\\n\\1.+?;)\\n|' +
  1106. // match a variable in a declaration list
  1107. '\\n +' + varName + ' *=.+?,'
  1108. ), '');
  1109. // remove a varaible at the start of a variable declaration list
  1110. source = source.replace(RegExp('(var +)' + varName + ' *=.+?,\\s+'), '$1');
  1111. // remove a variable at the end of a variable declaration list
  1112. source = source.replace(RegExp(',\\s*' + varName + ' *=.+?;'), ';');
  1113. return removeFromCreateIterator(source, varName);
  1114. }
  1115. /**
  1116. * Replaces the `funcName` function body in `source` with `funcValue`.
  1117. *
  1118. * @private
  1119. * @param {String} source The source to inspect.
  1120. * @param {String} varName The name of the function to replace.
  1121. * @returns {String} Returns the modified source.
  1122. */
  1123. function replaceFunction(source, funcName, funcValue) {
  1124. var match = matchFunction(source, funcName);
  1125. if (match) {
  1126. // clip snippet after the JSDoc comment block
  1127. match = match.replace(/^\s*(?:\/\/.*|\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)\n/, '');
  1128. source = source.replace(match, function() {
  1129. return funcValue.trimRight() + '\n';
  1130. });
  1131. }
  1132. return source;
  1133. }
  1134. /**
  1135. * Replaces the `varName` variable declaration value in `source` with `varValue`.
  1136. *
  1137. * @private
  1138. * @param {String} source The source to inspect.
  1139. * @param {String} varName The name of the variable to replace.
  1140. * @returns {String} Returns the modified source.
  1141. */
  1142. function replaceVar(source, varName, varValue) {
  1143. // replace a variable that's not part of a declaration list
  1144. var result = source.replace(RegExp(
  1145. '(( *)var ' + varName + ' *= *)' +
  1146. '(?:.+?;|(?:Function\\(.+?|.*?[^,])\\n[\\s\\S]+?\\n\\2.+?;)\\n'
  1147. ), function(match, captured) {
  1148. return captured + varValue + ';\n';
  1149. });
  1150. if (source == result) {
  1151. // replace a varaible at the start or middle of a declaration list
  1152. result = source.replace(RegExp('((?:var|\\n) +' + varName + ' *=).+?,'), function(match, captured) {
  1153. return captured + ' ' + varValue + ',';
  1154. });
  1155. }
  1156. if (source == result) {
  1157. // replace a variable at the end of a variable declaration list
  1158. result = source.replace(RegExp('(,\\s*' + varName + ' *=).+?;'), function(match, captured) {
  1159. return captured + ' ' + varValue + ';';
  1160. });
  1161. }
  1162. return result;
  1163. }
  1164. /**
  1165. * Hard-codes the `strict` template option value for `iteratorTemplate`.
  1166. *
  1167. * @private
  1168. * @param {String} source The source to process.
  1169. * @param {Boolean} value The value to set.
  1170. * @returns {String} Returns the modified source.
  1171. */
  1172. function setUseStrictOption(source, value) {
  1173. // inject or remove the "use strict" directive
  1174. source = source.replace(/^([\s\S]*?function[^{]+{)(?:\s*'use strict';)?/, '$1' + (value ? "\n 'use strict';" : ''));
  1175. // replace `strict` branch in `iteratorTemplate` with hard-coded option
  1176. source = source.replace(getIteratorTemplate(source), function(match) {
  1177. return match.replace(/(template\()(?:\s*"'use strict.+)?/, '$1' + (value ? '\n "\'use strict\';\\n" +' : ''));
  1178. });
  1179. return source;
  1180. }
  1181. /*--------------------------------------------------------------------------*/
  1182. /**
  1183. * Creates a debug and/or minified build, executing the `callback` for each.
  1184. * The `callback` is invoked with two arguments; (filePath, outputSource).
  1185. *
  1186. * Note: For a list of commands see `displayHelp()` or run `lodash --help`.
  1187. *
  1188. * @param {Array} [options=[]] An array of commands.
  1189. * @param {Function} callback The function called per build.
  1190. */
  1191. function build(options, callback) {
  1192. options || (options = []);
  1193. // the debug version of `source`
  1194. var debugSource;
  1195. // used to specify the source map URL
  1196. var sourceMapURL;
  1197. // used to report invalid command-line arguments
  1198. var invalidArgs = _.reject(options.slice(options[0] == 'node' ? 2 : 0), function(value, index, options) {
  1199. if (/^(?:-o|--output)$/.test(options[index - 1]) ||
  1200. /^(?:category|exclude|exports|iife|include|moduleId|minus|plus|settings|template)=.*$/.test(value)) {
  1201. return true;
  1202. }
  1203. var result = [
  1204. 'backbone',
  1205. 'csp',
  1206. 'legacy',
  1207. 'mobile',
  1208. 'modern',
  1209. 'modularize',
  1210. 'strict',
  1211. 'underscore',
  1212. '-c', '--stdout',
  1213. '-d', '--debug',
  1214. '-h', '--help',
  1215. '-m', '--minify',
  1216. '-o', '--output',
  1217. '-p', '--source-map',
  1218. '-s', '--silent',
  1219. '-V', '--version'
  1220. ].indexOf(value) > -1;
  1221. if (!result && /^(?:-p|--source-map)$/.test(options[index - 1])) {
  1222. result = true;
  1223. sourceMapURL = value;
  1224. }
  1225. return result;
  1226. });
  1227. // report invalid arguments
  1228. if (invalidArgs.length) {
  1229. console.log(
  1230. '\n' +
  1231. 'Invalid argument' + (invalidArgs.length > 1 ? 's' : '') +
  1232. ' passed: ' + invalidArgs.join(', ')
  1233. );
  1234. displayHelp();
  1235. return;
  1236. }
  1237. // display help message
  1238. if (_.find(options, function(arg) {
  1239. return /^(?:-h|--help)$/.test(arg);
  1240. })) {
  1241. displayHelp();
  1242. return;
  1243. }
  1244. // display `lodash.VERSION`
  1245. if (_.find(options, function(arg) {
  1246. return /^(?:-V|--version)$/.test(arg);
  1247. })) {
  1248. console.log(_.VERSION);
  1249. return;
  1250. }
  1251. /*------------------------------------------------------------------------*/
  1252. // backup `dependencyMap` to restore later
  1253. var dependencyBackup = _.cloneDeep(dependencyMap);
  1254. // used to specify a custom IIFE to wrap Lo-Dash
  1255. var iife = options.reduce(function(result, value) {
  1256. var match = value.match(/iife=(.*)/);
  1257. return match ? match[1] : result;
  1258. }, null);
  1259. // the path to the source file
  1260. var filePath = path.join(__dirname, 'lodash.js');
  1261. // flag to specify a Backbone build
  1262. var isBackbone = options.indexOf('backbone') > -1;
  1263. // flag to specify a Content Security Policy build
  1264. var isCSP = options.indexOf('csp') > -1 || options.indexOf('CSP') > -1;
  1265. // flag to specify only creating the debug build
  1266. var isDebug = options.indexOf('-d') > -1 || options.indexOf('--debug') > -1;
  1267. // flag to indicate that a custom IIFE was specified
  1268. var isIIFE = typeof iife == 'string';
  1269. // flag to specify creating a source map for the minified source
  1270. var isMapped = options.indexOf('-p') > -1 || options.indexOf('--source-map') > -1;
  1271. // flag to specify only creating the minified build
  1272. var isMinify = options.indexOf('-m') > -1 || options.indexOf('--minify') > -1;
  1273. // flag to specify a mobile build
  1274. var isMobile = isCSP || options.indexOf('mobile') > -1;
  1275. // flag to specify a modern build
  1276. var isModern = isMobile || options.indexOf('modern') > -1;
  1277. // flag to specify a modularize build
  1278. var isModularize = options.indexOf('modularize') > -1;
  1279. // flag to specify writing output to standard output
  1280. var isStdOut = options.indexOf('-c') > -1 || options.indexOf('--stdout') > -1;
  1281. // flag to specify skipping status updates normally logged to the console
  1282. var isSilent = isStdOut || options.indexOf('-s') > -1 || options.indexOf('--silent') > -1;
  1283. // flag to specify `_.assign`, `_.bindAll`, and `_.defaults` are
  1284. // constructed using the "use strict" directive
  1285. var isStrict = options.indexOf('strict') > -1;
  1286. // flag to specify an Underscore build
  1287. var isUnderscore = isBackbone || options.indexOf('underscore') > -1;
  1288. // flag to specify a legacy build
  1289. var isLegacy = !(isModern || isUnderscore) && options.indexOf('legacy') > -1;
  1290. // used to specify methods of specific categories
  1291. var categories = options.reduce(function(result, value) {
  1292. return /category/.test(value) ? optionToArray(value) : result;
  1293. }, []);
  1294. // used to specify the ways to export the `lodash` function
  1295. var exportsOptions = options.reduce(function(result, value) {
  1296. return /exports/.test(value) ? optionToArray(value).sort() : result;
  1297. }, isUnderscore
  1298. ? ['commonjs', 'global', 'node']
  1299. : exportsAll.slice()
  1300. );
  1301. // used to specify the AMD module ID of Lo-Dash used by precompiled templates
  1302. var moduleId = options.reduce(function(result, value) {
  1303. var match = value.match(/moduleId=(.*)/);
  1304. return match ? match[1] : result;
  1305. }, 'lodash');
  1306. // used to specify the output path for builds
  1307. var outputPath = options.reduce(function(result, value, index) {
  1308. if (/-o|--output/.test(value)) {
  1309. result = options[index + 1];
  1310. result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result));
  1311. }
  1312. return result;
  1313. }, '');
  1314. // used to match external template files to precompile
  1315. var templatePattern = options.reduce(function(result, value) {
  1316. var match = value.match(/template=(.+)$/);
  1317. return match
  1318. ? path.join(fs.realpathSync(path.dirname(match[1])), path.basename(match[1]))
  1319. : result;
  1320. }, '');
  1321. // used when precompiling template files
  1322. var templateSettings = options.reduce(function(result, value) {
  1323. var match = value.match(/settings=(.+

Large files files are truncated, but you can click here to view the full file