commit 0d6955fac113e9a83a37137f27216734b290ea5a Author: Sven Slootweg Date: Wed Jun 19 14:12:40 2024 +0200 Initial version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md new file mode 100644 index 0000000..e17607d --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# @promistream/fork-select + +A general-purpose forking [Promistream](https://promistream.cryto.net/). Lets you fork a pipeline into an arbitrary number of downstream forks, and divide values among them based on an arbitrary predicate function. Can be used directly, or as a basis for other types of forking streams. + +Stream characteristics: +- __Promistream version:__ 0 +- __Stream type:__ Fork +- __Supports parallelization:__ Yes (order-preserving) +- __Buffering:__ Unbounded; one internal buffer per fork, buffer only fills as needed to unblock other forks +- __Fork distribution strategy:__ User-specified + +## Example + +A runnable version of this example is included in the package as `example.js`. + +```js +"use strict"; + +const pipe = require("@promistream/pipe"); +const debug = require("@promistream/debug"); +const fromIterable = require("@promistream/from-iterable"); +const forkSelect = require("@promistream/fork-select"); +const collect = require("@promistream/collect"); + +(async () => { + let [ a, b ] = await pipe([ + fromIterable([ 0, 0, 0, 1, 1, 2 ]), + debug("source"), + forkSelect(2, (value) => { + return value % 2; + }) + ]).read(); + + setTimeout(async () => { + try { + let bResults = await pipe([ + b, + // debug("pipeline B"), + collect() + ]).read(); + + console.log({ bResults }); // { bResults: [ 1, 1 ] } + } catch (error) { + console.error("error from B", error); + } + }, 1000); + + try { + let aResults = await pipe([ + a, + // debug("pipeline A"), + collect() + ]).read(); + + console.log({ aResults }); // { aResults: [ 0, 0, 0, 2 ] } + } catch (error) { + console.error("error from A", error); + } +})(); +``` + +## API + +### forkSelect(forkCount, select) + +Creates a new forkSelect stream. Note that only the value assignment is configurable; errors (including `EndOfStream` and `Aborted` markers) are always broadcast to all forks. + +- __forkCount:__ *Required.* The amount of forks to create. +- __select:__ *Required.* The predicate callback to determine which fork a given value should be sent to. Receives the value as its argument, and is expected to return (a Promise of) the index of the fork to send it to. An array of fork indexes may also be specified to send the value to multiple forks. diff --git a/example.js b/example.js new file mode 100644 index 0000000..78ba268 --- /dev/null +++ b/example.js @@ -0,0 +1,43 @@ +"use strict"; + +const pipe = require("@promistream/pipe"); +const debug = require("@promistream/debug"); +const fromIterable = require("@promistream/from-iterable"); +const forkSelect = require("./"); +const collect = require("@promistream/collect"); + +(async () => { + let [ a, b ] = await pipe([ + fromIterable([ 0, 0, 0, 1, 1, 2 ]), + debug("source"), + forkSelect(2, (value) => { + return value % 2; + }) + ]).read(); + + setTimeout(async () => { + try { + let bResults = await pipe([ + b, + // debug("pipeline B"), + collect() + ]).read(); + + console.log({ bResults }); // { bResults: [ 1, 1 ] } + } catch (error) { + console.error("error from B", error); + } + }, 1000); + + try { + let aResults = await pipe([ + a, + // debug("pipeline A"), + collect() + ]).read(); + + console.log({ aResults }); // { aResults: [ 0, 0, 0, 2 ] } + } catch (error) { + console.error("error from A", error); + } +})(); diff --git a/index.js b/index.js new file mode 100644 index 0000000..50ca1e2 --- /dev/null +++ b/index.js @@ -0,0 +1,51 @@ +"use strict"; + +const range = require("range").range; +const pushBuffer = require("push-buffer"); + +const derivedStream = require("@promistream/derived-stream"); + +const { validateArguments } = require("@validatem/core"); +const required = require("@validatem/required"); +const isInteger = require("@validatem/is-integer"); +const isPositive = require("@validatem/is-positive"); +const isFunction = require("@validatem/is-function"); + + +module.exports = function createForkSelectForks(_streamCount, _selectionCallback) { + let [ streamCount, selectionCallback ] = validateArguments(arguments, { + streamCount: [ required, isInteger, isPositive ], + selectionCallback: [ required, isFunction ] + }); + + return derivedStream((source) => { + let buffer = pushBuffer({ + lanes: streamCount, + select: selectionCallback, + pull: async () => source.read() + }); + + return range(0, streamCount).map((streamIndex) => { + return { + _promistreamVersion: true, + _promistreamIsSource: true, + description: `fork-select stream (${streamIndex})`, + abort: function (reason) { + return source.abort(reason); + }, + peek: async function () { + // TODO: Improve the behaviour here somehow, maybe buffering up read values on every peek? + return (buffer.countLanes(streamIndex).values > 0); + }, + read: async function () { + try { + let value = await buffer.request(streamIndex); + return value; + } catch (error) { + throw error; + } + } + }; + }); + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..b708497 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "@promistream/fork-select", + "version": "0.1.0", + "description": "General-purpose forking stream", + "main": "index.js", + "repository": "http://git.cryto.net/promistream/fork-select.git", + "files": [ + "example.js", + "index.js", + "README.md" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "promistream", + "fork" + ], + "author": "Sven Slootweg ", + "license": "WTFPL OR CC0-1.0", + "dependencies": { + "@promistream/derived-stream": "^0.1.0", + "@validatem/core": "^0.5.0", + "@validatem/is-function": "^0.1.0", + "@validatem/is-integer": "^0.1.0", + "@validatem/is-positive": "^1.0.0", + "@validatem/required": "^0.1.1", + "push-buffer": "^1.1.1", + "range": "^0.0.3" + }, + "devDependencies": { + "@promistream/collect": "^0.1.1", + "@promistream/debug": "^0.1.0", + "@promistream/from-iterable": "^0.1.0", + "@promistream/pipe": "^0.1.6" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..dfb635a --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,736 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@promistream/derived-stream': + specifier: ^0.1.0 + version: 0.1.0 + '@validatem/core': + specifier: ^0.5.0 + version: 0.5.0 + '@validatem/is-function': + specifier: ^0.1.0 + version: 0.1.0 + '@validatem/is-integer': + specifier: ^0.1.0 + version: 0.1.0 + '@validatem/is-positive': + specifier: ^1.0.0 + version: 1.0.0 + '@validatem/required': + specifier: ^0.1.1 + version: 0.1.1 + push-buffer: + specifier: ^1.1.1 + version: 1.1.1 + range: + specifier: ^0.0.3 + version: 0.0.3 + +devDependencies: + '@promistream/collect': + specifier: ^0.1.1 + version: 0.1.1 + '@promistream/debug': + specifier: ^0.1.0 + version: 0.1.0 + '@promistream/from-iterable': + specifier: ^0.1.0 + version: 0.1.0 + '@promistream/pipe': + specifier: ^0.1.6 + version: 0.1.6 + +packages: + + /@joepie91/promise-defer@1.0.1: + resolution: {integrity: sha512-yjDrKMpO155Ajmk+r3RG4WNGbrwd4Mj8UHqJtBSoIL9usT6cC0jhy1yn7dzJiKmYFxvCvgxDbjcWNFNCwQ9UUw==} + dev: false + + /@joepie91/unreachable@1.0.0: + resolution: {integrity: sha512-vZRJ5UDq4mqP1vgSrcOLD3aIfS/nzwsvGFOOHv5sj5fa1Ss0dT1xnIzrXKLD9pu5EcUvF3K6n6jdaMW8uXpNEQ==} + dev: true + + /@promistream/aborted@0.1.2: + resolution: {integrity: sha512-rLQgZTFr0r7yWtDbqA8zT5F4TKDiOiyowlAxSKiSY4XM+XVYeNq7k9SXIxVhLczjKh1Cv0nlvvZ7cZ41UjZPwQ==} + dependencies: + default-value: 1.0.0 + error-chain: 0.1.3 + + /@promistream/collect@0.1.1: + resolution: {integrity: sha512-zXnp8SFm2dFsvJBASLfYMUxfaNkvzyhU56WT1iAXxlN5w2Rb0vArP2pIXvpbiSVrWkUObNeZ8t715nGxqsWEow==} + dependencies: + '@promistream/simple-sink': 0.1.1 + dev: true + + /@promistream/debug@0.1.0: + resolution: {integrity: sha512-/9fjQMCBvx7PWUp6xfyeyVY4vN7YnUeAge64i3uDsD02iPtU7c+Ra0Ozr3EhUhn7WXe09s/gJ/+oFvWS3PeH2Q==} + dependencies: + colorette: 2.0.20 + dev: true + + /@promistream/derived-stream@0.1.0: + resolution: {integrity: sha512-M+qRF+d197uFiAY7AoMVttaBiTRF0niA3zjmwwu+oesZX2lq1D6hlBV8vgzY04Y38Nx5pLXnaNbe1gVZz6Fz0g==} + dependencies: + '@promistream/aborted': 0.1.2 + '@promistream/end-of-stream': 0.1.2 + '@validatem/core': 0.3.17 + '@validatem/is-function': 0.1.0 + '@validatem/required': 0.1.1 + bluebird: 3.7.2 + error-chain: 0.1.3 + dev: false + + /@promistream/end-of-stream@0.1.2: + resolution: {integrity: sha512-rOeAIkcVZW6oYox2Jc1z/00iLVx0w0cIlcD/TbR798Qg5M5/nhErtjSG08QAtuaPSxAFKNl5ipAD8HHGV5esJw==} + dependencies: + default-value: 1.0.0 + error-chain: 0.1.3 + + /@promistream/from-iterable@0.1.0: + resolution: {integrity: sha512-P4wehrvRZu/QTkN0fBNvItZD1jwchv1p76q4yirXIDQclA08mN2QMR6heFLMSBYD2NPRoX+3smZCsRfJgfcmcA==} + dependencies: + '@promistream/end-of-stream': 0.1.2 + '@promistream/simple-source': 0.1.4 + '@validatem/core': 0.3.17 + '@validatem/error': 1.1.0 + '@validatem/required': 0.1.1 + dev: true + + /@promistream/is-aborted@0.1.1: + resolution: {integrity: sha512-2AYo+MFu0wNKXCEDHexaFWoESiUzHfGZgWpazbdA6OyU/AJsHRfMwKzE7awmgi1u0T43k5nLwwJXIiTypajSiw==} + dev: true + + /@promistream/is-end-of-stream@0.1.1: + resolution: {integrity: sha512-GZn7W0wrUen7kkgWCcwFFgr0g/ftfuddnuK/Tp0MLWCCJA4hyAboglCZP0JzEJdi34gClEP8lCfDwGekw18LHg==} + dev: true + + /@promistream/no-value@1.0.0: + resolution: {integrity: sha512-PY/1gj60YKRRpzLY0UyM/b1OzXZS+5lvrVMrU3BzjTDv31P0EaCAb2X39DKQAfoX0ygiXOHewCaLVX1/+IZsTA==} + dev: false + + /@promistream/pipe@0.1.6: + resolution: {integrity: sha512-B/n4WPJ/goXALCWJYgZV0M/lLMIF5OuaqvxezJq/lcSCo9RuV82wmdJBZd+IEmc6Ykn/EYTFtUHCnRjkl56+3w==} + dependencies: + '@validatem/allow-extra-properties': 0.1.0 + '@validatem/anything': 0.1.0 + '@validatem/array-of': 0.1.3 + '@validatem/core': 0.3.17 + '@validatem/error': 1.1.0 + '@validatem/remove-nullish-items': 0.1.0 + '@validatem/required': 0.1.1 + '@validatem/wrap-error': 0.3.0 + dev: true + + /@promistream/propagate-abort@0.1.7: + resolution: {integrity: sha512-BR0XZMirAjO1IRpyTtOG4n0fGuuvRGJsO8Hmn4HOJXhi10onX3GlfCNZN2tqe4Mq/5fEDgRNGNUHjCY7naDYUA==} + dev: true + + /@promistream/propagate-peek@0.1.1: + resolution: {integrity: sha512-4xfkSmtPQzlvL4+KCquPHX7sPXiAACGJac/y7fB3Sv6ZKXAT/cjTfms1nEjlDGn1nroN0MzReBza2HnpF59deg==} + dev: true + + /@promistream/simple-sink@0.1.1: + resolution: {integrity: sha512-M6dQMUIPjFTRB+xIwBMqIrPghWORoreGoNAl2F/5oshBlX6+X2F+RAeUuz6plDymwq2eoVL5pvSUR4zYdMdRjQ==} + dependencies: + '@promistream/is-aborted': 0.1.1 + '@promistream/is-end-of-stream': 0.1.1 + '@promistream/propagate-abort': 0.1.7 + '@promistream/propagate-peek': 0.1.1 + '@validatem/core': 0.3.17 + '@validatem/default-to': 0.1.0 + '@validatem/is-function': 0.1.0 + '@validatem/required': 0.1.1 + '@validatem/wrap-value-as-option': 0.1.0 + bluebird: 3.7.2 + dev: true + + /@promistream/simple-source@0.1.4: + resolution: {integrity: sha512-dMAVpcX2WC40IVMA6zvSAcgwxXjDVj4QIQzOyDdXgOnKjCRnGPhtUvK2ST5Jiw8/lVpEYx0bviqgezttU3IaFg==} + dependencies: + '@joepie91/unreachable': 1.0.0 + '@promistream/aborted': 0.1.2 + '@promistream/end-of-stream': 0.1.2 + '@promistream/is-end-of-stream': 0.1.1 + '@validatem/core': 0.3.17 + '@validatem/is-function': 0.1.0 + '@validatem/required': 0.1.1 + '@validatem/wrap-value-as-option': 0.1.0 + bluebird: 3.7.2 + error-chain: 0.1.3 + dev: true + + /@validatem/allow-extra-properties@0.1.0: + resolution: {integrity: sha512-9jihpYxw1vp4FdjnbN0bTVZMLYv//9OjFNTsVLG5OV4xHESwtgkgQEF5/N5rY1iBwoH/pcKuRl44MBZ8eMdrKw==} + dependencies: + '@validatem/with-context': 0.1.2 + + /@validatem/annotate-errors@0.1.2: + resolution: {integrity: sha512-EuX7pzdYI/YpTmZcgdPG481Oi3elAg8JWh/LYXuE1h6MaZk3A8eP5DD33/l7EoKzrysn6y8nCsqNa1ngei562w==} + dependencies: + '@validatem/match-validation-error': 0.1.0 + + /@validatem/any-property@0.1.3: + resolution: {integrity: sha512-jYWxif5ff9pccu7566LIQ/4+snlApXEJUimBywzAriBgS3r4eDBbz3oZFHuiPmhxNK/NNof5YUS+L6Sk3zaMfg==} + dependencies: + '@validatem/annotate-errors': 0.1.2 + '@validatem/combinator': 0.1.2 + '@validatem/error': 1.1.0 + '@validatem/validation-result': 0.1.2 + '@validatem/virtual-property': 0.1.0 + default-value: 1.0.0 + + /@validatem/anything@0.1.0: + resolution: {integrity: sha512-VJcygPpLw2fAhh29m2qL1AybHY7Ewl7xpvVgNIZpqUwMsSZXWSmzmbZhqE4Sr6Wy2n6FbZVzVoUFREO589SPcQ==} + dev: true + + /@validatem/array-of@0.1.3: + resolution: {integrity: sha512-awaNPfmhv91tI3916WTwGaUq4mFpqJbNXiBFdeTzVp4S2KmczelVwIpZ6gyzvfXFOlQTVtq65RjD7C/G8u4n0Q==} + dependencies: + '@validatem/annotate-errors': 0.1.2 + '@validatem/combinator': 0.1.2 + '@validatem/is-array': 0.1.1 + '@validatem/validation-result': 0.1.2 + '@validatem/with-context': 0.1.2 + dev: true + + /@validatem/combinator@0.1.2: + resolution: {integrity: sha512-vE8t1tNXknmN62FlN6LxQmA2c6TwVKZ+fl/Wit3H2unFdOhu7SZj2kRPGjAXdK/ARh/3svYfUBeD75pea0j1Sw==} + + /@validatem/core@0.3.17: + resolution: {integrity: sha512-VahE9TAKpaU13BcVQI/Dc9j/xsm/BgloRM0v1HjOMpoJ16tOkKQkUdOgiDCG4zmEek1bG3v9Zu4lS1lubgjLMw==} + dependencies: + '@validatem/annotate-errors': 0.1.2 + '@validatem/any-property': 0.1.3 + '@validatem/error': 1.1.0 + '@validatem/match-validation-error': 0.1.0 + '@validatem/match-versioned-special': 0.1.1 + '@validatem/match-virtual-property': 0.1.0 + '@validatem/normalize-rules': 0.1.3 + '@validatem/required': 0.1.1 + '@validatem/validation-result': 0.1.2 + '@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 + flatten: 1.0.3 + indent-string: 4.0.0 + is-arguments: 1.1.1 + supports-color: 7.2.0 + syncpipe: 1.0.0 + + /@validatem/core@0.5.0: + resolution: {integrity: sha512-hLEdoRFRvFGUqHFFK0eR8r7sTJaqQjzB81FVMp86esZJiBrblnWhpZtzVouguoaAaKFX9oiWI3nAQc73xYrTJg==} + dependencies: + '@validatem/annotate-errors': 0.1.2 + '@validatem/any-property': 0.1.3 + '@validatem/error': 1.1.0 + '@validatem/match-validation-error': 0.1.0 + '@validatem/match-versioned-special': 0.1.1 + '@validatem/match-virtual-property': 0.1.0 + '@validatem/normalize-rules': 0.1.3 + '@validatem/required': 0.1.1 + '@validatem/validation-result': 0.1.2 + '@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.1.1 + supports-color: 7.2.0 + syncpipe: 1.0.0 + dev: false + + /@validatem/default-to@0.1.0: + resolution: {integrity: sha512-UE/mJ6ZcHFlBLUhX75PQHDRYf80GFFhB+vZfIcsEWduh7Nm6lTMDnCPj4MI+jd9E/A7HV5D1yCZhaRSwoWo4vg==} + dependencies: + is-callable: 1.2.7 + + /@validatem/dynamic@0.1.2: + resolution: {integrity: sha512-TNZMUO9McL2kFYdLWTYSD+zxxZ9fbK9Si+3X5u/JngOWAq7PFxbU7o2oxREkwiSIZi5cjBCK/hvrZMWyl+FWEA==} + dependencies: + '@validatem/combinator': 0.1.2 + + /@validatem/either@0.1.9: + resolution: {integrity: sha512-cUqlRjy02qDcZ166/D6duk8lrtqrHynHuSakU0TvMGMBiLzjWpMJ+3beAWHe+kILB5/dlXVyc68ZIjSNhBi8Kw==} + dependencies: + '@validatem/combinator': 0.1.2 + '@validatem/error': 1.1.0 + '@validatem/match-validation-error': 0.1.0 + '@validatem/validation-result': 0.1.2 + flatten: 1.0.3 + dev: true + + /@validatem/error@1.1.0: + resolution: {integrity: sha512-gZJEoZq1COi/8/5v0fVKQ9uX54x5lb5HbV7mzIOhY6dqjmLNfxdQmpECZPQrCAOpcRkRMJ7zaFhq4UTslpY9yA==} + + /@validatem/forbidden@0.1.0: + resolution: {integrity: sha512-5GpgXt33z15oXZJwd+BKzEcX56YrU1Ysqe3NM20L9OzuSCJYbWU6xR6mMHkYVfF3TDLfkC8csOiKG2UnduCLhw==} + dependencies: + '@validatem/error': 1.1.0 + + /@validatem/has-shape@0.1.8: + resolution: {integrity: sha512-x2i8toW1uraFF2Vl6WBl4CScbBeg5alrtoCKMyXbJkHf2B5QxL/ftUh2RQRcBzx6U0i7KUb8vdShcWAa+fehRQ==} + dependencies: + '@validatem/annotate-errors': 0.1.2 + '@validatem/combinator': 0.1.2 + '@validatem/error': 1.1.0 + '@validatem/validation-result': 0.1.2 + array-union: 2.1.0 + as-expression: 1.0.0 + assure-array: 1.0.0 + default-value: 1.0.0 + flatten: 1.0.3 + + /@validatem/is-array@0.1.1: + resolution: {integrity: sha512-XD3C+Nqfpnbb4oO//Ufodzvui7SsCIW/stxZ39dP/fyRsBHrdERinkFATH5HepegtDlWMQswm5m1XFRbQiP2oQ==} + dependencies: + '@validatem/error': 1.1.0 + dev: true + + /@validatem/is-boolean@0.1.1: + resolution: {integrity: sha512-eIFq+mCBEDgAp4ezaPn1mbVZd2H+IkQG3CcEFnLSlqfg1XKY5uv8AOI08+UqeWS+C7AIFk3rEqRg63+OuPCpsg==} + dependencies: + '@validatem/error': 1.1.0 + is-boolean-object: 1.1.2 + + /@validatem/is-function@0.1.0: + resolution: {integrity: sha512-UtVrwTGhaIdIJ0mPG5XkAmYZUeWgRoMP1G9ZEHbKvAZJ4+SXf/prC0jPgE0pw+sPjdQG4hblsXSfo/9Bf3PGdQ==} + dependencies: + '@validatem/error': 1.1.0 + is-callable: 1.2.7 + + /@validatem/is-integer@0.1.0: + resolution: {integrity: sha512-sSp66uxfirIFMqro64DAdfM+UKo+IICmHdy/x3ZJXUM9F4byz/GyFmhR4wfcQswywwF1fqKw9458GE38fozjOQ==} + dependencies: + '@validatem/error': 1.1.0 + '@validatem/is-number': 0.1.3 + dev: false + + /@validatem/is-number@0.1.3: + resolution: {integrity: sha512-GjnbKYfYa0cTCJmsr5OUbylxTKHHZ6FDtJixWl+lEuXzeELDoYRp2UAjzfjTXJ9g2BumESqI/t0hap5rw5tEyQ==} + dependencies: + '@validatem/error': 1.1.0 + is-number-object: 1.0.7 + dev: false + + /@validatem/is-plain-object@0.1.1: + resolution: {integrity: sha512-aNGbNIbKRpYI0lRBczlTBbiA+nqN52ADAASdySKg2/QeSCVtYS4uOIeCNIJRAgXe/5sUnLTuL4pgq628uAl7Kw==} + dependencies: + '@validatem/error': 1.1.0 + is-plain-obj: 2.1.0 + + /@validatem/is-positive@1.0.0: + resolution: {integrity: sha512-ei8YL+IxwdZd7QGaR9coAo/MJRJKMqN3RunoM6lLbtFGPJyMa6hOlcLWiZ9UmRI9qE96YUHr+AI80AJ91SeOYg==} + dependencies: + '@validatem/error': 1.1.0 + '@validatem/is-number': 0.1.3 + is-negative-zero: 2.0.3 + dev: false + + /@validatem/is-string@0.1.1: + resolution: {integrity: sha512-iyRVYRPgRt2ZlWyc7pzN1WkO6apzE8at39XQa4WUr8qRPfJn12V4khS9MumWbZs8N2qqajrxMigB2LJUCKOCRg==} + dependencies: + '@validatem/error': 1.1.0 + is-string: 1.0.7 + + /@validatem/match-special@0.1.0: + resolution: {integrity: sha512-TFiq9Wk/1Hoja4PK85WwNYnwBXk3+Lgoj59ZIMxm2an1qmNYp8j+BnSvkKBflba451yIn6V1laU9NJf+/NYZgw==} + + /@validatem/match-validation-error@0.1.0: + resolution: {integrity: sha512-6akGTk7DdulOreyqDiGdikwRSixQz/AlvARSX18dcWaTFc79KxCLouL2hyoFcor9IIUhu5RTY4/i756y4T1yxA==} + dependencies: + '@validatem/match-versioned-special': 0.1.1 + + /@validatem/match-versioned-special@0.1.1: + resolution: {integrity: sha512-RRNeFSgzqSo0sKck/92a+yC9zKdt+DD6y4TK70+VDKVppdWsb8YzC/FBTucseN1OYrr1KcBPKNVZePg1NTROYw==} + + /@validatem/match-virtual-property@0.1.0: + resolution: {integrity: sha512-ssd3coFgwbLuqvZftLZTy3eHN0TFST8oTS2XTViQdXJPXVoJmwEKBpFhXgwnb5Ly1CE037R/KWpjhd1TP/56kQ==} + + /@validatem/normalize-rules@0.1.3: + resolution: {integrity: sha512-HHPceAP2ce9NWymIZrgLCTzpdwXNRBCCB5H6ZPc5ggOrbmh4STpT83fLazleHtvYNlqgXZ4GjQOvCwrjaM+qEA==} + dependencies: + '@validatem/has-shape': 0.1.8 + '@validatem/is-plain-object': 0.1.1 + '@validatem/match-special': 0.1.0 + assure-array: 1.0.0 + default-value: 1.0.0 + flatten: 1.0.3 + is-plain-obj: 2.1.0 + + /@validatem/one-of@0.1.1: + resolution: {integrity: sha512-lIgxnkNRouPx5Ydddi8OaAxmzp1ox44OJnrJPRrJkU4ccz9Yb7GSJ+wQJNVkAZCar+DGTDMoXoy51NwDnsf4sw==} + dependencies: + '@validatem/error': 1.1.0 + + /@validatem/remove-nullish-items@0.1.0: + resolution: {integrity: sha512-cs4YSF47TA/gHnV5muSUUqGi5PwybP5ztu5SYnPKxQVTyubvcbrFat51nOvJ2PmUasyrIccoYMmATiviXkTi6g==} + dev: true + + /@validatem/required@0.1.1: + resolution: {integrity: sha512-vI4NzLfay4RFAzp7xyU34PHb8sAo6w/3frrNh1EY9Xjnw2zxjY5oaxwmbFP1jVevBE6QQEnKogtzUHz/Zuvh6g==} + + /@validatem/validation-result@0.1.2: + resolution: {integrity: sha512-okmP8JarIwIgfpaVcvZGuQ1yOsLKT3Egt49Ynz6h1MAeGsP/bGHXkkXtbiWOVsk5Tzku5vDVFSrFnF+5IEHKxw==} + dependencies: + default-value: 1.0.0 + + /@validatem/virtual-property@0.1.0: + resolution: {integrity: sha512-JUUvWtdqoSkOwlsl20oB3qFHYIL05a/TAfdY4AJcs55QeVTiX5iI1b8IoQW644sIWWooBuLv+XwoxjRsQFczlQ==} + + /@validatem/with-context@0.1.2: + resolution: {integrity: sha512-noAWf4CsmU+BCz+KOg3GPq9+R9BQLWOQnOgWVfkYHFdLnnbLhl8w/ONdzvFzUYGHIZGKZwsWVCp+Kwz/tAfMnA==} + dependencies: + '@validatem/combinator': 0.1.2 + + /@validatem/wrap-error@0.1.3: + resolution: {integrity: sha512-86ANJACPGbH8jD/C/tUTZNgQh9xCePUKq4wf5ZRcwOvtIDaZO98FI9cdoT2/zS1CzQCp3VWlwz16YT6FNjJJJA==} + dependencies: + '@validatem/combinator': 0.1.2 + '@validatem/error': 1.1.0 + '@validatem/match-validation-error': 0.1.0 + '@validatem/validation-result': 0.1.2 + as-expression: 1.0.0 + default-value: 1.0.0 + split-filter-n: 1.1.3 + + /@validatem/wrap-error@0.3.0: + resolution: {integrity: sha512-km5v6F/Xm7j8W/tmCmht2BTzxMLSpBUJ5MdhJD7ABEut/fdO0tNca1u1imTnWCULCJcdDHbNtpSmDMvXFg3E7Q==} + dependencies: + '@validatem/combinator': 0.1.2 + '@validatem/error': 1.1.0 + '@validatem/match-validation-error': 0.1.0 + '@validatem/validation-result': 0.1.2 + as-expression: 1.0.0 + default-value: 1.0.0 + split-filter-n: 1.1.3 + dev: true + + /@validatem/wrap-value-as-option@0.1.0: + resolution: {integrity: sha512-gWDkfyU0DOsbinE9iqvRSJ+NxuynChyueJsC+AFm3EYbe8+s7V2gRs3qkJ4mq7hOlUbEh8tgCWQfZZvr+IdVFw==} + dependencies: + '@validatem/either': 0.1.9 + '@validatem/is-plain-object': 0.1.1 + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + /as-expression@1.0.0: + resolution: {integrity: sha512-Iqh4GxNUfxbJdGn6b7/XMzc8m1Dz2ZHouBQ9DDTzyMRO3VPPIAXeoY/sucRxxxXKbUtzwzWZSN6jPR3zfpYHHA==} + + /assure-array@1.0.0: + resolution: {integrity: sha512-igvOvGYidAcJKr6YQIHzLivUpAdqUfi7MN0QfrEnFtifQvuw6D0W4oInrIVgTaefJ+QBVWAj8ZYuUGNnwq6Ydw==} + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + /capture-promise@1.0.0: + resolution: {integrity: sha512-40FXZr0YaUWw2q6T8DcUOIF885saJni87ZbAOXkwDB14nMl6M1vIYAKUs2BjoeMyqnv3PGqEcDskGUXvgNIbZw==} + dev: false + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /clone-regexp@2.2.0: + resolution: {integrity: sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==} + engines: {node: '>=6'} + dependencies: + is-regexp: 2.1.0 + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /create-error@0.3.1: + resolution: {integrity: sha512-n/Q4aSCtYuuDneEW5Q+nd0IIZwbwmX/oF6wKcDUhXGJNwhmp2WHEoWKz7X+/H7rBtjimInW7f0ceouxU0SmuzQ==} + + /debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /default-value@1.0.0: + resolution: {integrity: sha512-y6j7G55tgWG7nfjXUNy/WkTLGExiPEUlhGv0zqgqKdlOwJnDDy/dbk7yCozn4biAGIRnMI+9fyZ1V2fZ7tjp6Q==} + dependencies: + es6-promise-try: 0.0.1 + + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + /error-chain@0.1.3: + resolution: {integrity: sha512-Hx/Yd7w6ku+bTIGzPxdgKAoZSADCf4EnM9CEcIyr75vw/FH/wbZ23YnKKv7ZQB80F4s7ZSVJ/9UPXk03SQsACQ==} + dependencies: + '@validatem/allow-extra-properties': 0.1.0 + '@validatem/core': 0.3.17 + '@validatem/default-to': 0.1.0 + '@validatem/dynamic': 0.1.2 + '@validatem/error': 1.1.0 + '@validatem/forbidden': 0.1.0 + '@validatem/is-boolean': 0.1.1 + '@validatem/is-function': 0.1.0 + '@validatem/is-plain-object': 0.1.1 + '@validatem/is-string': 0.1.1 + '@validatem/one-of': 0.1.1 + '@validatem/required': 0.1.1 + '@validatem/wrap-error': 0.1.3 + chalk: 2.4.2 + fromentries: 1.3.2 + is.object: 1.0.0 + syncpipe: 1.0.0 + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + /es6-promise-try@0.0.1: + resolution: {integrity: sha512-T6f3cNyF8y+3uua2IDGpGmeoDe2w7PXGfPGS94TyLfQLPzYVvZUfM8dQuN4DuVXpelK4tg9F7zKzZHzNS2f2IQ==} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /execall@2.0.0: + resolution: {integrity: sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==} + engines: {node: '>=8'} + dependencies: + clone-regexp: 2.2.0 + + /flatten@1.0.3: + resolution: {integrity: sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==} + deprecated: flatten is deprecated in favor of utility frameworks such as lodash. + + /fromentries@1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.4 + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: false + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + /is-regexp@2.1.0: + resolution: {integrity: sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==} + engines: {node: '>=6'} + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + + /is.object@1.0.0: + resolution: {integrity: sha512-BdDP6tLXkf0nrCnksLobALJxkt2hmrVL6ge1oRuzGU4Lb9NpreEbhhuCcY6HMzx/qo3Dff9DJ3jf0x9+U0bNMQ==} + engines: {node: '>=6.1'} + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + + /push-buffer@1.1.1: + resolution: {integrity: sha512-K7pUfiHoobqHkYAlpvSHaJ7GED0gGoKj9R5BgxMzkmldPrsL6EJQr5KBFYFV2fYqDK5hIllOQySb6ftM3oAG9w==} + dependencies: + '@joepie91/promise-defer': 1.0.1 + '@promistream/no-value': 1.0.0 + '@validatem/core': 0.5.0 + '@validatem/default-to': 0.1.0 + '@validatem/dynamic': 0.1.2 + '@validatem/is-boolean': 0.1.1 + '@validatem/is-function': 0.1.0 + '@validatem/is-integer': 0.1.0 + '@validatem/one-of': 0.1.1 + '@validatem/required': 0.1.1 + assure-array: 1.0.0 + capture-promise: 1.0.0 + debug: 4.3.5 + single-concurrent: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /range@0.0.3: + resolution: {integrity: sha512-OxK2nY2bmeEB4NxoBraQIBOOeOIxoBvm6yt8MA1kLappgkG3SyLf173iOtT5woWycrtESDD2g0Nl2yt8YPoUnw==} + engines: {node: '>=0.8'} + dev: false + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + /single-concurrent@1.0.0: + resolution: {integrity: sha512-lYx5vhQB1jhpVnS11rAZLTDId3E3cJFCteOvl6tsXmRPm1hfCQGFXFAgP12gUQJ4MRh3Cvt8eXwmnE8RIimzGw==} + dependencies: + '@validatem/core': 0.5.0 + '@validatem/is-function': 0.1.0 + '@validatem/required': 0.1.1 + capture-promise: 1.0.0 + debug: 4.3.5 + transitivePeerDependencies: + - supports-color + dev: false + + /split-filter-n@1.1.3: + resolution: {integrity: sha512-EU0EjvBI/mYBQMSAHq+ua/YNCuThuDjbU5h036k01+xieFW1aNvLNKb90xLihXIz5xJQX4VkEKan4LjSIyv7lg==} + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /syncpipe@1.0.0: + resolution: {integrity: sha512-cdiAFTnFJRvUaNPDc2n9CqoFvtIL3+JUMJZrC3kA3FzpugHOqu0TvkgNwmnxPZ5/WjAzMcfMS3xm+AO7rg/j/w==} + dependencies: + assure-array: 1.0.0