grunt.config breaks real object when config gets values
- Dominant language
- JavaScript
- Stars
- 12.2k
- Forks
- 1.5k
- PR merge metrics
- No merged PRs in 30d
Description
See [marked#376](https://github.com/chjj/marked/issues/376) for the context of this issue.
I have searched why a real object (`new marked.Renderer()` in my case) losts its member functions when `grunt.config(['assemble','options')` is called and I came to what follows (from `grunt/node_modules/grunt-legacy-util/index.js`) :
``` javascript
...
// Recurse through objects and arrays, executing fn for each non-object.
util.recurse = function recurse(value, fn, fnContinue) {
var obj;
if (fnContinue && fnContinue(value) === false) {
// Skip value if necessary.
return value;
} else if (util.kindOf(value) === 'array') {
// If value is an array, recurse.
return value.map(function(value) {
return recurse(value, fn, fnContinue);
});
} else if (util.kindOf(value) === 'object') {
// If value is an object, recurse.
obj = {};
Object.keys(value).forEach(function(key) {
obj[key] = recurse(value[key], fn, fnContinue);
});
return obj;
} else {
// Otherwise pass value into fn and return.
return fn(value);
}
};
...
```
when a real object is copied, `recurse` goes through its properties without never taking the member functions.
I fixed the bug with the following by testing if a constructor exists on the object :
``` javascript
// Recurse through objects and arrays, executing fn for each non-object.
util.recurse = function recurse(value, fn, fnContinue) {
var obj;
if (fnContinue && fnContinue(value) === false) {
// Skip value if necessary.
return value;
} else if (util.kindOf(value) === 'array') {
// If value is an array, recurse.
return value.map(function(value) {
return recurse(value, fn, fnContinue);
});
} else if (util.kindOf(value) === 'object') {
// ------------------------------------------------------------
// Patch : If value is an instance of, just pass value
if (util.kindOf(value.constructor) === 'function') {
return value;
}
// ------------------------------------------------------------
// If value is an object, recurse.
obj = {};
Object.keys(value).forEach(function(key) {
obj[key] = recurse(value[key], fn, fnContinue);
});
return obj;
} else {
// Otherwise pass value into fn and return.
return fn(value);
}
};
...
```
Any thought on whether this fix is correct or not ?
And if not, what would be the correct one ?
Contributor guide
Research direction
The behavior is in grunt/node_modules/grunt-legacy-util/index.js, in util.recurse; start there and compare handling of plain objects with instances such as new marked.Renderer(). Confirm that grunt.config preserves instance methods while still recursing through ordinary objects and arrays; no test file is named in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100