Giter VIP home page Giter VIP logo

tcomb-validation's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tcomb-validation's Issues

Surface custom errors from subtypes?

Are there any plans to allow custom validation errors on a subtype? I've got the following subtype:

t.subtype(t.Str, function (string) {
    try {
        JSON.parse(string);
        return true;
    } catch (e) {
        // surface e.message?
        return false;
    }
}, "JSON Schema");

Customize messages on a per-Type basis

It's currently possible to customize the messaging for a particular property:

var Identifier = subtype(Str, function (v) {
  return /^[a-z._-]{1,32}$/.test(v);
}, 'Identifier');

var Thing = struct({
  id: Identifier
});

validate(Thing, {id: 'lol invalid'}, {
  messages: {
    id: ':path invalid. :actual must be a string containing only alphanumeric characters, hyphens, underscores and dots, and be between 1 and 32 characters long.'
  }
});

But this gets awkward when you re-use the same type in multiple places:

var RelatedThing = Thing.extend({ parentId: Identifer });

Instead of repeating the same message (or putting it into a variable and repeating that), It would be much DRYer to define messages for types/predicates instead of fields. This would also give the advantage that one can give more specific error messages:

validate(RelatedThing, {id: 'totally_valid', parentId: 'not so valid'}, {
  typeMessages: {
    Str: ':actual at :path must be a string.',
    Identifier: ':actual at :path must contain 1-32 alphanumeric characters, hyphens, underscores or dots.'
  }
});

What do you think?

Add support for custom error messages

Proposal: an optional getValidationErrorMessage(value, path) on the type constructor:

var ShortString = t.subtype(t.String, function (s) {
  return s.length < 3;
});

ShortString.getValidationErrorMessage = function (value) {
  if (!value) {
    return 'Required';
  }
  if (s.length >= 3) {
    return 'Too long my friend';
  }
};

validate('abc', ShortString).firstError().message; // => 'Too long my friend'

How to keep DRY?

In order to keep the validation logic in one place, one may define a custom combinator:

function mysubtype(type, getValidationErrorMessage, name) {
  var Subtype = t.subtype(type, function (x) {
    return !t.String.is(getValidationErrorMessage(x));
  }, name);
  Subtype.getValidationErrorMessage = getValidationErrorMessage;
  return Subtype;
}

var ShortString = mysubtype(t.String, function (s) {
  if (!value) {
    return 'Required';
  }
  if (s.length >= 3) {
    return 'Too long my friend';
  }
});

Having trouble using Date validation

Surprisingly, most samples do not deal with Date. I have an object that I want to validate the date with. The object I want to supply is:
{ dateTimeGiven: "2001-01-01" } and my struct is:
const newType = t.struct ({ dateTimeGiven: t.Date});

I am getting invalid date for every date that I supply. Can you provide a direct sample of how to validate a date given in a json object? Thanks.

Jim

Question about the RegExp type and how it's used.

I'm a bit confused about the RegExp type shown in the readme. Normally you would want to test a field against a RegExp pattern, e.g. check for a valid email, rather than check that a field is a RegExp pattern (as shown in the example). Would you have to create a refinement for the former use case of checking a field against a pattern? Why would you want a RegExp type in tcomb otherwise? What would it be used for?

[question] Extra value in error.paths array

Hi 👋 big fan of tcomb and just started exploring this lib for validation.

Had a question when I have this setup:

const betterString = t.refinement(t.String, x => x !== '', 'BetterString')

const State = t.struct({
  state: betterString,
  code: t.maybe(t.Number)
}, {name:'State'})

const Code = t.struct({
  code: t.Number,
  state: t.maybe(t.String)
}, {name:'Code'})

const Union = t.union([State, Code], 'StateOrCode')

Union.dispatch = (obj) => {
  return betterString.is(obj['state']) ? State : Code
}

const data = {
  '32897284': {
    state: '',
    code: null
  }
}

which basically i want either state or code to be filled, both being filled is ok as well otherwise its an erorr
everything works great with this setup however in the errors.path i get the following ['32897284', 1, 'code'] not sure
why i need that number 1 in there.

i tracked the code down to Line 223 which concats an index with the paths
but im not sure i follow the logic for this to be in the paths array and was hoping for some insight

is this a bug or works as expected?

Update playground?

The version of tcomb being used by the playground seems quite old, in particular there is no default dispatch defined for Union types.

`tcomb-validation` error message doesn't contain struct name

For some reason tcomb-validation outputs different from tcomb error message — it doesn't account for name option of t.struct.

Example:

const Schema = t.struct({
  name: t.String,
  surname: t.maybe(t.String),
  age: t.Integer,
  tags: t.list(t.String)
}, { name: 'Person', strict: true })

Schema(data)
console.log(tv.validate(data, Schema).errors)

tcomb will produce

[tcomb] Invalid value undefined supplied to Person/name: String

tcomb-validation will produce

Invalid value undefined supplied to /name: String

Note how tcomb prints Person as name from struct, but tcomb-validate does not.

Is it per design?

custom validation messages does not work when value is undefined.

var ShortString = t.subtype(t.String, function (s) {
  return s.length < 3;
});

ShortString.getValidationErrorMessage = function (value) {
  if (!value) {
    return 'Required';
  }
  if (value.length >= 3) {
    return 'Too long my friend';
  }
};
validate(undefined, ShortString) // returns the default error message instead of the custom one.

Struct with predicate

I am using version 3.2.2 and I am trying to build a library of reusable validators around tcomb-validator.

So I first defined my custom field validators which are predicates and then wanted to compose an object validator using the structure like follow:

       ` var Title = function (s) {
              return s.length > 2 && s.length <= 255;
        }`

        `Title.getValidationErrorMessage = function (value) {
            if (!value) {
                return 'document.validation.error.missing';
            }

            if (value.length <= 2) {
                return 'document.validation.error.tooShort';
            }

            if (payload.title.length > 255) {
                return 'document.validation.error.tooLong';
            }
        };`

And then used like this:

        `var BaseDocument = t.struct({
            title: Title,
            body: OtherCustomType,
        });
        var payload = {
            title: "abcd",
            body: "some other valid value",
        };
        var validationResult = validate(payload, BaseDocument);`

But in this case, even if the payload is valid and the validationResult.isValid() returns true

Too awkward to use.

Nice idea I like it but the API is too difficult to use.

I want to have assert throw a useful error I don't think having people download another npm package to get sensible feedback as to why asserts are failing makes sense.

var VinylFile = tcomb.struct({
    cwd: tcomb.Str,
    path: tcomb.Str,
    base: tcomb.Str
});

tcomb.assert(VinylFile.is(myVinylFileInstance)); //This should throw an error with the first error as it's message not "assert failed".

assert failed is useless as a message. I'm trying to use tcomb in a current project and frankly it's not giving me the quick and clean feedback I would expect it to.

Merge this with tcomb and have assert throw good errors so I don't have to launch node-inspector.

The lines of code required by someone using this library should be

  1. require library.
  2. write type annotations.
  3. assert an object is of type x.

If an assert fails the error needs to be excellent and tell the developer exactly why it failed.

Path in dict errors includes all keys upto the error.

Example to reproduce (in the playground):

var Dict = t.dict(Str, Str);
validate({a: "a", b: "b", c: "c", d: 0}, Dict);

Error message:

/a/b/c/d is 0 should be a Str

I'd expect it to just be:

/d is 0 should be a Str

TypeScript definitions

Hi,

So, following this, I guess the next logical step would be to provide typescript definitions for tcomb-validation. Would it be easier to implement?

Localization support in `getValidationErrorMessage`?

Hi and thanks for the great lib!

I have one question though: what is the proper way to return localized error messages from getValidationErrorMessage function?

The problem is I have to pass user's locale into this function somehow in order to return proper error message and the only solution I found now is to construct one struct per locale (but I don't like it):

// ./structs/ShortString.js

const _ = require('lodash');
const t = require('tcomb');

const intl = require('./intl');

module.exports = _.memoize(locale => {
    const ShortString = t.subtype(t.String, s => s.length < 3);

    ShortString.getValidationErrorMessage = value => {
        if (!value) {
            return intl(locale, 'Required');
        }

        if (value.length >= 3) {
            return intl(locale, 'Too long my friend');
        }
    };

    return ShortString;
});

// Some Express.js middleware
const ShortString = require('./structs/ShortString');

app.use((req, res) => {
    const locale = getUserLocale(req);

    const validationResult = validate(req.query.str, ShortString(locale));
});

The other solution could be is to pass an external options (or context) argument to validate().
Then this example would look like this:

// ./structs/ShortString.js

const _ = require('lodash');
const t = require('tcomb');

const intl = require('./intl');

const ShortString = t.subtype(t.String, s => s.length < 3);

ShortString.getValidationErrorMessage = (value, context) => {
    const { locale } = context;

    if (!value) {
        return intl(locale, 'Required');
    }

    if (value.length >= 3) {
        return intl(locale, 'Too long my friend');
    }
};

module.exports = ShortString;

// Some Express.js middleware
const ShortString = require('./structs/ShortString');

app.use((req, res) => {
    const locale = getUserLocale(req);

    const validationResult = validate(req.query.str, ShortString, { locale });
});

What do you think about it?

Default messages

I'd like the ability to set a default error message in tcomb-validation for certain scenarios. For example, currently the default message that tcomb-validation gives you is 'Invalid value ' + stringify(actual) + ' supplied to ' + to;

Which is fine. But I'd like all required fields to say to + ' is required' without having to specify it in each field. I'm using this w/ tcomb-form and I can set the error message in each field, but it would be much nicer if I could just have all required fields use a default for that condition...

Don't run check again for error message

The "solution" to keep check and related error message dry looks more like a workaround.

Issues:

  • The (probably expensive) check is run twice.
  • It relies on any state considered by check being identical at the time of the check and the time when getValidationErrorMessage is called. One candidate for a non-identical world state is e.g. a new Date().

Instead, the check should be able to leave check (failure) details which are provided to (e.g.) getValidationErrorMessage.

Union of structs

should this be working?

const data = {
  text: 'whyoff'
};

const attributes = t.union([
  t.struct({ text: t.String }),
  t.struct({ url: t.String })
], 'Attributes');

const result = validate(data, attributes);

console.log(result);
=========================================
Struct {
  errors: 
   [ Struct {
       message: 'Invalid value {\n  "text": "whyoff"\n} supplied to Attributes',
       actual: [Object],
       expected: [Object],
       path: [] } ],
  value: { text: 'whyoff' } }

Question about usage and need

Excuse me but I'm a little bit puzzled about the need of tcomb-validation, what's the gain of this:

const tv = require('tcomb-validation');

tv.validate(1, tv.String).isValid();   // => false
tv.validate('a', tv.String).isValid(); // => true

Versus this:

const t = require('tcomb');

const aString = t.String(1);
const bString = t.String('a');

Wasn't the whole point of tcomb to have an identity function which did validation in the background?

With tcomb-validation now I have to add boilerplate code to check every single thing.

Please, don't misunderstand me, I'm not trolling, it's I'm not seeing the benefit, but since someone took the time to make tcomb-validation, then I guess I'm missing something.

http post validation

hi, when I use restify create an API, and use validation like:

var check = t.struct({
    username: t.String,
    realname: t.String,
    password: t.String,
    age: t.Number,
    active: t.Boolean
});

module.exports = {
    name : 'User',
    check: check
};
function create(req, res, next) {
    var result = t.validate(req.body, validate.User.check);
    var values = new validate.User.check(req.body);

    if (!result.isValid()) {
        res.send(422, result.errors);
    }
}

when I send a post request with params "age=20", then throw an Exception, cannot cat age param type to number

throw new TypeError('[tcomb] ' + message);
  ^

TypeError: [tcomb] Invalid value "20" supplied to Struct{username: String, realname: String, password: String, age: Number, active: Boolean}/age: Number

Please fix dependencies

207 error Darwin 14.4.0
208 error argv "/usr/local/bin/iojs" "/usr/local/bin/npm" "i" "--save" "tcomb-validation"
209 error node v2.3.3
210 error npm v2.11.3
211 error code EPEERINVALID
212 error peerinvalid The package tcomb does not satisfy its siblings' peerDependencies requirements!
212 error peerinvalid Peer [email protected] wants tcomb@^1.0.0
213 verbose exit [ 1, true ]

Cross validation question

Hello
I have found an issue #29 that partially answers my question.

I have a form

var crossValidation = function(p){

    var regexp;

    switch(p.document_type){
        case 2: // Birth certificate
            regexp = /^\w+[А-Я]{2}\d{6}$/;
            break;
        case 4: // Seaman's discharge book
            regexp = /^[\d\w]{2}\d{7}$/;
            break;
    }

    return regexp.test(value);
};

var Person = t.subtype(
    t.struct({
        document_type: t.Number,
        document_number: t.String
    }),
    crossValidation
);

I need to mark as invalid only field "Document number" but not the whole form. Is there a way to implement it?

allow casting schema

var Point = t.struct({
  x: t.Number,
  y: t.Number
});

validate({x: 0, y: 0, z: 0}, Point)

Validation Result will skip z: 0 right now. Which is exactly what i want but without running the validations. given an input and a schema, cast the input based on schema.

tcomb-validations is already doing the casting when validating the input. If we can expose this casting as a function which would just cast and not run the validations.

Something like cast({x: 0, y: 0, z: 0}, Point) ruturns the { x: 0, y: 0 } and not run the validations.

http post validation (Number Params Problem)

hi, when I use restify create an API, and use validation like:

var check = t.struct({
    username: t.String,
    realname: t.String,
    password: t.String,
    age: t.Number,
    active: t.Boolean
});

module.exports = {
    name : 'User',
    check: check
};
function create(req, res, next) {
    var result = t.validate(req.body, validate.User.check);

    if (!result.isValid()) {
        res.send(422, result.errors);
    } else {
        //var values = new validate.User.check(req.body);
        var values = result.value;
        //var values = new validate.User.check(result.value);
        console.log(values);

        return User.create(values)
            .then(function (entity) {
                res.send(entity);
            })
            .catch(function (err) {
                return next(new errors.InternalError(err.message));
            });
    }
}

when I send a post request with params "age=20", then throw an Exception, and return 422, cannot cat age param type from string to number

[
    {
        "message": "Invalid value \"30\" supplied to /age: Number",
        "actual": "30",
        "path": [
            "age"
        ]
    },
    {
        "message": "Invalid value \"1\" supplied to /active: Boolean",
        "actual": "1",
        "path": [
            "active"
        ]
    }
]

How to deal w server side validation exceptions

For instance, the password you entered passes validation but comes back from the server as incorrect.

So, now you want to manually create a validation exception against this password, perhaps even use the server side error message you got back, and update the UI accordingly. How do you do that?

Dict example from README not working

First, pls look at this:

An error in documentation?!

var Country = t.enums.of('IT, US', 'Country'); // 'IT, US' should be "IT", "US" ???

Second:

import tc from "tcomb";
import {validate} from "tcomb-validation";

// a dictionary of numbers
let Country = tc.enums.of("IT", "US", "Country");
let Warranty = tc.dict(Country, tc.Number);

console.log(validate({US: 2, IT: 1}, Warranty).isValid()); // => false instead of true

Error message:

{ message: 'Invalid value "IT" supplied to /IT: Country',
  actual: 'IT',
  expected: 
   { [Function: Enums]
     meta: { kind: 'enums', map: [Object], name: 'Country' },
     displayName: 'Country',
     is: [Function] },
  path: [ 'IT' ] }

Dependent validations for structs

Is it possible to validate one field of a struct depending on the value of another? In particular, I have a startDate and an optional endDate field, and I would like to make sure that endDate is after startDate, if endDate is given.

More specifically, if I do something like

var MyType = t.struct({
  startDate: t.Dat,
  endDate: t.maybe(t.Dat),
  foo: t.Num
});

How can I validate MyType as a whole? It doesn't seem like struct takes a validator function as an argument?

Maybe value converted from undefined to null after validation?

Not sure if the value should change after the validation is done, it should stay undefined?

const t = require("tcomb-validation");

const Point = t.struct({
    x: t.maybe(t.Number),
    y: t.maybe(t.Number),
}, "Point");

const p1 = Point({ x: 12 });
console.log(p1); 
// Struct { x: 12, y: undefined } -- notice y is undefined

console.log(t.validate({ x: 3234 }, Point)); 
// Struct { errors: [], value: Struct { x: 3234, y: null } } -- notice y here has null value

In code it's strictly set to null? https://github.com/gcanti/tcomb-validation/blob/master/index.js#L132

Async validation support ?

Hi @gcanti , tcomb validation is really great (helped so much in sharing validation code on different environment & write code in an understandable manner).
One missing feature though is the ability to do async validation.
Any plan to add this feature ?

Empy list validation

I'm trying to validate a list of emails with t-comb forms and a custom factory (tags input)

It seems like an empty list does not get passed to the custom validation.
Is there a reason that an empty list is valid ? shouldn't only a maybe empty list be valid ?

import email from 'email-validation';
import {validate} from 'tcomb-validation';
var t = require('tcomb-form');

let mailForm = t.list(t.subtype(t.Str, (s) => email.valid(s)));
let result = validate([], mailForm);
console.log(result.isValid()); // returns true for empty lists

How to modify struct value

Source:

var values = new validate.User.check(req.body);
let sha256 = crypto.createHash("sha256")
let newPwd = sha256.update(values.password).digest("hex")
console.log(values)
console.log(values.password)
console.log(newPwd)
values.password = newPwd
console.log(values.password)

Console print:

Struct {
  username: 'test',
  password: '123456',
  realname: '测试一下',
  age: '25',
  role_id: '1',
  active: '0' }
123456
8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
123456

I wnat to crypt 'password' field, But Failed

Question about validation options

I'm using tcomb-form which of course uses tcomb-validation. I have a custom type which I've defined like this:

minLength(length) {
        let type = t.subtype(t.Str, s => s.length >= length, 'minlength');
        type.getValidationErrorMessage = function (value, path, context) {
            console.log('minLength', context);

            if (!type.is(value)) {
                var label = context.fields[path].label;
                return `${label} must be at least ${length} characters long. '${value}' is too short.`
            }
        }

        return type;
    }

The question I'm wondering about is with regards to the context passed into the validate() method. What is the intent of this context object? I noticed in the tcomb-form that it's passing in an object with {path:this.props.ctx.path, context:this.props.context} which seems a bit strange to me because now my form basically looks like this:

<Form options={this.state.options} context={this.state.options} />

Our requirement is to display the label associated w/ the field in the error message, not the path (they often differ in our schema). The reason that feels strange to me is that I'm already giving the form a reference to this.state.options... am I misusing this property?

Brainstorming some ideas

Hi Giulio!

I wrote a big article / proposition about validation here:
ansman/validate.js#50

I think it should be interesting to you as well because Tcomb-validation has a lot of the same weaknesses as ValidateJs and Joi. No separate parsing step (e.g. no idiomatic way to decipher L10n of input data, no way to "jump through" formats (like splitting tags into array), etc.). You may answer there or here if you wish, I will pick up the discussion anyway.

[rfc] ValidationError: relax message type

Hi Giulio!

Currently I am returning i18n keys from getValidationErrorMessage inside my application. I'd like to return an object instead so that I can use it as props for react-intl's <FormattedMessage> component.

For this reason I'd like to change https://github.com/gcanti/tcomb-validation/blob/master/index.js#L9 from t.String to t.Any.

By doing this I can avoid my validation code to be coupled to react-intl or any other future i18n mechanism, and I don't need any special code to handle dynamic locale changes.

Please let me know your opinion on this!

InvalidDate is not detected as invalid

When DatePicker is displayed the value for it set to current date.
If the value was not changed before submit the value that comes with the form is InvalidDate

In index.js in tcomb-validation there is

validators.enums = function validateIrreducible(x, type, path) {
    return {
      value: x,
      errors: type.is(x) ? [] : [ValidationError.of(x, type, path)]
    };
  };

type.is(x) returns true in case of InvalidDate that is why no error was detected. Probably there is a need to check something like this:

if (Object.prototype.toString.call(x) === '[object Date]'  &&  isNaN(v.getTime())))
  // create an error

or set the value for the date field to current date

Could you please take a look?

Strict validation of `structs`

Hi!
I've got one question: is it possible to strictly validate tcomb structs, so this will fail:

validate(
    { a: 'ok', b: 'invalid extra prop' },
    struct({ a: Str })
); // => fail because of extra `b` prop

Another custom messages question

Hello, I am using tcomb-validation but cannot figure out how to use it to display custom error messages. I am currently using my own code to validate form models as follows and would appreciate some direction as to how I can switch to using tcomb-validation which is otherwise great for typechecking.

Here is an example of what I am currently doing:

const string = (msg) => {
    return function validate$string (arg) {
        let value = _.isFunction(arg) ? arg() : arg;

        if (!value || !_.isString(value)) {
            return msg || `"${typeof value}" provided instead of "string"`;
        }
    };
};

const min = (check, msg) => {
    msg = msg || `Value should be at least ${check}`;
    return function validate$min (arg) {
        let value = _.isFunction(arg) ? arg() : arg;

        if (_.isFinite(Number(value))) {
            if (value < check) return msg;
        } else {
            if (_.size(value) < check) return msg;
        }
    };
};

const all = function (...args) {
    const predicates = _.flatten(args);
    return function validate$all (value) {
        for (let pred of predicates) {
            let err = pred(value);
            if (err) return err;
        }
    };
};

I can use the above functions as follows to display custom error messages:

// Generate a validator and provide custom error messages
const validatePassword = all([
    string('Password must be provided'), 
    min(10, 'Short passwords are not allowed; please use at least 10 characters')
]);

validatePassword('1234567') //=> 'Short passwords are not allowed...'

Basically validatePassword returns the first error message that it encounters.

Another example:

const validateStartDate = dateIsAfter(Date.now(), 'Date must be in the future');

// Validator gets the value lazily
const validateEndDate = dateIsAfter(() => startDate, 'Date must be after start date');

Is something like this possible with tcomb-validation? I couldn't figure it out from the documentation so far.

Somewhat related, how do tcomb-validation and tcomb-form keep types from being disable in production mode? I though that the type checking gets disable when NODE_ENV === 'production'. I like that but in case of forms, one would want to keep the checking enabled.

Thanks for your help and a providing a great tool.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.