Skip to content
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

Validator ideas #4

Closed
86 of 87 tasks
SamVerschueren opened this issue Oct 4, 2017 · 14 comments
Closed
86 of 87 tasks

Validator ideas #4

SamVerschueren opened this issue Oct 4, 2017 · 14 comments

Comments

@SamVerschueren
Copy link
Collaborator

SamVerschueren commented Oct 4, 2017

Want to open a thread to discuss and think about all the nice validators/predicates we want to implement. Feel free to provide feedback, add new things, remove things etc. It's just a draft about things we could add.

all

Primitives

string

number

boolean

symbol (#28)

undefined (#28)

null (#28)

Built-in types

array

Date

Error

Map

object

set

weakMap

weakSet

function (#30)

buffer (#30)

regExp (#30)

promise (#30)

typedArray (#30)

int8Array(value) (#30)

uint8Array(value) (#30)

uint8ClampedArray(value) (#30)

int16Array(value) (#30)

uint16Array(value) (#30)

int32Array(value) (#30)

uint32Array(value) (#30)

float32Array(value) (#30)

float64Array(value) (#30)

arrayBuffer(value) (#30)

sharedArrayBuffer(value)

Was added in Node.js 9 if I'm not mistaken, so can't add it.

dataView(value) (#38)

nan(value) (#38)

nullOrUndefined(value) (#38)

iterable(value) (#30)

@sindresorhus
Copy link
Owner

sindresorhus commented Oct 5, 2017

Great! I was actually going to open this exact issue yesterday, but got busy. I've been having this draft for a while:

all

  • optional (Means undefined is allowed) (Note: I don't think we should allow null, to align with default parameters)
  • not (Inverts the following predicates)
  • not(type) (Inverts just the argument) (Example: ow.string.not(ow.empty))
  • any (For multiple predicates, for example, when something can be both a string and array)
  • is(function) (Accepts a function that receives the value from ow and is expected to return a boolean)

string

  • length(number)
  • minLength(number)
  • maxLength(number)
  • match(regex: RegExp) (Seems like matches would better align with other names like includes, startsWidth?)
  • startsWith(string)
  • endsWith(string)
  • includes(string)
  • empty (Only useful when used with .not)
  • nonEmpty
  • equal(string)
  • alphanumeric
  • numeric
  • date

number

  • inRange(start: number, end: number)
  • integer
  • equal(number)
  • positive
  • negative
  • finite
  • min(number)
  • max(number)

boolean

  • true
  • false

array

  • ofType(type, …) (Accepts any is.x type) (TODO: Would be useful if this could also support any ow predicate for each element, so you could do: ow.array.ofType(ow.string.minLength(5)))
  • length(number)
  • minLength(number)
  • maxLength(number)
  • startsWith(string)
  • endsWith(string)
  • includes(string, …)
  • includesAny(string, …)
  • empty (Only useful when used with .not)
  • nonEmpty
  • deepEqual(array)

object

  • valuesOfType(type, …) (Accepts any is.x type)
  • plain
  • empty (Only useful when used with .not)
  • nonEmpty
  • deepEqual(object)
  • instanceOf(object)
  • hasKeys(property, …)
  • hasAnyKeys(property, …)

date

  • before(date)
  • after(date)

error

  • evalError
  • rangeError
  • referenceError
  • syntaxError
  • typeError
  • uriError
  • name(string)
  • message(string)
  • messageIncludes(string)

map

  • size(number)
  • minSize(number)
  • maxSize(number)
  • keysOfType(type, …)
  • valuesOfType(type, …)
  • hasKeys(string, …)
  • hasValues(string, …)
  • hasAnyKeys(string, …)
  • hasAnyValues(string, …)
  • empty (Only useful when used with .not)
  • nonEmpty
  • deepEqual(map)

set

  • size(number)
  • minSize(number)
  • maxSize(number)
  • ofType(type, …)
  • has(string, …)
  • hasAny(string, …)
  • empty (Only useful when used with .not)
  • nonEmpty
  • deepEqual(set)

weakMap

  • keysOfType(type, …)
  • hasKeys(string, …)
  • hasAnyKeys(string, …)

weakSet

  • ofType(type, …)
  • has(string, …)
  • hasAny(string, …)

undefined

null

symbol

function

buffer

regExp

promise

typedArray

int8Array(value)

uint8Array(value)

uint8ClampedArray(value)

int16Array(value)

uint16Array(value)

int32Array(value)

uint32Array(value)

float32Array(value)

float64Array(value)

arrayBuffer(value)

sharedArrayBuffer(value)

dataView(value)

nan(value)

nullOrUndefined(value)

iterable(value)


gt(value: number)
lt(value: number)

I think min and max is clearer and more readable. What do you think?

float (number-is-float)

I don't really see the point of float. 1 could be a float too. I don't see the value of differentiating it. integer, however, could be useful, for when you only accept whole numbers.

negativeZero (negative-zero)
positiveZero (positive-zero)

I've honestly never needed this. Let's skip it until there are actual valid needs.

@SamVerschueren
Copy link
Collaborator Author

I don't really see the point of float

Never needed it. Was just going through @kevva and your packages to see what we could use :).

I've honestly never needed this. Let's skip it until there are actual valid needs.

👌 Me neither.

I think min and max is clearer and more readable.

I'm fine with both. I might have a slight preference for gt and lt because I feel it reads easier.

ow(5, ow.number.gt(4));
//=> 5 should be a number greater than 4

ow(5, ow.number.min(4));
//=> 5 should be a number with a minimum of 4

One thing I thought about as well is to have an is predicate on every type which accepts a function. This could keep ow lighter with less built-in dependencies.

const ow = require('ow');
const inRange = require('in-range');
const validDate = require('vali-date');
const positive = require('is-positive');

ow(5, ow.number.is(positive).is(x => inRange(x, 0, 10));

ow('2017-05-21', ow.string.is(validDate));

It's just an example though, I think having things like positive and inRange in ow itself would be very nice. The is method could be just an extra which allows people to easily extend it.

@sindresorhus
Copy link
Owner

sindresorhus commented Oct 5, 2017

One thing I thought about as well is to have an is predicate on every type which accepts a function.

Good idea! I agree it would be useful. I've added it to the proposal.

@sindresorhus
Copy link
Owner

I'm fine with both. I might have a slight preference for gt and lt because I feel it reads easier.

I agree. It shows the intent better, and ow is all about adding readability. I think it should be greaterThan instead of gt though.

@SamVerschueren
Copy link
Collaborator Author

Thinking about it, I believe min and greaterThan are not identical.

min: value >= x
greaterThan: value > x

The intent of greaterThan might be clearer, because with min, users might not be sure if x is included or excluded. But don't think it justifies that we should implement both.

@sindresorhus
Copy link
Owner

sindresorhus commented Oct 18, 2017

Thinking about it, I believe min and greaterThan are not identical.

I never implied they were.

But don't think it justifies that we should implement both.

I think it does. There's a reason we have both > and >= in most programming languages. It also makes the error message better.

@sindresorhus
Copy link
Owner

But maybe min should be greaterThanOrEqual? For consistency? I dunno.

@SamVerschueren
Copy link
Collaborator Author

So we should add greaterThan and greaterThanOrEqual right?

@sindresorhus
Copy link
Owner

That's my suggestion, yes. The latter is a bit verbose but good for readability, and better than min for consistency.

@SamVerschueren
Copy link
Collaborator Author

Good idea! Added!

@SamVerschueren
Copy link
Collaborator Author

We're almost done with this list, so I was looking into the ones that we didn't implement yet. I have a question regarding optional

optional (Means undefined is allowed) (Note: I don't think we should allow null, to align with default parameters)

Should it be

ow(x, ow.optional.string.minLength(4));

// or

ow(x, ow.string.optional.minLength(4));

Or both of course.

If we go for either 2 or 3 (both), this mean we could write something like ow.string.minLength(4).optional.maxLength(5) which doesn't really make sense. That's why I'm more in favour of 1.

@sindresorhus
Copy link
Owner

Lets go with 1

@sindresorhus
Copy link
Owner

notType(type) (Inverts just the argument) (Example: ow.string.notType(ow.empty))

I think it's better to just do #71

@sindresorhus
Copy link
Owner

Closing as we've done all of these. Wow!

68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f6c3045786b3845557a534c7372457245512f67697068792e676966

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants