{"_id":"joiful-experiments","_rev":"197439","name":"joiful-experiments","description":"Object schema validation (experimental fork)","dist-tags":{"latest":"1.2.2"},"maintainers":[{"name":"ariaminaei","email":"aria.minaei@gmail.com"}],"time":{"modified":"2021-06-03T12:29:59.000Z","created":"2013-11-05T12:42:23.422Z","1.2.2":"2013-11-05T12:42:23.422Z"},"users":{},"repository":{"type":"git","url":"git://github.com/AriaMinaei/joiful-experiments"},"versions":{"1.2.2":{"name":"joiful-experiments","description":"Object schema validation (experimental fork)","version":"1.2.2","repository":{"type":"git","url":"git://github.com/AriaMinaei/joiful-experiments"},"main":"index","keywords":["schema","validation"],"engines":{"node":"0.10.x"},"dependencies":{"hoek":"1.x.x"},"devDependencies":{"lab":"1.x.x"},"scripts":{"test":"make test-cov"},"licenses":[{"type":"BSD","url":"http://github.com/AriaMinaei/joiful-experiments/raw/master/LICENSE"}],"contributors":[{"name":"Van Nguyen","email":"the.gol.effect@gmail.com"},{"name":"Eran Hammer","email":"eran@hueniverse.com","url":"http://hueniverse.com"},{"name":"Wyatt Preul","email":"wpreul@gmail.com","url":"http://jsgeek.com"}],"readmeFilename":"README.md","bugs":{"url":"https://github.com/AriaMinaei/joiful-experiments/issues"},"_id":"joiful-experiments@1.2.2","dist":{"shasum":"00fa915b4a97a7c3810a08884cc2739578bc3d63","size":174486,"noattachment":false,"key":"/joiful-experiments/-/joiful-experiments-1.2.2.tgz","tarball":"http://registry.cnpm.dingdandao.com/joiful-experiments/download/joiful-experiments-1.2.2.tgz"},"_from":".","_npmVersion":"1.3.11","_npmUser":{"name":"ariaminaei","email":"aria.minaei@gmail.com"},"maintainers":[{"name":"ariaminaei","email":"aria.minaei@gmail.com"}],"directories":{},"publish_time":1383655343422,"_cnpm_publish_time":1383655343422,"_hasShrinkwrap":false}},"readme":"<a href=\"https://github.com/spumko\"><img src=\"https://raw.github.com/spumko/spumko/master/images/from.png\" align=\"right\" /></a>\n![joi Logo](https://raw.github.com/spumko/joi/master/images/joi.png)\n\nObject schema validation (This is a temporary fork to experiment with some additional validators, including inheritance validation.)\n\n[![Build Status](https://secure.travis-ci.org/AriaMinaei/joiful-experiments.png)](http://travis-ci.org/AriaMinaei/joiful-experiments)\n\n\n# Table of Contents\n\n<img src=\"https://raw.github.com/spumko/joi/master/images/validation.png\" align=\"right\" />\n* [Introduction](#introduction \"Introduction\")\n* [Type Registry](#type-registry \"Type Registry\")\n* [Constraints](#constraints \"Constraints\")\n  * [BaseType](#basetype \"BaseType\")\n  * [String](#string \"String\")\n  * [Number](#number \"Number\")\n  * [Boolean](#boolean \"Boolean\")\n  * [Array](#array \"Array\")\n  * [Object](#object \"Object\")\n  * [Function](#function \"Function\")\n  * [Any](#any \"Any\")\n* [Usage](#usage \"Usage\")\n  * [Config Syntax](#config-syntax \"Config Syntax\")\n  * [Evaluation Order](#evaluation-order \"Evaluation Order\")\n* [Special Options](#special-options \"Special Options\")\n* [Security Considerations](#security-considerations \"Security Considerations\")\n* [Examples](#examples \"Examples\")\n* [References](#references \"References\")\n  * [Reference A: Other Types](#reference-a-other-types \"Reference A: Other Types\")\n\n\n# Introduction\n\nThe **joi** validation system is used to validate JavaScript objects based on a rich descriptive schema.\nSchema validation is the process of ensuring that objects match pre-defined expectations.\n\nFor example, the following schema:\n```javascript\nvar Joi = require('joi');\n\nvar schema = {\n    username: Joi.types.String().alphanum().min(3).max(30).with('birthyear').required(),\n    password: Joi.types.String().regex(/[a-zA-Z0-9]{3,30}/).without('access_token'),\n    access_token: Joi.types.String(),\n    birthyear: Joi.types.Number().min(1850).max(2012),\n    email: Joi.types.String().email()\n};\n```\n\ndefines these constraints:\n* 'username'\n    * a required string\n    * must contain only alphanumeric characters\n    * at least 3 chars long but no more than 30\n    * must be accompanied by 'birthyear' (logical AND)\n* 'password'\n    * an optional string\n    * must satisfy the custom regex\n    * cannot appear together with 'access_token'\n* 'access_token'\n    * an optional, unconstrained string\n* 'birthyear'\n    * an integer between 1850 and 2012\n* 'email'\n    * a valid email address string\n\nThe above constraints point out some non-obvious features:\n* Keys are optional by default\n* Strings are by default utf-8 encoded\n* relationships are defined in an additive fashion\n    * \"X.join(Y), Y.join(Z)\" is the same as requiring all three to be present: \"X AND Y AND Z\"\n    * Likewise \"X.xor(Y), Y.xor(Z)\" => requires that only one of three be present: \"X XOR Y XOR Z\"\n* .regex may or may not override other string-related constraints (.alphanum, .min, .max)\n    ** constraints are evaluated in order\n* order of chained functions matter\n    ** \".min(0).max(100).min(1)\" sets the min to 1, overwriting the result of the first min call\n    ** if \".regex(/[a-z]{0,3}/)\" and \".max(50)\" both supplied, only the overlap is valid (length 3 or less = valid)\n\nBelow is an example of how to validate an object against the above schema:\n\n```javascript\nvar err = Joi.validate(obj, schema);\n// err will be set if the object failed to validate against the schema\n```\n\n# Type Registry\n\nThe Types object is pre-populated with a mutable list of JavaScript's valid data types. However, for convenience, the registry also includes subset helpers with common constraints already applied. For a list of helpers see the following sections...\n\n* [String](#string \"String\")\n* [Number](#number \"Number\")\n* [Boolean](#boolean \"Boolean\")\n* [Array](#array \"Array\")\n* [Object](#object \"Object\")\n* [Function](#function \"Function\")\n* [Any](#any \"Any\")\n\nAny custom, user-defined data type is derived from one of the base types (although it may also combine additional types for sub-elements). Thus, there are two valid ways of creating your own types.\n\nThe first method is to add the type directly to the Type Registry. This makes the new type explicitly available as a base Type.\n\n```javascript\nvar IntDef = _.extends({}, Number, function () {\n\n    // Constructor\n    return this.integer();\n});\n\nTypes.set(\"Int\", IntDef);\nvar Int = Types.Int;\n```\n\nThe second, simpler, and more acceptable method is to alias the new Type within the config file.\n\n```javascript\nvar PositiveInt = Number().integer().min(0)\nPositiveInt.max(999999);\n```\n\nThus, subsequent calls to the new \"type\" will behave as fully registered types in much less code.\n\n*Note: The first method may eventually be deprecated. Then, the Type Registry becomes non-mutable which simplies the logic significantly.*\n\n*Note: See \"Reference A\" before suggesting a pre-included Type for the Type Registry.*\n\n\n## Constraints\n\nConstraints are functions that restrict the input value in some way.\n\nBy default, all without explicit constraints, Types are optional.\n\n### Implementation\n\n```javascript\nvar schema = {\n    username: Joi.types.String().min(6).max(30).allow('admin').deny('Administrator'),\n};\n```\n\nThe above example demonstrates that even though the username has a minimum length of 6, extra constraints can be appended that allow 'admin' to be used as a username. Likewise, even though 'Administrator' would be allowed by the other constraints, it is explicitly denied by the _'deny'_ constraint.\n\n### By Type\n\n#### BaseType\n\nAll types inherit the following builtin constraints:\n\n##### BaseType.required()\n\nSpecifies that the input may not be undefined (unspecified).\n\n##### BaseType.allow(value)\n\nSpecifies that the input may equal this value.  This is type specific, so you cannot allow a number on a string type and vice-versa.\n\nThis function is idempotent.\n\n*Note: This function does not verify that value is the correct type.*\n\n##### BaseType.deny(value)\n\nSpecifies that the input may NOT equal this value.\n\nThis function is idempotent.\n\n*Note: This function does not verify that value is the correct type.*\n\n##### Basetype.valid(a1[, a2, ...])\n\nSpecifies an arbitrary number of valid values for this input.\n\nIf no inputs are supplied, it returns an Error.\n\nIf one or more of inputs given do not match the basic type, an Error is raised.\n\n##### Basetype.invalid(a1[, a2, ...])\n\nSpecifies an arbitrary number of invalid values for this input.\n\nIf no inputs are supplied, it returns an Error.\n\nIf one or more of inputs given do not match the basic type, an Error is raised.\n\n##### BaseType.with(a1[, a2, ...])\n\nSpecifies an arbitrary number of inputs that must also be supplied (a1..an) with this input.\n\n*Note: This may or may not have aliases in the final version (.join, .with, .and... etc)*\n\n##### BaseType.without(a1[, a2, ...])\n\nSpecifies an arbitrary number of inputs that cannot exist alongside this input (logical XOR).\n\n*Note: This may or may not have aliases in the final version (.disjoin, .without, .xor... etc)*\n\n##### BaseType.nullOk()\n\nSpecifies that the value is allowed to be null.\n\n##### BaseType.rename(to[, options])\n\nSpecifies a key to rename the current parameter to.\n\nOptions take the form of an object with the follow default values:\n\n```javascript\n{\n    deleteOrig: false,\n    allowMult: false,\n    allowOverwrite: false\n}\n```\n\nThe option \"deleteOrig\" specifies whether or not to delete the original key of the param (effectively a permanent \"move\").\n\nThe option \"allowMult\" specifies whether or not multiple parameters can be renamed to a single key.\n\nThe option \"allowOverwrite\" specifies whether or not the rename function can overwrite existing keys.\n\n\n#### String\n\nStrings, by default, match JavaScript Strings. They are typically unbounded in length unless limited by interpreter. They are encoded in UTF-8 (this is true in Node.js at least). They may contain any allowable characters in the specified encoding.\n\nThe Type Registry's implementation of String also includes some builtin constraints:\n\n##### String.emptyOk()\n\nSpecifies that the input may be equal to '' (the empty string).\n\n##### String.min(n)\n\nSpecifies a minimum length for this input string, inclusive.\n\nIf n is not specified, it returns an Error.\n\nIf n is not a non-negative integer, it returns an Error.\n\n##### String.max(n)\n\nSpecifies a maximum length for this input string, inclusive.\n\nIf n is not specified, it returns an Error.\n\nIf n is not a positive integer, it returns an Error.\n\n##### String.alphanum()\n\nSpecifies that this input may only consist of alphanumeric characters.\n\n##### String.regex(pattern)\n\nSpecifies that this input matches the given RegExp pattern.\n\nIf pattern is not specified, it returns an Error.\n\nIf pattern is not a valid RegExp object, it returns an error.\n\n##### String.email()\n\nSpecifies that this input is a valid email string.\n\n##### String.date()\n\nSpecifies that this input is a valid Date string (locale string but also accepts unix timestamp in milliseconds).\n\n##### String.encoding(enc)\n\nSpecifies an explicit encoding for this input string.\n\n*Warning: This may or may not be included in the final version. A better solution may be to forcibly convert from the encoding specified by enc to utf-8. However, this is not always possible (i.e. UTF-16 converting to UTF-8 would truncate a lot of characters).*\n\n\n#### Number\n\n##### Number.integer()\n\nSpecifies that this input be a valid integer.\n\n##### Number.float()\n\nSpecifies that this input be a valid float or double.\n\n##### Number.min(n)\n\nSpecifies a minimum value for this input, inclusive.\n\nIf n is not specified, it returns an Error.\n\nIf n is not an integer, it returns an Error.\n\n##### Number.max(n)\n\nSpecifies a maximum value for this input, inclusive.\n\nIf n is not specified, it returns an Error.\n\nIf n is not an integer, it returns an Error.\n\n\n#### Boolean\n\nBoolean values accept a case-insensitive string parameter. If the value is \"true\", true is returned. Otherwise, false is returned.\n\n*Note: Boolean has no special methods other than those inherited from BaseType*\n\n\n#### Array\n\n**Note**\nArray values take the querystring form of\n```\n?cars=1&cars=2\n```\nand get converted to\n```\n{ cars: [ '1', '2' ] }\n```\nby the server.\n\n*Note: Array has no special methods other than those inherited from BaseType*\n\n\n##### Array.includes(n1, n2, ...)\n\nSpecifies allowed types for the array value to include. The values of n1, n2, ... are Type Registry constraints (usually of other types).\n\n##### Array.excludes(n1, n2, ...)\n\nSpecifies allowed types for the array value to exclude. The values of n1, n2, ... are Type Registry constraints (usually of other types).\n\n\n#### Object\n\n##### Object.allowOtherKeys()\n\nWill cause any unknown keys in the object being validated to not cause the object to be invalid.\n\n\n#### Function\n\nFunction types accept any value that is a function.\n\n*Note: Function has no special methods other than those inherited from BaseType*\n\n\n#### Any\n\nAccept any type of value where the value is not null.  By default the value must not be null but is allowed to be undefined.  To change this behavior use either the _'required'_ or _'nullOk'_ methods.\n\n*Note: Any has no special methods other than those inherited from BaseType*\n\n## Usage\n\n### Config Syntax\n\nIn Hapi's routes configuration array, the routes are listed as JavaScript objects. Route objects may include an optional \"query\" key, the value of which should be an object. This object should associate querystring input names to validation constraints.\n\n```javascript\nvar queryObj = {\n  input_name: constraints\n};\n```\n\nIn the above code example, \"input_name\" must conform to typical JavaScript object key constraints (no spaces, no quotes unless escaped and surrounded by quotes, etc).\n\nIn place of \"constraints\", there should be a combination of constraints. The combination of constraints must be formed starting from a valid base type. The base type may be followed by zero or more pre-defined constraint functions chained consecutively. These combinations can be pre-combined into \"alias\" variables that may also be followed by zero or more pre-defined constraint functions chained consecutively. An example is shown below:\n\n```javascript\nBase().constraint_one().constraint_two()...\n\nBaseAlias = Base().constraint()\nBaseAlias.constraint_one().constraint_two()...\n```\n\nConstraint functions may accept optional and arbitrary parameters.\n\nEvery call must have its own `Base()` prefix. This creates a new validation object. Otherwise, it will retain settings from any prior constraints.\n\n### Evaluation Order\n\n#### Overrides\n\nEach constraint is evaluated independantly and in order of chaining. In some cases, a subsequent constraint may override a prior constraint:\n\n```javascript\nString.required().optional() # This input will be considered optional\nString.required(false).required() # This input will be considered required\n```\n\nConstraints that can override modify the query validation state upon the function's evocation. The actual evaluation is performed at the end of the chain (or once the entire querystring validation is finished).\n\nThese constraint functions are special cases:\n* required/optional\n* with/without\n* rename\n\nRename is always performed at the end of the chain.\n\n\n###### With/Without\n\nBelow is an example of a schema that is likely to be used for defining a username/password constraint.  Notice that _'with'_ is used on the _'username'_ to indicate that _'password'_ is required to appear whenever _'username'_ exists.  Similarly, _'password'_ has a constraint indicating that the key _'access_token'_ must not exist when _'password'_ exists.\n\n```javascript\nusername: Joi.types.String().with('password'),\npassword: Joi.types.String().without('access_token')\n```\n\n#### Overrules\n\nYet, in another case, a prior constraint may overrule a subsequent constraint:\n\n```javascript\nTypes.String().max(5).max(10) # This input cannot be larger than 5 characters\nTypes.String().max(3).regex(/.{0,5}/) # This input cannot be larger than 3 characters\n```\n\nThis should apply to all other constraints that do not override.\n\n\n\n## Special Options\n\nJoi has special settings that will modify certain behaviors.\n\n### Global\n\n#### Skip Functions\n\nOn occasion, an object must be validated which contains functions as properties. To force Joi to ignore validation on such functions, use the `skipFunctions` option:\n\n    Joi.settings.skipFunctions = true;\n\n\n#### Save Conversions\n\nThrough the process of validation, some inputs will be converted to accommodate the various constraint functions. For example, if an input is of type Joi.Types.Number() but is defined as a string, the validator will convert to Number during validation. This does not persist and does not affect the original input.\n\nTo force Joi to save the conversion, use the `saveConversions` option:\n\n    Joi.settings.saveConversions = true;\n\n\n#### Skip Conversions\n\nBy default Joi tries to parse and convert object's values into correct type. You might want to disable this behaviour e.g. when you are validating program's internal objects instead of user input.\n\nTo force Joi to not convert object values, use the `skipConversions` option:\n\n    Joi.settings.skipConversions = true;\n\n\n#### Allow Extra Keys & Strip Extra Keys\n\nBy default Joi will throw an error on keys that are not specified in the configuration object.\n\nTo force Joi to not throw errors when it encounters an unknown key, use the `allowExtraKeys` option:\n\n    Joi.settings.allowExtraKeys = true;\n\nIf you'd like Joi to remove the unknown keys from the object, enable both the `stripExtraKeys` option and the `allowExtraKeys` option:\n\n    Joi.settings.allowExtraKeys = true;\n    Joi.settings.stripExtraKeys = true;\n\n### Local\n\nAll global options may be overridden by specifying the option directly on the schema object.\n\n#### Custom Messages\n\nJoi error messages can be updated and replaced with localized versions.  Use the `languagePath` option to specify a file path to a JSON file that contains error messages.  Each message supports a mustache style template with the following keys:\n\n - `{{key}}` - the schema property that fails validation\n - `{{value}}` - the invalid value assigned to the key\n - `{{validTypes}}` - an optional list of acceptable inputs\n\n```javascript\nvar S = Joi.Types.String();\nvar config = {\n  username: S().alphanum().min(3).max(30),\n  password: S().regex(/[a-zA-Z0-9]{3,30}/),\n  languagePath: Path.join(__dirname, 'languages', 'en-US.json')\n};\n\nJoi.validate({\n  username: 'ab',\n  password: '1'\n}, config);\n```\n\n\n### Type-Specific\n\n#### Short Circuit Breakout\n\nWhen validating an input for a specific type with lots of constraints, Joi will, by default, return error immediately upon the first error condition. In some rare cases, iterating through all of the constraint functions is actually ideal (to identify all the reasons why an input is invalid at once). To force Joi to evaluate all constraints, use the `shortCircuit` option:\n\n    var S = Joi.Types.String();\n    S.options.shortCircuit = false;\n    var schema = {\n      nickname: S().valid('Silly').min(2)\n    }\n    schema.nickname.validate('o', null, null, errors) // => populates errors with all failing constraints\n\n    // alternative way\n    var input = { amount: 2.5 };\n    var schema = { amount: T.Number().integer().min(3).max(5).noShortCircuit() };\n\n    Joi.validate(input, schema);\n\n\n#### Non-Exclusive Valid\n\nThe `.valid` constraint is currently exclusive - if the input is NOT one of the values passed to `.valid`, the validator returns false. In the event this is too strict, use the hidden `__allowOnly` option.\n\n    var S = Joi.Types.String();\n    S.__allowOnly = false;\n    var schema = {\n      username: S().valid('walmart')\n    }\n    schema.username.validate('test') // => this returns true\n\n\n\n## Security Considerations\n\nEncodings could potentially play a role in security - some strings in one encoding, when exec()'d in another encoding could execute malicious code. If this type of validation is enabled, it will likely provide little to no explicit protection for developers. Developers could unintentionally (and even worse, unknowingly) expose a significant security risk.\n\n## Examples\n\n### Validating username and password\n\n```javascript\nvar Joi = require('joi');\n\nvar schema = {\n    username: Joi.types.String().alphanum().min(3).max(30).required(),\n    password: Joi.types.String().regex(/[a-zA-Z0-9]{3,30}/).required(),\n};\n\nvar invalidObj = { username: 'roger' };\nvar validObj = { username: 'roger', password: 'pa55word' };\n\nvar err = Joi.validate(invalidObj, schema);\nif (err) throw err;\n\nvar err = Joi.validate(validObj, schema);\nif (err) throw err;\n```\n\nExecuting the above code outputs the following:\n```\nError: [ValidationError]: the value of `password` is not allowed to be undefined\n```\n\n### Validating a number\n\n```javascript\nvar Joi = require('joi');\n\nvar schema = {\n    num: Joi.types.Number().required()\n};\n\nvar obj = { num: '1' };\n\nvar err = Joi.validate(obj, schema);\nif (err) throw err;\nelse console.log('Success!');\n```\n\nExecuting the above code outputs the following:\n```\nSuccess!\n```\n\n## References\n### Reference A: Other Types\n\n#### \"null\"\n\nThe \"null\" variable is considered to be of type \"object\". An alias could easily be added for this type if necessary. However, for the purposes of querystring validation, this appears to be unnecessary.\n\n#### \"undefined\"\n\nUnlike null, undefined is its own type with its own special properties. For the purposes of querystring validation, any blank or indefinite inputs will appear as blank strings (\"\"). As far as I know, there is no way to force the undefined object into the querystring. Thus, unless otherwise proven, \"undefined\" will not be included in the Type Registry.\n","_attachments":{},"readmeFilename":"README.md","bugs":{"url":"https://github.com/AriaMinaei/joiful-experiments/issues"}}