-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Feature/set #2961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Feature/set #2961
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import isNumber from './isNumber.js'; | ||
| import isArray from './isArray.js'; | ||
| import isObject from './isObject.js'; | ||
|
|
||
|
|
||
| export default function set (obj, path, value) { | ||
| var key = String(path[0]); | ||
|
||
|
|
||
| if (path.length === 1) { | ||
| obj[key] = value; | ||
| return; | ||
| } | ||
|
|
||
| if (!isArray(obj[key]) || !isObject(obj[key])) { | ||
|
||
| var nextKey = path[1]; | ||
| obj[key] = isNumber(nextKey) ? [] : {}; | ||
|
||
| } | ||
|
|
||
| return set(obj[key], path.slice(1), value); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,14 @@ | ||||||
| import isArray from './isArray.js'; | ||||||
| import isObject from './isObject.js'; | ||||||
| import _set from './_set.js'; | ||||||
|
|
||||||
|
|
||||||
| // set the value in given path | ||||||
|
||||||
| export default function set (obj, path, value) { | ||||||
|
||||||
| export default function set (obj, path, value) { | |
| export default function set(obj, path, value) { |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By convention, Underscore functions allow you to pass a single path component as a bare string or number instead of an array. Take path through _.toPath instead of rejecting it if it is not an array.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're checking path.length here and then again in the internal set function. Not a big deal, but slightly inefficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't see other option better than this. I like this implementation. Please let me know if you have an idea how to improve it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please refer to the approach I suggested in #2948. If you do postorder assignment instead of preorder assignment, you can check for path.length === 0 only in the internal function and immediately return value if true. You can avoid lookahead beyond path[0] in that case by replacing obj instead of obj[key].
Referring again to #2948, I also realize that your code is still vulnerable to prototype pollution. You need to fix that as well.
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1255,4 +1255,29 @@ | |||||||||
| assert.deepEqual(_.mapObject(protoObj, _.identity), {a: 1}, 'ignore inherited values from prototypes'); | ||||||||||
|
|
||||||||||
| }); | ||||||||||
|
|
||||||||||
|
|
||||||||||
| QUnit.test('set', function(assert) { | ||||||||||
| // returns first argument if first argument is primitive type | ||||||||||
| assert.strictEqual(_.set(undefined, ['some', 'path'], 'some value'), undefined); | ||||||||||
| assert.strictEqual(_.set(null, ['some', 'path'], 'some value'), null); | ||||||||||
| assert.strictEqual(_.set(12, ['some', 'path'], 'some value'), 12); | ||||||||||
| assert.strictEqual(_.set(BigInt(1), ['some', 'path'], 'some value'), BigInt(1)); | ||||||||||
|
||||||||||
| assert.strictEqual(_.set(BigInt(1), ['some', 'path'], 'some value'), BigInt(1)); | |
| if (typeof BigInt != 'undefined') { | |
| assert.strictEqual(_.set(BigInt(1), ['some', 'path'], 'some value'), BigInt(1)); | |
| } |
You'll find similar code elsewhere in this module.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree with this difference. Numeric keys are implicitly converted to strings. Array indices are actually strings, too. The second test should generate the same value as the first.
| assert.deepEqual(_.set({x: 10}, [0, 0], 'my value'), {x: 10, '0': ['my value']}); | |
| assert.deepEqual(_.set({x: 10}, [0, '0'], 'my value'), {x: 10, '0': {'0': 'my value'}}); | |
| assert.deepEqual(_.set({x: 10}, [0, 0], 'my value'), {x: 10, '0': ['my value']}); | |
| assert.deepEqual(_.set({x: 10}, [0, '0'], 'my value'), {x: 10, '0': ['my value']}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three changes needed for this internal function as a whole:
set, so it does not need to be in a separate module (compareisEqual). Please move it into./set.js. You can call itdeepSet(cf.deepGet).