{"_id":"@anil-labs/validator","_rev":"3-312608aa68016b7ea28adfc099fcf275","name":"@anil-labs/validator","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@anil-labs/validator","version":"0.1.0","keywords":["validation","validator","typescript","vue","quasar","form","rules","schema"],"license":"MIT","_id":"@anil-labs/validator@0.1.0","maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"homepage":"https://github.com/anilkumarthakur60/validator#readme","bugs":{"url":"https://github.com/anilkumarthakur60/validator/issues"},"dist":{"shasum":"cb47e78ce02e0a1335f0626772813de247634bdb","tarball":"https://registry.npmjs.org/@anil-labs/validator/-/validator-0.1.0.tgz","fileCount":7,"integrity":"sha512-LY8I5FyX0nwRdzQuDetfIrkNN9LdAiUUvct8gfORYZDc/j8/Jc6x22sp5tiMzbvpxJuddPY5AABzWYcDWvjJkQ==","signatures":[{"sig":"MEYCIQDdQI9jwf34IYKJkZC3SC89szBroB/GopYm56RTT8DKxgIhAPoSMLP+Ia+46n0rmU9jlAP6pPFhNSMrz3KEVvaiMeiW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":317035},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"gitHead":"ef867bac647b86750133e34447b5a909b962ea17","scripts":{"dev":"vite","demo":"vite --config demo/vite.config.ts","lint":"eslint .","test":"vitest run --config vitest.config.ts","build":"tsup","format":"prettier --write .","coverage":"vitest run --coverage --config vitest.config.ts","docs:dev":"vitepress dev docs","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","demo:build":"vite build --config demo/vite.config.ts","docs:build":"vitepress build docs","test:watch":"vitest --config vitest.config.ts","docs:preview":"vitepress preview docs","format:check":"prettier --check .","check:exports":"publint && attw --pack .","demo:typecheck":"vue-tsc --noEmit -p demo/tsconfig.json","prepublishOnly":"npm run lint && npm run typecheck && npm run test && npm run build && npm run check:exports"},"_npmUser":{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"},"repository":{"url":"git+https://github.com/anilkumarthakur60/validator.git","type":"git"},"_npmVersion":"11.11.0","description":"An expressive, strictly-typed validation library for TypeScript — framework-agnostic core plus a chainable Quasar/Vue rule builder.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vue":"^3.5.35","tsup":"^8.5.1","vite":"^8.0.12","eslint":"^10.4.1","vitest":"^4.1.7","publint":"^0.3.21","vue-tsc":"^3.3.2","prettier":"^3.8.3","vitepress":"^1.6.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.9.1","typescript-eslint":"^8.60.0","@vitejs/plugin-vue":"^6.0.7","@vue/language-core":"^3.3.2","@vitest/coverage-v8":"^4.1.7","@arethetypeswrong/cli":"^0.18.3","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/validator_0.1.0_1780136061970_0.6179128107618672","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@anil-labs/validator","version":"0.2.0","keywords":["validation","validator","typescript","form","rules","schema","laravel","framework-agnostic","vue","quasar"],"author":{"name":"Anil Kumar Thakur","email":"anilkumarthakur60@gmail.com"},"license":"MIT","_id":"@anil-labs/validator@0.2.0","maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"homepage":"https://github.com/anilkumarthakur60/validator/tree/main/packages/validator#readme","bugs":{"url":"https://github.com/anilkumarthakur60/validator/issues"},"dist":{"shasum":"34e125a9453bc405177f42e21df798dd5349bbb9","tarball":"https://registry.npmjs.org/@anil-labs/validator/-/validator-0.2.0.tgz","fileCount":9,"integrity":"sha512-YE1pMdgRHGLt4XG+RqLZxGLdAlkdB1nCcEkW0kNAAlmulI4qtrACI8IagYmUgxFxc7VM8T4hvKzSz5KcAufhiw==","signatures":[{"sig":"MEYCIQCtsiwpxTr7iHGQaM8KBYVzUw8O6olE6ZqDry0wvqMtLAIhANZNdQX+JLFXySjS91h+XBlSnbCfnxjslvbte6QDylzN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@anil-labs%2fvalidator@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":665175},"main":"./dist/index.cjs","type":"module","_from":"file:anil-labs-validator-0.2.0.tgz","types":"./dist/index.d.ts","unpkg":"./dist/index.global.js","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","check:exports":"publint && attw --pack .","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"},"jsdelivr":"./dist/index.global.js","_resolved":"/tmp/87862f05124e2ce3d2834e3e61ceb36f/anil-labs-validator-0.2.0.tgz","_integrity":"sha512-YE1pMdgRHGLt4XG+RqLZxGLdAlkdB1nCcEkW0kNAAlmulI4qtrACI8IagYmUgxFxc7VM8T4hvKzSz5KcAufhiw==","repository":{"url":"git+https://github.com/anilkumarthakur60/validator.git","type":"git","directory":"packages/validator"},"_npmVersion":"10.8.2","description":"An expressive, strictly-typed, framework-agnostic validation library for TypeScript — a Laravel-style dataset validator plus a chainable single-field rule builder.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.10","publint":"^0.3.21","typescript":"~6.0.3","@vitest/coverage-v8":"^4.1.10","@arethetypeswrong/cli":"^0.18.5"},"_npmOperationalInternal":{"tmp":"tmp/validator_0.2.0_1784398720494_0.2996474175439081","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@anil-labs/validator","version":"0.3.0","description":"An expressive, strictly-typed, framework-agnostic validation library for TypeScript — a Laravel-style dataset validator plus a chainable single-field rule builder.","keywords":["validation","validator","typescript","form","rules","schema","laravel","framework-agnostic","vue","quasar"],"license":"MIT","author":{"name":"Anil Kumar Thakur","email":"anilkumarthakur60@gmail.com"},"homepage":"https://github.com/anilkumarthakur60/validator/tree/main/packages/validator#readme","repository":{"type":"git","url":"git+https://github.com/anilkumarthakur60/validator.git","directory":"packages/validator"},"bugs":{"url":"https://github.com/anilkumarthakur60/validator/issues"},"type":"module","sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/index.global.js","jsdelivr":"./dist/index.global.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"engines":{"node":">=20"},"publishConfig":{"access":"public"},"devDependencies":{"@arethetypeswrong/cli":"^0.18.5","@vitest/coverage-v8":"^4.1.10","publint":"^0.3.21","tsup":"^8.5.1","typescript":"~6.0.3","vitest":"^4.1.10"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","check:exports":"publint && attw --pack ."},"_id":"@anil-labs/validator@0.3.0","_integrity":"sha512-kGjW3F+0cE2wdE2Zdhio69SUdsbnwREPKC/hGiSrPexooBsoOp1QumaWScsUWrVzWafMDPhZKiUWRDsYOjAq9Q==","_resolved":"/tmp/381e63781aef4e0d8cbef723fabeff04/anil-labs-validator-0.3.0.tgz","_from":"file:anil-labs-validator-0.3.0.tgz","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-kGjW3F+0cE2wdE2Zdhio69SUdsbnwREPKC/hGiSrPexooBsoOp1QumaWScsUWrVzWafMDPhZKiUWRDsYOjAq9Q==","shasum":"a7b07f91106fdc50885f09c5c2e077c315b666dd","tarball":"https://registry.npmjs.org/@anil-labs/validator/-/validator-0.3.0.tgz","fileCount":9,"unpackedSize":697246,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@anil-labs%2fvalidator@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDvAC6bfEGgsOAtjQ0/c8ouHoNDm//M4Fm3t+KQokoFXgIhANffwung58TTz1k/TjHNUFGInuicbT6qP8Of1fc3qQ75"}]},"_npmUser":{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"},"directories":{},"maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/validator_0.3.0_1784480979050_0.28195371110154177"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-30T10:14:21.795Z","modified":"2026-07-19T17:09:39.545Z","0.1.0":"2026-05-30T10:14:22.105Z","0.2.0":"2026-07-18T18:18:40.663Z","0.3.0":"2026-07-19T17:09:39.228Z"},"bugs":{"url":"https://github.com/anilkumarthakur60/validator/issues"},"author":{"name":"Anil Kumar Thakur","email":"anilkumarthakur60@gmail.com"},"license":"MIT","homepage":"https://github.com/anilkumarthakur60/validator/tree/main/packages/validator#readme","keywords":["validation","validator","typescript","form","rules","schema","laravel","framework-agnostic","vue","quasar"],"repository":{"type":"git","url":"git+https://github.com/anilkumarthakur60/validator.git","directory":"packages/validator"},"description":"An expressive, strictly-typed, framework-agnostic validation library for TypeScript — a Laravel-style dataset validator plus a chainable single-field rule builder.","maintainers":[{"name":"anilkumarthakur","email":"anilkumarthakur60@gmail.com"}],"readme":"# @anil-labs/validator\n\n[![npm](https://img.shields.io/npm/v/%40anil-labs%2Fvalidator.svg)](https://www.npmjs.com/package/@anil-labs/validator)\n[![CI](https://github.com/anilkumarthakur60/validator/actions/workflows/ci.yml/badge.svg)](https://github.com/anilkumarthakur60/validator/actions/workflows/ci.yml)\n[![bundle size](https://img.shields.io/badge/bundle-~15%20KB%20min%2Bbrotli-blue)](https://github.com/anilkumarthakur60/validator/blob/main/.size-limit.cjs)\n[![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n\nAn **expressive**, strictly-typed validation library for TypeScript.\n\n- 🧩 **Framework-agnostic core** — works in Node (Express, NestJS, Fastify), the browser, workers, and edge runtimes.\n- 🎯 **Comprehensive rule set** — 100+ built-in rules with human-friendly messages, dot/`*` wildcard nesting, `MessageBag`, `validated()`/`safe()`, conditional & cross-field rules.\n- 🪝 **Two APIs, one engine** — a full dataset `Validator.make(data, rules)` **and** a chainable single-field builder for Quasar/Vue `:rules`.\n- 🔒 **100% TypeScript, zero `any`** — compiled under the strictest settings, **100% test coverage**.\n- 🧠 **Type inference** — pass a rules literal and `validated()` returns a precisely-typed object (`InferRules`), no `as const` needed.\n- ⚡ **Async-ready** — pluggable resolvers for `exists`, `unique`, `current_password`, and `Password.uncompromised()`.\n\n> 📖 **Full documentation:** run `pnpm docs:dev` (VitePress) or see the [`docs/`](https://github.com/anilkumarthakur60/validator/tree/main/docs) directory.\n\n---\n\n## Install\n\n```bash\nnpm install @anil-labs/validator\n```\n\nShips ESM + CJS with bundled type declarations. Requires Node ≥ 20.\n\n### CDN — no build step\n\nThe package also ships a minified IIFE with every export on a `Validator` global:\n\n```html\n<script src=\"https://unpkg.com/@anil-labs/validator\"></script>\n<script>\n  const { Validator, validation } = window.Validator\n  Validator.make({ email: 'oops' }, { email: 'required|email' }).fails() // true\n</script>\n```\n\n(Also available from jsDelivr: `https://cdn.jsdelivr.net/npm/@anil-labs/validator`.)\n\n---\n\n## Quick start\n\n### Dataset validation\n\n```ts\nimport { Validator } from '@anil-labs/validator'\n\nconst validator = Validator.make(\n  {\n    title: 'Hello world',\n    author: { name: 'Ada' },\n    users: [{ email: 'a@b.com' }, { email: 'oops' }],\n  },\n  {\n    title: 'required|string|max:255',\n    'author.name': ['required'],\n    'users.*.email': 'required|email',\n  },\n)\n\nif (validator.fails()) {\n  validator.errors().first('users.1.email')\n  // \"The users.1.email field must be a valid email address.\"\n  validator.errors().messages() // { \"users.1.email\": [...] }\n} else {\n  const data = validator.validated()\n}\n```\n\n### Type inference\n\nPass the rules as a literal and `validated()` is fully typed — no `as const`, no\nseparate interface:\n\n```ts\nconst data = Validator.make(\n  { title: 'Hi', count: 5, author: { name: 'Ada' }, users: [{ email: 'a@b.com' }] },\n  {\n    title: 'required|string',\n    count: 'required|integer',\n    'author.name': 'required|string',\n    'users.*.email': 'required|email',\n    note: 'nullable|string',\n  },\n).validate()\n\n// data: {\n//   title: string; count: number; author: { name: string };\n//   users: { email: string }[]; note?: string | null\n// }\ndata.users[0]?.email // ✅ typed\n```\n\nUse `InferRules<typeof rules>` to derive the type without running validation. The\nengine validates but doesn't coerce, so inferred types reflect each rule's\nintended type — see the [Type inference guide](./docs/guide/type-inference.md).\n\n### Fluent builder (Quasar / Vue `:rules`)\n\n```vue\n<script setup lang=\"ts\">\nimport { validation } from '@anil-labs/validator'\n</script>\n\n<template>\n  <q-input v-model=\"email\" :rules=\"[validation.required().email().toRule()]\" />\n  <!-- .toRule() is optional — a chain is directly callable -->\n  <q-input v-model=\"age\" :rules=\"[validation.required().integer().between(1, 120)]\" />\n</template>\n```\n\n### Rule objects\n\n```ts\nimport { Validator, Rule, Password, FileRule } from '@anil-labs/validator'\n\nValidator.make(data, {\n  role: [Rule.in(['admin', 'editor'])],\n  status: [Rule.enum(ServerStatus)],\n  username: ['required', Rule.anyOf([['email'], ['alpha_dash', 'min:6']])],\n  email: [Rule.email().rfcCompliant().preventSpoofing()],\n  title: [Rule.string().min(3).max(255)],\n  starts_at: [Rule.date().afterToday()],\n  password: ['required', 'confirmed', Password.min(8).mixedCase().numbers().symbols()],\n  avatar: [FileRule.image().max('2mb').dimensions(Rule.dimensions().maxWidth(1000))],\n})\n```\n\n### Async rules (backend / network)\n\n```ts\nconst v = Validator.make(body, { email: 'required|email|unique:users' }).withResolvers({\n  unique: async (q) => (await db.count(q.table, { [q.column]: q.value })) === 0,\n})\n\nif (await v.failsAsync()) {\n  // 422 { errors: v.errors().messages() }\n}\n```\n\n---\n\n## Using it on a Node backend\n\nThe engine is pure TypeScript with no DOM coupling. Example Express handler:\n\n```ts\nimport { Validator } from '@anil-labs/validator'\n\napp.post('/users', async (req, res) => {\n  const v = Validator.make(req.body, {\n    name: 'required|string|max:255',\n    email: 'required|email|unique:users',\n    password: 'required|min:8|confirmed',\n  }).withResolvers({\n    unique: async (q) => (await db.count(q.table, { [q.column]: q.value })) === 0,\n  })\n\n  if (await v.failsAsync()) return res.status(422).json({ errors: v.errors().messages() })\n  return res.status(201).json(await db.create(v.validated()))\n})\n```\n\n> Server notes: `dimensions` needs a browser image decoder, so it passes on Node (use `sharp` in a custom rule for real checks). File rules need the global `File` (Node ≥ 20).\n\n---\n\n## Custom rules\n\n```ts\n// 1. Inline closure\nvalidation.required().custom((v) => String(v).startsWith('HC-') || 'Must start with HC-')\n\n// 2. Rule object\nimport type { ValidationRuleObject } from '@anil-labs/validator'\nclass Uppercase implements ValidationRuleObject {\n  validate(attribute: string, value: unknown, fail: (m: string) => void) {\n    if (String(value) !== String(value).toUpperCase()) fail('The :attribute must be uppercase.')\n  }\n}\n\n// 3. Global named rule\nimport { registerRule, defaultMessages } from '@anil-labs/validator'\nregisterRule('slug', { validate: (ctx) => /^[a-z0-9-]+$/.test(String(ctx.value)) })\ndefaultMessages.slug = 'The :attribute must be a valid slug.'\n\n// 4. Quasar builder rule\nvalidation.extend('nepaliPhone', (v) => /^(\\+977)?9[78]\\d{8}$/.test(String(v)) || 'Invalid phone.')\nvalidation.required().rule('nepaliPhone')\n```\n\n---\n\n## Developing (from the monorepo root)\n\n| Script | Purpose |\n| --- | --- |\n| `pnpm build` | Build the publishable library (`dist/`, incl. the CDN IIFE) |\n| `pnpm test` / `pnpm test:coverage` | Run the Vitest suite (100% coverage gate) |\n| `pnpm lint` / `pnpm typecheck` | Strict, type-aware lint + typecheck |\n| `pnpm docs:dev` | VitePress documentation site |\n| `pnpm example:vanilla` / `pnpm example:vue` | Interactive demo apps |\n| `pnpm --filter @anil-labs/validator run check:exports` | `publint` + `attw` package validation |\n\n## License\n\n[MIT](./LICENSE)\n","readmeFilename":"README.md"}