{"id":30046739,"url":"https://github.com/jasgigli/gigli.js","last_synced_at":"2026-01-20T17:01:29.514Z","repository":{"id":305118483,"uuid":"1021976828","full_name":"jasgigli/gigli.js","owner":"jasgigli","description":"  Metamorphic, type-safe validation engine for TypeScript. Unified runtime, builder, decorator, and string rule support.","archived":false,"fork":false,"pushed_at":"2025-07-18T14:13:23.000Z","size":1748,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-11T13:50:04.617Z","etag":null,"topics":["cli","engine","gigli","gigli-js","jasgigli","javascript","json","library","npm-package","package","typescript","validation","validator"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/gigli.js","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jasgigli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-18T08:51:36.000Z","updated_at":"2025-07-19T20:55:10.000Z","dependencies_parsed_at":"2025-07-18T12:55:35.130Z","dependency_job_id":null,"html_url":"https://github.com/jasgigli/gigli.js","commit_stats":null,"previous_names":["jasgigli/validex"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jasgigli/gigli.js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasgigli%2Fgigli.js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasgigli%2Fgigli.js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasgigli%2Fgigli.js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasgigli%2Fgigli.js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jasgigli","download_url":"https://codeload.github.com/jasgigli/gigli.js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasgigli%2Fgigli.js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28607624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T16:10:39.856Z","status":"ssl_error","status_checked_at":"2026-01-20T16:10:39.493Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","engine","gigli","gigli-js","jasgigli","javascript","json","library","npm-package","package","typescript","validation","validator"],"created_at":"2025-08-07T08:53:48.815Z","updated_at":"2026-01-20T17:01:29.496Z","avatar_url":"https://github.com/jasgigli.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/giglijs.png\" alt=\"Gigli.js Logo\" width=\"180\" /\u003e\n  \u003ch1\u003eGigli.js\u003c/h1\u003e\n  \u003cp\u003e\u003cb\u003eMetamorphic, type-safe validation engine for TypeScript \u0026 JavaScript\u003c/b\u003e\u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://www.npmjs.com/package/gigli.js\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/gigli.js?style=flat-square\" alt=\"NPM Version\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://img.shields.io/npm/dm/gigli.js?style=flat-square\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/gigli.js?style=flat-square\" alt=\"NPM Downloads\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://bundlephobia.com/result?p=gigli.js\"\u003e\u003cimg src=\"https://img.shields.io/bundlephobia/minzip/gigli.js?style=flat-square\" alt=\"Bundle Size\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/jasgigli/gigli.js/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/jasgigli/gigli.js/ci.yml?branch=main\u0026style=flat-square\" alt=\"Build Status\"\u003e\u003c/a\u003e\n    \u003c!-- \u003ca href=\"https://codecov.io/gh/jasgigli/gigli.js\"\u003e\u003cimg src=\"https://codecov.io/gh/jasgigli/gigli.js/branch/main/graph/badge.svg?style=flat-square\" alt=\"Code Coverage\"\u003e\u003c/a\u003e --\u003e\n    \u003ca href=\"https://github.com/jasgigli/gigli.js/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/gigli.js?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/gigli.js\"\u003e\u003cimg src=\"https://img.shields.io/npm/types/gigli.js?style=flat-square\" alt=\"Types\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/jasgigli/gigli.js/pulls\"\u003e\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square\" alt=\"PRs Welcome\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003cb\u003eUnified runtime, builder, decorator, and string rule support. Generate OpenAPI/JSON Schema. Use in Node.js, React, Express, NestJS, and more.\u003c/b\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n---\n\n# 🚀 Why Gigli.js?\n\nGigli.js is not just another validator. It's a \u003cb\u003emetamorphic engine\u003c/b\u003e that adapts to your coding style—builder, decorator, or string rules—without sacrificing type safety, power, or extensibility.\n\n- 🧩 \u003cb\u003eUnified API\u003c/b\u003e: Mix \u0026 match builder, decorator, and string rules\n- 🦾 \u003cb\u003eType Inference\u003c/b\u003e: Full TypeScript support, everywhere\n- 🛠️ \u003cb\u003eExtensible\u003c/b\u003e: Custom rules, transformers, and definitions\n- 🔍 \u003cb\u003eDetailed Error Tracing\u003c/b\u003e: See exactly why validation failed\n- 🏗️ \u003cb\u003eSchema Generation\u003c/b\u003e: OpenAPI \u0026 JSON Schema out of the box\n- ⚡ \u003cb\u003eZero dependencies\u003c/b\u003e, works in Node.js, browsers, and modern runtimes\n\n---\n\n# 📦 Installation\n\n```bash\nnpm install gigli.js\n```\n\n---\n\n# 🏁 Quick Start\n\n```typescript\nimport { v } from 'gigli.js';\n\nconst UserSchema = v.object({\n  username: v.string().min(3),\n  email: v.string().email(),\n});\n\nconst result = UserSchema.safeParse({ username: 'bob', email: 'bob@email.com' });\nconsole.log(result.success); // true\n```\n\n---\n\n# 🌱 Progressive Examples\n\n## 1️⃣ Basic Validation\n\n```typescript\nimport { v } from 'gigli.js';\n\nconst UserSchema = v.object({\n  username: v.string().min(3),\n  email: v.string().email(),\n});\n\nUserSchema.parse({ username: 'ab', email: 'bad' }); // Throws with detailed error\n```\n\n## 2️⃣ Type Inference\n\n```typescript\ntype User = v.infer\u003ctypeof UserSchema\u003e;\n// User: { username: string; email: string }\n```\n\n## 3️⃣ Error Handling \u0026 Flattening\n\n```typescript\ntry {\n  UserSchema.parse({ username: 'ab', email: 'bad' });\n} catch (err) {\n  console.log(err.flatten());\n  /*\n  {\n    input: { username: 'ab', email: 'bad' },\n    errors: [\n      { path: ['username'], message: 'String must be at least 3 characters' },\n      { path: ['email'], message: 'Invalid email address' }\n    ]\n  }\n  */\n}\n```\n\n## 4️⃣ Advanced Builder Features\n\n```typescript\nconst PostSchema = v.object({\n  id: v.string().uuid(),\n  title: v.string().min(5).max(100),\n  tags: v.array(v.string().min(2)).optional(),\n  author: UserSchema, // Schemas are composable!\n  status: v.string().from('enum:values=draft|published|archived'),\n  meta: v.union([\n    v.object({ type: v.literal('text'), content: v.string() }),\n    v.object({ type: v.literal('image'), url: v.string().url() })\n  ])\n});\n```\n\n## 5️⃣ Nested Objects, Arrays, Optionals, Enums\n\n```typescript\nconst BlogSchema = v.object({\n  posts: v.array(PostSchema),\n  owner: v.object({\n    id: v.string().uuid(),\n    name: v.string(),\n    roles: v.array(v.string().from('enum:values=admin|editor|user')),\n  }),\n  settings: v.object({\n    commentsEnabled: v.boolean().optional(),\n    theme: v.string().default('light'),\n  })\n});\n```\n\n## 6️⃣ Decorator API (for OOP \u0026 NestJS fans)\n\n```typescript\nimport { v, ValidatedModel } from 'gigli.js';\n\n@v.Refine((dto) =\u003e dto.password === dto.passwordConfirm, {\n  message: \"Passwords don't match\",\n  path: ['passwordConfirm'],\n})\nclass CreateUserDto extends ValidatedModel {\n  @v.Rule(v.string().email())\n  email: string;\n\n  @v.Rule('string:min=8,max=50')\n  password: string;\n\n  @v.Rule(v.string())\n  passwordConfirm: string;\n}\n\nconst userDto = CreateUserDto.from({\n  email: 'foo@bar.com',\n  password: 'secret123',\n  passwordConfirm: 'secret123',\n});\n```\n\n## 7️⃣ Pipeline API (for complex workflows)\n\n```typescript\nconst OrderPipeline = v.pipeline()\n  .transform((data) =\u003e ({ ...data, orderId: data.id.toLowerCase() }))\n  .validate(v.object({ orderId: v.string().min(1) }))\n  .dispatch('paymentMethod', {\n    'credit_card': v.object({ card: v.string().creditCard() }),\n    'paypal': v.object({ email: v.string().email() }),\n  })\n  .refine((order) =\u003e order.total \u003e 0, { message: 'Order total must be positive' })\n  .effect({\n    onSuccess: (data) =\u003e console.log('Order Validated', data.orderId),\n    onFailure: (trace) =\u003e console.error('Order Failed', trace),\n  });\n\nconst result = OrderPipeline.safeParse(orderData);\n```\n\n## 8️⃣ Custom Rules, Transformers, and Definitions\n\n```typescript\nv.registerRule('isEven', (value) =\u003e typeof value === 'number' \u0026\u0026 value % 2 === 0);\nv.registerTransformer('trim', (value) =\u003e typeof value === 'string' ? value.trim() : value);\nv.define('slug', 'string:min=3|regex:^[a-z0-9-]+$');\n\nconst SlugSchema = v.string().from('slug').transform('trim');\n```\n\n---\n\n# 🧑‍💻 CLI Usage\n\n```sh\nnpx gigli codegen --schema ./src/schemas.ts --target openapi\nnpx gigli codegen --schema ./src/schemas.ts --target jsonschema\nnpx gigli analyze --schema ./src/schemas.ts\nnpx gigli --help\n```\n\n---\n\n# 🏆 Feature Comparison\n\n| Feature                        | Zod | Yup | class-validator | \u003cb\u003eGigli.js\u003c/b\u003e |\n|-------------------------------|:---:|:---:|:--------------:|:--------------:|\n| Type Inference                 | ✅  | ❌  | ✅             | ✅             |\n| Chainable Schema Builder       | ✅  | ✅  | ❌             | ✅             |\n| Decorator API                  | ❌  | ❌  | ✅             | ✅             |\n| Portable String Rules          | ❌  | ❌  | ❌             | ✅             |\n| Unified Runtime (Mix \u0026 Match)  | ❌  | ❌  | ❌             | ✅             |\n| Validation Pipelines \u0026 Dispatch| ❌  | ❌  | ❌             | ✅             |\n| Detailed Error Tracing         | ❌  | ❌  | ❌             | ✅             |\n| Auto OpenAPI/JSON Schema Gen   | ❌  | ❌  | ❌             | ✅             |\n| Extensible (Rules/Transformers)| ⚠️  | ⚠️  | ⚠️             | ✅             |\n\n---\n\n# 🌍 Use It Everywhere\n\n- Node.js, Deno, Bun, Cloudflare Workers\n- React, Vue, Svelte, Solid\n- Express, NestJS, tRPC, REST, GraphQL\n- Works in browsers and modern runtimes\n\n---\n\n# 🔗 Documentation \u0026 Resources\n\n- 📖 \u003cb\u003e[Full Usage Guide](docs/USAGE.md)\u003c/b\u003e\n- 🧩 \u003cb\u003eAPI Reference\u003c/b\u003e: See above and in-code docs\n- 💡 \u003cb\u003eExamples\u003c/b\u003e: [examples/](examples/)\n- 📝 \u003cb\u003e[Contributing Guide](CONTRIBUTING.md)\u003c/b\u003e\n- 🐞 \u003cb\u003e[Report Issues](https://github.com/jasgigli/gigli.js/issues)\u003c/b\u003e\n- 📦 \u003cb\u003e[NPM Package](https://www.npmjs.com/package/gigli.js)\u003c/b\u003e\n- ⚖️ \u003cb\u003e[License (MIT)](LICENSE)\u003c/b\u003e\n\n---\n\n# 🤝 Contributing\n\nWe are building the future of data validation, and we'd love your help! Please read our \u003cb\u003e[CONTRIBUTING.md](CONTRIBUTING.md)\u003c/b\u003e to get started. Whether it's a bug report, a new feature, or a documentation improvement, all contributions are welcome!\n\n---\n\n# 🪪 License\n\nGigli.js is open-source software licensed under the \u003cb\u003eMIT License\u003c/b\u003e.\n\n---\n\n# 🏷️ Keywords\n\nvalidation, validator, typescript, schema, zod, yup, class-validator, openapi, jsonschema, decorators, cli, nodejs, react, express, nestjs, type-safe, builder, portable, runtime, inference, extensible, pipeline, unified, metamorphic\n\n## Usage\n\n### ESM (Node.js with `\"type\": \"module\"` or `.mjs` files)\n\n```js\nimport { v } from 'gigli.js';\n\nconst UserSchema = v.object({\n  username: v.string().min(3),\n  email: v.string().email(),\n});\n\n(async () =\u003e {\n  const result = await UserSchema.safeParse({ username: 'bob', email: 'bob@email.com' });\n  console.log('safeParse:', result); // { success: true, data: ..., error: null }\n  try {\n    const parsed = await UserSchema.parse({ username: 'bob', email: 'bob@email.com' });\n    console.log('parse:', parsed); // { username: 'bob', email: 'bob@email.com' }\n  } catch (err) {\n    console.error('parse error:', err);\n  }\n})();\n```\n\n---\n\n### CommonJS (default Node.js or `.js` files)\n\n```js\nconst { v } = require('gigli.js');\n\nconst UserSchema = v.object({\n  username: v.string().min(3),\n  email: v.string().email(),\n});\n\n(async () =\u003e {\n  const result = await UserSchema.safeParse({ username: 'bob', email: 'bob@email.com' });\n  console.log('safeParse:', result); // { success: true, data: ..., error: null }\n  try {\n    const parsed = await UserSchema.parse({ username: 'bob', email: 'bob@email.com' });\n    console.log('parse:', parsed); // { username: 'bob', email: 'bob@email.com' }\n  } catch (err) {\n    console.error('parse error:', err);\n  }\n})();\n```\n\n---\n\n### TypeScript\n\nTypeScript types are included automatically. You can use the same import as ESM:\n\n```ts\nimport { v } from 'gigli.js';\n// ...rest of your code\n```\n\n---\n\n### API\n\n- `schema.safeParse(data)` — Returns `{ success, data, error }`. Does not throw.\n- `schema.parse(data)` — Returns parsed data or throws on error.\n\nBoth methods are **async** and must be awaited.\n\n---\n\n## Connect with the Author\n\n- GitHub: [https://github.com/jasgigli/gigli.js](https://github.com/jasgigli/gigli.js)\n- Twitter: [@jasgiigli](https://x.com/jasgiigli)\n- LinkedIn: [jasgigli](https://www.linkedin.com/in/jasgigli/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasgigli%2Fgigli.js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjasgigli%2Fgigli.js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasgigli%2Fgigli.js/lists"}