0.3.0 • Published 4 days ago

@the-minimal/validator v0.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
4 days ago

Validator image

Joe was in search of a simple data validation library that he could learn in 15 minutes.

He envisioned a tool with minimal blocking time and low CPU/memory overhead.

He hoped for something he could easily extend to meet his specific requirements.

Are you like Joe? If so, then Validator might just be what you're looking for!

Stubborn opinions

Validator is pretty stubborn and doesn't want to be a Jack of all trades.

As a result it has many opinions that might not sit well with some folks.

Focusing solely on data validation allows us to greatly optimize this library.

I advocate for tools that excel in a single task.

I believe that, in most cases, we should validate data before performing any transformation.

This approach simplifies and maintains a clear mental model of what data validation is and how it should be implemented in our applications.

JSON data types do not require asynchronous validation.

Avoid introducing side effects within validations.

Don't do this:

// definition
const validate = and([
  string,
  minLength(5),
  async (v) => {
    if(!(await File.exists(v))) {
      throw Error("File does not exist");
    }
  }
]);

// endpoint
await validate(filename);

Do this instead:

// definition
const validate = and([
  string,
  minLength(5),
]);

// endpoint
validate(filename);

if(!(await File.exists(filename))) {
  throw Error("File does not exist");
}

Compilation with Function/eval syntax is not allowed in all environments and, more importantly, it would mean maintaining two different runtime implementations, which I do not want.

It also sacrifices initial blocking for faster subsequent runs, which might be useful in some scenarios. However, this library is primarily designed for serverless runtimes, where this would result in drastically slower performance.

In order to allow such methods, we would have to make the schema accessible from the outside.

This would change the design from using individual callable validations to using objects with properties, one of which is the validation.

Additionally, this would make it possible, for example, to extend any object, even if we don't want users to have such capability.

To address this issue, we would need to introduce some form of object schema freezing.

All of this complicates the API, slows down the library, and increases the bundle size.

You can make an object extendable by exporting its schema separately and then spreading it inside another schema.

The main focus of this library is the data validation of JSON (primarily from fetch requests).

JSON does not support these data types, so it makes no sense to include them in this library.

If you want to use this library with these higher-level primitives, then I recommend validating the input of these primitives.

You should always define concrete types.

Otherwise, what's the point of using TypeScript together with this library?

Checking strictly for null or undefined alone makes no sense.

You always want to know if something can be something or nothing.

Therefore, you should always use nullable, optional, or nullish instead.

Focused features

Validator is a watchful eye that plagues your editor with errors if you feed it data you haven't agreed upon, but otherwise, it stays quiet as a mouse.

  • Everything is an Assertion
  • Assertions are simple functions
  • Assertions are composed together
  • Assertions are type-safe
  • Assertions are tree-shakeable

Incredible numbers

Validator is an obsessed overachiever who wants to be the smallest and fastest one on the track.

  • 40 Assertions
  • 835 bytes bundle
  • ~ 5x faster data validation than Zod
  • ~ 200x less memory consumption than Zod
  • ~ 50x faster type-checking than Zod
  • 1 runtime dependency
  • 100% test coverage

Simple examples

string("Hello, World!");
number(420);
boolean(true);
value(26);
notValue(0);
minValue(18);
maxValue(100);
rangeValue(18, 100);
length(5);
notLength(0);
minLength(8);
maxLength(16);
rangeLength(8, 16);
const register = object({
  email: and([string, rangeLength(5, 35), email]),
  password: and([string, rangeLength(8, 16)]),
  role: union(["ADMIN", "USER"]),
  friends: array(string)
});

register("Oh no this is gonna throw");

register({
  email: "yamiteru@icloud.com",
  password: "Test123456",
  role: "ADMIN",
  friends: ["Joe"]
});

Great journey

Are you really Joe?

Do you dare to let this demon command you?

If so, repeat the spell below and good luck on your journey!

yarn add @the-minimal/validator

Notes

  • All reported sizes are for minified and gzipped code
  • Reproducible and highly detailed benchmarks are on the way
  • Validation and Assertion are the same things
0.3.0

4 days ago

0.2.2

11 days ago

0.2.1

12 days ago

0.2.0

13 days ago

0.1.2

14 days ago

0.1.1

14 days ago

0.1.0

15 days ago

0.0.5

17 days ago

0.0.4

17 days ago

0.0.3

18 days ago

0.0.2

19 days ago

0.0.1

19 days ago