Add Joi.func().class()#1308
Add Joi.func().class()#1308Marsup merged 1 commit intohapijs:masterfrom wswoodruff:add-func-class-validation
Conversation
|
Replaces #1305 |
lib/is-class.js
Outdated
| @@ -0,0 +1,3 @@ | |||
| 'use strict'; | |||
|
|
|||
| module.exports = (func) => (/^\s*class\s/).test(func.toString()); | |||
There was a problem hiding this comment.
This seems... too simple. Haha. I expected to need more than "stringify and see if it says 'class'", but I can't justify that expectation. So.. good job! 👍
There was a problem hiding this comment.
Haha, credit to @devinivy's haute lib for the one-liner! https://github.com/devinivy/haute/blob/master/lib/index.js#L157
There was a problem hiding this comment.
And in turn to Felix Kling on stack overflow :P! https://stackoverflow.com/a/30760236
Just keep in mind the test used in haute is only good if you already know you have a function.
There was a problem hiding this comment.
That's true! We could validate that with a regular string like 'class hahaha Im just a string ya see!'
There was a problem hiding this comment.
We should check to make sure func.toString is a function that we can execute before we try to (or that func is indeed a function). Don't want to throw an error here.
Ideally I think it would be worth making sure it is a function as well. So if this was instead typeof func === 'function' && (/^\s*....); that way we know that there should be a toString() method on it as well.
As this code stands right now the following would pass incorrectly:
(/^\s*class\s/).test(['class '].toString()); // trueNext part would be why is \s* being expected in the RegExp? There aren't any leading whitespace characters from the Function.toString() method from what I've seen in the MDN docs nor from my testing. It seems like we should instead just have /^class\s/ as our RegExp.
There was a problem hiding this comment.
The whitespace is technically allowed at the beginning because according to the spec "The use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent." It's possible that that's an impractical concern, but I don't see the harm. At the same time I suppose we're not checking for semicolons and it would clearly be silly to do so, so I see your point.
I am similarly concerned about creating a runtime error if the helper is misused, but it's also valid to say as a precondition that the input to the helper must be a function.
test/types/object.js
Outdated
| const testFunc = function () {}; | ||
| const testClass = class MyClass {}; | ||
|
|
||
| classSchema.validate({ _class: testFunc }, (err, invalidValue) => { |
There was a problem hiding this comment.
Can we not use the Helper that we have just like in the other tests?
Also, can we add some additional negative test cases such as undefined, null, ['class '], etc. It looks like there are some cases in the current code where we could throw an error instead of actually responding with a Joi error.
There was a problem hiding this comment.
Sure thing, updated!
lib/is-class.js
Outdated
| @@ -0,0 +1,3 @@ | |||
| 'use strict'; | |||
|
|
|||
| module.exports = (func) => (/^\s*class\s/).test(func.toString()); | |||
There was a problem hiding this comment.
We should check to make sure func.toString is a function that we can execute before we try to (or that func is indeed a function). Don't want to throw an error here.
Ideally I think it would be worth making sure it is a function as well. So if this was instead typeof func === 'function' && (/^\s*....); that way we know that there should be a toString() method on it as well.
As this code stands right now the following would pass incorrectly:
(/^\s*class\s/).test(['class '].toString()); // trueNext part would be why is \s* being expected in the RegExp? There aren't any leading whitespace characters from the Function.toString() method from what I've seen in the MDN docs nor from my testing. It seems like we should instead just have /^class\s/ as our RegExp.
lib/language.js
Outdated
| maxArity: 'must have an arity lesser or equal to {{n}}', | ||
| ref: 'must be a Joi reference' | ||
| ref: 'must be a Joi reference', | ||
| class: 'must be an ES6 class' |
There was a problem hiding this comment.
Wouldn't we just say "must be a class"? We shouldn't be having an ES6 Class and then later an ES7 Class. (This is a bit of a pedantic comment, but I'd rather make it than not)
lib/types/object/index.js
Outdated
| } | ||
|
|
||
| class() { | ||
|
|
There was a problem hiding this comment.
Should I add a check right here to see if this._flags.func === true?
There was a problem hiding this comment.
The way that this is setup right now the flag this._flags.func could have not been set. The reason why being that a user could do Joi.object().class() or Joi.func().class().
Additionally the flag this._flags.func just ensures that we have set the flag that it should be a function, it doesn't validate that the input coming into isClass is actually a function. I would personally use typeof func in the isClass method.
|
@DavidTPate This should be ready for another look! |
|
I'm still thinking about the split. |
|
Splitting object and func? Might be a cool idea, I'll bet you're trying to weigh how much work that might be. What you think? |
|
If you think there should be a change like splitting func / class out of object, lemme know some of your thoughts on approach and I can give it a shot |
test/types/object.js
Outdated
|
|
||
| Helper.validate(classSchema, [ | ||
| [{ _class: ['class '] }, false, null, { | ||
| message: 'child "_class" fails because ["_class" must be a Function]', |
There was a problem hiding this comment.
Interesting, so I'm guessing this is the side-effect of this being off Joi.func() where we have the this._flags.func flag set for validation.
It makes sense given the implementation that we are returned the error "_class" must be a Function my initial thought was that we would get "_class" must be a class. But returning the base type first is the same way it works for any of our other types (ie. Joi.string().uuid())
There was a problem hiding this comment.
Yup! So in order to cover the additional function type check, typeof func === 'function' I had to use the is-class.js helper directly in the tests
DavidTPate
left a comment
There was a problem hiding this comment.
The changes look good to me, but also want to get @Marsup's thoughts on this as he mentioned he is thinking about a few things.
|
Separated the func from the object, can you rebase @wswoodruff ? |
test/types/object.js
Outdated
|
|
||
| }); | ||
|
|
||
| describe('func().class()', () => { |
There was a problem hiding this comment.
It shouldn't be there, there's a file for function tests.
|
@Marsup Test is failing because eslint doesn't like the object |
|
Why did you take branch v12 in the first place? 😛 |
|
Ohhh I thought you wanted me to rebase off of |
|
This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions. |
|
This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions. |
functionis not valid againstJoi.func().class()classis valid againstJoi.func().class()