Coder Social home page Coder Social logo

alexjpotter / fluentvalidation-ts Goto Github PK

View Code? Open in Web Editor NEW
83.0 83.0 6.0 1.34 MB

A TypeScript-first library for building strongly-typed validation rules

License: Apache License 2.0

JavaScript 7.41% TypeScript 91.84% CSS 0.71% Shell 0.04%
fluent fluentvalidation form form-validation formik typescript validation

fluentvalidation-ts's People

Contributors

alexjpotter avatar

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

Watchers

 avatar  avatar  avatar

fluentvalidation-ts's Issues

Cannot chain .mustAsync method

Maybe I missed this in the docs somewhere but I can't seem to chain .mustAsync and I'm unsure if I'm doing something wrong or if it is just not possible. The following example does not work. I'll keep digging in the docs and code but it'd be great if someone could help me understand why this does not work. Thanks ๐Ÿ˜„

import { AsyncValidator } from 'fluentvalidation-ts';

type MyType = {
    field: string;
};

class Test extends AsyncValidator<MyType> {
    constructor() {
        super();

        this.ruleFor('field')
            .mustAsync(async () => true)
            .mustAsync(async () => true);
    }
}

Checking the Result

Hi, really like the library. I was looking at class-validator and immediately hit the problem of not being able to validate properties together or set a validator for a nested object. I also have my roots in C# so I found your library via fluentvalidation.
The only problem I am having right now is that it is not very convenient to check if the result is actually failed validation or a successful one. Is this intentional?
I would expect to be able to call .isValid() on the result of the validation. How would you recommend checking for success?
Checking if there are no keys on the result via Object.keys(result).length === 0?

`notEmpty` does not check `notNull()` implicitly

tl;dr

When you want to have a rule like 'Check that a string is neither null nor empty' you have to use notNull() in combination with notEmpty explicitly, so do:

this.ruleFor('name').notNull().notEmpty();

because

this.ruleFor('name').notEmpty();

would let name = null to be valid.

Export ValueValidationResult

Hi Alex,

First of all, thanks for your library and the work you have invested in it. I usually use Fluent Validation in .net so it was a great surprise to find your library and use it in typescript.

I need to import the ValueValidationResult type for certain cascading validations inside nested components.

Before (v2.3.0) you could import from node_modules/fluentvalidation-ts/dist, but now (v3.1.0) in dist there is only index.d.ts

Could you consider exporting Value ValidationResult in dist/index.d.ts in future versions?

export { AsyncValidator, ValidationErrors, SyncValidator as Validator, ValueValidationResult };

TIA! Regards

multiple when/unless calls in the same chain not consistent with FluentValidation behaviour

In FluentValidation it is possible to string together multiple when statements for a single property. In this library the behaviour does not work as expected. For example:

this.ruleFor("days")
      .notEmpty()
      .must([beNumeric, beAnInteger, beGreaterThanOrEqualTo(0)])
      .withMessage("days must be greater than or equal to 0")
      .must([beNumeric, beAnInteger, beLessThan(2000000000)])
      .withMessage("The maximum allowed number size is 1,999,999,999")
      .must((value, model) => asNumber(value) > 0 || asNumber(model.otherDays) > 0)
      .withMessage("days and otherDays cannot both be 0")
      .when((model) => model.dayCode== "weekday")
      .null()
      .withMessage("days must not be entered for weekendDays")
      .when((model) => model.dayCode!= "weekendDay");

Is not the same as:

this.ruleFor("days")
      .notEmpty()
      .must([beNumeric, beAnInteger, beGreaterThanOrEqualTo(0)])
      .withMessage("days must be greater than or equal to 0")
      .must([beNumeric, beAnInteger, beLessThan(2000000000)])
      .withMessage("The maximum allowed number size is 1,999,999,999")
      .must((value, model) => asNumber(value) > 0 || asNumber(model.otherDays) > 0)
      .withMessage("days and otherDays cannot both be 0")
      .when((model) => model.dayCode== "weekday");

this.ruleFor("days")
      .null()
      .withMessage("days must not be entered for weekendDays")
      .when((model) => model.dayCode!= "weekendDay");

The second set of code provides the expected behaviour.

How do I mix `must` and native validators?

If I want to create a new validator called beInteger, I want to combine a few rules:

  • greater than or equal to (-2) ** 31
  • less than or equal to 2 ** 31 - 1
  • scale 0, precision 10

Is there a way to combine the first two custom rules with the built-in scalePrecision validator and pass it to must?

Date Validation

How Can I do the Date Validations? I didn't find any references

Uncaught (in promise) TypeError: e2 is null

Uncaught (in promise) TypeError: e2 is null
    _validate CoreValidator.ts:138
    validate CoreValidator.ts:482
    runValidateHandler Formik.tsx:199
    runValidateHandler Formik.tsx:198
    runAllValidations Formik.tsx:314
    validateFormWithHighPriority Formik.tsx:336
    useEventCallback Formik.tsx:1213
    useFormik Formik.tsx:352

The only way I have found to stop this is to remove all the validation rules.

What's going on?

Validate "array of objects" property in a class

Issue: Can't find a way of validating objects in a ReadonlyArray property of an object.

  • Using this.ForEach('packages') yields the following error: "Argument of type '"packages"' is not assignable to parameter of type 'never'"

  • Ideal solution: this.ruleForEach('packages').must(value => value.weight.grams < 1000);

[Bug] Class extends value undefined is not a constructor or null

Hello;

I'm using webpack + typescript to compile my app, but I'm getting an error when building for production. Everything works in development mode. There error I'm getting is Uncaught TypeError: Class extends value undefined is not a constructor or null. Do you have any idea what's going on, or have you seen that before?

support for async validations

Any plans for supporting async validations in the future?

Would be super great if the must validation would allow for returning a promise from the custom function (or a new, mustAsync was introduced), so that we could use requests to server to, for example, validate that the username is not already taken.

	this.ruleFor("userName")
	  .must(async (userName) => {
	   // todo add request to api
	    return false;
	  })
	 .withMessage("username already taken");

how can do IF validate

Hi, thanks for your validation library!

This very nice, but I have some trouble when need validate some value with IF rule.

Exemple: IF value not empty validate it

Module '"fluentvalidation-ts"' declares 'ValidationErrors' locally, but it is not exported

Up to version 2.3.0 I was able to use the type ValidationErrors as the mechanism I've created to validate my Vue components needs to track them. I was able to use:

import type { ValidationErrors } from 'fluentvalidation-ts/dist/ValidationErrors';

From version 3.0.2 I can no longer access that type:

import type { ValidationErrors } from 'fluentvalidation-ts';

Module '"fluentvalidation-ts"' declares 'ValidationErrors' locally, but it is not exported. ts(2459)

Would it be possible to expose that type?

TY

ValidationErrors returns empty object if no errors

Hello,

First of all, thanks for the library! It's awesome as I have been using fluent validator for C# for a long time, and was missing this in typescript. Great work.

My issue - If there are no validation errors, methods .validate and .validateAsync returns an empty object {}.
Then to check if there are errors I have to each time check if return value is an empty object.

Example (using lodash):

const validationError = await Validators.CreateOrderRequestValidator(req).validateAsync(req.body);
_.isEmpty(validationError) ? res.status(200).json(await addOrder(req.body)) : res.status(400).json(validationError);

Example (without lodash):

const validationError = await Validators.CreateOrderRequestValidator(req).validateAsync(req.body);
Object.keys(validationError).length > 0 ? res.status(200).json(await addOrder(req.body)) : res.status(400).json(validationError);

For me it's a bit inconvenient, would prefer if these methods would either return ValidationError or null instead {} ?
So I could replace above code with:

const validationError = await Validators.CreateOrderRequestValidator(req).validateAsync(req.body);
validationError  ? res.status(400).json(validationError) : res.status(200).json(await addOrder(req.body));

Perhaps as a workaround I could try wrapping these methods in my own custom one, and check this empty object once..
Thanks!

[Bug] Expression produces a union type that is too complex to represent

Hello;

I am using your library to validate that a date fits between a min and max date. We are actually using a string to back the date because we don't care about time or timezones, just the literal date. Here's our "fake" date class:

type Digit = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0;
type NonZeroDigit = Exclude<Digit, 0>;

type ISODateYear = `20${Digit}${Digit}`;
type ISODateMonth = `0${NonZeroDigit}` | `1${0 | 1 | 2}`;
type ISODateDay = `0${NonZeroDigit}` | `${1 | 2}${Digit}` | `3${0 | 1}`;

// type ISODate = "2000-01-01" | "2000-01-02" | "2000-01-03" | "2000-01-04" | "2000-01-05" | "2000-01-06" | "2000-01-07" | "2000-01-08" | "2000-01-09" | "2000-01-10" | "2000-01-11" | "2000-01-12" | ... 37187 more ... | "2099-12-31"
export type ISODate = `${ISODateYear}-${ISODateMonth}-${ISODateDay}`;

If I have a rule on a property with such a type, we are getting an error:

    // Expression produces a union type that is too complex to represent.
    this.ruleFor("myDate").notNull().notEmpty().must(fitIntoSqlDateTime);

How is your library composing types such that I would get this error? What can I do to work around it?

[Question/Possible Enhancement] Can I specify the whole object in ruleFor(...) instead of a property?

I have used https://fluentvalidation.net/, which the docs for this library reference as an influence for this library, and indeed they do look very similar. In the C# version, I can write RuleFor(x => x).Must(...);, and I'm wondering if there is any way to do the same here? Something akin to the following

import { Validator } from 'fluentvalidation-ts';

type FormModel = {
    name: string;
    age: number;
};

export default class MyValidator extends Validator<FormModel>
{
    constructor() {
        super();

        this.ruleFor(x => x) // This isn't allowed. I don't want to specify a property here.
            .must(x => x.name === "test" && x.age === 5);
    }
}

I realize I could do something like

this.ruleFor("name").must((_, x) => x.name === "test" && x.age === 5);

but that feels like a hack. I also realize that it would be more proper to break this into 2 validation rules, 1 for name and another for age. This was just a quick example to illustrate the goal.

Thanks in advance!

Support for error codes

Are there any plans to support error codes as part of the validation result?
I imagine something like this:

this.ruleFor('name')
  .notEmpty()
  .withMessage('Please enter your name')
  .withCode('invalidName');

The problem is that the ValueValidationResult would have to be changed to contain objects instead of simple strings:

{ 
    name: {
        message: 'Please enter your name' 
        code: 'invalidName'
    }
}

which would probably be a breaking change.

[Enhancement] Allow rules to be specified on transformed values (`.ruleForTransformed`)

Your library looks awesome, except one little part.

When I change a name of a property I want the Typescript compiler to throw me a warning about where that property was in the project, so I can go and change them.

So, it's more of a suggestion than an issue, to actually have it like this:

RuleFor(x => x.name)

You have already the structure of a type generic so that means that you have thought of that. Anyways, something to think of!

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.