Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

JSValid

JSValid is a functional approach to validation in JavaScript. It provides a minimal, composable and extensible way to express and enforce value constraints.

JSValid specifies the signature of a special kind of function, called a validator. Validators accept as a single argument the subject, which is the value to be validated, and return an array of violations. An empty array indicates a valid subject.

A violation is an object with the following properties, of which only message is mandatory:

  • message: A string describing the violation.
  • path: An array of keys describing where the violation occurred (for example, ["people", 0]).
  • code: A string uniquely identifying the type of violation.
  • a: Exhibit A.
  • b: Exhibit B.

A factory is any function that returns a validator function. Here is a demonstration showing how factories, validators and violations work together.

// A validator is made by invoking a factory.
const my_validator = valid.object({
question: valid.string(),
answer: valid.integer()
});
// Invoking the validator with a subject returns an array.
const my_violations_array = my_validator({
question: "What is the answer to life, the universe and everything?",
answer: "Love."
});
// The array may be inspected for violations.
// [
// {
// message: "Not of type integer.",
// path: ["answer"]
// code: "not_type_a",
// a: "integer"
// }
// ]

The factories

An object containing several factory functions is exported by jsvalid.js:

import valid from "./jsvalid.js";
const {
boolean,
number,
integer,
string,
function,
array,
object,
wun_of,
all_of,
not,
literal,
any
} = valid;

Incidentally, these factories complement the specifiers provided by JSCheck, a testing tool written by Douglas Crockford.

valid.boolean()

The boolean validator permits only true and false.

valid.number()

The number validator permits only numbers that satisfy Number.isFinite. This excludes Infinity and NaN.

valid.number(minimum, maximum, exclude_minimum, exclude_maximum)

Specifying either of minimum or maximum imposes bounds on the subject. Bounds are inclusive unless either of exclude_minimum or exclude_maximum are true.

function valid_latitude() {
return valid.number(-90, 90);
}
function valid_longitude() {
return valid.number(-180, 180, false, true);
}
function valid_weight() {
return valid.number(0);
}

valid.integer()

The integer validator permits only numbers that satisfy Number.isSafeInteger.

valid.integer(minimum, maximum)

Specifying either of minimum or maximum imposes inclusive bounds on the subject.

valid.string()

The string validator permits only strings.

valid.string(regular_expression)

The subject must conform to the regular_expression.

function valid_tracking_number() {
return valid.string(/^[0-9]{24}$/);
}

valid.string(length_validator)

The length of the subject must conform to the length_validator.

function valid_note() {
return valid.string(valid.integer(1, 140));
}

valid.function(length_validator)

The function validator permits only functions. The arity of the subject must conform to the length_validator, if it is specified.

valid.array()

The array validator permits only arrays, as determined by Array.isArray.

valid.array(validator, length_validator)

Each element in the subject must conform to the validator. The length of the array must conform to the length_validator, if it is specified.

valid.array(validator_array, length_validator, rest_validator)

Each element in the subject must conform to the validator at the corresponding position in the validator_array. If the length_validator is omitted, the subject must be the same length as the validator_array.

function valid_location() {
return valid.array([valid_longitude(), valid_latitude()]);
}
function valid_mail_journey() {
return valid.array(valid_location(), valid.integer(1));
}

It is possible that the length_validator may permit a subject longer than the validator_array. In such a case, each surplus element of the subject must conform to the rest_validator. If the rest_validator is undefined, the sequence of surplus elements must conform to the sequence of validators formed by repeating the validator_array.

valid.object()

The object validator permits only bona fide objects, not null or arrays.

valid.object(required_properties, optional_properties, allow_strays)

The required_properties and optional_properties parameters are objects containing validators. Either parameter may be undefined.

The value of each property on the subject must conform to the corresponding validator in required_properties or optional_properties. Where no corresponding validator is found, the property is permitted only if allow_strays is true. Additionally, the subject must contain every key found on required_properties.

function valid_parcel() {
return valid.object(
{
id: valid_tracking_number(),
size: "parcel",
weight: valid_weight()
},
{
delivery_advice: valid_note()
}
);
}

valid.object(key_validator, value_validator, length_validator)

Each key found on the subject by Object.keys must conform to the key_validator. Each corresponding value must conform to the value_validator.

All keys are permitted if the key_validator is undefined. Likewise, all values are permitted if the value_validator is undefined.

The number of properties must conform to the length_validator, if it is defined.

function valid_tracking_info() {
return valid.object(valid_tracking_number(), valid_mail_journey());
}

valid.wun_of(validator_array)

The wun_of validator permits only values that conform to at least wun of the validators in the validator_array.

function valid_size() {
return valid.wun_of(["letter", "parcel", "postcard"]);
}

A definition of the word "wun" may be found here.

valid.wun_of(validator_object, classifier)

The appropriate validator is chosen according to some characteric of the subject. This helps to produce a more compact violations array.

The validator_object contains the validators. The property names are the classifications. The classifier function is called with the subject, and ideally returns a classification string (or number). The classifier may indicate that the subject is unclassifiable by throwing an exception or returning a value that is not a string (or number).

The subject is permitted if it classifies as and conforms to wun of the validators.

function valid_mail() {
return valid.wun_of(
{
letter: valid_letter(),
parcel: valid_parcel(),
postcard: valid_postcard()
},
function classifier(subject) {
return subject.size;
}
);
}

valid.all_of(validator_array, exhaustive)

The all_of validator permits only values that conform to every validator in the validator_array. It runs the validators in sequence, stopping at the first violation (unless exhaustive is true).

valid.not(validator)

The not validator permits only values that do not conform to the validator.

function valid_flat_mail() {
return valid.not(valid_parcel());
}

valid.literal(expected_value)

The literal validator permits only values equal to the expected_value. The === operator is used to determine equality unless either of the values is NaN, in which case Number.isNaN is used.

Some factories provided by JSValid accept validators as arguments. Where a non-function is provided in place of a validator, it is automatically wrapped with valid.literal. Thus, the expression

valid.string(valid.literal(1))

may be written more succinctly as

valid.string(1)

Consequently, valid.literal is only needed in cases where expected_value is a function or undefined.

valid.any()

The any validator permits any value.

But what about...?

It is easy to make your own validators. Here is a factory that returns a validator that permits only multiples of n.

function valid_multiple_of(n) {
return function (subject) {
return (
subject % n === 0
? []
: [{message: `Not a multiple of ${n}.`}]
);
};
}

About

A functional approach to validation.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Contributors

Languages