Remove node_modules from repository

main
Sven Slootweg 3 months ago
parent 146afeaa64
commit 4b51b49cd5

1
.gitignore vendored

@ -0,0 +1 @@
node_modules

107
node_modules/.modules.yaml generated vendored

@ -1,107 +0,0 @@
hoistPattern:
- '*'
hoistedDependencies:
/@validatem/annotate-errors/0.1.2:
'@validatem/annotate-errors': private
/@validatem/any-property/0.1.3:
'@validatem/any-property': private
/@validatem/combinator/0.1.2:
'@validatem/combinator': private
/@validatem/has-shape/0.1.8:
'@validatem/has-shape': private
/@validatem/is-plain-object/0.1.1:
'@validatem/is-plain-object': private
/@validatem/is-string/0.1.1:
'@validatem/is-string': private
/@validatem/match-special/0.1.0:
'@validatem/match-special': private
/@validatem/match-validation-error/0.1.0:
'@validatem/match-validation-error': private
/@validatem/match-versioned-special/0.1.1:
'@validatem/match-versioned-special': private
/@validatem/match-virtual-property/0.1.0:
'@validatem/match-virtual-property': private
/@validatem/normalize-rules/0.1.3:
'@validatem/normalize-rules': private
/@validatem/validation-result/0.1.2:
'@validatem/validation-result': private
/@validatem/virtual-property/0.1.0:
'@validatem/virtual-property': private
/array-union/2.1.0:
array-union: private
/as-expression/1.0.0:
as-expression: private
/assure-array/1.0.0:
assure-array: private
/call-bind/1.0.7:
call-bind: private
/clone-regexp/2.2.0:
clone-regexp: private
/create-error/0.3.1:
create-error: private
/default-value/1.0.0:
default-value: private
/define-data-property/1.1.4:
define-data-property: private
/es-define-property/1.0.0:
es-define-property: private
/es-errors/1.3.0:
es-errors: private
/es6-promise-try/0.0.1:
es6-promise-try: private
/execall/2.0.0:
execall: private
/flatten/1.0.3:
flatten: private
/function-bind/1.1.2:
function-bind: private
/get-intrinsic/1.2.4:
get-intrinsic: private
/gopd/1.0.1:
gopd: private
/has-flag/4.0.0:
has-flag: private
/has-property-descriptors/1.0.2:
has-property-descriptors: private
/has-proto/1.0.3:
has-proto: private
/has-symbols/1.0.3:
has-symbols: private
/has-tostringtag/1.0.2:
has-tostringtag: private
/hasown/2.0.2:
hasown: private
/indent-string/4.0.0:
indent-string: private
/is-arguments/1.1.1:
is-arguments: private
/is-plain-obj/2.1.0:
is-plain-obj: private
/is-regexp/2.1.0:
is-regexp: private
/is-string/1.0.7:
is-string: private
/set-function-length/1.2.2:
set-function-length: private
/supports-color/7.2.0:
supports-color: private
/syncpipe/1.0.0:
syncpipe: private
included:
dependencies: true
devDependencies: true
optionalDependencies: true
injectedDeps: {}
layoutVersion: 5
nodeLinker: isolated
packageManager: pnpm@8.14.1
pendingBuilds: []
prunedAt: Tue, 18 Jun 2024 22:21:43 GMT
publicHoistPattern:
- '*eslint*'
- '*prettier*'
registries:
default: https://registry.npmjs.org/
skipped: []
storeDir: /home/sven/.local/share/pnpm/store/v3
virtualStoreDir: .pnpm

@ -1,5 +0,0 @@
# @validatem/annotate-errors
Documentation for this module has not been written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,30 +0,0 @@
"use strict";
const annotateErrors = require("./");
const ValidationError = require("@validatem/error");
let errors = [
new ValidationError("Error A"),
new ValidationError("Error B", { path: [ "somewhere" ] }),
];
annotateErrors({
errors: errors,
pathSegments: ["some", "path"]
});
console.log(errors);
/*
[ { ValidationError: Error A
<stacktrace>
path: [ 'some', 'path' ],
___validatem_isValidationError: true,
___validatem_errorVersion: 1,
message: 'Error A' },
{ ValidationError: Error B
<stacktrace>
path: [ 'some', 'path', 'somewhere' ],
___validatem_isValidationError: true,
___validatem_errorVersion: 1,
message: 'Error B' } ]
*/

@ -1,25 +0,0 @@
"use strict";
const matchValidationError = require("@validatem/match-validation-error");
module.exports = function annotateErrors(options) {
if (options.pathSegments == null) {
throw new Error(`'pathSegments' is a required option`);
} else if (!Array.isArray(options.pathSegments)) {
throw new Error(`'pathSegments' must be an array`);
} else if (options.errors == null) {
throw new Error(`'errors' is a required option`);
} else if (!Array.isArray(options.errors)) {
throw new Error(`'errors' must be an array`);
} else {
// NOTE: We mutate the error here, because Error objects are not safely cloneable
for (let error of options.errors) {
// Leave non-ValidationError errors alone, even though they should not be present
if (matchValidationError(error)) {
error.path = options.pathSegments.concat(error.path);
}
}
return options.errors;
}
};

@ -1,15 +0,0 @@
{
"name": "@validatem/annotate-errors",
"description": "Utility for annotating one or more ValidationErrors with the path at which they occurred",
"version": "0.1.2",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/annotate-errors.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/match-validation-error": "^0.1.0"
},
"devDependencies": {
"@validatem/error": "^1.0.0"
}
}

@ -1 +0,0 @@
../../../@validatem+match-validation-error@0.1.0/node_modules/@validatem/match-validation-error

@ -1 +0,0 @@
../../../@validatem+annotate-errors@0.1.2/node_modules/@validatem/annotate-errors

@ -1,5 +0,0 @@
# @validatem/array-of
Documentation for this module has not been fully written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,38 +0,0 @@
"use strict";
const anyProperty = require("./");
const { validateValue } = require("@validatem/core");
const isString = require("@validatem/is-string");
let validator = anyProperty({
key: [ isString ],
value: [ isString ]
});
let objectA = {
foo: "bar",
baz: "qux"
};
console.log(validateValue(objectA, validator)); // { foo: 'bar', baz: 'qux' }
let objectB = {
foo: "bar",
baz: 42
};
console.log(validateValue(objectB, validator)); /*
AggregrateValidationError: One or more validation errors occurred:
- At baz -> (value): Must be a string
*/
let SomeSymbol = Symbol("SomeSymbol");
let objectC = {
foo: "bar",
[SomeSymbol]: "qux"
};
console.log(validateValue(objectC, validator)); /*
AggregrateValidationError: One or more validation errors occurred:
- At Symbol(SomeSymbol) -> (key): Must be a string
*/

@ -1,58 +0,0 @@
"use strict";
const defaultValue = require("default-value");
const ValidationError = require("@validatem/error");
const combinator = require("@validatem/combinator");
const annotateErrors = require("@validatem/annotate-errors");
const virtualProperty = require("@validatem/virtual-property");
const validationResult = require("@validatem/validation-result");
module.exports = function (rules) {
if (rules.key == null && rules.value == null) {
throw new Error(`Must specify either a 'key' or 'value' property in the ruleset`);
} else {
let keyRules = defaultValue(rules.key, []);
let valueRules = defaultValue(rules.value, []);
let validator = combinator((object, applyValidators) => {
let newObject = {};
let allErrors = [];
if (typeof object !== "object" || Array.isArray(object)) {
throw new ValidationError("Must be an object");
} else {
// NOTE: Reflect.ownEntries is used here to ensure we capture the Symbol-typed keys as well
for (let key of Reflect.ownKeys(object)) {
let value = object[key];
let keyAsString = key.toString(); // Again, to deal with Symbol-typed keys.
let { errors: keyErrors, newValue: newKey } = applyValidators(key, keyRules);
let { errors: valueErrors, newValue } = applyValidators(value, valueRules);
let annotatedKeyErrors = annotateErrors({
pathSegments: [ keyAsString, virtualProperty("key") ],
errors: keyErrors
});
let annotatedValueErrors = annotateErrors({
pathSegments: [ keyAsString, virtualProperty("value") ],
errors: valueErrors
});
newObject[newKey] = newValue;
allErrors.push(...annotatedKeyErrors, ...annotatedValueErrors);
}
return validationResult({
errors: allErrors,
newValue: newObject
});
}
});
validator.callIfNull = false;
return validator;
}
};

@ -1,26 +0,0 @@
{
"name": "@validatem/any-property",
"description": "Validatem combinator for validating both the keys and values of a mapping object",
"keywords": [
"validatem",
"validator",
"combinator"
],
"version": "0.1.3",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/any-property.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/annotate-errors": "^0.1.2",
"@validatem/combinator": "^0.1.0",
"@validatem/error": "^1.0.0",
"@validatem/validation-result": "^0.1.1",
"@validatem/virtual-property": "^0.1.0",
"default-value": "^1.0.0"
},
"devDependencies": {
"@validatem/core": "^0.3.1",
"@validatem/is-string": "^0.1.0"
}
}

@ -1 +0,0 @@
../../../@validatem+combinator@0.1.2/node_modules/@validatem/combinator

@ -1 +0,0 @@
../../../@validatem+error@1.1.0/node_modules/@validatem/error

@ -1 +0,0 @@
../../../@validatem+validation-result@0.1.2/node_modules/@validatem/validation-result

@ -1 +0,0 @@
../../../@validatem+virtual-property@0.1.0/node_modules/@validatem/virtual-property

@ -1 +0,0 @@
../../default-value@1.0.0/node_modules/default-value

@ -1,21 +0,0 @@
# @validatem/combinator
Documentation for this module has not been fully written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.
A partial draft for the future documentation is below:
----
Used for specifying Validatem 'combinators', ie. validators that need to manually control what rules to apply to what (sub-)values. Typically used for validating data structures which have multiple internal values to validate, like in the [`arrayOf(...)`](https://www.npmjs.com/package/@validatem/array-of) combinator, or when validation should be conditional, like in the [`when(...)`](https://www.npmjs.com/package/@validatem/when) and [`either(...)`](https://www.npmjs.com/package/@validatem/either) combinators.
Note that this package doesn't actually really *do* anything. It just produces a special versioned object type, that's recognized (and handled accordingly) by the Validatem core; which will 'inject' the `applyValidators` function into your combinator, which you can use to apply a set of validation rules to a value.
This slightly odd dependency-injection design exists because `applyValidators` is tightly interwoven with the rest of the Validatem core, and it's not really possible to extract it out into a separate package without basically moving all of the core into it, defeating the point of packaging this separately.
## Why is this a separate package?
One of the design goals of Validatem is to minimize how much complexity and code you're adding to your project. Because of that, all of the plumbing used by validators and combinators is packaged as granularly as possible. This prevents the situation where you have 20 copies of the entire Validatem core floating around in your project, just because different validators happen to depend on slightly different versions.
By having several small 'plumbing' packages, validators *never* need to depend on `@validatem/core`, but only on the specific bits of plumbing that they need.

@ -1,17 +0,0 @@
"use strict";
const combinator = require("./");
const { validateValue } = require("@validatem/core");
const isString = require("@validatem/is-string");
function createPassthroughCombinator(rules) {
// This is a dummy combinator that just applies the rules to the value (with the given context) as-normal. You could add any custom logic in here on when/how to apply validators, how to interpret the input rules/arguments of the factory function (if any), how to post-process the errors, and so on. You may want to look at some real combinators (`has-shape`, `array-of`, `dynamic`, `when`, etc.) to see some more realistic examples of how to effectively use this API.
return combinator((value, applyValidators, context) => {
return applyValidators(value, rules, context);
});
};
let result = validateValue("fourty-two", createPassthroughCombinator([ isString ]));
console.log(result); // fourty-two

@ -1,13 +0,0 @@
"use strict";
module.exports = function defineCombinator(callback) {
return {
callback: callback,
callIfNull: true,
___validatem_isSpecial: true,
___validatem_isCombinator: true,
___validatem_combinatorVersion: 1
};
};
module.exports.__modulePath = __dirname;

@ -1,13 +0,0 @@
{
"name": "@validatem/combinator",
"description": "API for defining Validatem combinators",
"version": "0.1.2",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/combinator.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"devDependencies": {
"@validatem/core": "^0.3.1",
"@validatem/is-string": "^0.1.0"
}
}

@ -1 +0,0 @@
../../../@validatem+annotate-errors@0.1.2/node_modules/@validatem/annotate-errors

@ -1 +0,0 @@
../../../@validatem+any-property@0.1.3/node_modules/@validatem/any-property

@ -1,3 +0,0 @@
{
"extends": "@joepie91/eslint-config"
}

@ -1,92 +0,0 @@
# @validatem/core
![Validatem logo](https://validatem.cryto.net/validatem-logo.svg)
The last validation library you'll ever need.
* Does __every kind of validation__, and does it well: it doesn't matter whether you're validating function arguments, form data, JSON request bodies, configuration files, or whatever else. As long as it's structured data of some sort, Validatem can deal with it.
* Supports the notion of __virtual properties__ in validation errors, which means that even if your data *isn't* already structured data (eg. an encoded string of some sort), you can bring your own parser, and have it integrate cleanly.
* __Easy to read__; both the code that *uses* Validatem, and the validation error messages that it produces! Your validation code doubles as in-code format documentation, and users get clear feedback about what's wrong.
* Fully __composable__: it's trivial to use third-party validators, or to write your own (reusable!) validators, whether fully custom or made up of a few other validators chained together.
* Supports __value transformation__, which means that you can even encode things like "this value defaults to X" or "when this value is a number, it will be wrapped like so" in your validation code; this can save you a bunch of boilerplate, and makes your validation code *even more complete* as format documentation.
* Validatem has a __small and modular core__, and combined with its composability, this means you won't pull any more code into your project than is strictly necessary to make your validators work! This is also an important part of making Validatem suitable for use in libraries, eg. for argument validation.
* Many __off-the-shelf validators__ are already available! You can find the full list [here](https://validatem.cryto.net/modules).
* Extensively __documented__, with clear documentation on what is considered valid, and what is not. Likewise, the plumbing libraries that you can use to write your own validators and combinators, are also well-documented.
While Validatem is suitable for any sort of validation, this unique combination of features and design choices makes it *especially* useful for validating arguments in the public API of libraries, unlike other validation libraries!
For example, you might write something like the following (from the [`icssify` library](https://git.cryto.net/joepie91/icssify/src/master/index.js)):
```js
module.exports = function (browserify, options) {
validateArguments(arguments, [
[ "browserify", required ],
[ "options", allowExtraProperties({
mode: oneOf([ "local", "global" ]),
before: arrayOf([ required, isPostcssPlugin ]),
after: arrayOf([ required, isPostcssPlugin ]),
extensions: arrayOf([ required, isString ])
})]
]);
// Implementation code goes here ...
};
```
And calling it like so:
```js
icssify(undefined, {
mode: "nonExistentMode",
before: [ NaN ],
unspecifiedButAllowedOption: true
})
```
... would then produce an error like this:
```
ValidationError: One or more validation errors occurred:
- At browserify: Required value is missing
- At options -> mode: Must be one of: 'local', 'global'
- At options -> before -> 0: Must be a PostCSS plugin
```
## Still under construction!
I'm currently preparing Validatem for its 1.0.0 release. Until then, documentation will be missing in many places (though an example.js is usually included in each module!), the website probably won't work yet, and some bits of the API might still change.
In principle, Validatem is reliable enough already to use in real-world code - I use it in various of my own libraries and other projects. But be aware that you may need to change your code when 1.0.0 hits!
## Getting stuck?
__If you've read the documentation and you're still not quite sure how to solve your problem, please ask your question on the issue tracker!__
Usage questions are often documentation or usability bug reports in disguise. By asking your question on the issue tracker, you help us improve the documentation - so that the next person with your question doesn't need to ask!
## Why not just use Typescript?
Because it's strict in all the wrong places. It will yell at your perfectly valid abstraction just because you haven't figured out the magic incantation to make the compiler *believe* that it is valid, and at the same time it's incapable of doing business logic validation such as "is this a valid URL?" - *by design*.
Real-world validation is about more than just whether something is a string or a number. Validatem can deal with this; Typescript cannot.
## Why are there so many packages?
Dependencies often introduce a lot of unnecessary complexity into a project. To avoid that problem, I've designed Validatem to consist of a lot of small, separately-usable pieces - even much of the core plumbing has been split up that way, specifically the bits that may be used by validator and combinator functions.
This may sound counterintuitive; doesn't more dependencies mean *more* complexity? But in practice, "a dependency" in and of itself doesn't have a complexity cost at all; it's the code that is *in* the dependency where the complexity lies. The bigger a dependency is, the more complexity there is in that dependency, and the bigger the chance that some part of that complexity isn't even being used in your project!
By packaging things as granularly as possible, you end up only importing code into your project *that you are actually using*. Any bit of logic that's never used, is somewhere in a package that is never even installed. As an example: using 10 modules with 1 function each, will add less complexity to your project than using 1 module with 100 functions.
This has a lot of benefits, for both you and me:
- __Easier to audit/review:__ When only the code you're actually using is added to your project, there will be less code for you to review. And because each piece is designed to be [loosely coupled](https://gist.github.com/joepie91/7f03a733a3a72d2396d6#coupled) and extensively documented, you can review each (tiny) piece in isolation; without having to trawl through mountains of source code to figure out how it's being called and what assumptions are being made there.
- __Easier to version and maintain:__ Most of the modules for Validatem will be completely done and feature-complete the moment they are written, never needing any updates at all. When occasionally a module *does* need an update, it will almost certainly not be one that breaks the API, because the API for each module is so simple that there isn't much *to* break.
- __Easier to upgrade:__ Because of almost nothing ever breaking the API, it also means that you'll rarely need to manually upgrade anything, if ever! The vast majority of module updates can be automatically applied, even many years into the future, *even* if a new (breaking) version of `validatem/@core` is ever released down the line.
- __Easier to fork:__ If for any reason you want to fork any part of Validatem, you can do so easily - *without* also having to maintain a big pile of validators, combinators, internals, and so on. You only need to fork and maintain the bit where you want to deviate from the official releases.
Of course, there being so many packages means it can be more difficult to find the specific package you want. That is why [the Validatem website has an extensive, categorized list](https://validatem.cryto.net/modules) of all the validators, combinators and utilities available for Validatem. Both officially-maintained ones, and third-party modules!
---
Further documentation will be added later!

@ -1,27 +0,0 @@
"use strict";
const { validateArguments, RemainingArguments } = require(".");
const isString = require("@validatem/is-string");
const isBoolean = require("@validatem/is-boolean");
const isNumber = require("@validatem/is-number");
const required = require("@validatem/required");
const arrayOf = require("@validatem/array-of");
function testFunction(one, two, three, ... rest) {
validateArguments(arguments, {
one: [ required, isString ],
two: [ required, isNumber ],
three: [ required, isBoolean ],
[RemainingArguments]: [ required, arrayOf(isString) ],
});
}
testFunction("foo", "bar", null, "baz", 42);
/*
AggregrateValidationError: One or more validation errors occurred:
- At two: Must be a number
- At three: Required value is missing
- At array -> 1: Must be a string
- At mapping -> d -> (value): Must be a boolean
*/

@ -1,45 +0,0 @@
"use strict";
const { validateValue } = require("./");
const isString = require("@validatem/is-string");
const isBoolean = require("@validatem/is-boolean");
const isNumber = require("@validatem/is-number");
const required = require("@validatem/required");
const arrayOf = require("@validatem/array-of");
const anyProperty = require("@validatem/any-property");
let data = {
one: "foo",
two: "bar",
array: [
"A",
false,
"C"
],
mapping: {
a: true,
b: false,
c: false,
d: NaN
}
};
validateValue(data, {
one: [ required, isString ],
two: [ required, isNumber ],
three: [ required, isBoolean ],
optional: [ isString ],
array: [ required, arrayOf([ required, isString ]) ],
mapping: [ required, anyProperty({
key: [ required ],
value: [ required, isBoolean ]
}) ]
});
/*
AggregrateValidationError: One or more validation errors occurred:
- At two: Must be a number
- At three: Required value is missing
- At array -> 1: Must be a string
- At mapping -> d -> (value): Must be a boolean
*/

@ -1,15 +0,0 @@
"use strict";
// Forcibly import this module before anything else, to make our cyclical dependency hack work (details are in ./src/compose-rules.js)
require("./src/compose-rules");
module.exports = {
// TODO: Provide a 'basePathsToIgnore' option for all of the below methods, so that third-party modules could wrap these methods without having themselves show up as the source of the error? Their base paths can then be treated like internals paths in the error parsing code that pinpoints the validation call site.
validateArguments: require("./src/api/validate-arguments"),
validateOptions: require("./src/api/validate-options"),
validateValue: require("./src/api/validate-value"),
testValue: require("./src/api/test-value"),
AggregrateValidationError: require("./src/aggregrate-validation-error"),
RemainingArguments: require("./src/api/validate-arguments/remaining-arguments-symbol")
};

@ -1,44 +0,0 @@
{
"name": "@validatem/core",
"description": "The last validation library you'll ever need.",
"keywords": [
"validation",
"input",
"verification",
"data"
],
"version": "0.5.0",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/core.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/annotate-errors": "^0.1.2",
"@validatem/any-property": "^0.1.0",
"@validatem/error": "^1.0.0",
"@validatem/match-validation-error": "^0.1.0",
"@validatem/match-versioned-special": "^0.1.0",
"@validatem/match-virtual-property": "^0.1.0",
"@validatem/normalize-rules": "^0.1.0",
"@validatem/required": "^0.1.0",
"@validatem/validation-result": "^0.1.1",
"@validatem/virtual-property": "^0.1.0",
"as-expression": "^1.0.0",
"assure-array": "^1.0.0",
"create-error": "^0.3.1",
"default-value": "^1.0.0",
"execall": "^2.0.0",
"indent-string": "^4.0.0",
"is-arguments": "^1.0.4",
"supports-color": "^7.1.0",
"syncpipe": "^1.0.0"
},
"devDependencies": {
"@joepie91/eslint-config": "^1.1.0",
"@validatem/array-of": "^0.1.0",
"@validatem/is-boolean": "^0.1.0",
"@validatem/is-number": "^0.1.1",
"@validatem/is-string": "^0.1.0",
"eslint": "^6.8.0"
}
}

@ -1,196 +0,0 @@
"use strict";
const indentString = require("indent-string");
const matchVirtualProperty = require("@validatem/match-virtual-property");
const asExpression = require("as-expression");
const syncpipe = require("syncpipe");
const AggregrateValidationError = require("./aggregrate-validation-error");
const parseStacktrace = require("./parse-stacktrace");
const { dim, dimBold, highlight, highlightBold } = require("./colors");
// TODO: Omit the "At (root)" for path-less errors, to avoid confusion when singular values are being compared?
// TODO: Move out the path generating logic into a separate module, to better support custom error formatting code
// FIXME: Remove duplicate subError-less error messages, when heuristics are enabled? eg. multiple "Must be an array" for different arrayOf combinators
function joinPathSegments(segments) {
return (segments.length > 0)
? segments.join(" -> ")
: "(root)";
}
// FIXME: Render error codes (grayed out) after error messages, as a stable identifier
function renderErrorList(errors, subErrorLevels = 0) {
let rephrasedErrors = errors.map((error, i) => {
let pathSegments = error.path.map((segment) => {
if (segment == null) {
throw new Error(`Unexpected empty path segment encountered; this is a bug, please report it!`);
} else if (typeof segment === "string" || typeof segment === "number") {
return highlight(String(segment));
} else if (matchVirtualProperty(segment)) {
return dim(`(${segment.name})`);
} else {
throw new Error(`Unexpected path segment encountered: ${segment}; this is a bug, please report it!`);
}
});
let lineCharacter = (i < errors.length - 1)
? "├─"
: "└─";
let mainLine = asExpression(() => {
if (subErrorLevels > 0) {
let message = (pathSegments.length > 0)
? `${lineCharacter} ${joinPathSegments(pathSegments)}: ${error.message}`
: `${lineCharacter} ${error.message}`;
return message;
} else {
return (pathSegments.length > 0)
? ` - At ${joinPathSegments(pathSegments)}: ${error.message}`
: ` - ${error.message}`;
}
});
if (error.subErrors != null && error.subErrors.length > 0) {
let renderedSubErrors = renderErrorList(error.subErrors, subErrorLevels + 1);
let isLastError = (i === errors.length - 1);
if (subErrorLevels > 0 && !isLastError) {
return syncpipe(renderedSubErrors, [
(_) => indentString(_, 3),
(_) => indentString(_, 1, { indent: "│" }),
(_) => mainLine + "\n" + _
]);
} else {
return mainLine + "\n" + indentString(renderedSubErrors, 4);
}
} else {
return mainLine;
}
});
return rephrasedErrors.map((error) => {
return `${error}`;
}).join("\n");
}
function determineLocation() {
try {
throw new Error(`Dummy error to obtain a stacktrace`);
} catch (error) {
try {
let externalFrames = syncpipe(error, [
(_) => parseStacktrace(_),
(_) => removeInternalFrames(_),
]);
if (externalFrames.length > 0) {
return syncpipe(externalFrames, [
(_) => _[0],
(_) => {
return {
... _,
shortPath: abbreviatePath(_.location.path)
};
}
]);
} else {
return null;
}
} catch (parsingError) {
// If *anything at all* went wrong, we will just give up and return nothing, because the stacktrace parsing code is fragile, and we don't want that to be a reason for someone not to get a validation error displayed to them.
// FIXME: Do we want to have this visible as a warning in 1.0.0? Or should this warning be opt-in, for when the user wants more detail about *why* the location of the error could not be determined? Since there may be legitimate reasons for that to occur, eg. in bundled code without source maps.
console.warn("An error occurred during stacktrace parsing; please report this as a bug in @validatem/core!", parsingError);
}
}
}
// NOTE: This must be changed if aggregrate-errors.js is ever moved within the module!
let internalBasePathRegex = /(.+)src$/;
function getInternalBasePath() {
let match = internalBasePathRegex.exec(__dirname);
if (match != null) {
return match[1];
} else {
throw new Error(`Did not find expected basePath, instead got: ${__dirname}`);
}
}
function removeInternalFrames(stack) {
let internalBasePath = getInternalBasePath();
if (stack[0].location != null && stack[0].location.path != null && stack[0].location.path.startsWith(internalBasePath)) {
// We are running a normal environment with sensible stacktraces.
return stack.filter((frame) => {
return (
!frame.location.anonymous
&& !frame.location.path.startsWith(internalBasePath)
);
});
} else {
// We're probably in a bundled environment, with errors not being sourcemapped. Use an alternate, less reliable strategy. This will still break when code is minified.
let lastValidationFrame = stack.findIndex((frame) => {
return (frame.functionName != null && frame.functionName.includes("createValidationMethod"));
});
if (lastValidationFrame === -1) {
// Welp, this didn't work either. We'll just return an empty stack then, treating every frame as (possibly) internal, to cause the origin to be displayed as unknown.
return [];
} else {
return stack.slice(lastValidationFrame + 1);
}
}
}
function abbreviatePath(path) {
// TODO: Maybe add a special case for paths within node_modules? For when an error originates from a package the user is depending on.
let segments = path.split(/[\\\/]/);
let [ thirdLast, secondLast, last ] = segments.slice(-3);
if (last != null) {
let isIndexFile = /^index\.[a-z0-9]+$/.test(last);
let relevantSegments = (isIndexFile)
? [ thirdLast, secondLast, last ]
: [ secondLast, last ];
return relevantSegments.join("/");
} else {
// This path is extremely short, so we'll just return it as-is.
return segments.join("/");
}
}
module.exports = function aggregrateAndThrowErrors(errors) {
if (errors.length > 0) {
let detailLines = renderErrorList(errors);
let frame = determineLocation();
let locationString = asExpression(() => {
if (frame != null) {
let functionString = asExpression(() => {
if (frame.alias != null && frame.functionName != null) {
return `${frame.alias} [${frame.functionName}]`;
} else if (frame.functionName != null) {
return `'${frame.functionName}'`;
} else {
return dimBold("(unnamed function)");
}
});
return `${highlightBold(functionString)} in ${highlightBold(frame.shortPath)}, at line ${highlightBold(frame.location.line)} (${frame.location.path})`;
} else {
return dimBold(`(could not determine location)`);
}
});
return new AggregrateValidationError(`One or more validation errors occurred at ${locationString}:\n${detailLines}`, {
errors: errors
});
}
};

@ -1,5 +0,0 @@
"use strict";
const createError = require("create-error");
module.exports = createError("AggregrateValidationError", { errors: [] });

@ -1,12 +0,0 @@
"use strict";
const applyValidators = require("../apply-validators");
// NOTE: This will *not* give you access to either the errors or the transformed value! It's typically used for conditional logic in business logic *after* the initial validation has already taken place. This allows for reusing the entire ecosystem of Validatem validators for "does this value match format X, if yes, run this code"-type logic.
// FIXME: Put this in the documentation instead.
module.exports = function (value, rules) {
let { errors } = applyValidators(value, rules);
return (errors.length === 0);
};

@ -1,120 +0,0 @@
"use strict";
const isArguments = require("is-arguments");
const asExpression = require("as-expression");
const syncpipe = require("syncpipe");
const ValidationError = require("@validatem/error");
const annotateErrors = require("@validatem/annotate-errors");
const virtualProperty = require("@validatem/virtual-property");
const splitArray = require("../../split-array");
const applyValidators = require("../../apply-validators");
const createValidationMethod = require("../validation-method");
const RemainingArguments = require("./remaining-arguments-symbol");
// TODO: Simplify below by treating it like an array or object? Or would that introduce too much complexity through specialcasing?
// TODO: Find a way to produce validatem-style errors for the below invocation errors, without introducing recursion
// TODO: Maybe create a validatedFunction(rules, (foo, bar) => ...) type abstraction for "pre-processed", more performant validation usecases? At the cost of having to specify the validation rules outside of the function, which you'd need to do anyway in that case. Upside would be that you don't need to specify `arguments` manually anymore.
// TODO: Special-case callsite extraction from stacktrace when using validateArguments, as the user will probably be interested in where the validator-fenced code was *called from*, not where the rules are defined (unlike with validateValue)
function arrayToNormalized(array) {
return array.map((definition) => {
let [ name, ...rules ] = definition;
if (typeof name !== "string") {
throw new Error("First item in the argument rules list must be the argument name");
} else {
return {
name: name,
rules: rules
};
}
});
}
function objectToNormalized(object) {
// NOTE: Not using Object.entries because we also want to catch Symbol keys
// NOTE: Reflect.ownKeys is not ordered correctly, Symbols always come last! When object syntax is used, we just assume that the user correctly specified any RemainingArguments symbol at the end.
return Reflect.ownKeys(object).map((key) => {
let value = object[key];
return {
name: key,
rules: value
};
});
}
function applyDefinitions(args, definitions, remainingArgumentsIndex) {
let results = definitions.map(({ name, rules }, i) => {
let argument = args[i];
let validatorResult = applyValidators(argument, rules);
return {
errors: annotateErrors({
pathSegments: (name === RemainingArguments)
? [ virtualProperty(`arguments from ${remainingArgumentsIndex} onwards`) ] // TODO: Better description?
: [ name ],
errors: validatorResult.errors
}),
newValue: (validatorResult.newValue !== undefined)
? validatorResult.newValue
: argument
};
});
return {
errors: syncpipe(results, [
(_) => _.map((result) => result.errors),
(_) => _.flat(Infinity)
]),
newValue: results.map((result) => result.newValue)
};
}
module.exports = createValidationMethod((args, argumentDefinitions) => {
if (!isArguments(args)) {
throw new Error(`First argument is not an 'arguments' object; maybe you forgot to put it before the validation rules?`);
} else if (argumentDefinitions == null) {
throw new Error(`Validation rules (second argument) are missing; maybe you forgot to specify them?`);
} else {
let normalizedDefinitions = (Array.isArray(argumentDefinitions))
? arrayToNormalized(argumentDefinitions)
: objectToNormalized(argumentDefinitions);
let definitionCount = normalizedDefinitions.length;
let remainingArgumentsIndex = normalizedDefinitions.findIndex(({ name }) => name === RemainingArguments);
let hasRemainingArguments = (remainingArgumentsIndex !== -1);
let remainingArgumentsComeLast = (remainingArgumentsIndex === definitionCount - 1);
if (hasRemainingArguments && !remainingArgumentsComeLast) {
throw new Error(`A RemainingArguments entry can only be the last item`);
} else if (!hasRemainingArguments && args.length > definitionCount) {
return {
errors: [ new ValidationError(`Got ${args.length} arguments, but only expected ${definitionCount}`) ],
// Cast the below to an array, for consistency with *success* output, in case we ever want to expose the new values to the user in an error case too.
newValue: Array.from(args)
};
} else {
let normalizedArguments = asExpression(() => {
let argumentsAsArray = Array.from(args);
if (hasRemainingArguments) {
let [ positionalArguments, remainingArguments ] = splitArray(argumentsAsArray, [ remainingArgumentsIndex ]);
if (remainingArguments.length > 0) {
// Add all of the remaining arguments as a *single array value*, to make applying validation rules easier
return positionalArguments.concat([ remainingArguments ]);
} else {
return positionalArguments;
}
} else {
return argumentsAsArray;
}
});
return applyDefinitions(normalizedArguments, normalizedDefinitions, remainingArgumentsIndex);
}
}
});

@ -1,3 +0,0 @@
"use strict";
module.exports = Symbol("RemainingArguments");

@ -1,13 +0,0 @@
"use strict";
const assureArray = require("assure-array");
const validateArguments = require("./validate-arguments");
module.exports = function (args, optionsRules) {
let result = validateArguments(args, [
["options"].concat(assureArray(optionsRules))
]);
return result[0];
};

@ -1,6 +0,0 @@
"use strict";
const applyValidators = require("../apply-validators");
const createValidationMethod = require("./validation-method");
module.exports = createValidationMethod(applyValidators);

@ -1,17 +0,0 @@
"use strict";
const aggregrateErrors = require("../aggregrate-errors");
module.exports = function createValidationMethod(validationFunction) {
return function (... args) {
let { errors, newValue } = validationFunction(... args);
let aggregratedError = aggregrateErrors(errors);
if (aggregratedError != null) {
throw aggregratedError;
} else {
return newValue;
}
};
};

@ -1,33 +0,0 @@
"use strict";
const normalizeRules = require("@validatem/normalize-rules");
const matchValidationError = require("@validatem/match-validation-error");
const validationResult = require("@validatem/validation-result");
const composeRules = require("./compose-rules");
module.exports = function applyValidators(value, rules, context = {}) {
let normalizedRules = normalizeRules(rules, { normalizeObjects: true });
let validator = composeRules.compose(normalizedRules);
// FIXME: Document this option!
let finalContext = (process.env.VALIDATEM_NO_HEURISTICS === "1")
? { ...context, __validatemNoHeuristics: true }
: context;
let { errors, newValue } = validator(value, finalContext);
// NOTE: We mutate the error here, because Error objects are not safely cloneable
for (let error of errors) {
if (matchValidationError(error) && error.value == null) {
error.value = value;
}
}
return validationResult({
errors: errors,
newValue: (newValue !== undefined)
? newValue
: value
});
};

@ -1,32 +0,0 @@
"use strict";
const supportsColor = require("supports-color");
// NOTE: We do some manual ANSI escape code stuff here for now, because using `chalk` would significantly inflate the bundle size of the core.
// TODO: Find a better solution for this.
let openHighlight, openDim, openHighlightBold, openDimBold, closeColor;
if (supportsColor.stderr) {
openHighlight = `\u001b[32m`; // green
openDim = `\u001b[90m`; // gray
openHighlightBold = `\u001b[32;1m`; // green bold
openDimBold = `\u001b[90;1m`; // gray bold
// closeColor = `\u001b[39m`; // Does not reset bold!
closeColor = `\u001b[0m`;
} else {
openHighlight = "";
openDim = "";
openHighlightBold = "";
openDimBold = "";
closeColor = "";
}
module.exports = {
dim: (string) => openDim + string + closeColor,
highlight: (string) => openHighlight + string + closeColor,
dimBold: (string) => openDimBold + string + closeColor,
highlightBold: (string) => openHighlightBold + string + closeColor,
};

@ -1,114 +0,0 @@
"use strict";
const ValidationError = require("@validatem/error");
const matchValidationError = require("@validatem/match-validation-error");
const validationResult = require("@validatem/validation-result");
const isRequiredMarker = require("./is-special/required");
const isValidationResult = require("./is-special/validation-result");
const isCombinator = require("./is-special/combinator");
const applyValidators = require("./apply-validators");
// NOTE: If a validator returns a transformed value, the *next* validator in line will receive this *transformed* value instead of the original value. This allows composing/chaining different transformations, and keeping that model consistent with how providing an array of validators would work. If this behaviour is not desirable, the user can wrap `ignoreResult` around the offending validator to retain the previous (potentially original input) value.
// NOTE: Assigning to a property *on* module.exports as a cyclic dependency handling workaround for compose-rules -> apply-validators -> compose-rules -> ...
// This works because apply-validators gets a reference the default `module.exports` object when it requires compose-rules (this module) and it can complete initialization, *after* which we make our compose-rules implementation available as a property on said (already-referenced) object.
module.exports.compose = function composeValidators(validators) {
let isRequired = validators.some((rule) => isRequiredMarker(rule));
let nonMarkerRules = validators.filter((rule) => !isRequiredMarker(rule));
function callRule({ rule, value, context }) {
try {
let result = isCombinator(rule)
? rule.callback(value, applyValidators, context)
: rule(value, context);
if (result !== undefined) {
if (isValidationResult(result)) {
if (Array.isArray(result.errors)) {
let nonValidationErrors = result.errors.filter((error) => !matchValidationError(error));
if (nonValidationErrors.length === 0) {
return {
errors: result.errors,
newValue: result.newValue
};
} else {
// We should never reach this point, but it could possibly occur if someone erroneously includes non-ValidationError errors in a validationResult. Note that this is a last-ditch handler, and so we only throw the first non-ValidationError error and let the user sort out the rest, if any.
throw nonValidationErrors[0];
}
} else {
throw new Error(`The 'errors' in a validationResult must be an array`);
}
} else if (result != null && matchValidationError(result)) {
return {
errors: [ result ],
newValue: undefined
};
} else {
return {
errors: [],
newValue: result
};
}
} else {
return {
errors: [],
newValue: undefined
};
}
} catch (error) {
if (matchValidationError(error)) {
return {
errors: [ error ],
newValue: undefined
};
} else {
throw error;
}
}
}
return function composedValidator(value, context) {
// FIXME: Does this still need to be a special case, now that we have the callIfNull property?
if (isRequired && value == null) {
return validationResult({
errors: [ new ValidationError(`Required value is missing`) ],
newValue: value
});
} else {
let lastValue = value;
let errors = [];
for (let rule of nonMarkerRules) {
if (lastValue != null || rule.callIfNull === true) {
let result = callRule({
rule: rule,
value: lastValue,
context: context
});
if (result.newValue !== undefined) {
lastValue = result.newValue;
}
if (result.errors.length > 0) {
errors = result.errors;
break;
}
} else {
continue;
}
}
return validationResult({
errors: errors,
// NOTE: The below conditional is to make a composed series of validator mirror a normal validator, in the sense that it only returns a `newValue` if something has actually changed. For transparent composability, we want to be as close to the behaviour of a non-composed validator as possible.
newValue: (lastValue !== value)
? lastValue
: undefined
});
}
};
};

@ -1,10 +0,0 @@
"use strict";
const createVersionedSpecialCheck = require("@validatem/match-versioned-special");
module.exports = createVersionedSpecialCheck({
markerProperty: "___validatem_isCombinator",
versionProperty: "___validatem_combinatorVersion",
friendlyName: "a combinator",
expectedVersions: [ 1 ]
});

@ -1,10 +0,0 @@
"use strict";
const createVersionedSpecialCheck = require("@validatem/match-versioned-special");
module.exports = createVersionedSpecialCheck({
markerProperty: "___validatem_isRequiredMarker",
versionProperty: "___validatem_requiredMarkerVersion",
friendlyName: "a required-field marker",
expectedVersions: [ 1 ]
});

@ -1,10 +0,0 @@
"use strict";
const createVersionedSpecialCheck = require("@validatem/match-versioned-special");
module.exports = createVersionedSpecialCheck({
markerProperty: "___validatem_isValidationResult",
versionProperty: "___validatem_validationResultVersion",
friendlyName: "a validation result object",
expectedVersions: [ 1 ]
});

@ -1,130 +0,0 @@
"use strict";
// FIXME: Move this into its own package!
const execall = require("execall");
const defaultValue = require("default-value");
// I'm so, so sorry...
let lineRegex = /\s+at\s+(?:(?:((?:[^\[\n])+)\[as ([^\]]+)\] |((?:[^\(\n])+))\(([^\)\n]+)\)|([^\n]+))(?:\n|$)/gm;
let geckoLineRegex = /^([^@\n]*)@(.+)/gm;
let numberRegex = /^\d+$/;
function maybeTrim(value) {
if (value != null) {
let trimmed = value.trim();
if (trimmed.length > 0) {
return trimmed;
} else {
return null;
}
} else {
return value;
}
}
function isLocation(locationString) {
return (locationString.split(":").length > 2);
}
function splitLocation(locationString) {
let parts = locationString.split(":");
if (parts.length > 2) {
let pathPartCount = parts.length - 2;
return [
parts.slice(0, pathPartCount).join(":"),
parts[pathPartCount],
parts[pathPartCount + 1],
];
}
}
function parseLocation(locationString) {
if (locationString === "<anonymous>") {
return { anonymous: true };
} else {
let parts = splitLocation(locationString);
if (parts != null && numberRegex.test(parts[1]) && numberRegex.test(parts[2])) {
return {
path: parts[0],
line: parseInt(parts[1]),
column: parseInt(parts[2])
};
} else {
throw new Error(`Could not parse location from string: ${locationString}`);
}
}
}
function extractFramesV8(stack) {
let matches = execall(lineRegex, stack);
if (matches.length > 0) {
return matches.map((match) => {
let groups = match.subMatches;
return {
functionName: maybeTrim(defaultValue(groups[0], groups[2])),
alias: groups[1],
location: parseLocation(defaultValue(groups[3], groups[4]))
};
});
} else {
return null;
}
}
function extractFramesGecko(stack) {
let matches = execall(geckoLineRegex, stack);
if (matches.length > 0) {
return matches.map((match) => {
let groups = match.subMatches;
return {
functionName: maybeTrim(groups[0]),
location: parseLocation(groups[1])
};
});
} else {
return null;
}
}
function extractFrames(stack) {
// TODO: Maybe make this code even more cautious, and match each stacktrace line individually, aborting as soon as any one line cannot be parsed?
return defaultValue(
extractFramesV8(stack),
() => extractFramesGecko(stack),
{ evaluate: true }
);
}
module.exports = function parseStackTrace(error) {
let stack = error.stack;
let lines = stack.split("\n");
let firstStackLine = lines
.map((line) => line.trim())
.findIndex((line) => isLocation(line));
if (firstStackLine !== -1) {
let cleanStack = lines
.slice(firstStackLine)
.join("\n");
let extracted = extractFrames(cleanStack);
if (extracted != null) {
return extracted;
} else {
throw new Error(`Could not extract stacktrace frames`);
}
} else {
throw new Error(`Could not find a stacktrace frame`);
}
};

@ -1,22 +0,0 @@
"use strict";
// FIXME: Move this into its own package
module.exports = function splitArray(array, indexes) {
let segments = [];
let lastIndex = 0;
for (let index of indexes) {
if (index < array.length) {
segments.push(array.slice(lastIndex, index));
lastIndex = index;
} else {
throw new Error(`Attempted to split at index ${index}, but array only has ${array.length} items`);
}
}
// Final segment, from last specified index to end of array; this is because the indexes only define the *split points*, and so the total amount of segments is always one more than that.
segments.push(array.slice(lastIndex));
return segments;
};

@ -1 +0,0 @@
../../../@validatem+error@1.1.0/node_modules/@validatem/error

@ -1 +0,0 @@
../../../@validatem+match-validation-error@0.1.0/node_modules/@validatem/match-validation-error

@ -1 +0,0 @@
../../../@validatem+match-versioned-special@0.1.1/node_modules/@validatem/match-versioned-special

@ -1 +0,0 @@
../../../@validatem+match-virtual-property@0.1.0/node_modules/@validatem/match-virtual-property

@ -1 +0,0 @@
../../../@validatem+normalize-rules@0.1.3/node_modules/@validatem/normalize-rules

@ -1 +0,0 @@
../../../@validatem+required@0.1.1/node_modules/@validatem/required

@ -1 +0,0 @@
../../../@validatem+validation-result@0.1.2/node_modules/@validatem/validation-result

@ -1 +0,0 @@
../../../@validatem+virtual-property@0.1.0/node_modules/@validatem/virtual-property

@ -1 +0,0 @@
../../as-expression@1.0.0/node_modules/as-expression

@ -1 +0,0 @@
../../assure-array@1.0.0/node_modules/assure-array

@ -1 +0,0 @@
../../create-error@0.3.1/node_modules/create-error

@ -1 +0,0 @@
../../default-value@1.0.0/node_modules/default-value

@ -1 +0,0 @@
../../execall@2.0.0/node_modules/execall

@ -1 +0,0 @@
../../indent-string@4.0.0/node_modules/indent-string

@ -1 +0,0 @@
../../is-arguments@1.1.1/node_modules/is-arguments

@ -1 +0,0 @@
../../supports-color@7.2.0/node_modules/supports-color

@ -1 +0,0 @@
../../syncpipe@1.0.0/node_modules/syncpipe

@ -1,35 +0,0 @@
# @validatem/error
This package contains the `ValidationError` type for [`validatem`](https://www.npmjs.com/package/@validatem/core).
__A VERY IMPORTANT NOTE:__ You should *always* use the caret notation (eg. `^1.0.0`) when depending on this package. NPM and Yarn will do this by default when you `npm install @validatem/error` or `yarn add @validatem/error`, but some people turn this off - don't do that here, or things might break!
## Why is this a separate package?
Because it makes forwards compatibility easier. Even if [`@validatem/core`](https://www.npmjs.com/package/@validatem/core) ever needs a breaking release, chances are that the error format remains unchanged. Making the error type separately versionable, means that in that scenario validators should stay compatible with both the old *and* the new version of the core, without validator authors needing to update anything.
## License, donations, and other boilerplate
Licensed under either the [WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), at your choice. In practice, that means it's more or less public domain, and you can do whatever you want with it. Giving credit is *not* required, but still very much appreciated! I'd love to [hear from you](mailto:admin@cryto.net) if `validatem` was useful to you.
Creating and maintaining open-source modules is a lot of work. A donation is also not required, but much appreciated! You can donate [here](http://cryto.net/~joepie91/donate.html).
## API
### new ValidationError(message, [properties])
The constructor for `validatem`'s `ValidationError` type. This is invoked like any other `Error` constructor, but you may optionally pass extra metadata that should be stored on the error.
__Note that, for performance reasons (preventing stacktrace collection), the returned object does not *actually* inherit from `Error`!__ This should not affect its correct functioning, considering that the stacktraces of individual validators are not used in Validatem, and `ValidationError`s should never be thrown outside of a validator context anyway.
__Unless you are implementing a parser and using virtual properties, you probably do not need to specify the `path` property.__ Combinators like `arrayOf` will insert their path segments after-the-fact by themselves, your validator does not need to do this.
* __message:__ A description of the validation problem. This should be formatted in such a way that it describes the *requirement*, and *not* how it failed; for example, it should say "Must be a string" rather than "Is not a string".
* __properties:__ *Optional.* An object of properties to attach to the new error object.
* __path:__ An array of 'path segment' strings that describes the location of the validation error.
## Changelog
### v1.0.0 (April 20, 2020)
Initial release.

@ -1,19 +0,0 @@
"use strict";
// NOTE: We don't actually inherit from the real Error here, because collecting stacktraces is very expensive and largely useless for our purposes. Validatem's own error reporting is clear enough, and if not, that's a bug in Validatem anyway.
function ValidationError(message, properties) {
this.message = message;
Object.assign(this, {
path: [],
___validatem_isValidationError: true,
___validatem_errorVersion: 1
});
Object.assign(this, properties);
}
ValidationError.prototype.name = "ValidationError";
module.exports = ValidationError;
module.exports.__modulePath = __dirname;

@ -1,8 +0,0 @@
{
"name": "@validatem/error",
"version": "1.1.0",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/error.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0"
}

@ -1 +0,0 @@
../../../@validatem+annotate-errors@0.1.2/node_modules/@validatem/annotate-errors

@ -1 +0,0 @@
../../../@validatem+combinator@0.1.2/node_modules/@validatem/combinator

@ -1 +0,0 @@
../../../@validatem+error@1.1.0/node_modules/@validatem/error

@ -1,5 +0,0 @@
# @validatem/has-shape
Documentation for this module has not been fully written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,35 +0,0 @@
"use strict";
const hasShape = require("./");
const { validateValue } = require("@validatem/core");
const isString = require("@validatem/is-string");
let validator = hasShape({
foo: [ isString ],
unused: [ isString ]
});
let objectA = {
foo: "bar"
};
console.log(validateValue(objectA, validator)); // { foo: 'bar' }
let objectB = {
foo: 42
};
console.log(validateValue(objectB, validator)); /*
AggregrateValidationError: One or more validation errors occurred:
- At foo: Must be a string
*/
let objectC = {
foo: "hello world",
otherProperty: "baz"
};
console.log(validateValue(objectC, validator)); /*
AggregrateValidationError: One or more validation errors occurred:
- At (root): Encountered an unexpected property 'otherProperty'
*/

@ -1,100 +0,0 @@
"use strict";
const asExpression = require("as-expression");
const defaultValue = require("default-value");
const assureArray = require("assure-array");
const flatten = require("flatten");
const arrayUnion = require("array-union");
const ValidationError = require("@validatem/error");
const validationResult = require("@validatem/validation-result");
const annotateErrors = require("@validatem/annotate-errors");
const combinator = require("@validatem/combinator");
function containsRules(rules) {
// TODO: We cannot use normalize-rules here (for now) since that would create a cyclical dependency; figure out a way to work around this, maybe by removing the hasShape feature in `normalize-rules`, or moving the flattening itself out into a separate `flatten-rules` package?
if (rules == null) {
return false;
} else {
// TODO: Switch to `Array#flat` once Node 10.x goes EOL (April 2021)
let flattenedRules = flatten(assureArray(rules));
if (!flattenedRules.some((rule) => rule != null)) {
return false;
} else {
return true;
}
}
}
module.exports = function hasShape(rules) {
let validator = combinator((object, applyValidators, context) => {
let allowExtraProperties = defaultValue(context.allowExtraProperties, false);
let unexpectedPropertyErrors = asExpression(() => {
if (!allowExtraProperties) {
return Reflect.ownKeys(object).map((propertyName) => {
if (!containsRules(rules[propertyName])) {
return new ValidationError(`Encountered an unexpected property '${propertyName}'`);
} else {
return null;
}
}).filter((error) => {
return (error != null);
});
} else {
return [];
}
});
if (unexpectedPropertyErrors.length > 0) {
return validationResult({
errors: unexpectedPropertyErrors,
newValue: object
});
} else {
let errors = [];
let newObject = {};
// We need to consider the keys from the ruleset (for detecting missing required properties) *and* the keys from the actual object (for handling extraneous values).
let allKeys = arrayUnion(
Reflect.ownKeys(rules),
Reflect.ownKeys(object)
);
for (let key of allKeys) {
let value = object[key];
let rule = rules[key];
if (rule != null) {
let { errors: keyErrors, newValue } = applyValidators(value, rule);
let annotatedErrors = annotateErrors({
pathSegments: [ key ],
errors: keyErrors
});
errors.push(... annotatedErrors);
// Don't scatter explicit `undefined`s across the result object, just because an optional rule existed for some properties but the corresponding value didn't
if (newValue !== undefined) {
newObject[key] = newValue;
}
} else {
// Extraneous property
// FIXME: Assign non-enumerable if the source property was non-enumerable!
newObject[key] = value;
}
}
return validationResult({
errors: errors,
newValue: newObject
});
}
});
validator.callIfNull = false;
return validator;
};

@ -1,29 +0,0 @@
{
"name": "@validatem/has-shape",
"description": "Validatem combinator for validating that a value has certain keys that pass certain validators (eg. object validation)",
"keywords": [
"validatem",
"validator",
"combinator"
],
"version": "0.1.8",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/has-shape.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/annotate-errors": "^0.1.2",
"@validatem/combinator": "^0.1.0",
"@validatem/error": "^1.0.0",
"@validatem/validation-result": "^0.1.1",
"array-union": "^2.1.0",
"as-expression": "^1.0.0",
"assure-array": "^1.0.0",
"default-value": "^1.0.0",
"flatten": "^1.0.3"
},
"devDependencies": {
"@validatem/core": "^0.3.1",
"@validatem/is-string": "^0.1.0"
}
}

@ -1 +0,0 @@
../../../@validatem+validation-result@0.1.2/node_modules/@validatem/validation-result

@ -1 +0,0 @@
../../array-union@2.1.0/node_modules/array-union

@ -1 +0,0 @@
../../as-expression@1.0.0/node_modules/as-expression

@ -1 +0,0 @@
../../assure-array@1.0.0/node_modules/assure-array

@ -1 +0,0 @@
../../default-value@1.0.0/node_modules/default-value

@ -1 +0,0 @@
../../flatten@1.0.3/node_modules/flatten

@ -1 +0,0 @@
../../../@validatem+error@1.1.0/node_modules/@validatem/error

@ -1,5 +0,0 @@
# @validatem/is-non-empty-string
Documentation for this module has not been written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,11 +0,0 @@
"use strict";
const { validateValue } = require("@validatem/core");
const isNonEmptyString = require("./");
console.log(validateValue("hello world", [ isNonEmptyString ])); // hello world
console.log(validateValue("", [ isNonEmptyString ])); /*
AggregrateValidationError: One or more validation errors occurred:
- At (root): String must not be empty
*/

@ -1,13 +0,0 @@
"use strict";
const ValidationError = require("@validatem/error");
const isString = require("@validatem/is-string");
module.exports = [
isString,
function isNonEmptyString(value) {
if (value.length === 0) {
throw new ValidationError(`String must not be empty`);
}
}
];

@ -1,20 +0,0 @@
{
"name": "@validatem/is-non-empty-string",
"description": "Validatem validator for ensuring that a value is a non-empty string",
"keywords": [
"validatem",
"validator"
],
"version": "0.1.0",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/is-non-empty-string.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/error": "^1.0.0",
"@validatem/is-string": "^0.1.1"
},
"devDependencies": {
"@validatem/core": "^0.3.3"
}
}

@ -1 +0,0 @@
../../../@validatem+is-string@0.1.1/node_modules/@validatem/is-string

@ -1 +0,0 @@
../../../@validatem+error@1.1.0/node_modules/@validatem/error

@ -1,5 +0,0 @@
# @validatem/is-plain-object
Documentation for this module has not been written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,11 +0,0 @@
"use strict";
const { validateValue } = require("@validatem/core");
const isPlainObject = require("./");
console.log(validateValue({ foo: "bar" }, [ isPlainObject ])); // { foo: 'bar' }
console.log(validateValue(new Date(), [ isPlainObject ])); /*
AggregrateValidationError: One or more validation errors occurred:
- At (root): Must be a plain object (eg. object literal)
*/

@ -1,10 +0,0 @@
"use strict";
const ValidationError = require("@validatem/error");
const isPlainObj = require("is-plain-obj");
module.exports = function(value) {
if (!isPlainObj(value)) {
throw new ValidationError("Must be a plain object (eg. object literal)");
}
};

@ -1,20 +0,0 @@
{
"name": "@validatem/is-plain-object",
"description": "Validatem validator for ensuring that a value is a plain object (eg. object literal)",
"keywords": [
"validatem",
"validator"
],
"version": "0.1.1",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/is-plain-object.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/error": "^1.0.0",
"is-plain-obj": "^2.1.0"
},
"devDependencies": {
"@validatem/core": "^0.3.1"
}
}

@ -1 +0,0 @@
../../is-plain-obj@2.1.0/node_modules/is-plain-obj

@ -1 +0,0 @@
../../../@validatem+error@1.1.0/node_modules/@validatem/error

@ -1,5 +0,0 @@
# @validatem/is-string
Documentation for this module has not been written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,11 +0,0 @@
"use strict";
const { validateValue } = require("@validatem/core");
const isString = require("./");
console.log(validateValue("hello world", [ isString ])); // hello world
console.log(validateValue(42, [ isString ])); /*
AggregrateValidationError: One or more validation errors occurred:
- At (root): Must be a string
*/

@ -1,10 +0,0 @@
"use strict";
const ValidationError = require("@validatem/error");
const isString = require("is-string");
module.exports = function (value) {
if (!isString(value)) {
throw new ValidationError("Must be a string");
}
};

@ -1,20 +0,0 @@
{
"name": "@validatem/is-string",
"description": "Validatem validator for ensuring that a value is a string",
"keywords": [
"validatem",
"validator"
],
"version": "0.1.1",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/is-string.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@validatem/error": "^1.0.0",
"is-string": "^1.0.5"
},
"devDependencies": {
"@validatem/core": "^0.3.1"
}
}

@ -1 +0,0 @@
../../is-string@1.0.7/node_modules/is-string

@ -1,5 +0,0 @@
# @validatem/match-special
Documentation for this module has not been written yet. By the time it reaches 1.0.0, it will have full documentation.
In the meantime, check out the `example.js` file in the repository for a usage demonstration.

@ -1,11 +0,0 @@
"use strict";
const matchSpecial = require("./");
const virtualProperty = require("@validatem/virtual-property");
let propertyA = "foo";
let propertyB = virtualProperty("bar");
console.log(matchSpecial(propertyA)); // false
console.log(matchSpecial(propertyB)); // true

@ -1,5 +0,0 @@
"use strict";
module.exports = function matchSpecial(value) {
return (value != null && value.___validatem_isSpecial === true);
};

@ -1,12 +0,0 @@
{
"name": "@validatem/match-special",
"description": "Utility for checking whether something is a special (plumbing) object of some kind",
"version": "0.1.0",
"main": "index.js",
"repository": "http://git.cryto.net/validatem/match-special.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"devDependencies": {
"@validatem/virtual-property": "^0.1.0"
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save