diff --git a/build.js b/build.js index ec001679b..d380bd73e 100755 --- a/build.js +++ b/build.js @@ -1243,7 +1243,7 @@ /*------------------------------------------------------------------------*/ // backup `dependencyMap` to restore later - var dependencyBackup = _.clone(dependencyMap, true); + var dependencyBackup = _.cloneDeep(dependencyMap); // used to specify a custom IIFE to wrap Lo-Dash var iife = options.reduce(function(result, value) { @@ -1386,28 +1386,42 @@ }); // include Lo-Dash's methods if explicitly requested - if (isUnderscore && result) { - exposeAssign = result.indexOf('assign') > -1; - exposeForIn = result.indexOf('forIn') > -1; - exposeForOwn = result.indexOf('forOwn') > -1; - exposeIsPlainObject = result.indexOf('isPlainObject') > -1; - useUnderscoreClone = result.indexOf('clone') < 0; + if (isUnderscore) { + if (result) { + exposeAssign = result.indexOf('assign') > -1; + exposeForIn = result.indexOf('forIn') > -1; + exposeForOwn = result.indexOf('forOwn') > -1; + exposeIsPlainObject = result.indexOf('isPlainObject') > -1; + } + useUnderscoreClone = plusMethods.indexOf('clone') < 0; } // update dependencies if (isMobile) { - dependencyMap.reduceRight = ['forEach', 'keys']; + dependencyMap.reduceRight = _.without(dependencyMap.reduceRight, 'isEqual', 'isString'); } if (isUnderscore) { - dependencyMap.contains = ['indexOf']; - dependencyMap.isEqual = ['isArray', 'isFunction']; - dependencyMap.isEmpty = ['isArray', 'isString']; - dependencyMap.max = ['isArray']; - dependencyMap.min = ['isArray']; - dependencyMap.pick = []; - dependencyMap.template = ['defaults', 'escape']; + dependencyMap.contains = _.without(dependencyMap.contains, 'isString'); + dependencyMap.countBy = _.without(dependencyMap.countBy, 'isEqual', 'keys'); + dependencyMap.every = _.without(dependencyMap.every, 'isEqual', 'keys'); + dependencyMap.filter = _.without(dependencyMap.filter, 'isEqual', 'keys'); + dependencyMap.find = _.without(dependencyMap.find, 'isEqual', 'keys'); + dependencyMap.groupBy = _.without(dependencyMap.groupBy, 'isEqual', 'keys'); + dependencyMap.isEqual = _.without(dependencyMap.isEqual, 'forIn', 'isArguments'); + dependencyMap.isEmpty = ['isArray', 'isString']; + dependencyMap.map = _.without(dependencyMap.map, 'isEqual', 'keys'); + dependencyMap.max = _.without(dependencyMap.max, 'isEqual', 'isString', 'keys'); + dependencyMap.min = _.without(dependencyMap.min, 'isEqual', 'isString', 'keys'); + dependencyMap.pick = _.without(dependencyMap.pick, 'forIn', 'isObject'); + dependencyMap.reduce = _.without(dependencyMap.reduce, 'isEqual', 'keys'); + dependencyMap.reject = _.without(dependencyMap.reject, 'isEqual', 'keys'); + dependencyMap.some = _.without(dependencyMap.some, 'isEqual', 'keys'); + dependencyMap.sortBy = _.without(dependencyMap.sortBy, 'isEqual', 'keys'); + dependencyMap.sortedIndex = _.without(dependencyMap.sortedIndex, 'isEqual', 'keys'); + dependencyMap.template = _.without(dependencyMap.template, 'keys', 'values'); + dependencyMap.uniq = _.without(dependencyMap.uniq, 'isEqual', 'keys'); if (useUnderscoreClone) { - dependencyMap.clone = ['assign', 'isArray']; + dependencyMap.clone = _.without(dependencyMap.clone, 'forEach', 'forOwn'); } } // add method names required by Backbone and Underscore builds @@ -1462,9 +1476,10 @@ } if (isUnderscore) { // remove unneeded variables - source = removeVar(source, 'cloneableClasses'); - source = removeVar(source, 'ctorByClass'); - + if (useUnderscoreClone) { + source = removeVar(source, 'cloneableClasses'); + source = removeVar(source, 'ctorByClass'); + } // remove `_.templateSettings.imports assignment source = source.replace(/,[^']*'imports':[^}]+}/, ''); @@ -1494,7 +1509,7 @@ if (useUnderscoreClone) { source = replaceFunction(source, 'clone', [ ' function clone(value) {', - ' return value && objectTypes[typeof value]', + ' return isObject(value)', ' ? (isArray(value) ? slice(value) : assign({}, value))', ' : value', ' }' @@ -1755,6 +1770,11 @@ .replace(/!argsAreObjects[^:]+:\s*/g, ''); }); + // remove `_.isEqual` use from `createCallback` + source = source.replace(matchFunction(source, 'createCallback'), function(match) { + return match.replace(/isEqual\(([^,]+), *([^,]+)[^)]+\)/, '$1 === $2'); + }); + // remove conditional `charCodeCallback` use from `_.max` and `_.min` _.each(['max', 'min'], function(methodName) { source = source.replace(matchFunction(source, methodName), function(match) { @@ -2127,13 +2147,11 @@ source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug;|.+?hasDontEnumBug *=.+/g, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var nonEnumArgs;|.+?nonEnumArgs *=.+/g, ''); } - if (isRemoved(source, 'createIterator', 'bind', 'keys', 'template')) { + if (isRemoved(source, 'createIterator', 'bind', 'keys')) { source = removeVar(source, 'isBindFast'); + source = removeVar(source, 'isV8'); source = removeVar(source, 'nativeBind'); } - if (isRemoved(source, 'createIterator', 'bind', 'isArray', 'isPlainObject', 'keys', 'template')) { - source = removeVar(source, 'reNative'); - } if (isRemoved(source, 'createIterator', 'keys')) { source = removeVar(source, 'nativeKeys'); source = removeKeysOptimization(source); diff --git a/test/test-build.js b/test/test-build.js index 7eac00836..2dee0ff66 100644 --- a/test/test-build.js +++ b/test/test-build.js @@ -774,6 +774,9 @@ equal('imports' in lodash.templateSettings, false, '_.templateSettings should not have an "imports" property: ' + basename); equal(lodash.uniqueId(0), '1', '_.uniqueId should ignore a prefix of `0`: ' + basename); + var collection = [{ 'a': { 'b': 1, 'c': 2 } }]; + deepEqual(lodash.where(collection, { 'a': { 'b': 1 } }), []); + start(); }); }); @@ -833,8 +836,8 @@ var lodash = context._, clone = lodash.clone(array, true); - deepEqual(array, clone, basename); - notEqual(array, clone, basename); + ok(_.isEqual(array, clone), basename); + notEqual(array[0], clone[0], basename); start(); }); }); @@ -1025,7 +1028,7 @@ deepEqual(lodash.sortBy([3, 2, 1], _.identity), array, basename); ok(lodash.isEqual(circular1, circular2), basename); - var actual = lodash.clone(circular1, true); + var actual = lodash.cloneDeep(circular1); ok(actual != circular1 && actual.b == actual, basename); start(); }); @@ -1065,78 +1068,94 @@ }) ); - commands.forEach(function(command) { - asyncTest('`lodash ' + command +'`', function() { - var start = _.after(2, _.once(QUnit.start)); + commands.forEach(function(origCommand) { + _.times(3, function(index) { + var command = origCommand; - build(['--silent'].concat(command.split(' ')), function(data) { - var methodNames, - basename = path.basename(data.outputPath, '.js'), - context = createContext(), - isUnderscore = /underscore/.test(command), - exposeAssign = !isUnderscore; + if (index == 1) { + if (/mobile/.test(command)) { + return; + } + command = 'mobile ' + command; + } + if (index == 2) { + if (/category|underscore/.test(command)) { + return; + } + command = 'underscore ' + command; + } + asyncTest('`lodash ' + command +'`', function() { + var start = _.after(2, _.once(QUnit.start)); - try { - vm.runInContext(data.source, context); - } catch(e) { - console.log(e); - } - // add method names explicitly - if (/include/.test(command)) { - methodNames = command.match(/include=(\S*)/)[1].split(/, */); - } - // add method names required by Backbone and Underscore builds - if (/backbone/.test(command) && !methodNames) { - methodNames = backboneDependencies.slice(); - } - if (isUnderscore) { - if (methodNames) { - exposeAssign = methodNames.indexOf('assign') > -1; - } else { - methodNames = underscoreMethods.slice(); + build(['--silent'].concat(command.split(' ')), function(data) { + var methodNames, + basename = path.basename(data.outputPath, '.js'), + context = createContext(), + isUnderscore = /underscore/.test(command), + exposeAssign = !isUnderscore; + + try { + vm.runInContext(data.source, context); + } catch(e) { + console.log(e); + } + // add method names explicitly + if (/include/.test(command)) { + methodNames = command.match(/include=(\S*)/)[1].split(/, */); + } + // add method names required by Backbone and Underscore builds + if (/backbone/.test(command) && !methodNames) { + methodNames = backboneDependencies.slice(); + } + if (isUnderscore) { + if (methodNames) { + exposeAssign = methodNames.indexOf('assign') > -1; + } else { + methodNames = underscoreMethods.slice(); + } + } + // add method names explicitly by category + if (/category/.test(command)) { + // resolve method names belonging to each category (case-insensitive) + methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) { + var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1); + return result.concat(getMethodsByCategory(capitalized)); + }, methodNames || []); + } + // init `methodNames` if it hasn't been inited + if (!methodNames) { + methodNames = allMethods.slice(); + } + if (/plus/.test(command)) { + methodNames = methodNames.concat(command.match(/plus=(\S*)/)[1].split(/, */)); + } + if (/minus/.test(command)) { + methodNames = _.without.apply(_, [methodNames] + .concat(expandMethodNames(command.match(/minus=(\S*)/)[1].split(/, */)))); + } + if (/exclude/.test(command)) { + methodNames = _.without.apply(_, [methodNames] + .concat(expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */)))); } - } - // add method names explicitly by category - if (/category/.test(command)) { - // resolve method names belonging to each category (case-insensitive) - methodNames = command.match(/category=(\S*)/)[1].split(/, */).reduce(function(result, category) { - var capitalized = category[0].toUpperCase() + category.toLowerCase().slice(1); - return result.concat(getMethodsByCategory(capitalized)); - }, methodNames || []); - } - // init `methodNames` if it hasn't been inited - if (!methodNames) { - methodNames = allMethods.slice(); - } - if (/plus/.test(command)) { - methodNames = methodNames.concat(command.match(/plus=(\S*)/)[1].split(/, */)); - } - if (/minus/.test(command)) { - methodNames = _.without.apply(_, [methodNames] - .concat(expandMethodNames(command.match(/minus=(\S*)/)[1].split(/, */)))); - } - if (/exclude/.test(command)) { - methodNames = _.without.apply(_, [methodNames] - .concat(expandMethodNames(command.match(/exclude=(\S*)/)[1].split(/, */)))); - } - // expand aliases and categories to real method names - methodNames = expandMethodNames(methodNames).reduce(function(result, methodName) { - return result.concat(methodName, getMethodsByCategory(methodName)); - }, []); + // expand aliases and categories to real method names + methodNames = expandMethodNames(methodNames).reduce(function(result, methodName) { + return result.concat(methodName, getMethodsByCategory(methodName)); + }, []); - // remove nonexistent and duplicate method names - methodNames = _.uniq(_.intersection(allMethods, expandMethodNames(methodNames))); + // remove nonexistent and duplicate method names + methodNames = _.uniq(_.intersection(allMethods, expandMethodNames(methodNames))); - if (!exposeAssign) { - methodNames = _.without(methodNames, 'assign'); - } - var lodash = context._ || {}; - methodNames.forEach(function(methodName) { - testMethod(lodash, methodName, basename); + if (!exposeAssign) { + methodNames = _.without(methodNames, 'assign'); + } + var lodash = context._ || {}; + methodNames.forEach(function(methodName) { + testMethod(lodash, methodName, basename); + }); + + start(); }); - - start(); }); }); });