{"id":19162745,"url":"https://github.com/centre-for-humanities-computing/validator","last_synced_at":"2026-02-10T19:36:36.531Z","repository":{"id":57101341,"uuid":"370625702","full_name":"centre-for-humanities-computing/validator","owner":"centre-for-humanities-computing","description":null,"archived":false,"fork":false,"pushed_at":"2025-05-26T13:42:50.000Z","size":210,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-27T04:22:07.114Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/centre-for-humanities-computing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-05-25T08:48:08.000Z","updated_at":"2025-05-26T13:42:53.000Z","dependencies_parsed_at":"2024-06-25T09:16:20.181Z","dependency_job_id":"c12f651c-12cd-4664-a9d7-8d5f47dcb72e","html_url":"https://github.com/centre-for-humanities-computing/validator","commit_stats":{"total_commits":107,"total_committers":2,"mean_commits":53.5,"dds":"0.42056074766355145","last_synced_commit":"2ffcf77a017acbcc61417dc977e8928199d7c84b"},"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/centre-for-humanities-computing/validator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centre-for-humanities-computing%2Fvalidator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centre-for-humanities-computing%2Fvalidator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centre-for-humanities-computing%2Fvalidator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centre-for-humanities-computing%2Fvalidator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/centre-for-humanities-computing","download_url":"https://codeload.github.com/centre-for-humanities-computing/validator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/centre-for-humanities-computing%2Fvalidator/sbom","scorecard":{"id":270986,"data":{"date":"2025-08-11","repo":{"name":"github.com/centre-for-humanities-computing/validator","commit":"3c8f6017b3104a15968e361def04685be3ba0cc6"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"1 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":3,"reason":"7 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-x574-m823-4x7w","Warn: Project is vulnerable to: GHSA-4r4m-qw57-chr8","Warn: Project is vulnerable to: GHSA-xcj6-pq6g-qj4x","Warn: Project is vulnerable to: GHSA-356w-63v5-8wf4","Warn: Project is vulnerable to: GHSA-859w-5945-r5v3","Warn: Project is vulnerable to: GHSA-9crc-q9x8-hgqq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T13:20:36.966Z","repository_id":57101341,"created_at":"2025-08-17T13:20:36.966Z","updated_at":"2025-08-17T13:20:36.966Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29313160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T17:48:59.043Z","status":"ssl_error","status_checked_at":"2026-02-10T17:45:37.240Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":[],"created_at":"2024-11-09T09:13:02.720Z","updated_at":"2026-02-10T19:36:36.504Z","avatar_url":"https://github.com/centre-for-humanities-computing.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Validator\n\nA fluent validator API for validating function arguments, form-data etc.\n\n## Installation\n\n```\nnpm install @chcaa/validator\n```\n\n## Getting Started\n\nImport the module and create a new `Validator` (see examples further down for different kinds of validators).\n\n```js\nimport { Validator } from '@chcaa/validator';\n\nlet test = Validator.createOnErrorThrowValidator();\n\nlet person = {\n    name: \"Peter\"\n};\ntest(person.name).fulfillAllOf(name =\u003e [\n    name.is.aString('\"name\" must be a string'),\n    name.is.equalTo('Peter', '\"name\" must be \"Peter\"')\n]);\n\n// or make a set of reusable rules\nlet ruleSet = Validator.createOnErrorNextPathRuleSet();\nruleSet.addRule('name', (name) =\u003e name.fulfillAllOf(name =\u003e [\n    name.is.aString('\"name\" must be a string'),\n    name.is.equalTo('Peter', '\"name\" must be \"Peter\"')\n]));\n\nlet validationResult = ruleSet.validate(person);\nconsole.log(validationResult.getAllErrors());\n```\n\nSee also the JsDoc for each method for further examples.\n\n## Test Function Arguments\n\nIf an argument does not meet the requirements, we want to throw a `ValidationError` so we\ncreate a `Validator` which throws an error when a test fails.\n\n```js\nfunction add(x, y) {\n    let test = Validator.createOnErrorThrowValidator('Argument error for add');\n    test(x).is.aNumber('x must be a number but was ${VALUE}');\n    test(y).is.aNumber('y must be a number but was ${VALUE}');\n}\n```\n\n## Test Form Data and Objects\n\nWhen testing form data, we would like to be able to gather information and show it to the user. We can then\ncreate a `Validator` which just breaks if a test fails instead of throwing an Error. To keep\nthe error messages separated in the `ValidationResult`, we supply an `errorPrefixPath` as the second argument to `test`.\n\n````js\nfunction validateUserForm(username, age) {\n    let test = Validator.createOnErrorBreakValidator();\n    test(username, 'username').fulfillAllOf(username =\u003e [\n        username.is.aString('Username must be a string'),\n        username.does.match(/\\w{4, 25}/, \"Username must only contain a-zA-Z0-9_ and have a length of 4-25 characters\")\n    ]);\n    test(age, 'age').fulfillAllOf(age =\u003e [\n        age.is.anInteger('Age must be an integer'),\n        age.is.inRange(0, 120, 'Age must be in range 0 - 120')\n    ]);\n    // show the errors to the user\n    let validationResult = Validator.validationResult(test);\n    if (!validationResult.isValid()) {\n        console.log(validationResult.getAllErrors());\n        // or\n        console.log(validationResult.getError('username'));\n        console.log(validationResult.getError('age'));\n    }\n}\n````\n\nThe data from above could also be validated as an object instead of individual values, we then make use of\na `Validator` in `ON_ERROR_NEXT_PATH` mode to move on to the next path when a test fails, so we can gather\ninformation about all paths. If we only wanted the error message for the first path which failed, we\ncould use an `ON_ERROR_BREAK` `Validator`.\n\n```js\nfunction validateUserForm(user) {\n    let test = Validator.createOnErrorNextPathValidator();\n    test(user).fulfillAllOf(user =\u003e [\n        user.prop('username').fulfillAllOf(username =\u003e [\n            username.is.aString('Username must be a string'),\n            username.does.match(/\\w{4, 25}/, \"Username must only contain a-zA-Z0-9_ and have a length of 4-25 characters\")\n        ]),\n        user.prop('age').fulfillAllOf(age =\u003e [\n            age.is.anInteger('Age must be an integer'),\n            age.is.inRange(0, 120, 'Age must be in range 0 - 120')\n        ])\n    ]);\n    // show the errors to the user\n    let validationResult = Validator.validationResult(test);\n    if (!validationResult.isValid()) {\n        console.log(validationResult.getAllErrors());\n        // or\n        console.log(result.getError('username'));\n        console.log(result.getError('age'));\n        //\n        for (let path of validationResult.errorPaths()) {\n            console.log(validationResult.getError(path));\n        }\n    }\n}\n```\n\n## Reusing Rules\n\nRules can be stored and reused using a `RuleSet`.\n\nFor objects, a single set of rules for a whole object can be applied using `Validator#prop()` to access\neach property, as the examples above, but it is more performant and sometimes easier to read\nif rules are divided by each property and added separately.\n\n```js\nlet ruleSet = Validator.createOnErrorBreakRuleSet();\nruleSet.addRule('username', username =\u003e username.fulfillAllOf(username =\u003e [\n    username.is.aString('Username must be a string'),\n    username.does.match(/\\w{4, 25}/, \"Username must only contain a-zA-Z0-9_ and have a length of 4-25 characters\")\n]));\nruleSet.addRule('age', (age) =\u003e age.fulfillAllOf(age =\u003e [\n    age.is.anInteger('Age must be an integer'),\n    age.is.inRange(0, 120, 'Age must be in range 0 - 120')\n]));\n\nlet user = {\n    username: 'johndoe',\n    age: 45\n}\n\n// simple test if a user is valid\nif (ruleSet.isValid(user)) {\n    // do something useful here\n}\n\n// or get detailed validation results\nlet validationResult = ruleSet.validate(user);\nconsole.log(validationResult.getAllErrors()); // all erros\nconsole.log(validationResult.getError('age')); // first error\nconsole.log(validationResult.getErrors('age')); // all errors for path\n\n// we can also test individual paths \nif (ruleSet.isValid(user, 'age')) {\n    // do something\n}\n// or validate and get a result only for a single path\nvalidationResult = ruleSet.validate(user, 'age');\n\n// values can also be validated directly against paths\nlet ageIsValid = ruleSet.isValueValid(23, 'age');\nvalidationResult = ruleSet.validateValue(23, 'age');\n```\n\n### Supplying Values not Known at the Time of Rule Creation\n\nWhen creating rules for reuse, some values may not be known at the time the rule is created because they are unknown or change\nregularly. Or we could want to create a generic set of rules which can be used in different contexts.\n\"Context\" values can be passed-in to a rule at validation time and referenced by the rule by adding a second\nparameter to the rule function as shown in the below example.\n\n```js\nlet ruleSet = Validator.createOnErrorBreakRuleSet();\nruleSet.addRule('username', (username, reservedUsernames) =\u003e username.fulfillAllOf(username =\u003e [\n    username.is.aString('Username must be a string'),\n    username.does.match(/\\w{4, 25}/, \"Username must only contain a-zA-Z0-9_ and have a length of 4-25 characters\"),\n    username.isNot.in(reservedUsernames, '${VALUE} is a reserved username')\n]));\n\nlet reservedUsernames = await fetchReservedUsernames(); // fetch reserved usernamed from some server\n\nlet user = {\n    username: 'admin'\n}\n\nruleSet.validate(user, 'username', reservedUsernames); // we pass in the \"context\" arg as the third object to validate\n// if we want to validate all paths for an object and need to supply a context argument, we need to pass in \"undefined\"\n// for the \"path\" parameter. (in this case both examples gives the same result as we only have a rule for \"username\")\nruleSet.validate(user, undefined, reservedUsernames);\n```\n\n## Error Messages\n\nError messages can be supplied for the individual test and as combined messages for `fulfill()`, `fulfillAllOf()`, `fulfillOneOf()` and `each()`.\n\nIndividual messages are supplied as an argument to the test:\n\n```js\nlet test = Validator.createOnErrorBreakValidator();\ntest('Peter').is.equalTo('Peter', `\"Peter\" must be equal to \"Peter\"`);\n```\n\nCombined messages is supplied as a second argument to e.g. `fulfillAllOf()`:\n\n```js\nlet test = Validator.createOnErrorBreakValidator();\ntest('Peter').fulfillAllOf(peter =\u003e [\n    peter.is.aString(),\n    peter.is.equalTo('Peter')\n], '\"Peter\" must be a string and be equal to \"Peter\"');\n```\n\nWhen using combined messages, it is important **not** to add individual messages as well as these will overrule the combined message.\n\nAll error messages for the same `Validator` can have the same prefix which can be provided when creating the `Validator`.\n\n```js\nlet test = Validator.createOnErrorBreakValidator('Name error');\ntest('Peter').fulfillAllOf(peter =\u003e [\n    peter.is.aString('must be a string'),\n    peter.is.equalTo('Peter', 'must equal \"Peter\"')\n]);\n```\n\n### Arguments\n\nArguments for error messages can be passed in as a single value (if only one is needed) or as an array of values and be\nreferenced by their index number.\n\n`string`, `number`, and `array` or `Set` of `string` and `number` is\nallowed. An `array` and `Set` of values will be inserted in `JSON` format e.g. `[\"string\", 3, 4, \"string2\"]`.\nWhen passing an `array` of values it must always be passed in a surrounding `array`, even if only a single\nargument is needed, to be able to distinguish between an `array` of arguments and an `array` of values.\n\n```js\nlet person = { name: \"Peter\", age: 41 };\nlet test = Validator.createOnErrorNextPathValidator('Person error');\ntest(person).prop('age').is.inRange(18, 99, 'The age must be in range ${0} - ${1}', [18, 99]);\n```\n\n### Context Placeholders\n\nThe different paths and values in the current validation context can be referenced in the error messages using the following\nplaceholders:\n\n- `${VALUE}` - The value currently being tested.\n- `${PATH}` - The full path of the current value under test, including `errorPrefixPath` and `errorContextPaths` if supplied.\n- `${PATHx}` - The full path at index `x` of the current value under test when multiple `errorContextPaths` is supplied using `Validator#errorContext()`.\n- `${CURRENT_PATH}` - The path for the current value under test.\n- `${PARENT_PATH}` - The full parent path of `${CURRENT_PATH}`.\n\n```js\nlet person = { name: \"Peter\", age: 41 };\nlet test = Validator.createOnErrorNextPathValidator('Person error');\ntest(person).fulfillAllOf(person =\u003e [\n    person.prop('name').fulfillAllOf(name =\u003e [\n        name.is.aString('${PATH} must be a string but was ${VALUE}'),\n        name.prop('length').is.inRange(4, 25, 'The ${CURRENT_PATH} of ${PARENT_PATH} must be 4 - 25 but was ${VALUE}')\n    ])\n]);\n\n// test individual values and use the `errorPrefixPath` to get the same result as above\ntest(person.name, 'name').fulfillAllOf(name =\u003e [\n    name.is.aString('${PATH} must be a string but was ${VALUE}'),\n    name.prop('length').is.inRange(4, 25, 'The ${CURRENT_PATH} of ${PARENT_PATH} must be 4 - 25 but was ${VALUE}')\n]);\n\n// test values together and add the error for both paths if the test fails\ntest(person).errorContext('name', 'age').fulfillOneOf(person =\u003e [\n    person.prop('name').isNot.nil(),\n    person.prop('age').isNot.nil()\n], 'At least one of ${PATH0} or ${PATH1} must have a value');\n// if the test fails both path will have the error\nlet validationResult = Validator.validationResult(test);\nconsole.log(validationResult.getErrors('name'));\nconsole.log(validationResult.getErrors('age'));\n\n```\n\n## Debugging\n\nDebug messages can be toggled on and off by calling `Validator.debug(true|false)`.\n\n## Validator Factory and Static Methods\n\n- `Validator.create(errorPrefix, mode): testFunction` - Creates a new validator with the given mode.\n  The returned \"test\" function gives access to the verb context, which returns the predicate used for performing the actual tests.\n- `Validator.createOnErrorThrowValidator(errorPrefix): testFunction` - Creates a new validator which throws an `ValidationError` if a test fails.\n- `Validator.createOnErrorBreakValidator(errorPrefix): testFunction` - Creates a new validator which breaks if a test fails.\n- `Validator.createOnErrorNextPathValidator(errorPrefix): testFunction` - Creates a new validator which moves on to the next path if a test fails.\n- `Validator.createRuleSet(errorPrefix): RuleSet` - Creates a `RuleSet` with the given mode.\n- `Validator.createOnErrorThrowRuleSet(errorPrefix): RuleSet` - Creates a new `RuleSet` which throws an `ValidationError` if a test fails.\n- `Validator.createOnErrorBreakRuleSet(errorPrefix): RuleSet` - Creates a new `RuleSet` which breaks if a test fails.\n- `Validator.createOnErrorNextPathRuleSet(errorPrefix): RuleSet` - Creates a new `RuleSet` which moves on to the next path if a test fails.\n- `Validator.validationResult(testFunction)` - Get the `ValidationResult` of the test function.\n- `Validator.debug(true|false)` - enable / disable debugging messages.\n\n## Validator Overview\n\n- `does: ValidatorContext`\n- `doesNot: ValidatorContext`\n- `is: ValidatorContext`\n- `isNot: ValidatorContext`\n- `optional: Validator` - Only validate the following predicates if the current value is *not* `nil` (`null` or `undefined`).\n- `optionalNull: Validator` - Only validate the following predicates if the current value is *not* `null`.\n- `optionalUndefined: Validator` - Only validate the following predicates if the current value is *not* `undefined`.\n- `value: *` - The actual value for this context.\n- `conditionally(predicate(validator)): Validator` - Only validate the following tests if the passed in predicate is fulfilled.\n- `each(predicate, [errorMessage, [messageArgs]]): boolean` - Validate each element in the `iterable` against the predicate.\n- `transform(tranformer): Validator` - Transform the current value into something else, e.g., making a `string` lowercase.\n- `prop(path): Validator` - Get a `Validator` for the `path` relative to the current context value (typically an object).\n- `errorContext(...contextPath)` - Rewrite the error context for the current validator context making it possible to change which path(s) should fail on error.\n- `fulfill(predicate): ValidatorContext` - Alias for `does.fulfill()`.\n- `fulfillOneOf(predicates): ValidatorContext` - Alias for `does.fulfillOneOf()`.\n- `fulfillAllOf(predicates): ValidatorContext` - Alias for `does.fulfillAllOf()`.\n\n## ValidatorContext Overview\n\nAll methods take an optional `errorMessage` and `messageArgs` as the last two arguments, and all methods\nreturn a `boolean`.\n\n- `anArray()`\n- `aBoolean()`\n- `aFloatString()`\n- `aFunction()`\n- `anInteger()`\n- `anIntegerString()`\n- `aNumber()`\n- `anObject()`\n- `aString()`\n- `empty()`\n- `endWith(endStr)`\n- `equalTo(otherValue)`\n- `fulfill(predicate)`\n- `fulfillAllOf(predicates)`\n- `fulfillOneOf(predicates)`\n- `greaterThan(value)`\n- `greaterThanOrEqualTo(value)`\n- `identicalTo(otherValue)`\n- `in(values)`\n- `inRange(start, end)`\n- `lessThan(value)`\n- `lessThanOrEqualTo(value)`\n- `match(regex)`\n- `nil()`\n- `startWith(startStr)`\n\n## RuleSet Overview\n\n- `addRule(path, rule): RuleSet` - Add a rule for the given path to the `RuleSet` in the form of a function which will be called when rule is tested.\n- `isValid(object, [path]): boolean` - Test if the property paths of the object are valid. The path or paths to test can be optionally passed in as the second\n  argument.\n- `isValueValid(value, [path]): boolean` - Test if the value is valid. The path or paths to test can be optionally passed in as the second argument.\n- `validate(object, [[path, [isObject]]): ValidationResult` - Validate the object which, depending on the mode of the `RuleSet`, will produce\n  a `ValidationResult` with errors or throw an `ValidationError` if the object is not valid.\n- `validateValue(value, [path]): ValidationResult` - Validate the value which depending on the mode of the `RuleSet` will produce a `ValidationResult` with\n  errors or throw an `ValidationError`if the object is not valid.\n\n## ValidationResult Overview\n\n- `getError(path): string` - Get the first error for the given path.\n- `getErrors(path): string[]` - Get all errors for the given path.\n- `getAllErrors(): string[]` - Get all errors.\n- `errorPaths(): Iterable\u003cstring\u003e` - The paths with errors.\n- `isValid(): boolean` - `true` of there is no errors otherwise `false`.\n- `isPathValid(path): boolean` - `true` if the given path is valid otherwise `false`.\n- `reset()` - Reset the validation result. (Not relevant in the context of a RuleSet as this always creates a new instance for every test).\n\n## Stack Traces\nNode.js has a default stack trace limit set to [10 frames](https://v8.dev/docs/stack-trace-api). This can cause problems \nwhen validating a set of deeply nested rules as validator functions such as `fulfill()`, `fulfillAllOf()` etc. creates a new stack frame\nevery time they are called.\n\nIf it is not obvious to tell by the stack trace where the validation started this is typically a symptom of some frames \nin the stack trace are missing. This can be corrected by setting `Error.stackTraceLimit = Infinity` at the start of the application.\n\n\n[//]: # (TODO Add section for Predicate function)\n\n[//]: # (TODO Add section for Transform function)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcentre-for-humanities-computing%2Fvalidator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcentre-for-humanities-computing%2Fvalidator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcentre-for-humanities-computing%2Fvalidator/lists"}