mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-10 19:07:49 +00:00
Add _.flattenDeep and allow _.template to be called with its legacy options param signature.
This commit is contained in:
40
lodash.js
40
lodash.js
@@ -745,14 +745,14 @@
|
|||||||
* `chain`, `chunk`, `compact`, `compose`, `concat`, `constant`, `countBy`,
|
* `chain`, `chunk`, `compact`, `compose`, `concat`, `constant`, `countBy`,
|
||||||
* `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
|
* `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
|
||||||
* `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
|
* `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, `flatten`,
|
||||||
* `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
|
* `flattenDeep`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`,
|
||||||
* `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
|
* `forOwnRight`, `functions`, `groupBy`, `indexBy`, `initial`, `intersection`,
|
||||||
* `invoke`, `keys`, `keysIn`, `map`, `mapValues`, `matches`, `memoize`, `merge`,
|
* `invert`, `invoke`, `keys`, `keysIn`, `map`, `mapValues`, `matches`, `memoize`,
|
||||||
* `mixin`, `negate`, `noop`, `omit`, `once`, `pairs`, `partial`, `partialRight`,
|
* `merge`, `mixin`, `negate`, `noop`, `omit`, `once`, `pairs`, `partial`,
|
||||||
* `partition`, `pick`, `pluck`, `property`, `pull`, `pullAt`, `push`, `range`,
|
* `partialRight`, `partition`, `pick`, `pluck`, `property`, `pull`, `pullAt`,
|
||||||
* `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`,
|
* `push`, `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`,
|
||||||
* `splice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`,
|
* `sort`, `sortBy`, `splice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`,
|
||||||
* `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
|
* `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
|
||||||
* `unzip`, `values`, `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`,
|
* `unzip`, `values`, `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`,
|
||||||
* and `zipObject`
|
* and `zipObject`
|
||||||
*
|
*
|
||||||
@@ -3466,6 +3466,24 @@
|
|||||||
return baseFlatten(array, isDeep);
|
return baseFlatten(array, isDeep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively flattens a nested array.
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @memberOf _
|
||||||
|
* @category Array
|
||||||
|
* @param {Array} array The array to recursively flatten.
|
||||||
|
* @returns {Array} Returns the new flattened array.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* _.flattenDeep([1, [2], [3, [[4]]]]);
|
||||||
|
* // => [1, 2, 3, 4];
|
||||||
|
*/
|
||||||
|
function flattenDeep(array) {
|
||||||
|
var length = array ? array.length : 0;
|
||||||
|
return length ? baseFlatten(array, true) : [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the index at which the first occurrence of `value` is found in `array`
|
* Gets the index at which the first occurrence of `value` is found in `array`
|
||||||
* using strict equality for comparisons, i.e. `===`. If `fromIndex` is negative,
|
* using strict equality for comparisons, i.e. `===`. If `fromIndex` is negative,
|
||||||
@@ -8092,6 +8110,7 @@
|
|||||||
* @param {RegExp} [options.interpolate] The "interpolate" delimiter.
|
* @param {RegExp} [options.interpolate] The "interpolate" delimiter.
|
||||||
* @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
|
* @param {string} [options.sourceURL] The sourceURL of the template's compiled source.
|
||||||
* @param {string} [options.variable] The data object variable name.
|
* @param {string} [options.variable] The data object variable name.
|
||||||
|
* @param- {Object} [otherOptions] Enables the legacy `options` param signature.
|
||||||
* @returns {Function} Returns the compiled template function.
|
* @returns {Function} Returns the compiled template function.
|
||||||
* @example
|
* @example
|
||||||
*
|
*
|
||||||
@@ -8159,13 +8178,13 @@
|
|||||||
* };\
|
* };\
|
||||||
* ');
|
* ');
|
||||||
*/
|
*/
|
||||||
function template(string, options) {
|
function template(string, options, otherOptions) {
|
||||||
// based on John Resig's `tmpl` implementation
|
// based on John Resig's `tmpl` implementation
|
||||||
// http://ejohn.org/blog/javascript-micro-templating/
|
// http://ejohn.org/blog/javascript-micro-templating/
|
||||||
// and Laura Doktorova's doT.js
|
// and Laura Doktorova's doT.js
|
||||||
// https://github.com/olado/doT
|
// https://github.com/olado/doT
|
||||||
var settings = lodash.templateSettings;
|
var settings = lodash.templateSettings;
|
||||||
options = assign({}, options, settings, assignOwnDefaults);
|
options = assign({}, otherOptions || options, settings, assignOwnDefaults);
|
||||||
string = String(string == null ? '' : string);
|
string = String(string == null ? '' : string);
|
||||||
|
|
||||||
var imports = assign({}, options.imports, settings.imports, assignOwnDefaults),
|
var imports = assign({}, options.imports, settings.imports, assignOwnDefaults),
|
||||||
@@ -9067,6 +9086,7 @@
|
|||||||
lodash.dropWhile = dropWhile;
|
lodash.dropWhile = dropWhile;
|
||||||
lodash.filter = filter;
|
lodash.filter = filter;
|
||||||
lodash.flatten = flatten;
|
lodash.flatten = flatten;
|
||||||
|
lodash.flattenDeep = flattenDeep;
|
||||||
lodash.forEach = forEach;
|
lodash.forEach = forEach;
|
||||||
lodash.forEachRight = forEachRight;
|
lodash.forEachRight = forEachRight;
|
||||||
lodash.forIn = forIn;
|
lodash.forIn = forIn;
|
||||||
|
|||||||
204
test/test.js
204
test/test.js
@@ -3700,7 +3700,7 @@
|
|||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
QUnit.module('lodash.flatten');
|
QUnit.module('flatten methods');
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var args = arguments;
|
var args = arguments;
|
||||||
@@ -3710,80 +3710,117 @@
|
|||||||
deepEqual(_.flatten(array), [['a'], ['b']]);
|
deepEqual(_.flatten(array), [['a'], ['b']]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should work with `isDeep`', 1, function() {
|
test('should work with `isDeep`', 2, function() {
|
||||||
var array = [[['a']], [['b']]];
|
var array = [[['a']], [['b']]],
|
||||||
deepEqual(_.flatten(array, true), ['a', 'b']);
|
expected = ['a', 'b'];
|
||||||
|
|
||||||
|
deepEqual(_.flatten(array, true), expected);
|
||||||
|
deepEqual(_.flattenDeep(array), expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should flatten `arguments` objects', 1, function() {
|
test('should flatten `arguments` objects', 3, function() {
|
||||||
deepEqual(_.flatten([args, args]), [1, 2, 3, 1, 2, 3]);
|
var array = [args, [args]],
|
||||||
|
expected = [1, 2, 3, args];
|
||||||
|
|
||||||
|
deepEqual(_.flatten(array), expected);
|
||||||
|
|
||||||
|
expected = [1, 2, 3, 1, 2, 3];
|
||||||
|
deepEqual(_.flatten(array, true), expected);
|
||||||
|
deepEqual(_.flattenDeep(array), expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should perform a shallow flatten when used as a callback for `_.map`', 1, function() {
|
test('should execute without options when used as a callback for `_.map`', 2, function() {
|
||||||
var array = [[[['a']]], [[['b']]]];
|
var array = [[[['a']]], [[['b']]]];
|
||||||
|
|
||||||
deepEqual(_.map(array, _.flatten), [[['a']], [['b']]]);
|
deepEqual(_.map(array, _.flatten), [[['a']], [['b']]]);
|
||||||
|
deepEqual(_.map(array, _.flattenDeep), [['a'], ['b']]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should treat sparse arrays as dense', 4, function() {
|
test('should treat sparse arrays as dense', 6, function() {
|
||||||
var array = [[1, 2, 3], Array(3)],
|
var array = [[1, 2, 3], Array(3)],
|
||||||
expected = [1, 2, 3];
|
expected = [1, 2, 3];
|
||||||
|
|
||||||
expected.push(undefined, undefined, undefined);
|
expected.push(undefined, undefined, undefined);
|
||||||
|
|
||||||
_.each([_.flatten(array), _.flatten(array, true)], function(actual) {
|
_.each([_.flatten(array), _.flatten(array, true), _.flattenDeep(array)], function(actual) {
|
||||||
deepEqual(actual, expected);
|
deepEqual(actual, expected);
|
||||||
ok('4' in actual);
|
ok('4' in actual);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should work with extremely large arrays', 1, function() {
|
test('should work with extremely large arrays', 3, function() {
|
||||||
// test in modern browsers
|
// test in modern browsers
|
||||||
if (freeze) {
|
if (freeze) {
|
||||||
try {
|
var expected = Array(5e5);
|
||||||
var expected = Array(5e5),
|
|
||||||
actual = _.flatten([expected]);
|
|
||||||
|
|
||||||
deepEqual(actual, expected);
|
_.times(3, function(index) {
|
||||||
} catch(e) {
|
try {
|
||||||
ok(false);
|
if (index) {
|
||||||
}
|
var actual = actual == 1 ? _.flatten([expected], true) : _.flattenDeep([expected]);
|
||||||
} else {
|
} else {
|
||||||
skipTest();
|
actual = _.flatten(expected);
|
||||||
}
|
}
|
||||||
});
|
deepEqual(actual, expected);
|
||||||
|
} catch(e) {
|
||||||
test('should work with empty arrays', 2, function() {
|
ok(false);
|
||||||
var array = [[], [[]], [[], [[[]]]]];
|
}
|
||||||
|
});
|
||||||
deepEqual(_.flatten(array), [[], [], [[[]]]]);
|
|
||||||
deepEqual(_.flatten(array, true), []);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should support flattening of nested arrays', 2, function() {
|
|
||||||
var array = [1, [2], [3, [4]]];
|
|
||||||
|
|
||||||
deepEqual(_.flatten(array), [1, 2, 3, [4]]);
|
|
||||||
deepEqual(_.flatten(array, true), [1, 2, 3, 4]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return an empty array for non array-like objects', 1, function() {
|
|
||||||
deepEqual(_.flatten({ 'a': 1 }), []);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return a wrapped value when chaining', 4, function() {
|
|
||||||
if (!isNpm) {
|
|
||||||
var wrapped = _([1, [2], [3, [4]]]),
|
|
||||||
actual = wrapped.flatten();
|
|
||||||
|
|
||||||
ok(actual instanceof _);
|
|
||||||
deepEqual(actual.value(), [1, 2, 3, [4]]);
|
|
||||||
|
|
||||||
actual = wrapped.flatten(true);
|
|
||||||
ok(actual instanceof _);
|
|
||||||
deepEqual(actual.value(), [1, 2, 3, 4]);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skipTest(4);
|
skipTest(3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should work with empty arrays', 3, function() {
|
||||||
|
var array = [[], [[]], [[], [[[]]]]],
|
||||||
|
expected = [[], [], [[[]]]];
|
||||||
|
|
||||||
|
deepEqual(_.flatten(array), expected);
|
||||||
|
|
||||||
|
expected = [];
|
||||||
|
deepEqual(_.flatten(array, true), expected);
|
||||||
|
deepEqual(_.flattenDeep(array), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should support flattening of nested arrays', 3, function() {
|
||||||
|
var array = [1, [2], [3, [4]]],
|
||||||
|
expected = [1, 2, 3, [4]];
|
||||||
|
|
||||||
|
deepEqual(_.flatten(array), expected);
|
||||||
|
|
||||||
|
expected = [1, 2, 3, 4];
|
||||||
|
deepEqual(_.flatten(array, true), expected);
|
||||||
|
deepEqual(_.flattenDeep(array), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return an empty array for non array-like objects', 3, function() {
|
||||||
|
var expected = [];
|
||||||
|
|
||||||
|
deepEqual(_.flatten({ 'a': 1 }), expected);
|
||||||
|
deepEqual(_.flatten({ 'a': 1 }, true), expected);
|
||||||
|
deepEqual(_.flattenDeep({ 'a': 1 }), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return a wrapped value when chaining', 6, function() {
|
||||||
|
if (!isNpm) {
|
||||||
|
var wrapped = _([1, [2], [3, [4]]]),
|
||||||
|
actual = wrapped.flatten(),
|
||||||
|
expected = [1, 2, 3, [4]];
|
||||||
|
|
||||||
|
ok(actual instanceof _);
|
||||||
|
deepEqual(actual.value(), expected);
|
||||||
|
|
||||||
|
expected = [1, 2, 3, 4];
|
||||||
|
actual = wrapped.flatten(true);
|
||||||
|
ok(actual instanceof _);
|
||||||
|
deepEqual(actual.value(), expected);
|
||||||
|
|
||||||
|
actual = wrapped.flattenDeep();
|
||||||
|
ok(actual instanceof _);
|
||||||
|
deepEqual(actual.value(), expected);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
skipTest(6);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}(1, 2, 3));
|
}(1, 2, 3));
|
||||||
@@ -9804,36 +9841,40 @@
|
|||||||
strictEqual(compiled({ 'value': true }), 'yap');
|
strictEqual(compiled({ 'value': true }), 'yap');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should work with custom `_.templateSettings` delimiters', 1, function() {
|
test('should work with custom delimiters', 2, function() {
|
||||||
var settings = _.clone(_.templateSettings);
|
_.times(2, function(index) {
|
||||||
|
var settingsClone = _.clone(_.templateSettings);
|
||||||
|
|
||||||
_.assign(_.templateSettings, {
|
var settings = _.assign(index ? _.templateSettings : {}, {
|
||||||
'escape': /\{\{-([\s\S]+?)\}\}/g,
|
'escape': /\{\{-([\s\S]+?)\}\}/g,
|
||||||
'evaluate': /\{\{([\s\S]+?)\}\}/g,
|
'evaluate': /\{\{([\s\S]+?)\}\}/g,
|
||||||
'interpolate': /\{\{=([\s\S]+?)\}\}/g
|
'interpolate': /\{\{=([\s\S]+?)\}\}/g
|
||||||
|
});
|
||||||
|
|
||||||
|
var compiled = _.template('<ul>{{ _.each(collection, function(value, index) { }}<li>{{= index }}: {{- value }}</li>{{ }); }}</ul>', index ? null : settings),
|
||||||
|
expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>';
|
||||||
|
|
||||||
|
strictEqual(compiled({ 'collection': ['a & A', 'b & B'] }), expected);
|
||||||
|
_.assign(_.templateSettings, settingsClone);
|
||||||
});
|
});
|
||||||
|
|
||||||
var compiled = _.template('<ul>{{ _.each(collection, function(value, index) { }}<li>{{= index }}: {{- value }}</li>{{ }); }}</ul>'),
|
|
||||||
expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>';
|
|
||||||
|
|
||||||
strictEqual(compiled({ 'collection': ['a & A', 'b & B'] }), expected);
|
|
||||||
_.assign(_.templateSettings, settings);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should work with `_.templateSettings` delimiters containing special characters', 1, function() {
|
test('should work with custom delimiters containing special characters', 2, function() {
|
||||||
var settings = _.clone(_.templateSettings);
|
_.times(2, function(index) {
|
||||||
|
var settingsClone = _.clone(_.templateSettings);
|
||||||
|
|
||||||
_.assign(_.templateSettings, {
|
var settings = _.assign(index ? _.templateSettings : {}, {
|
||||||
'escape': /<\?-([\s\S]+?)\?>/g,
|
'escape': /<\?-([\s\S]+?)\?>/g,
|
||||||
'evaluate': /<\?([\s\S]+?)\?>/g,
|
'evaluate': /<\?([\s\S]+?)\?>/g,
|
||||||
'interpolate': /<\?=([\s\S]+?)\?>/g
|
'interpolate': /<\?=([\s\S]+?)\?>/g
|
||||||
|
});
|
||||||
|
|
||||||
|
var compiled = _.template('<ul><? _.each(collection, function(value, index) { ?><li><?= index ?>: <?- value ?></li><? }); ?></ul>', index ? null : settings),
|
||||||
|
expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>';
|
||||||
|
|
||||||
|
strictEqual(compiled({ 'collection': ['a & A', 'b & B'] }), expected);
|
||||||
|
_.assign(_.templateSettings, settingsClone);
|
||||||
});
|
});
|
||||||
|
|
||||||
var compiled = _.template('<ul><? _.each(collection, function(value, index) { ?><li><?= index ?>: <?- value ?></li><? }); ?></ul>'),
|
|
||||||
expected = '<ul><li>0: a & A</li><li>1: b & B</li></ul>';
|
|
||||||
|
|
||||||
strictEqual(compiled({ 'collection': ['a & A', 'b & B'] }), expected);
|
|
||||||
_.assign(_.templateSettings, settings);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should work with no delimiters', 1, function() {
|
test('should work with no delimiters', 1, function() {
|
||||||
@@ -9842,9 +9883,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should support the "imports" option', 1, function() {
|
test('should support the "imports" option', 1, function() {
|
||||||
var options = { 'imports': { 'a': 1 } },
|
var compiled = _.template('<%= a %>', { 'imports': { 'a': 1 } });
|
||||||
compiled = _.template('<%= a %>', options);
|
|
||||||
|
|
||||||
strictEqual(compiled({}), '1');
|
strictEqual(compiled({}), '1');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -9863,6 +9902,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should support the legacy `options` param signature', 1, function() {
|
||||||
|
var compiled = _.template('<%= data.a %>', null, { 'variable': 'data' });
|
||||||
|
strictEqual(compiled({ 'a': 1 }), '1');
|
||||||
|
});
|
||||||
|
|
||||||
test('should use a `with` statement by default', 1, function() {
|
test('should use a `with` statement by default', 1, function() {
|
||||||
var compiled = _.template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'),
|
var compiled = _.template('<%= index %><%= collection[index] %><% _.each(collection, function(value, index) { %><%= index %><% }); %>'),
|
||||||
actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] });
|
actual = compiled({ 'index': 1, 'collection': ['a', 'b', 'c'] });
|
||||||
@@ -11677,7 +11721,7 @@
|
|||||||
|
|
||||||
var acceptFalsey = _.difference(allMethods, rejectFalsey);
|
var acceptFalsey = _.difference(allMethods, rejectFalsey);
|
||||||
|
|
||||||
test('should accept falsey arguments', 192, function() {
|
test('should accept falsey arguments', 193, function() {
|
||||||
var emptyArrays = _.map(falsey, _.constant([])),
|
var emptyArrays = _.map(falsey, _.constant([])),
|
||||||
isExposed = '_' in root,
|
isExposed = '_' in root,
|
||||||
oldDash = root._;
|
oldDash = root._;
|
||||||
|
|||||||
Reference in New Issue
Block a user