npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rustic-validator

v0.6.5

Published

Simply naive validator.

Downloads

12

Readme

Test statusCodeQL statusDependenies

Rustic validator

Overview

It`s like LEGO© for data validation. Just write some simple rules, add any messages and join them together.

Example

import { validate } from "rustic-validator"

const isNonEmpty = (val: string): boolean => val.length > 0
const isName = (val: string): boolean => /^\w+$/.test(val)
const isAlice = (val: string): boolean => val === "Alice"
const onlyHumanRule = [isName, "You are not human"] as const
const onlyAliceRule = [
  isAlice,
  (val: string) => `You are ${val}, not Alice!`,
] as const

validate("Bob", isNonEmpty, onlyHumanRule, onlyAliceRule)
// => [ false, 'You are Bob, not Alice!' ]
validate("Alice", isNonEmpty, onlyHumanRule, onlyAliceRule)
// => [ true ]

Description

This library gets a test suit like the list of rules, and the rule is ordinary function (value: unknown) => boolean, singe or paired with the message. Use native JS, without wired chaining with fancy probe names.

Test suit passes from first to last rule, stoping on the first fail case. Full scan version included too. Any value type is allowed.

Moreover, with the main validation library come some helpful utils to process check results. For example - get a resume for the complex result. See below.

Full TS support and full test cover included.

Install

# using yarn
yarn add rustic-validator
# using npm
npm install rustic-validator

Important about rules notations

Due to the lack of JS native type Tuple, it is a little bit tricky to have simplicity at rules and type-safe checking at one time.

while this in place notation works well, as TS correctly get type as Tuple [(unknown) => boolean, string]

validate("foo", [checkFn, "message"])

this example will not work, because TS cast rule as Array (string | (unknown) => boolean)[], not Tuple.

const rule = [checkFn, "message"]
validate("foo", rule) // TS complain (string | (unknown) => boolean)[] IS NOT [(unknown) => boolean, string]

As a workaround its exists some ways:

  • use (string | (unknown) => boolean)[] instead [(unknown) => boolean, string], but its pointless by non-type safe at all

  • export all rules types and use them, but they are using generic notation like ShortRule<T> plus it needed to correct set to every rule

  • use tricky notation [checkFn, "message"] as const to ensure TS use Tuple type

So, here used last solutions as the simplest and brief

const rule = [checkFn, "message"] as const
validate("foo", rule) // all works well

/* type safe  */
const wrongRule = ["message", checkFn] as const
validate("foo", wrongRule) // will rase type error

Also, its may be used helper from utils (see below)

import { makeRule } from "rustic-validator/utils"

const isName = (val: string): boolean => /^\w+$/.test(val)
const onlyHumanRule = makeRule(isName, "You are not human")

// => onlyHumanRule type is Tuple [(val: string) => boolean, string]

Usage

Library export next functions:

validate()

import { validate } from "rustic-validator"

// (unknown, (unknown) => boolean) => [boolean]
validate("foo", checkFn)
// (unknown, [(unknown) => boolean]) => [boolean]
validate("foo", [checkFn])
// (unknown, [(unknown) => boolean, string]) => [boolean, string?]
validate("foo", [checkFn, "message"])
// (unknown, [(unknown) => boolean, number]) => [boolean, number?]
validate("foo", [checkFn, 42])
// (unknown, [(unknown) => boolean, (unknown) => string]) => [boolean, string?]
validate("foo", [checkFn, messageFn])
// any number and any kind of rules allowed
validate(
  "foo",
  [checkFn, messageFn], /// - execute success
  checkFn2, //           // - execute success
  [checkFn3, "message"], // - fail here
  [checkFn4, 401] //    // - not executed
)
// => [false, 'message']

validate("Bob", [(val) => val === "Alice", (val) => `${val} not Alice`])
// => [false, 'Bob not Alice']

Process test suite for value, on full success return one element list [ true ], on first fail one or two element list [isValid: boolean, message?: unknown] (depend on fail rule).

checkAll()

import { checkAll } from "rustic-validator"

// (unknown, (unknown) => boolean) => [[boolean]]
checkAll("foo", checkFn)
// (unknown, (unknown) => boolean, (unknown) => boolean) => [[boolean], [boolean]]
checkAll("foo", checkFn, checkFn2)
// (unknown, [(unknown) => boolean]) => [[boolean]]
checkAll("foo", [checkFn])
// (unknown, [(unknown) => boolean, string]) => [[boolean, string?]]
checkAll("foo", [checkFn, "message"])
// (unknown, [(unknown) => boolean, number]) => [[boolean, number?]]
checkAll("foo", [checkFn, 42])
// (unknown, [(unknown) => boolean, (unknown) => string]) => [[boolean, string?]]
checkAll("foo", [checkFn, messageFn])
// any number and any kind of rules allowed
checkAll(
  "foo",
  [checkFn, messageFn], /// - execute success
  checkFn2, //           // - execute success
  [checkFn3, "message"], // - fail here
  [checkFn4, 42] //      // - will execute
)
// => [[true], [true], [false, 'message'], [false, 42]]

checkAll("Bob", [(val) => val === "Alice", (val) => `${val} not Alice`])
// => [[false, 'Bob not Alice']]

Process full test suite for value, return full resultset list [[true], [isValid: boolean, message?: unknown]...].

getStatus()

import { getStatus } from "rustic-validator/utils"

// ([boolean]) => boolean
getStatus([false])
// ([[boolean]]) => boolean
getStatus([[false]])
// ([[boolean], [boolean]]) => boolean
getStatus([[true], [false]])
// ([[boolean, string]]) => boolean
getStatus([[false, "message"]])
// ([[boolean, number]]) => boolean
getStatus([[false, 42]])
// ([[boolean], [boolean, string]]) => boolean
getStatus([[true], [false, "message"]])
// and some bonus structure (see "idea to use")
getStatus({
  a: [[true], [true]], //          // - if execute - pass and yield to any other
  b: [false], //                   // - if execute - fail and prevent others
  c: [[true], [false, "message"]], // - if execute - fail and prevent others
})
// => false

getStatus([[true], [true], [false, "message"], [false, 42]])
// => false

Scan some variants of results for resume, return single result - on all success true, or at first fail false. In the case of using an object with check result, any fail element will case false result, object keys iteration are not determined.

getFirstError()

import { getFirstError } from "rustic-validator/utils"

// ([boolean]) => []
getFirstError([true])
// ([boolean]) => [boolean]
getFirstError([false])
// ([[boolean]]) => [boolean]
getFirstError([[false]])
// ([[boolean], [boolean]]) => [boolean]
getFirstError([[true], [false]])
// ([[boolean, string]]) => [boolean, string]
getFirstError([[false, "message"]])
// ([[boolean, number]]) => [boolean, number]
getFirstError([[false, 42]])
// ([[boolean], [boolean, string]]) => [boolean, string]
getFirstError([[true], [false, "message"]])
// and some bonus structure (just in case)
getFirstError({
  a: [[true], [true]], //            // - if execute - pass and yield to any other
  b: [[false], [false, "message2"]], // - if execute - fail at first and prevent others
  c: [[true], [false, "message"]], //// - if execute - fail and prevent others
})
// => [false] OR [false, "message"]

getFirstError([[true], [true], [false, 42], [false, "message"]])
// => [false, 42]

Scan some variants of results for first fail element, will return empty list [] if all tests succeed (no errors), or one or two-element list [false, message?: unknown] (depend on fail rule). In case of using an object with check, result any fail element (but first in list) may be returned, object keys iteration are not determined.

makeRule()

import { makeRule } from "rustic-validator/utils"

const isName = (val: string): boolean => /^\w+$/.test(val)
const onlyHumanRule = makeRule(isName, "You are not human")

// => onlyHumanRule type is [(val: string) => boolean, string]

Helper for building correct type rule, as Tuple.

QA

Is some validation rule included? Like isEmail, isPhone etc.

No, this rule is tightly bound to business values, it's simple to use your own rules.

Is only string supported?

No, any types supported, just ensure to handle it properly at test rule function.

Why does it exist?

At first - because I don't need form at modern web application with the state

Is it for webform only?

No, its works well with any data from any source.

Its for browser only?

No, use it in any environment, it's the zero-dependency library.

What about a size?

All library size less 1 kB Minified (384 B Minified + Gzipped)

Idea to use

It may be interesting to try this validation with the latest Vue with composition API and Pinia. As concept

// pinia store user.ts
import { defineStore } from 'pinia'
import { validate } from 'rustic-validator'

export const useUserStore = defineStore('model/user', () => {
  const userName = ref('')
  const userPassword = ref('')
  const userNameValidations = [/* some validation here */]
  const passwordValidations = [/* some validation here */]

  const modelValidation = computed(() => {
    userName: validate(userName.value, ...userNameValidations),
    userPassword: validate(userPassword.value, ...passwordValidations),
  })

  return {
    userName,
    userPassword,
    modelValidation,
  }
})

// vue component userLogin.ts
<template>
  <input v-model.trim="userName" :class="{'error': !modelValidation.userName[0]}">
  <p v-if="!modelValidation.userName[0]" class="error">
    {{ modelValidation.userName[1] }}
  </p>

  <input v-model.trim="userPassword" :class="{'error': !modelValidation.userPassword[0]}">
  <p v-if="!modelValidation.userPassword[0]" class="error">
    {{ modelValidation.userPassword[1] }}
  </p>

  <button :disabled="!isFormValid">Login</button>
</template>

<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { getStatus } from 'rustic-validator/utils'
import { useUserAuthStore } from '~/stores/model/user'

const userAuth = useUserAuthStore()
const { userName, userPassword, modelValidation } = storeToRefs(userAuth)
const isFormValid = computed(() => getStatus(modelValidation.value))
</script>

See also

  • v8n JavaScript fluent validation library
  • tsfv Typescript Fluent Validation Library
  • v9s Simple TypeScript-based validations

Contributing

Want to help? Contributions are welcome, but please be sure before submitting a pull request that you have first opened an issue to discuss the work with the maintainers first. This will ensure we're all on the same page before any work is done.

Send your feedback

Have some ideas, problems, or questions about the project? Post an issue in this repo.

License

The MIT License 2021 - Dmitrii Karpich.