{"id":15540446,"url":"https://github.com/poteto/validated-proxy","last_synced_at":"2025-04-23T17:04:01.566Z","repository":{"id":57390380,"uuid":"114084003","full_name":"poteto/validated-proxy","owner":"poteto","description":"Typesafe, validated ES2015 proxies","archived":false,"fork":false,"pushed_at":"2019-02-03T21:31:24.000Z","size":434,"stargazers_count":11,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-03T12:18:15.149Z","etag":null,"topics":["es2015","proxy","typescript","validations"],"latest_commit_sha":null,"homepage":"https://poteto.github.io/validated-proxy/","language":"TypeScript","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/poteto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-13T06:40:05.000Z","updated_at":"2024-06-12T16:11:25.000Z","dependencies_parsed_at":"2022-09-15T06:12:12.910Z","dependency_job_id":null,"html_url":"https://github.com/poteto/validated-proxy","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poteto%2Fvalidated-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poteto%2Fvalidated-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poteto%2Fvalidated-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poteto%2Fvalidated-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/poteto","download_url":"https://codeload.github.com/poteto/validated-proxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":220405529,"owners_count":16642490,"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":["es2015","proxy","typescript","validations"],"created_at":"2024-10-02T12:13:47.557Z","updated_at":"2024-10-18T20:25:48.397Z","avatar_url":"https://github.com/poteto.png","language":"TypeScript","readme":"# validated-proxy [![npm version](https://badge.fury.io/js/validated-proxy.svg)](https://badge.fury.io/js/validated-proxy) [![Build Status](https://travis-ci.org/poteto/validated-proxy.svg?branch=master)](https://travis-ci.org/poteto/validated-proxy) [![Coverage Status](https://coveralls.io/repos/github/poteto/validated-proxy/badge.svg?branch=master)](https://coveralls.io/github/poteto/validated-proxy?branch=master)\n\nA validated proxy represents a set of valid changes to be applied later onto any object. Each change is tested against an optional validation, and if valid, the change is stored and applied when executed.\n\n## Documentation\n\nLatest documentation is available [here](https://poteto.github.io/validated-proxy/).\n\n## Getting started\n\nInstall using `yarn`:\n\n```\nyarn add validated-proxy\n```\n\nOr using `npm`:\n\n```\nnpm install --save validated-proxy\n```\n\nThen import it and create a new validated proxy:\n\n```ts\nimport { validatedProxy } from 'validated-proxy';\nimport {\n  validatePresence,\n  validateLength,\n  validateNumber\n} from '../path/to/validators';\n\nconst user = {\n  name: 'Billy Bob',\n  age: 25\n};\nconst updatedUser = validatedProxy(user, {\n  validations: {\n    name: [validatePresence(true), validateLength({ min: 4 })],\n    age: [validatePresence(true), validateNumber({ gte: 18 })]\n  }\n});\n\n// valid changes\nupdatedUser.name = 'Michael Bolton';\nuser.name; // 'Billy Bob'\nupdatedUser.flush();\nuser.name; // 'Michael Bolton'\n\n// invalid changes\nupdatedUser.name = 'a';\nuser.name; // 'Billy Bob'\nupdatedUser.errors;\n// [\n//   {\n//     key: 'name',\n//     messages: ['name must be more than 4 characters'],\n//     value: 'a'\n//   }\n// ]\nupdatedUser.flush();\nuser.name; // 'Billy Bob'\n```\n\n## Custom validators\n\nA validator is a higher order function that returns a validation function. The validator can pass options to the validation function. The validation function is the function that is invoked when you set a value on the `BufferedProxy`.\n\nHere's an example of creating a validator that validates if a value is of a given `type`:\n\n```ts\nimport { ValidatorFunction } from 'validated-proxy';\n\ntype Primitive =\n  | 'boolean'\n  | 'number'\n  | 'string'\n  | 'symbol'\n  | 'null'\n  | 'undefined';\ntype NonPrimitive = 'object';\ninterface ValidatorOptions {\n  type: Primitive | NonPrimitive;\n}\n\nconst validateTypeof = ({ type }: ValidatorOptions): ValidatorFunction =\u003e {\n  return (key, newValue, oldValue) =\u003e {\n    return {\n      message: `${newValue} is not of type '${type}'`,\n      validation: typeof newValue === type\n    };\n  };\n};\n\nexport default validateTypeof;\n```\n\nNow you can use your validator like so:\n\n```ts\nimport { validatedProxy } from 'validated-proxy';\nimport validateTypeof from '../path/to/validateTypeof';\n\nconst user = { name: 'Billy Bob' };\nconst updatedUser = validatedProxy(user, {\n  validations: { name: validateTypeof({ type: 'string' }) }\n});\n\nupdatedUser.name = 123; // error\n```\n\n### Custom validator type safety\n\nIf you're creating a custom validator that relies on the new value to be of a certain type, you can specify it as a generic type parameter to `ValidatorFunction\u003cT\u003e` (where `T` is the type of your new value):\n\n```ts\nimport { ValidatorFunction } from 'validated-proxy';\n\ninterface ValidatorOptions {\n  is: number;\n}\n\nconst validateLength = ({\n  is\n}: ValidatorOptions): ValidatorFunction\u003cstring\u003e =\u003e {\n  return (key, newValue, oldValue) =\u003e {\n    return {\n      message: `${key} must be exactly ${is} characters`,\n      validation: is === newValue.length // `newValue` is a `string`\n    };\n  };\n};\n\nexport default validateLength;\n```\n\nWhen a custom `ValidatorFunction` is narrowed to a certain type, it will not typecheck if you try to use the function against a key on the original object that does not have the same value type. For example, the `validateLength` validator only works on `strings` (`number` does not have the `length` property):\n\n```ts\nimport validateLength from '../path/to/validateLength';\n\ninterface User {\n  name: string;\n  age: number;\n}\n\nconst user: Partial\u003cUser\u003e = { age: 21 };\nconst updatedUser = validatedProxy(user, {\n  validations: {\n    age: validateLength({ is: 3 }) // [ts] Type 'ValidatorFunction\u003cstring\u003e'\n                                   // is not assignable to type\n                                   // 'ValidatorFunction\u003cnumber\u003e |\n                                   // ValidatorFunction\u003cnumber\u003e[]'.\n  }\n})\n```\n\nMore examples can be seen [here](/test/support).\n\n## Custom error handlers\n\nThe error handler is a function that is called when an invalid value is set. This is in addition to the error that is already stored in the cache. By default, the error handler is a `no-op` (does nothing). You can specify a custom error handler; for example, you could throw an error, log error messages, send them to a server, etc:\n\n```ts\nconst proxy = validatedProxy(original, {\n  errorHandler: errorMessages =\u003e { /** do something here **/},\n  validations: /** ... */\n});\n```\n\n## Custom execution handlers\n\nThe execution handler is a function that is used to set the changes on the target object. By default, this is `Object.assign`. You can specify a custom execution handler; for example, you could use Lodash's `assign`, Ember's `set`, and so forth:\n\n```ts\nconst proxy = validatedProxy(original, {\n  executionHandler: (target, changes) =\u003e { /** do something here **/},\n  validations: /** ... */\n});\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoteto%2Fvalidated-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpoteto%2Fvalidated-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoteto%2Fvalidated-proxy/lists"}