{"_id":"@candraadidev/validator-core","_rev":"3-fac029e1a183d8dba78ee5a0cd719486","name":"@candraadidev/validator-core","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.1":{"name":"@candraadidev/validator-core","version":"0.1.1","_id":"@candraadidev/validator-core@0.1.1","maintainers":[{"name":"candraadidev","email":"candra.winanto@gmail.com"}],"dist":{"shasum":"a434ad7453c710c7f60c346fa339a3392b9befd1","tarball":"https://registry.npmjs.org/@candraadidev/validator-core/-/validator-core-0.1.1.tgz","fileCount":5,"integrity":"sha512-QuKKSyEN+oIeIwcE1b3Jd8H+RL/MMxZBGaTxlSVE4qGO6jYN3clB5cVk/t18g+Nz8Y4mJvApHOQBX7qzvnh/OQ==","signatures":[{"sig":"MEQCIB5ViNIAOA1s+9td6c70mjbv7koKSW2d6mlzrfFgXJK7AiAVPa7KkkZcEg2ksQ+cMGG7yu59MbWCapdkvsLTmZ4BmQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13219},"module":"fesm2022/candraadidev-validator-core.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/candraadidev-validator-core.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"770ea7d15230358156b9dc493ba307bb14cc3165","typings":"index.d.ts","_npmUser":{"name":"candraadidev","email":"candra.winanto@gmail.com"},"_npmVersion":"10.8.2","description":"This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.3.0","@angular/common":"^20.3.0"},"_npmOperationalInternal":{"tmp":"tmp/validator-core_0.1.1_1765557853610_0.018219481336556154","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@candraadidev/validator-core","version":"0.1.2","_id":"@candraadidev/validator-core@0.1.2","maintainers":[{"name":"candraadidev","email":"candra.winanto@gmail.com"}],"dist":{"shasum":"66bd89d8874eb89320d3a3195f5cbc082ba23d71","tarball":"https://registry.npmjs.org/@candraadidev/validator-core/-/validator-core-0.1.2.tgz","fileCount":5,"integrity":"sha512-S6TgmSHrQH9IRagV1sFpWTCdhvW4+4MeJQOv+VeFPV07t+fZHFLipZs/OsuXSWSIJ5ANCw6gd0rpa9DVd7EEUA==","signatures":[{"sig":"MEUCIAPoq8Sl/C9Kj1qHjSoUFDWvMGWpn5v6H9NKZv+LhjvMAiEAxJCS9Qo9mMzpXvHMus1glgNDCUPNqzVcxB5LoERFR+8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":16183},"module":"fesm2022/candraadidev-validator-core.mjs","exports":{".":{"types":"./index.d.ts","default":"./fesm2022/candraadidev-validator-core.mjs"},"./package.json":{"default":"./package.json"}},"gitHead":"770ea7d15230358156b9dc493ba307bb14cc3165","typings":"index.d.ts","_npmUser":{"name":"candraadidev","email":"candra.winanto@gmail.com"},"_npmVersion":"10.8.2","description":"@candraadidev/validator-core","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","dependencies":{"tslib":"^2.3.0"},"_hasShrinkwrap":false,"peerDependencies":{"@angular/core":"^20.3.0","@angular/common":"^20.3.0"},"_npmOperationalInternal":{"tmp":"tmp/validator-core_0.1.2_1765558277047_0.7551749375510213","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2025-12-12T16:44:13.502Z","modified":"2026-02-11T07:24:32.100Z","0.1.1":"2025-12-12T16:44:13.756Z","0.1.2":"2025-12-12T16:51:17.213Z"},"description":"@candraadidev/validator-core","maintainers":[{"email":"candra.winanto@gmail.com","name":"candraadiwinanto"}],"readme":"@candraadidev/validator-core\n\nDecorator-based validation library for Angular Reactive Forms.\nDefine validation rules directly inside TypeScript model classes using decorators — similar to DTO validation in NestJS.\nThis library allows you to keep validation rules centralized, consistent, reusable, and highly scalable for enterprise applications.\n\n\n✨ Features\n\n\n\n✔️ Decorator-based validation (@required, @MinLength, @Regex, @custom, ...)\n\n✔️ Centralized rules in model classes (similar to NestJS DTO)\n\n✔️ Works with Angular Reactive Forms\n\n✔️ Custom error message provider (injectable)\n\n✔️ Minimal, zero dependencies (except reflect-metadata)\n\n✔️ Fully tree-shakeable Angular library\n\n✔️ Supports dynamic + custom validation logic\n\n\n\n📦 Installation\n\nInstall from NPM:\n\n\nnpm install @candraadidev/validator-core reflect-metadata\n\n\n\nAdd to main.ts (or polyfills.ts):\nimport 'reflect-metadata';\n\nimport { ValidatorCoreModule } from '@candra-dev/validator-core';\n\n@NgModule({\n  imports: [\n    ValidatorCoreModule.forRoot()\n  ]\n})\nexport class AppModule {}\n\n\n🧭 Step-by-Step Guide\n⭐ Step 1 — Create a Model Class With Decorators\n\n// src/app/models/login.model.ts\n\nimport { Required, MinLength } from '@candra-dev/validator-core';\n\nexport class LoginModel {\n  @Required()\n  username!: string;\n\n  @Required()\n  @MinLength(6)\n  password!: string;\n}\n\n\n⭐ Step 2 — Build a Reactive Form Using the Model\n// src/app/login/login.component.ts\n\nimport { Component } from '@angular/core';\nimport { FormBuilder } from '@angular/forms';\nimport { buildValidator } from '@candra-dev/validator-core';\nimport { LoginModel } from '../models/login.model';\n\n@Component({\n  selector: 'app-login',\n  templateUrl: './login.component.html'\n})\nexport class LoginComponent {\n  form = this.fb.group({\n    username: [''],\n    password: ['']\n  }, {\n    validators: buildValidator(LoginModel)\n  });\n\n  constructor(private fb: FormBuilder) {}\n\n  submit() {\n    console.log(this.form.value);\n  }\n}\n\n\n⭐ Step 3 — Display Errors in Template\n<form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n\n  <input formControlName=\"username\" placeholder=\"Username\" />\n  <div *ngIf=\"form.errors?.username?.required\">\n    Username is required.\n  </div>\n\n  <input formControlName=\"password\" placeholder=\"Password\" />\n  <div *ngIf=\"form.errors?.password?.minLength\">\n    Password must be at least 6 characters.\n  </div>\n\n  <button type=\"submit\">Login</button>\n</form>\n\n🧠 Built-in Decorators\n| Decorator           | Description             |\n| ------------------- | ----------------------- |\n| `@Required()`       | Cannot be empty         |\n| `@MinLength(n)`     | Minimum length          |\n| `@MaxLength(n)`     | Maximum length          |\n| `@Regex(/pattern/)` | Must match pattern      |\n| `@Custom(fn)`       | Custom validation logic |\n\n🔥 Custom Validator Example\nimport { Required, Custom } from '@candra-dev/validator-core';\n\nexport class RegisterModel {\n  @Required()\n  password!: string;\n\n  @Required()\n  @Custom((value, obj) => value === obj.password)\n  confirmPassword!: string;\n}\n\n\n🎨 Custom Error Messages (Optional)\nYou can override all default messages.\n1️⃣ Create your own provider\n// src/app/services/my-error-messages.ts\n\nimport { IErrorMessageProvider } from '@candra-dev/validator-core';\n\nexport class MyErrorMessages implements IErrorMessageProvider {\n  getMessage(key: string, ctx?: any): string {\n    switch (key) {\n      case 'required':\n        return 'Wajib diisi!';\n      case 'minLength':\n        return `Minimal ${ctx?.min} karakter`;\n      default:\n        return 'Data tidak valid.';\n    }\n  }\n}\n\n\n2️⃣ Register it in AppModule\nValidatorCoreModule.forRoot({\n  useClass: MyErrorMessages\n})\n\nDone — now your custom messages apply globally.\n\n\n🔧 Full Decorator Example\nexport class ProductModel {\n  @Required()\n  name!: string;\n\n  @MinLength(3)\n  @MaxLength(50)\n  description!: string;\n\n  @Regex(/^[0-9]+$/)\n  price!: string;\n\n  @Custom((value, all) => value <= all.maxStock)\n  quantity!: number;\n\n  maxStock = 100;\n}\n\n⚙ API Reference\nbuildValidator(ModelClass)\nCreates an Angular validator that reads metadata from model decorators.\nform = fb.group({ ... }, { validators: buildValidator(MyModel) });\n\n\nDecorators\n\n    @Required()\n\n    @MinLength(n)\n\n    @MaxLength(n)\n\n    @Regex(/pattern/)\n\n    @Custom(fn)\n\nInjection Token\n\nERROR_MESSAGE_PROVIDER\n\n📄 License\nMIT License © 2025 Candra","readmeFilename":"README.md"}