{"id":25678011,"url":"https://github.com/gnodi/felv","last_synced_at":"2026-05-06T15:38:18.133Z","repository":{"id":57158435,"uuid":"96689786","full_name":"gnodi/felv","owner":"gnodi","description":"Simple easy and light JavaScript validator.","archived":false,"fork":false,"pushed_at":"2020-10-13T14:12:24.000Z","size":99,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-18T07:09:00.978Z","etag":null,"topics":["array","async","asynchronous","easy","fast","felv","javascript","js","json","light","lightweight","nodejs","object","schema","simple","type","validation","validator"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gnodi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-09T14:31:27.000Z","updated_at":"2020-10-13T14:12:21.000Z","dependencies_parsed_at":"2022-09-07T01:00:55.189Z","dependency_job_id":null,"html_url":"https://github.com/gnodi/felv","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnodi%2Ffelv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnodi%2Ffelv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnodi%2Ffelv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnodi%2Ffelv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gnodi","download_url":"https://codeload.github.com/gnodi/felv/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240504278,"owners_count":19812181,"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":["array","async","asynchronous","easy","fast","felv","javascript","js","json","light","lightweight","nodejs","object","schema","simple","type","validation","validator"],"created_at":"2025-02-24T15:35:14.722Z","updated_at":"2026-05-06T15:38:13.097Z","avatar_url":"https://github.com/gnodi.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# felv\n\n**felv** is a fast easy and light (synchronous and asynchronous) JavaScript validator.\n\n- Take only **2 minutes** to know if felv is made for you.\n- Take only **5 minutes** to try it.\n- Take only **15 minutes** to read this page and learn everything you need to know!\n\n[![Build][build-image]][build-url]\n[![Coverage Status][coverage-image]][coverage-url]\n[![Version][version-image]][version-url]\n[![Downloads][downloads-image]][downloads-url]\n[![Dependencies][dependencies-image]][dependencies-url]\n[![Dev Dependencies][dev-dependencies-image]][dev-dependencies-url]\n\n## Installation\nRun the following command to add the package to your dev dependencies:\n```sh\n$ npm install --save felv\n```\n\n## Use\n```js\nconst felv = require('felv');\n```\n\n### Example\n```js\nconst schema = {\n  // Value of 'a' key is required and must be a number.\n  a: {\n    required: true,\n    type: 'number'\n  },\n  // Value of 'b' key is an array of numbers and strings.\n  b: {\n    type: Array,\n    items: {\n      type: ['string', 'number']\n    }\n  },\n  // Value of 'c' key is an instance of Object\n  // with properties i and j which are booleans\n  // of default value `true`.\n  c: {\n    type: Object,\n    properties: {\n      i: {\n        default: true,\n        type: 'boolean'\n      },\n      j: {\n        default: true,\n        type: 'boolean'\n      }\n    }\n  },\n  // Value of 'd' key is an instance of Object\n  // with properties of variable names and string values.\n  d: {\n    type: Object,\n    items: {\n      type: 'string'\n    }\n  }\n};\n\nconst validatedValue = felv.validate(\n  {\n    a: 1,\n    b: [2, 'foo', 4],\n    c: {\n      i: false\n    },\n    d: {\n      x: 'foo',\n      y: 'bar'\n    }\n  },\n  schema\n);\n```\n\n`validatedValue` is equal to:\n```js\n{\n  a: 1,\n  b: [2, 'foo', 4],\n  c: {\n    i: false,\n    j: true\n  },\n  d: {\n    x: 'foo',\n    y: 'bar'\n  }\n}\n```\n\n### Validation\n#### Simple\nYou can easily validate a value from a schema:\n```js\nconst validatedValue = felv.validate(value, schema, options);\n```\n\n#### From a compiled schema\nFor repetitive validations, you should compile a validator to optimize validation performances. This can also be useful to detect schema format errors before validation occurs.\n```js\nconst validator = felv.compile(schema, options);\nconst validatedValue = validator.validate(value);\n```\n\n### Schema\nA schema is used to describe the format of a value. Each attribute of a schema is called a validation processor. A schema can embed other schemas to describe embedded structures thanks to some validation processors.\n\n#### Validation processors list\n##### Type\nYou can check the type of the value of a key:\n```js\n{\n  foo: {\n    type: 'number'\n  },\n  bar: {\n    type: Date\n  },\n  foobar: {\n    type: ['number', 'string'] // number or string items\n  }\n}\n```\n\nMatching values:\n```js\n{\n  foo: 2,\n  bar: new Date(),\n  foobar: 3\n}\n\n{\n  foo: 2,\n  bar: new Date(),\n  foobar: 'foo'\n}\n```\n\n##### Default\nYou can specify a default value:\n```js\n{\n  foo: {\n    default: 3,\n    type: 'number'\n  },\n  bar: {\n    default: 6\n  }\n}\n```\n\nMatching value:\n```js\n{\n  foo: 2\n}\n```\n\nValidated value:\n```js\n{\n  foo: 2,\n  bar: 6\n}\n```\n\n##### Required\nYou can specify a required value:\n```js\n{\n  foo: {\n    required: true,\n    type: 'number'\n  },\n  bar: {\n    type: 'number'\n  }\n}\n```\n\nMatching value:\n```js\n{\n  foo: 2\n}\n```\n\n##### Items\nYou can specify embedded items of arrays and objects:\n```js\n{\n  foo: {\n    type: Array,\n    items: {\n      type: 'number'\n    }\n  },\n  bar: {\n    type: Object,\n    items: {\n      type: 'number'\n    }\n  }\n}\n```\n\nMatching value:\n```js\n{\n  foo: [2, 3, 7],\n  bar: {a: 1, b: 5}\n}\n```\n\n##### Properties\nYou can specify properties of objects:\n```js\n{\n  foo: {\n    type: Object,\n    properties: {\n      a: {\n        required: true,\n        type: 'number'\n      },\n      b: {\n        default: 'bar',\n        type: 'string'\n      }\n    }\n  }\n}\n```\n\nMatching value:\n```js\n{\n  foo: {a: 4}\n}\n```\n\nValidated value:\n```js\n{\n  foo: {a: 4, b: 'bar'}\n}\n```\n\n##### Format\nYou can give a function to format input values:\n```js\n{\n  foo: {\n    format: value =\u003e (Array.isArray(value) ? value : [value]),\n    type: Array,\n    items: {\n      type: 'string'\n    }\n  }\n}\n```\n\nMatching value:\n```js\n{\n  foo: 'bar'\n}\n```\n\nValidated value:\n```js\n{\n  foo: ['bar']\n}\n```\n\n##### Validate\nYou can give a function to make custom validations and format output values:\n```js\n{\n  foo: {\n    type: 'number',\n    validate: (value, expected) =\u003e {\n      if (value \u003c 1 || value \u003e 9) {\n        // Throw a validation error.\n        expected('a number between 1 and 9');\n      }\n      return value;\n    }\n  },\n  bar: {\n    type: 'number',\n    // Alter validated value.\n    validate: value =\u003e (value \u003e 1 ? value * 10 : value)\n  }\n}\n```\n\nMatching value:\n```js\n{\n  foo: 4,\n  bar: 2\n}\n```\n\nValidated value:\n```js\n{\n  foo: 4,\n  bar: 20\n}\n```\n\n##### Error\nYou can specify a custom error message that will be set on error occurrence:\n```js\nconst schema = {\n  foo: {\n    required: true,\n    type: 'number',\n    error: 'You must specify a number for \"foo\"'\n  }\n};\n\ntry {\n  felv.validate({foo: 'bar'}, schema);\n} catch(error) {\n  console.log(error.customMessage); // Display `You must specify a number for \"foo\"`.\n}\n```\n\n#### Validation ways\nYou can specify different validation ways givin an array of schemas:\n```js\n{\n  foo: [\n    {\n      required: true,\n      type: 'number'\n    },\n    {\n      default: 'bar',\n      type: 'string'\n    }\n  ]\n}\n```\n\nMatching values:\n```js\n{foo: 2}\n\n{foo: 'foo'}\n\n{}\n```\n\nCorresponding validated values:\n```js\n{foo: 2}\n\n{foo: 'foo'}\n\n{foo: 'bar'}\n```\n\n#### Asynchronous validation\nYou can use asynchronous functions in validation processors accepting a function (like `format` and `validate`) or directly return a `Promise`. In that case, a `Promise` will be returned by the `validate` method.\n\nExample:\n```js\nconst asyncSchema = {\n  foo: {\n    validate: async (value) =\u003e {\n      const validatedValue = await asyncValidationFunction(value);\n      return validatedValue + 1;\n    }\n  },\n  bar: {\n    format: (value) =\u003e {\n      return new Promise((resolve, reject) =\u003e {\n        asyncFormattingFunction(formattedValue =\u003e resolve(formattedValue));\n      });\n    }\n  }\n};\nconst validatedValue = await felv.validate({foo: 3, bar: 4}, asyncSchema);\n```\n\n#### Validation processors dependencies\nFor simplicity, validation processors are independent from each other.\n\n#### Validation processors order\nValidation processors are processed in a specific order:\n1. format\n2. default\n3. required\n4. type\n5. items\n6. properties\n7. validate\n8. error\n\n### Options\nYou can modulate validation with following options:\n- async\n- convert\n- formatting\n- full\n- immutable\n- list\n- namespace\n- required\n- validation\n\n#### Async\nWhether or not to force a `Promise` result even on synchronous return.\n\nDefault value:\n```js\n{\n  async: false\n}\n```\n\n#### Convert\nWhether or not to automatically convert some value types.\n\nDefault value:\n```js\n{\n  convert: true\n}\n```\n\n- `string` =\u003e `boolean`:\n  * `\"false\"` =\u003e `false`\n  * `\"true\"` =\u003e `true`\n  * `\"0\"` =\u003e `false`\n  * `\"1\"` =\u003e `true`\n- `number` =\u003e `boolean`:\n  * `0` =\u003e `false`\n  * `!== 0` =\u003e `true`\n- `string` =\u003e `number`:\n  * `\"100\"` =\u003e `100`\n- `boolean` =\u003e `number`:\n  * `false` =\u003e `0`\n  * `true` =\u003e `1`\n\n#### Formatting\nA validation object to be passed as second argument (`options`) in `format` validation processors:\n```js\n{\n  foo: {\n    format: (value, options) =\u003e {\n      // Format value from options.\n    }\n  }\n}\n```\n\nDefault value:\n```js\n{\n  formatting: {}\n}\n```\n\n#### Full\nWhether or not to process full validation event after a first error occurred.\n\nDefault value:\n```js\n{\n  full: false\n}\n```\n\n#### Immutable\nWhether or not to use the original value for validated value.\nThis increase performances but must not be used for cases where the original value must be preserved.\n\nDefault value:\n```js\n{\n  immutable: false\n}\n```\n\n#### List\nWhether or not to process schema on a list of items (array or object) instead of an object with defined properties.\n\nDefault value:\n```js\n{\n  list: false\n}\n```\n\n#### Namespace\nA namespace to prefix paths in error messages.\n\nDefault value:\n```js\n{\n  namespace: '$'\n}\n```\n\n#### Required\nWhether or not fields are required by default.\n\nDefault value:\n```js\n{\n  required: false\n}\n```\n\n#### Validation\nA validation object to be passed as third argument (`options`) in `validate` validation processors:\n```js\n{\n  foo: {\n    validate: (value, expected, options) =\u003e {\n      // Validate 'value' from 'options'.\n      // Throw validation error with 'expected'.\n    }\n  }\n}\n```\n\u003e `expected` function take 3 arguments:\n\u003e - `{string} expectedType`: Expected type (or value description)\n\u003e - `{Array.\u003c*\u003e} [expectedValues]`: Optional expected values\n\u003e - `{string} [customMessage]`: Optional custom error message\n\nDefault value:\n```js\n{\n  validation: {}\n}\n```\n\n### Error handling\n#### Simple example\n```js\nconst validator = felv.compile({foo: {type: 'string'}});\ntry {\n  const validatedValue = validator.validate({foo: 3});\n} catch (error) {\n  // Error type: 'ValidationError'\n  console.log(error.name);\n  // Explicit message: '[$.foo](type) Expected value to be a string, got a number of value `3` instead'\n  console.log(error.message);\n  // Path of the failing value: '$.foo'\n  console.log(error.path);\n  // Failing schema attribute/validation processor: 'type'\n  console.log(error.attribute);\n  // Subject of failure: 'value'\n  console.log(error.subject);\n  // Expected type: 'string'\n  console.log(error.expectedType);\n  // Expected values: []\n  console.log(error.expectedValues);\n  // Got(gotten) type: 'number'\n  console.log(error.gotValue);\n  // Got(gotten) value: 3\n  console.log(error.gotValue);\n  // Custom message (not defined here): ''\n  console.log(error.customMessage);\n}\n```\n\n#### Full validation example\nYou can process full validation to retrieve all validation errors of a value against a schema.\nThis can be useful to validate a user form and return all errors for instance:\n```js\n// Compile form schema at program initialization.\nconst schema = {\n  firstname: {\n    required: true,\n    type: 'string',\n    // Define custom error message of occuring validation error.\n    error: 'Firstname must be filled'\n  },\n  lastname: {\n    required: true,\n    type: 'string'\n  },\n  email: {\n    required: true,\n    type: 'string',\n    validate: (value, expected) =\u003e {\n      if (!/@/.test(value)) {\n        // Define custom error message with third argument\n        // of expected function.\n        expected('email', null, 'Email is incorrect');\n      }\n      return value;\n    },\n    // `error` attribute does not overwrite already defined custom message\n    // like 'Email is incorrect' in above validate attribute function.\n    error: 'Email must be filled'\n  },\n  password: {\n    required: true,\n    type: 'string',\n    validate: (value, expected) =\u003e {\n      if (value.length \u003c 8) {\n        expected('a string of at least 8 character');\n      } else if (!/[A-Z]/.test(value)) {\n        expected('a string with at least one uppercase letter');\n      }\n      return value;\n    },\n    error: 'Password must at least contains 8 characters with at least one uppercase letter'\n  }\n};\nconst options = {\n  namespace: 'form',\n  full: true\n};\nconst validator = felv.compile(schema, options);\n```\n\n```js\n// Use compiled validator to validate user input on user subscription.\n// We assume `req.body` equals `{email: 'dumb', password: 'dumb'}`\ntry {\n  const validatedValue = validator.validate({\n    firstname: req.body.firstname,\n    lastname: req.body.lastname,\n    email: req.body.email,\n    password: req.body.email\n  });\n  // Do stuff like persisting user in database...\n} catch (error) {\n  // Error type: 'FullValidationError'\n  console.log(error.name);\n  // Use `error.pathErrorMessages` to get validation error messages associated with failing paths.\n  assert.deepEqual(error.pathErrorMessages, {\n    'form.firstname': 'Firstname must be filled',\n    'form.lastname': '[form.lastname](required) Expected value to be a defined value, got `undefined` instead',\n    'form.email': 'Email is incorrect',\n    'form.password': 'Password must at least contains 8 characters with at least one uppercase letter'\n  });\n  // Use `error.pathErrors` to get the validation errors instead of messages.\n  // Use `error.errorMessages` to get validation error message list.\n  assert.deepEqual(error.errorMessages, [\n    'Email is incorrect',\n    'Firstname must be filled',\n    'Password must at least contains 8 characters with at least one uppercase letter',\n    '[form.lastname](required) Expected value to be a defined value, got `undefined` instead'\n  ]);\n  // Use `error.errors` to get the validation errors instead of messages.\n}\n```\n\n### Testing\nMany `npm` scripts are available to help testing:\n```sh\n$ npm run {script}\n```\n- `check`: lint and check unit and integration tests\n- `lint`: lint\n- `test`: check unit tests\n- `test-coverage`: check coverage of unit tests\n- `test-debug`: debug unit tests\n- `test-integration`: check integration tests\n- `test-performance`: check performance (just for fun)\n- `test-watch`: work in TDD!\n\nUse `npm run check` to check that everything is ok.\n\n## Contributing\nIf you want to contribute, just fork this repository and make a pull request!\n\nYour development must respect these rules:\n- fast\n- easy\n- light\n\nYou must keep test coverage at 100%.\n\n## License\n[MIT](LICENSE)\n\n[build-image]: https://img.shields.io/travis/gnodi/felv.svg?style=flat\n[build-url]: https://travis-ci.org/gnodi/felv\n[coverage-image]:https://coveralls.io/repos/github/gnodi/felv/badge.svg?branch=master\n[coverage-url]:https://coveralls.io/github/gnodi/felv?branch=master\n[version-image]: https://img.shields.io/npm/v/felv.svg?style=flat\n[version-url]: https://npmjs.org/package/felv\n[downloads-image]: https://img.shields.io/npm/dm/felv.svg?style=flat\n[downloads-url]: https://npmjs.org/package/felv\n[dependencies-image]:https://david-dm.org/gnodi/felv.svg\n[dependencies-url]:https://david-dm.org/gnodi/felv\n[dev-dependencies-image]:https://david-dm.org/gnodi/felv/dev-status.svg\n[dev-dependencies-url]:https://david-dm.org/gnodi/felv#info=devDependencies\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnodi%2Ffelv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgnodi%2Ffelv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnodi%2Ffelv/lists"}