Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upGitHub is where the world builds software
Millions of developers and companies build, ship, and maintain their software on GitHub — the largest and most advanced development platform in the world.
Fix handling of `transform` props in b.require() #1262
Conversation
That is, test that transforms *can't* be added by calling b.require() (instead of b.transform()), because that shouldn't work.
* Don't set to anything based on `opts`. * Delete from sources of row props (file|opts) so that `transform` isn't present on the pushed row. There were mystery references to `row.transform` (aka `rec.transform`) in b.require(). One was in a nonsensical conditional assignment that was a no-op, and I couldn't identify a purpose for the other. See #1057. Meanwhile, a transform could be added via b.require() by passing a `transform` prop on one of the args. This seems to be accidental and undesirable.
Make sure a transform can't be added when b.require()'ing a stream.
|
|
||
| // Prevent .require() from adding transforms. See: module-deps and | ||
| // https://github.com/substack/node-browserify/pull/1057 | ||
| delete file.transform; |
zertosh
May 13, 2015
Member
You're mutating the object that was passed into require. This should be done after the xtend below.
|
I was looking at the test, I thought maybe something like this would be easier to understand, but I leave it up to you - feel free to ignore this comment: // don't use unicode/main.js - this is just for demo purposes
test('b.require transform prop file path', function (t) {
t.plan(2);
var b = browserify();
b.require([{
file: __dirname + '/unicode/main.js',
transform: through(function() {
t.fail('this should not be called');
})
}]);
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
});
test('b.require transform prop file path', function (t) {
t.plan(2);
var b = browserify();
b.require(__dirname + '/unicode/main.js', {
transform: through(function() {
t.fail('this should not be called');
})
});
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
});
test('b.require transform prop file stream', function (t) {
t.plan(2);
var s = through();
var b = browserify();
b.require(s, {
transform: through(function() {
t.fail('this should not be called');
})
});
s.write('module.exports = {};');
s.end();
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
}); |
Ok. The only reason I did that was to "head it off at the pass" and not have to do it separately for stream / non-stream, but point taken. I wanted to do some general refactoring on this method at some point to consolidate the stream / non-stream logic better in general, unify on usage of I don't think the general refactoring should break anything, but if you have the chance to look it over that'd be great. I'm a little bit concerned about the test coverage. I was trying to make it so the order value only gets incremented for streams when it'll be used (just to keep them sequential), so I originally made that conditional on
That's not a bad idea. I could kind of go either way, but doing it the way you suggest gives it a narrower focus, which probably isn't bad in this case. I kept the general structure I had with a parameterized function to avoid duplication (not sure if you were even suggesting changing that) but simplified it in the way you suggested: made the entry file content irrelevant and the transform a passthrough and just Here's an updated branch: Part that corresponds to original PR branch: And here's the general refactoring on top of that: The last commit, the general refactoring, could be a separate PR if necessary. |
Both
Yeah, I'm sorry - I don't mean to walk all over your PR :( The substack philosophy seems to emphasize duplication. Each spec is pretty self-contained with only minor exceptions. Also, each test seems to have their own fixtures, not a lot of sharing there either. IIRC, when using tap, until the plan count is met, you'll just sit around waiting for a timeout. So by using This is just a suggestion, please ignore it if you disagree: I'd make a test('b.require() file path with file.transform prop', function (t) {
t.plan(2);
var b = browserify();
var file = __dirname + '/require_transform/main.js';
b.require([{
file: file,
transform: through(function() {
t.fail('this should not be called');
})
}]);
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
});
test('b.require() file path with opts.transform prop', function (t) {
t.plan(2);
var b = browserify();
var file = __dirname + '/require_transform/main.js';
b.require(file, {
transform: through(function() {
t.fail('this should not be called');
})
});
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
});
test('b.require() file stream with file.transform prop', function (t) {
t.plan(2);
var b = browserify();
var file = fs.createReadStream(__dirname + '/require_transform/main.js');
b.require([{
file: file,
transform: through(function() {
t.fail('this should not be called');
})
});
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
})
test('b.require() file stream with opts.transform prop', function (t) {
t.plan(2);
var b = browserify();
var file = fs.createReadStream(__dirname + '/require_transform/main.js');
b.require(file, {
transform: through(function() {
t.fail('this should not be called');
})
});
b.bundle(function(err, src) {
t.ifError(err);
t.ok(src);
});
}); |
In what way?
Only because I didn't think of it, and it's a more dramatic refactoring (not that that's a bad thing). Maybe that is a better solution. If so, I'm all for it.
I'll have to check it out and make sure everything would come out right. The logic in that method is very convoluted, almost entirely lacking comments, and has questionable test coverage. Aside from that, you'd have to do something (maybe a private method and a public method) to prevent users from populating
I'm always open to constructive criticism and improvement.
My philosophy is generally to very much emphasize non-duplication. These tests are very closely related variations on a theme, differing only by a couple of parameters.
Yeah, I know that was a bit hokey to use that
I was under the impression that the way I authored it would avoid waiting for timeout. What does the tap documentation for
If there's entry.end(Buffer('";'));
I'll make an entry file specifically for these tests. I value your feedback, but I have to respectfully disagree that duplicating the bulk of the test code |
This is approximately what I see that looking like (based on master, tests passing): I think it probably is better. |
Heh, I think it's actually the simplest solution https://gist.github.com/zertosh/e66a3e96afc45228f02b
"Questionable test coverage" lol - so true. All of the // never true
if (file === expose && /^[\.]/.test(expose)) {
expose = '/' + path.relative(basedir, expose);
}
// if this is true.....
if (expose === undefined && this._options.exposeAll) {
expose = true;
}
// then this will throw because `path.relative` only
// takes string arguments - file -> stream
if (expose === true) {
expose = '/' + path.relative(basedir, file);
}I not sure about making public/private methods. If you mess with
Don't get me wrong, I'm not in favor of code duplication - except in tests :P Tests have to be the easiest possible to understand, with very little surface area for errors in themselves. Introducing abstractions or syntax works against that. But I won't block you over testing philosophy.
Yup. You're right. I just verified it |
The end result probably is. But it's a more dramatic refactoring because there's more to consider. For example, in your gist, does elimination of the
Yeah, I also moved the stream handling logic above that in my refactor that based on your idea of re-calling
I guess at this point I feel like we should do one thing or the other: either filter the props coming from the user or just document the methods well and say: "If you pass undocumented props then un(intended|wanted|documented) behavior may occur, and that behavior is subject to change. Don't create issues involving undocumented use of props."
Well, not all of it, right?:
Just to provide a hint? Anyway, I'm going to hold off on making any changes related to these |
You made it so that module-deps does that for you :)
I reallllyyyy like this policy - more so than filtering.
I guess what I meant was: "I think the only user of this API is the CLI". I don't see 99.9% of users every touching this functionality.
Yeah, an idiomatic hint. It goes very well with the above policy statement.
I think removing the props now will help with the refactor, since if anything breaks, it'll help guide the refactor. Just a thought. |
Yeah, I just didn't know if that gets invoked for a row with a
We could do that. Of course, people are still going to publish blog posts and stuff instructing people to use undocumented props and they're still going to post issues about it here.
Perhaps, but nonetheless it's a documented part of the public API.
Ok, we should keep that in mind for future consideration.
If we're not going to filter props and just have a hands-off policy instead then we don't need any of these commits (other than the general refactoring ones). |
I guess so. Do you want the policy to the read me and/or the "submitting issues" wiki page? |
Are you asking where I think it should go, or whether I want to do it? I think it should be in the readme and I think adding it to the "submitting issues" wiki is a great idea. I'll add it in either or both places if you want. |
Both? Either? Go for it in both! |

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.

Supersedes #1057.
EDIT 2015-05-13 4:52 eastern
See updated commits (discussed below):
Here's an updated branch:
Part that corresponds to original PR branch:
master...jmm:bbb1ab8
General refactoring on top of that:
jmm/node-browserify@bbb1ab8...b-require-transform2