{"id":28541450,"url":"https://github.com/zestia/ember-validation","last_synced_at":"2025-07-07T15:31:28.717Z","repository":{"id":29239575,"uuid":"116939986","full_name":"zestia/ember-validation","owner":"zestia","description":"Simple validation utils for Ember apps","archived":false,"fork":false,"pushed_at":"2025-07-07T14:16:44.000Z","size":6607,"stargazers_count":8,"open_issues_count":7,"forks_count":4,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-07-07T14:59:03.605Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/zestia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"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":"2018-01-10T09:53:12.000Z","updated_at":"2025-07-07T14:16:48.000Z","dependencies_parsed_at":"2024-02-06T10:42:17.392Z","dependency_job_id":"9a44f01c-d8d3-434b-91aa-f810a6c776ee","html_url":"https://github.com/zestia/ember-validation","commit_stats":null,"previous_names":[],"tags_count":53,"template":false,"template_full_name":null,"purl":"pkg:github/zestia/ember-validation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestia%2Fember-validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestia%2Fember-validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestia%2Fember-validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestia%2Fember-validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zestia","download_url":"https://codeload.github.com/zestia/ember-validation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zestia%2Fember-validation/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264101753,"owners_count":23557621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2025-06-09T20:08:33.130Z","updated_at":"2025-07-07T15:31:28.711Z","avatar_url":"https://github.com/zestia.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @zestia/ember-validation\n\n\u003c!-- [![Ember Observer][ember-observer-badge]][ember-observer-url] --\u003e\n\u003c!-- [![GitHub Actions][github-actions-badge]][github-actions-url] --\u003e\n\n[npm-badge]: https://img.shields.io/npm/v/@zestia/ember-validation.svg\n[npm-badge-url]: https://www.npmjs.com/package/@zestia/ember-validation\n[github-actions-badge]: https://github.com/zestia/ember-validation/workflows/CI/badge.svg\n[github-actions-url]: https://github.com/zestia/ember-validation/actions\n[ember-observer-badge]: https://emberobserver.com/badges/-zestia-ember-validation.svg\n[ember-observer-url]: https://emberobserver.com/addons/@zestia/ember-validation\n\nThis lightweight addon lets you validate an object, or an array of objects.\n\nIt works by running one or more functions against each property on the object (or array of objects), and returns a matching structure containing an array of messages that describe each property.\n\n### Installation\n\n```\nember install @zestia/ember-validation\n```\n\nAdd the following to `~/.npmrc` to pull @zestia scoped packages from Github instead of NPM.\n\n```\n@zestia:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=\u003cYOUR_GH_TOKEN\u003e\n```\n\n## Demo\n\nhttps://zestia.github.io/ember-validation\n\n## Features\n\n- Validates objects ✔︎\n- Validates arrays ✔︎\n- [Internationalisation](#internationalisation) ✔︎\n- [async constraints](#constraints) ✔︎\n- [adhoc constraints](#adhoc-constraints) ✔︎\n- [dynamic constraints](#dynamic-constraints) ✔︎\n- Uses [date-fns](https://date-fns.org) for date validation. ✔︎\n- Simple [restructuring](#utils) of error messages ✔︎\n\n## Notes\n\n- Making a constraint is as simple as writing a function that returns nothing if it passes, or a string if it fails.\n\n## Example\n\n```javascript\nimport validate from '@zestia/ember-validation';\nimport {\n  present,\n  maxLength,\n  truthy,\n  email,\n  date\n} from '@zestia/ember-validation/constraints';\n\nconst person = {\n  id: 1,\n  name: '',\n  emailAddress: 'joe@bloggs',\n  dateOfBirth: null,\n  terms: false\n};\n\nconst constraints = {\n  name() {\n    return [\n      present({ message: 'Please enter your name' }),\n      maxLength({ max: 255 })\n    ];\n  },\n\n  emailAddress() {\n    return [present(), email()];\n  },\n\n  dateOfBirth() {\n    return [present(), date({ format: 'dd/MM/yyyy' })];\n  },\n\n  terms() {\n    return [truthy({ message: 'Please accept the terms' })];\n  }\n};\n\nconst errors = await validate(person, constraints);\n\n/**\n *  {\n *    name: [\n *      'Please enter your name'\n *    ],\n *    terms: [\n *      'Please accept the terms'\n *    ],\n *    emailAddress: [\n *      'Invalid email'\n *    ],\n *    dateOfBirth: [\n *      'Required value',\n *      'Invalid date, expecting dd/MM/yyyy'\n *    ]\n *  }\n */\n```\n\n## Adhoc Constraints\n\nYou can validate properties that aren't actually on the object being validated. Here is a contrived example...\n\n```javascript\nconst person = {\n  firstName: 'Joe',\n  lastName: 'Bloggs'\n};\n\nconst constraints = {\n  firstName() {\n    return [present()];\n  },\n\n  lastName() {\n    return [present()];\n  },\n\n  name() {\n    return [nameIsUnique];\n  }\n};\n\nconst errors = await validate(person, constraints);\n\n/**\n *  {\n *    firstName: null,\n *    lastName: null,\n *    name: ['Must be unique']\n *  }\n */\n\nconst names = ['Joe Bloggs'];\n\nfunction nameIsUnique(value, object) {\n  if (names.includes(`${object.firstName} ${object.lastName}`)) {\n    return;\n  }\n\n  return 'Must be unique';\n}\n```\n\n## Dynamic Constraints\n\nBecause constraints are functions, this allows for a very powerful approach for validating arrays of objects.\nFor example, imagine you have an array of items of a _varying types_.\n\n```javascript\nconst items = [\n  { id: 1, value: '', type: 'text' },\n  { id: 2, value: '', type: 'number' },\n  { id: 3, value: '', type: 'email' },\n  { id: 4, value: '', type: 'date' }\n];\n\nconst constraints = (item) =\u003e {\n  return {\n    value() {\n      switch (item.type) {\n        case 'text':\n          return [present()];\n        case 'number':\n          return [present(), number()];\n        case: 'email':\n          return [present(), email()];\n        case: 'date':\n          return [present(), date({ format: 'dd/MM/yyyy' })];\n        default:\n          return [];\n      }\n    }\n  };\n}\n\nconst errors = await validate(items, constraints);\n\n/*\n *  [\n *    {\n *      value: ['Required value']\n *    },\n *    {\n *      value: ['Required value', 'Invalid number']\n *    },\n *    {\n *      value: ['Required value', 'Invalid email']\n *    },\n *    {\n *      value: ['Required value', 'Invalid date, expecting dd/MM/yyyy']\n *    }\n *  ]\n */\n```\n\n## Constraints\n\nThe following constraints come with this addon. Creating a constraint is as simple as making a function that returns a string if the constraint has failed. Constraints can be asynchronous too.\n\n- `bigDecimal`\n- `date`\n- `email`\n- `greaterThan`\n- `lessThan`\n- `maxLength`\n- `minLength`\n- `number`\n- `phoneNumber`\n- `present`\n- `truthy`\n\n## Internationalisation\n\nThere are a few approaches you can take to internationalise the error messages. The most obvious one would be to set the message property as the translated string, e.g.\n\n```javascript\nmessage: this.intl.t('too-large');\n```\n\nAlternatively, you could set the message just as the key, and internationalise it later in handlebars, e.g.\n\n```javascript\nmessage: 'too-large';\n```\n\nOr, as of version 5, you can provide a key, e.g.\n\n```javascript\nkey: 'too-large';\n```\n\n...along with a function that will be called for each failed constraint, e.g.\n\n```javascript\nimport { setMessageFn } from '@zestia/ember-validation';\n\nexport function initialize(appInstance) {\n  const intl = this.owner.lookup('service:intl');\n\n  setMessageFn((key, tokens) =\u003e intl.t(`validation.${key}`, tokens));\n}\n```\n\n## Utils\n\n- `setMessageFn`\u003cbr\u003e\n  Sets the function that will build a string for a given constraint\n\n- `messageFor`\u003cbr\u003e\n  Should be used as the return value of constraint function\n\n- `flattenErrors`\u003cbr\u003e\n  Flattens a validation result into a single array of _all_ the messages\n\n- `collateErrors`\u003cbr\u003e\n  Flattens a validation result into an array of the messages for each field\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzestia%2Fember-validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzestia%2Fember-validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzestia%2Fember-validation/lists"}