@dmail/action
Advanced tools
Comparing version
@@ -67,5 +67,5 @@ "use strict"; | ||
var _composeWithAllocatedMs = require("./src/composeWithAllocatedMs/composeWithAllocatedMs.js"); | ||
var _collect = require("./src/collect/collect.js"); | ||
Object.keys(_composeWithAllocatedMs).forEach(function (key) { | ||
Object.keys(_collect).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
@@ -75,3 +75,3 @@ Object.defineProperty(exports, key, { | ||
get: function get() { | ||
return _composeWithAllocatedMs[key]; | ||
return _collect[key]; | ||
} | ||
@@ -188,14 +188,2 @@ }); | ||
}); | ||
var _withAllocableMs = require("./src/withAllocableMs/withAllocableMs.js"); | ||
Object.keys(_withAllocableMs).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function get() { | ||
return _withAllocableMs[key]; | ||
} | ||
}); | ||
}); | ||
//# sourceMappingURL=index.js.map |
@@ -6,13 +6,17 @@ "use strict"; | ||
}); | ||
exports.isAction = exports.createAction = exports.isThenable = void 0; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
// more or less equivalent to | ||
// http://folktale.origamitower.com/api/v2.0.0/en/folktale.result.html | ||
// http://folktale.origamitower.com/api/v2.0.0/en/folktale.validation.html | ||
var isAction = exports.isAction = function isAction(value) { | ||
return value && typeof value.then === "function"; | ||
var _mixin = require("@dmail/mixin"); | ||
var isThenable = exports.isThenable = function isThenable(value) { | ||
if (_typeof(value) === "object" || typeof value === "function") { | ||
return typeof value.then === "function"; | ||
} | ||
}; | ||
var createAction = exports.createAction = function createAction() { | ||
var actionTalent = function actionTalent(_ref) { | ||
var unwrapThenable = _ref.unwrapThenable, | ||
valueOf = _ref.valueOf; | ||
var state = "unknown"; | ||
@@ -22,3 +26,2 @@ var result = void 0; | ||
var ignoreNext = false; | ||
var action = {}; | ||
@@ -49,9 +52,9 @@ var isPassing = function isPassing() { | ||
var pendingActions = []; | ||
var pendingHandlers = []; | ||
var runPendingActions = function runPendingActions() { | ||
pendingActions.forEach(function (pendingAction) { | ||
pendingAction.fn(action, result); | ||
var runPendingHandlers = function runPendingHandlers() { | ||
pendingHandlers.forEach(function (handler) { | ||
return handler(); | ||
}); | ||
pendingActions.length = 0; | ||
pendingHandlers.length = 0; | ||
}; | ||
@@ -62,4 +65,6 @@ | ||
if (isAction(value)) { | ||
if (value === action) { | ||
if ((0, _mixin.hasTalent)(actionTalent, value)) { | ||
// it would be a problem if value was an action derived | ||
// we should check with something reading getPrototypeOf | ||
if (value === valueOf()) { | ||
throw new Error("an action cannot pass/fail with itself"); | ||
@@ -73,6 +78,12 @@ } | ||
}); | ||
} else if (unwrapThenable && isThenable(value)) { | ||
value.then(function (value) { | ||
return handleResult(value, true); | ||
}, function (value) { | ||
return handleResult(value, false); | ||
}); | ||
} else { | ||
state = passing ? "passed" : "failed"; | ||
result = value; | ||
runPendingActions(); | ||
runPendingHandlers(); | ||
} | ||
@@ -126,3 +137,6 @@ }; | ||
var then = function then(onPassed, onFailed) { | ||
var nextAction = createAction(); | ||
// ici il faudrais ptet un lastvalueOf | ||
// sinon on replicate juste cette action mais on propage | ||
// pas les éventuel talents ajouté dynamiquement après | ||
var nextAction = (0, _mixin.replicate)(valueOf()); | ||
@@ -148,5 +162,3 @@ var nextActionHandler = function nextActionHandler() { | ||
if (isRunning()) { | ||
pendingActions.push({ | ||
fn: nextActionHandler | ||
}); | ||
pendingHandlers.push(nextActionHandler); | ||
} else { | ||
@@ -172,26 +184,3 @@ nextActionHandler(); | ||
var mixin = function mixin() { | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
// maybe allow only function, add use defineProperty to make them non enumerable ? | ||
args.forEach(function (arg) { | ||
var properties = typeof arg === "function" ? arg(action) : arg; | ||
if (properties && _typeof(properties) === "object") { | ||
Object.keys(properties).forEach(function (property) { | ||
if (action.hasOwnProperty(property)) { | ||
throw new Error("action mixin error: ".concat(property, " property exists")); | ||
} | ||
action[property] = properties[property]; | ||
}); | ||
} | ||
}); | ||
return action; | ||
}; | ||
return mixin(action, { | ||
mixin: mixin, | ||
return { | ||
getState: getState, | ||
@@ -209,3 +198,19 @@ getResult: getResult, | ||
then: then | ||
}); | ||
}; | ||
}; | ||
var createAction = exports.createAction = function createAction() { | ||
var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
_ref2$unwrapThenable = _ref2.unwrapThenable, | ||
unwrapThenable = _ref2$unwrapThenable === void 0 ? true : _ref2$unwrapThenable; | ||
return (0, _mixin.mixin)(_mixin.pure, function () { | ||
return { | ||
unwrapThenable: unwrapThenable | ||
}; | ||
}, actionTalent); | ||
}; | ||
var isAction = exports.isAction = function isAction(value) { | ||
return (0, _mixin.hasTalent)(actionTalent, value); | ||
}; // passed("foo").then(console.log) | ||
@@ -212,0 +217,0 @@ // const fs = require("fs") |
"use strict"; | ||
var _action = require("./action.js"); | ||
var _testCheap = require("@dmail/test-cheap"); | ||
var _action = require("./action.js"); | ||
var _assertions = require("./assertions.js"); | ||
var _mixin = require("@dmail/mixin"); | ||
(0, _testCheap.test)("action.js", function (_ref) { | ||
@@ -153,2 +155,10 @@ var ensure = _ref.ensure; | ||
}); | ||
ensure("action.fail(failedAction), fail with action wrapped value", function () { | ||
var failedAction = (0, _action.createAction)(); | ||
failedAction.fail(10); | ||
var action = (0, _action.createAction)(); | ||
action.fail(failedAction); | ||
(0, _assertions.assertFailed)(action); | ||
(0, _assertions.assertResult)(action, 10); | ||
}); | ||
ensure("action.then(onPass) call onpass immediatly when passed", function () { | ||
@@ -220,50 +230,23 @@ var action = (0, _action.createAction)(); | ||
}); | ||
ensure("action.mixin add property to action", function () { | ||
ensure("pass on talentedAction", function () { | ||
var action = (0, _action.createAction)(); | ||
var foo = function foo() {}; | ||
action.mixin({ | ||
foo: foo | ||
var passedValues = []; | ||
action.then(function (value) { | ||
passedValues.push(value); | ||
}); | ||
_assertions.assert.equal(action.foo, foo); | ||
}); | ||
ensure("action.mixin throw on existing property", function () { | ||
var action = (0, _action.createAction)(); | ||
_assertions.assert.throws(function () { | ||
return action.mixin({ | ||
pass: function pass() {} | ||
}); | ||
}); | ||
}); | ||
ensure("action mixin with a function", function () { | ||
var action = (0, _action.createAction)(); | ||
var firstArg = void 0; | ||
var foo = function foo() {}; | ||
action.mixin(function (arg) { | ||
firstArg = arg; | ||
var talentedAction = (0, _mixin.mixin)(action, function () { | ||
return { | ||
foo: foo | ||
foo: true | ||
}; | ||
}); | ||
talentedAction.then(function (value) { | ||
passedValues.push(value); | ||
}); | ||
talentedAction.pass("yo"); | ||
(0, _assertions.assertPassed)(action); | ||
(0, _assertions.assertPassed)(talentedAction); | ||
_assertions.assert.equal(firstArg, action); | ||
_assertions.assert.equal(action.foo, foo); | ||
_assertions.assert.deepEqual(passedValues, ["yo", "yo"]); | ||
}); | ||
ensure("action mixin can return null", function () { | ||
(0, _action.createAction)().mixin(function () { | ||
return null; | ||
}); | ||
}); | ||
ensure("action mixin returning non object are ignored", function () { | ||
(0, _action.createAction)().mixin(function () { | ||
return true; | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=action.test.js.map |
"use strict"; | ||
var _all = require("./all.js"); | ||
var _testCheap = require("@dmail/test-cheap"); | ||
@@ -7,4 +9,2 @@ | ||
var _all = require("./all.js"); | ||
var _assertions = require("../assertions.js"); | ||
@@ -11,0 +11,0 @@ |
"use strict"; | ||
var _aroundAction = require("./aroundAction.js"); | ||
var _testCheap = require("@dmail/test-cheap"); | ||
@@ -7,4 +9,2 @@ | ||
var _aroundAction = require("./aroundAction.js"); | ||
var _assertions = require("../assertions.js"); | ||
@@ -11,0 +11,0 @@ |
@@ -6,87 +6,119 @@ "use strict"; | ||
}); | ||
exports.collect = void 0; | ||
exports.collectSequenceWithAllocatedMs = exports.collectSequence = void 0; | ||
var _action = require("../action.js"); | ||
var _allocableMsTalent = require("../allocableMsTalent/allocableMsTalent.js"); | ||
var _fromFunction = require("../fromFunction/fromFunction.js"); | ||
var _mixin = require("@dmail/mixin"); | ||
var collect = exports.collect = function collect(iterable) { | ||
return (0, _fromFunction.fromFunction)(function (_ref) { | ||
var fail = _ref.fail, | ||
pass = _ref.pass; | ||
var results = []; | ||
var callCount = 0; | ||
var passedOrFailedCount = 0; | ||
var someHasFailed = false; | ||
var _action = require("../action"); | ||
var checkEnded = function checkEnded() { | ||
passedOrFailedCount++; | ||
var _passed = require("../passed/passed.js"); | ||
if (passedOrFailedCount === callCount) { | ||
var _compose = require("../compose/compose.js"); | ||
var collectSequence = exports.collectSequence = function collectSequence(iterable) { | ||
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
_ref$failureIsCritica = _ref.failureIsCritical, | ||
failureIsCritical = _ref$failureIsCritica === void 0 ? function () { | ||
return false; | ||
} : _ref$failureIsCritica; | ||
var results = []; | ||
var someHasFailed = false; | ||
return (0, _compose.compose)({ | ||
iterator: (0, _compose.createIterator)(iterable), | ||
composer: function composer(_ref2) { | ||
var value = _ref2.value, | ||
state = _ref2.state, | ||
index = _ref2.index, | ||
nextValue = _ref2.nextValue, | ||
done = _ref2.done, | ||
fail = _ref2.fail, | ||
pass = _ref2.pass; | ||
if (index > -1) { | ||
results.push({ | ||
state: state, | ||
result: value | ||
}); | ||
} | ||
if (state === "failed") { | ||
if (failureIsCritical(value)) { | ||
return fail(value); | ||
} | ||
someHasFailed = true; | ||
} | ||
if (done) { | ||
if (someHasFailed) { | ||
fail(results); | ||
} else { | ||
pass(results); | ||
return fail(results); | ||
} | ||
return pass(results); | ||
} | ||
}; | ||
var compositeOnPassed = function compositeOnPassed(result, index) { | ||
results[index] = { | ||
state: "passed", | ||
result: result | ||
}; | ||
checkEnded(); | ||
}; | ||
return nextValue; | ||
} | ||
}); | ||
}; | ||
var compositeOnFailed = function compositeOnFailed(result, index) { | ||
results[index] = { | ||
state: "failed", | ||
result: result | ||
}; | ||
checkEnded(); | ||
}; | ||
var createPassedActionWithAllocatedMs = function createPassedActionWithAllocatedMs(allocatedMs) { | ||
var action = (0, _mixin.mixin)((0, _action.createAction)(), _allocableMsTalent.allocableMsTalent); | ||
action.allocateMs(allocatedMs); | ||
action.pass(); | ||
return action; | ||
}; | ||
var run = function run(value, index) { | ||
if ((0, _action.isAction)(value)) { | ||
value.then(function (result) { | ||
return compositeOnPassed(result, index); | ||
}, function (result) { | ||
return compositeOnFailed(result, index); | ||
var collectSequenceWithAllocatedMs = exports.collectSequenceWithAllocatedMs = function collectSequenceWithAllocatedMs(iterable) { | ||
var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, | ||
_ref3$allocatedMs = _ref3.allocatedMs, | ||
allocatedMs = _ref3$allocatedMs === void 0 ? Infinity : _ref3$allocatedMs; | ||
var results = []; | ||
var someHasFailed = false; | ||
return (0, _compose.compose)({ | ||
from: createPassedActionWithAllocatedMs(allocatedMs), | ||
iterator: (0, _compose.createIterator)(iterable), | ||
composer: function composer(_ref4) { | ||
var action = _ref4.action, | ||
value = _ref4.value, | ||
state = _ref4.state, | ||
index = _ref4.index, | ||
nextValue = _ref4.nextValue, | ||
done = _ref4.done, | ||
fail = _ref4.fail, | ||
pass = _ref4.pass; | ||
if (index > -1) { | ||
results.push({ | ||
state: state, | ||
result: value | ||
}); | ||
} else { | ||
compositeOnPassed(value, index); | ||
} | ||
}; | ||
var index = 0; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
if (state === "failed") { | ||
if ((0, _allocableMsTalent.failureIsOutOfMs)(value)) { | ||
return fail(value); | ||
} | ||
try { | ||
for (var _iterator = iterable[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _value = _step.value; | ||
run(_value, index); | ||
callCount++; | ||
index++; | ||
someHasFailed = true; | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
if (done) { | ||
if (someHasFailed) { | ||
return fail(results); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
return pass(results); | ||
} | ||
var nextActionWithAllocableMs = (0, _mixin.mixin)((0, _passed.passed)(nextValue), _allocableMsTalent.allocableMsTalent); | ||
nextActionWithAllocableMs.allocateMs(action.getRemainingMs()); | ||
return nextActionWithAllocableMs; | ||
} | ||
checkEnded(); | ||
}); | ||
}; | ||
}; // export const collectConcurrent = (iterable, allocatedMs = Infinity) | ||
// export const collectConcurrentWithAllocatedMs = (iterable, allocatedMs = Infinity) | ||
//# sourceMappingURL=collect.js.map |
@@ -6,69 +6,110 @@ "use strict"; | ||
}); | ||
exports.composeTogether = exports.composeSequence = void 0; | ||
exports.compose = exports.createIterator = void 0; | ||
var _action = require("../action.js"); | ||
var _passed = require("../passed/passed.js"); | ||
var _all = require("../all/all.js"); | ||
var _fromFunction = require("../fromFunction/fromFunction.js"); | ||
var _sequence = require("../sequence/sequence.js"); | ||
var createIterator = exports.createIterator = function createIterator(iterable) { | ||
var iterator = iterable[Symbol.iterator](); | ||
var currentIndex = 0; | ||
var _passed = require("../passed/passed.js"); | ||
var iterate = function iterate() { | ||
var next = iterator.next(); | ||
var index = currentIndex; | ||
currentIndex++; | ||
return { | ||
done: next.done, | ||
value: next.value, | ||
index: index, | ||
iterable: iterable | ||
}; | ||
}; | ||
var _failed = require("../failed/failed.js"); | ||
return { | ||
iterate: iterate, | ||
iterable: iterable | ||
}; | ||
}; | ||
var _fromFunction = require("../fromFunction/fromFunction.js"); | ||
var compose = exports.compose = function compose(_ref) { | ||
var from = _ref.from, | ||
iterator = _ref.iterator, | ||
composer = _ref.composer; | ||
return (0, _fromFunction.fromFunction)(function (_ref2) { | ||
var fail = _ref2.fail, | ||
pass = _ref2.pass; | ||
var iterable = iterator.iterable, | ||
iterate = iterator.iterate; | ||
var pending = true; | ||
var _mapIterable = require("../mapIterable.js"); | ||
var breakAndPass = function breakAndPass(value) { | ||
pending = false; | ||
pass(value); | ||
}; | ||
var defaultHandle = function defaultHandle(_, value) { | ||
return (0, _passed.passed)(value); | ||
}; | ||
var breakAndFail = function breakAndFail(value) { | ||
pending = false; | ||
fail(value); | ||
}; | ||
var compose = function compose(iterable, _ref) { | ||
var _ref$handle = _ref.handle, | ||
handle = _ref$handle === void 0 ? defaultHandle : _ref$handle, | ||
composer = _ref.composer, | ||
_ref$failureIsCritica = _ref.failureIsCritical, | ||
failureIsCritical = _ref$failureIsCritica === void 0 ? function () { | ||
return false; | ||
} : _ref$failureIsCritica; | ||
var unwrap = function unwrap(value, handler) { | ||
var action = (0, _passed.passed)(value); | ||
action.then(function (value) { | ||
return handler(action, value, "passed"); | ||
}, function (value) { | ||
return handler(action, value, "failed"); | ||
}); | ||
}; | ||
var map = function map(value, index) { | ||
return (0, _fromFunction.mutateAction)((0, _action.isAction)(value) ? value : (0, _action.createAction)(), function (action) { | ||
return handle(action, value, index, iterable); | ||
}).then(function (result) { | ||
return { | ||
state: "passed", | ||
result: result | ||
}; | ||
}, // transform failed into passed so that sequence & all does not stop on first failure | ||
function (result) { | ||
return failureIsCritical(result) ? result : (0, _passed.passed)({ | ||
state: "failed", | ||
result: result | ||
var handleUnknown = function handleUnknown(action, value, state) { | ||
var _iterate = iterate(), | ||
done = _iterate.done, | ||
nextValue = _iterate.value, | ||
nextIndex = _iterate.index; | ||
var composerResult = composer({ | ||
index: nextIndex - 1, | ||
nextIndex: nextIndex, | ||
value: value, | ||
nextValue: nextValue, | ||
action: action, | ||
state: state, | ||
iterable: iterable, | ||
done: done, | ||
pass: breakAndPass, | ||
fail: breakAndFail | ||
}); | ||
}); | ||
}; | ||
iterable = (0, _mapIterable.mapIterable)(iterable, map); | ||
return composer(iterable).then( // but once are done, refails it when needed | ||
function (reports) { | ||
return reports.some(function (_ref2) { | ||
var state = _ref2.state; | ||
return state === "failed"; | ||
}) ? (0, _failed.failed)(reports) : (0, _passed.passed)(reports); | ||
}); | ||
}; | ||
if (pending) { | ||
if (done) { | ||
var handleLast = function handleLast(action, value, state) { | ||
composer({ | ||
index: nextIndex, | ||
nextIndex: nextIndex + 1, | ||
value: value, | ||
nextValue: undefined, | ||
action: action, | ||
state: state, | ||
iterable: iterable, | ||
done: done, | ||
pass: breakAndPass, | ||
fail: breakAndFail | ||
}); | ||
var composeSequence = exports.composeSequence = function composeSequence(iterable, params) { | ||
return compose(iterable, Object.assign({ | ||
composer: _sequence.sequence | ||
}, params)); | ||
}; | ||
if (pending) { | ||
throw new Error("composer must fail or pass when iteration is done"); | ||
} | ||
}; | ||
var composeTogether = exports.composeTogether = function composeTogether(iterable, params) { | ||
return compose(iterable, Object.assign({ | ||
composer: _all.all | ||
}, params)); | ||
unwrap(composerResult, handleLast); | ||
} else { | ||
unwrap(composerResult, handleUnknown); | ||
} | ||
} | ||
}; | ||
unwrap(from, handleUnknown); | ||
}); | ||
}; | ||
//# sourceMappingURL=compose.js.map |
"use strict"; | ||
var _compose = require("./compose.js"); | ||
var _testCheap = require("@dmail/test-cheap"); | ||
var _action = require("../action.js"); | ||
var _assert = require("assert"); | ||
var _passed = require("../passed/passed.js"); | ||
var _assert2 = _interopRequireDefault(_assert); | ||
var _failed = require("../failed/failed.js"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _compose = require("./compose.js"); | ||
var _assertions = require("../assertions.js"); | ||
(0, _testCheap.test)("compose.js", function (_ref) { | ||
var ensure = _ref.ensure; | ||
ensure("composeSequence with values", function () { | ||
var action = (0, _compose.composeSequence)([0, 1]); | ||
(0, _assertions.assertPassed)(action); | ||
_assertions.assert.deepEqual(action.getResult(), [{ | ||
state: "passed", | ||
result: 0 | ||
}, { | ||
state: "passed", | ||
result: 1 | ||
}]); | ||
}); | ||
ensure("composeSequence collect passed action", function () { | ||
var action = (0, _compose.composeSequence)([(0, _passed.passed)(0), (0, _passed.passed)(1)]); | ||
(0, _assertions.assertPassed)(action); | ||
_assertions.assert.deepEqual(action.getResult(), [{ | ||
state: "passed", | ||
result: 0 | ||
}, { | ||
state: "passed", | ||
result: 1 | ||
}]); | ||
}); | ||
ensure("composeSequence collect failed action", function () { | ||
var action = (0, _compose.composeSequence)([(0, _failed.failed)(0), (0, _failed.failed)(1)]); | ||
(0, _assertions.assertFailed)(action); | ||
_assertions.assert.deepEqual(action.getResult(), [{ | ||
state: "failed", | ||
result: 0 | ||
}, { | ||
state: "failed", | ||
result: 1 | ||
}]); | ||
}); | ||
ensure("composeSequence with critical failure", function () { | ||
var action = (0, _compose.composeSequence)([(0, _failed.failed)(0), (0, _failed.failed)(1), (0, _passed.passed)(2)], { | ||
failureIsCritical: function failureIsCritical(failure) { | ||
return failure === 1; | ||
} | ||
ensure("composer must call fail or pass on last iteration", function () { | ||
_assert2.default.throws(function () { | ||
(0, _compose.compose)({ | ||
iterator: (0, _compose.createIterator)([]), | ||
composer: function composer() {} | ||
}); | ||
}, function (e) { | ||
return e.message === "composer must fail or pass when iteration is done"; | ||
}); | ||
(0, _assertions.assertFailed)(action); | ||
(0, _assertions.assertResult)(action, 1); | ||
}); | ||
ensure("composeSequence complex example", function () { | ||
var action = (0, _compose.composeSequence)([0, 1, 2], { | ||
handle: function handle(action, value, index) { | ||
if (index === 0) { | ||
return (0, _passed.passed)(value); | ||
} | ||
if (index === 1) { | ||
return (0, _failed.failed)(value + 1); | ||
} | ||
return (0, _passed.passed)(value + 1); | ||
ensure("composer calling fail or pass on last iteration", function () { | ||
var action = (0, _compose.compose)({ | ||
iterator: (0, _compose.createIterator)([]), | ||
composer: function composer(_ref2) { | ||
var pass = _ref2.pass; | ||
pass(10); | ||
} | ||
}); | ||
_assertions.assert.deepEqual(action.getResult(), [{ | ||
state: "passed", | ||
result: 0 | ||
}, { | ||
state: "failed", | ||
result: 2 | ||
}, { | ||
state: "passed", | ||
result: 3 | ||
}]); | ||
_assert2.default.equal(action.getResult(), 10); | ||
}); | ||
ensure("composeSequence called in serie", function () { | ||
var firstAction = (0, _action.createAction)(); | ||
var secondAction = (0, _action.createAction)(); | ||
var callCount = 0; | ||
(0, _compose.composeSequence)([firstAction, secondAction], { | ||
handle: function handle(action) { | ||
callCount++; | ||
return action; | ||
} | ||
}); | ||
_assertions.assert.equal(callCount, 1); | ||
firstAction.pass(); | ||
_assertions.assert.equal(callCount, 2); | ||
}); | ||
ensure("composeTogether called concurrently", function () { | ||
var callCount = 0; | ||
(0, _compose.composeTogether)([0, 1], { | ||
handle: function handle() { | ||
callCount++; | ||
return (0, _action.createAction)(); | ||
} | ||
}); | ||
_assertions.assert.equal(callCount, 2); | ||
}); | ||
}); | ||
//# sourceMappingURL=compose.test.js.map |
@@ -6,7 +6,8 @@ "use strict"; | ||
}); | ||
exports.fromFunction = exports.mutateAction = void 0; | ||
exports.fromFunction = void 0; | ||
var _action = require("../action.js"); | ||
var mutateAction = exports.mutateAction = function mutateAction(action, fn) { | ||
var fromFunction = exports.fromFunction = function fromFunction(fn) { | ||
var action = (0, _action.createAction)(); | ||
var returnValue = fn(action); | ||
@@ -20,2 +21,4 @@ | ||
returnValue.then(action.pass, action.fail); | ||
} else if ((0, _action.isThenable)(returnValue)) { | ||
returnValue.then(action.pass, action.fail); | ||
} | ||
@@ -25,6 +28,2 @@ | ||
}; | ||
var fromFunction = exports.fromFunction = function fromFunction(fn) { | ||
return mutateAction((0, _action.createAction)(), fn); | ||
}; | ||
//# sourceMappingURL=fromFunction.js.map |
@@ -54,3 +54,37 @@ "use strict"; | ||
}); | ||
ensure("returning the action itself", function () { | ||
var action = (0, _fromFunction.fromFunction)(function (act) { | ||
return act; | ||
}); | ||
action.pass(); | ||
_assertions.assert.equal(action.getState(), "passed"); | ||
}); | ||
ensure("returning an other passed action", function () { | ||
var passedWith10 = (0, _fromFunction.fromFunction)(function (_ref2) { | ||
var pass = _ref2.pass; | ||
return pass(10); | ||
}); | ||
var action = (0, _fromFunction.fromFunction)(function () { | ||
return passedWith10; | ||
}); | ||
_assertions.assert.equal(action.getState(), "passed"); | ||
_assertions.assert.equal(action.getResult(), 10); | ||
}); | ||
ensure("returning an other failed action", function () { | ||
var failedWith10 = (0, _fromFunction.fromFunction)(function (_ref3) { | ||
var fail = _ref3.fail; | ||
return fail(10); | ||
}); | ||
var action = (0, _fromFunction.fromFunction)(function () { | ||
return failedWith10; | ||
}); | ||
_assertions.assert.equal(action.getState(), "failed"); | ||
_assertions.assert.equal(action.getResult(), 10); | ||
}); | ||
}); | ||
//# sourceMappingURL=fromFunction.test.js.map |
@@ -8,58 +8,44 @@ "use strict"; | ||
var _passed = require("../passed/passed.js"); | ||
var _compose = require("../compose/compose.js"); | ||
var _fromFunction = require("../fromFunction/fromFunction.js"); | ||
var reduce = exports.reduce = function reduce(iterable, reducer, initialValue) { | ||
return (0, _fromFunction.fromFunction)(function () { | ||
var iterator = iterable[Symbol.iterator](); | ||
var index = 0; | ||
var reducedValue = void 0; | ||
var iterator = (0, _compose.createIterator)(iterable); | ||
var _iterator$next = iterator.next(), | ||
done = _iterator$next.done, | ||
value = _iterator$next.value; | ||
if (initialValue === undefined) { | ||
var _iterator$iterate = iterator.iterate(), | ||
done = _iterator$iterate.done, | ||
value = _iterator$iterate.value; | ||
if (done) { | ||
if (initialValue === undefined) { | ||
throw new Error("reduce called on empty iterable without initialValue"); | ||
} | ||
return (0, _passed.passed)(initialValue); | ||
throw new Error("reduce called on empty iterable without initialValue"); | ||
} | ||
if (initialValue === undefined) { | ||
reducedValue = (0, _passed.passed)(value); | ||
var nextResult = iterator.next(); | ||
initialValue = value; | ||
} | ||
if (nextResult.done) { | ||
return reducedValue; | ||
return (0, _compose.compose)({ | ||
from: initialValue, | ||
iterator: iterator, | ||
composer: function composer(_ref) { | ||
var state = _ref.state, | ||
value = _ref.value, | ||
nextValue = _ref.nextValue, | ||
nextIndex = _ref.nextIndex, | ||
iterable = _ref.iterable, | ||
done = _ref.done, | ||
fail = _ref.fail, | ||
pass = _ref.pass; | ||
if (done) { | ||
return state === "passed" ? pass(value) : fail(value); | ||
} | ||
value = nextResult.value; | ||
index++; | ||
} else { | ||
reducedValue = (0, _passed.passed)(initialValue); | ||
if (state === "passed") { | ||
return reducer(value, nextValue, nextIndex, iterable); | ||
} | ||
return fail(value); | ||
} | ||
var iterate = function iterate(currentValue) { | ||
return reducedValue.then(function (result) { | ||
reducedValue = (0, _passed.passed)(reducer(result, currentValue, index, iterable)); | ||
index++; | ||
var _iterator$next2 = iterator.next(), | ||
value = _iterator$next2.value, | ||
done = _iterator$next2.done; | ||
if (done) { | ||
return reducedValue; | ||
} | ||
return iterate(value); | ||
}); | ||
}; | ||
return iterate(value); | ||
}); | ||
}; | ||
//# sourceMappingURL=reduce.js.map |
@@ -7,2 +7,6 @@ "use strict"; | ||
var _passed = require("../passed/passed.js"); | ||
var _failed = require("../failed/failed.js"); | ||
var _reduce = require("./reduce.js"); | ||
@@ -12,4 +16,2 @@ | ||
// import { passed } from "../passed/passed.js" | ||
// import { failed } from "../failed/failed.js" | ||
(0, _testCheap.test)("reduce.js", function (_ref) { | ||
@@ -53,11 +55,3 @@ var ensure = _ref.ensure; | ||
_assertions.assert.equal(calledWith.length, 4); | ||
_assertions.assert.equal(calledWith[0], firstValue); | ||
_assertions.assert.equal(calledWith[1], secondValue); | ||
_assertions.assert.equal(calledWith[2], 1); | ||
_assertions.assert.equal(calledWith[3], iterable); | ||
_assertions.assert.deepEqual(calledWith, [firstValue, secondValue, 1, iterable]); | ||
}); | ||
@@ -117,13 +111,11 @@ ensure("calls reducer with initialValue and first iterable value when initialValue", function () { | ||
}); | ||
ensure("when reducer returns a failed action, reduced action fails", function () { | ||
var value = 1; | ||
var action = (0, _reduce.reduce)([0, 1], function () { | ||
var failedAction = (0, _action.createAction)(); | ||
failedAction.fail(value); | ||
return failedAction; | ||
ensure("when reducer returns an intermediate failed action, reduced action fails", function () { | ||
var failure = 1; | ||
var action = (0, _reduce.reduce)([(0, _passed.passed)(), (0, _failed.failed)(failure), (0, _passed.passed)()], function (acc, value) { | ||
return value; | ||
}); | ||
(0, _assertions.assertFailed)(action); | ||
(0, _assertions.assertResult)(action, value); | ||
(0, _assertions.assertResult)(action, failure); | ||
}); | ||
}); | ||
//# sourceMappingURL=reduce.test.js.map |
@@ -14,2 +14,4 @@ "use strict"; | ||
var _compose = require("../compose/compose.js"); | ||
// ptet supprimer fn, maintenant qu'on a mapIterable non? | ||
@@ -24,9 +26,13 @@ // surtout qu'on utilisera surement composeSequence et pas sequence directement du coup | ||
fail = _ref.fail; | ||
var iterator = iterable[Symbol.iterator](); | ||
var _createIterator = (0, _compose.createIterator)(iterable), | ||
iterate = _createIterator.iterate; | ||
var results = []; | ||
var iterate = function iterate() { | ||
var _iterator$next = iterator.next(), | ||
done = _iterator$next.done, | ||
value = _iterator$next.value; | ||
var visit = function visit() { | ||
var _iterate = iterate(), | ||
done = _iterate.done, | ||
value = _iterate.value, | ||
index = _iterate.index; | ||
@@ -37,3 +43,3 @@ if (done) { | ||
var valueModified = fn(value); | ||
var valueModified = fn(value, index, iterable); | ||
@@ -43,3 +49,3 @@ if ((0, _action.isAction)(valueModified)) { | ||
results.push(result); | ||
iterate(); | ||
visit(); | ||
}, function (result) { | ||
@@ -50,7 +56,7 @@ fail(result); | ||
results.push(valueModified); | ||
iterate(); | ||
visit(); | ||
} | ||
}; | ||
iterate(); | ||
visit(); | ||
}); | ||
@@ -57,0 +63,0 @@ }; |
{ | ||
"name": "@dmail/action", | ||
"version": "1.7.0", | ||
"version": "2.0.0", | ||
"license": "MIT", | ||
@@ -21,8 +21,9 @@ "repository": { | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"@dmail/mixin": "4.0.0" | ||
}, | ||
"devDependencies": { | ||
"@dmail/command": "0.1.1", | ||
"@dmail/ensure": "0.0.2", | ||
"@dmail/prettiest": "0.2.1", | ||
"@dmail/shared-config": "1.1.1", | ||
"@dmail/prettiest": "1.0.0", | ||
"@dmail/shared-config": "3.1.0", | ||
"@dmail/test-cheap": "0.1.0", | ||
@@ -38,3 +39,3 @@ "babel-cli": "7.0.0-beta.0", | ||
"nyc": "11.2.1", | ||
"prettier": "1.7.0", | ||
"prettier": "1.9.1", | ||
"rimraf": "2.6.2" | ||
@@ -41,0 +42,0 @@ }, |
# Action | ||
[](https://badge.fury.io/js/%40dmail%2Faction) | ||
[](http://travis-ci.org/dmail/action) | ||
[](http://travis-ci.org/dmail/action) | ||
[](https://codecov.io/gh/dmail/action) | ||
Sort of Promise chainable synchronously and letting error throw | ||
@@ -5,5 +5,11 @@ // more or less equivalent to | ||
export const isAction = value => value && typeof value.then === "function" | ||
import { mixin, pure, hasTalent, replicate } from "@dmail/mixin" | ||
export const createAction = () => { | ||
export const isThenable = (value) => { | ||
if (typeof value === "object" || typeof value === "function") { | ||
return typeof value.then === "function" | ||
} | ||
} | ||
const actionTalent = ({ unwrapThenable, valueOf }) => { | ||
let state = "unknown" | ||
@@ -14,32 +20,41 @@ let result | ||
const action = {} | ||
const isPassing = () => state === "passing" | ||
const isFailing = () => state === "failing" | ||
const isPassed = () => state === "passed" | ||
const isFailed = () => state === "failed" | ||
const isRunning = () => state === "unknown" || isPassing() || isFailing() | ||
const isEnded = () => isPassed() || isFailed() | ||
const pendingActions = [] | ||
const runPendingActions = () => { | ||
pendingActions.forEach(pendingAction => { | ||
pendingAction.fn(action, result) | ||
}) | ||
pendingActions.length = 0 | ||
const pendingHandlers = [] | ||
const runPendingHandlers = () => { | ||
pendingHandlers.forEach((handler) => handler()) | ||
pendingHandlers.length = 0 | ||
} | ||
const handleResult = (value, passing) => { | ||
state = passing ? "passing" : "failing" | ||
if (isAction(value)) { | ||
if (value === action) { | ||
if (hasTalent(actionTalent, value)) { | ||
// it would be a problem if value was an action derived | ||
// we should check with something reading getPrototypeOf | ||
if (value === valueOf()) { | ||
throw new Error("an action cannot pass/fail with itself") | ||
} | ||
value.then(value => handleResult(value, true), value => handleResult(value, false)) | ||
value.then((value) => handleResult(value, true), (value) => handleResult(value, false)) | ||
} else if (unwrapThenable && isThenable(value)) { | ||
value.then((value) => handleResult(value, true), (value) => handleResult(value, false)) | ||
} else { | ||
state = passing ? "passed" : "failed" | ||
result = value | ||
runPendingActions() | ||
runPendingHandlers() | ||
} | ||
} | ||
const fail = value => { | ||
const fail = (value) => { | ||
if (ignoreNext) { | ||
@@ -61,3 +76,4 @@ ignoreNext = false | ||
} | ||
const pass = value => { | ||
const pass = (value) => { | ||
if (ignoreNext) { | ||
@@ -79,4 +95,8 @@ ignoreNext = false | ||
} | ||
const then = (onPassed, onFailed) => { | ||
const nextAction = createAction() | ||
// ici il faudrais ptet un lastvalueOf | ||
// sinon on replicate juste cette action mais on propage | ||
// pas les éventuel talents ajouté dynamiquement après | ||
const nextAction = replicate(valueOf()) | ||
const nextActionHandler = () => { | ||
@@ -98,5 +118,3 @@ let nextActionResult = result | ||
if (isRunning()) { | ||
pendingActions.push({ | ||
fn: nextActionHandler | ||
}) | ||
pendingHandlers.push(nextActionHandler) | ||
} else { | ||
@@ -108,4 +126,7 @@ nextActionHandler() | ||
} | ||
const getState = () => state | ||
const getResult = () => result | ||
const shortcircuit = (fn, value) => { | ||
@@ -115,20 +136,4 @@ willShortCircuit = true | ||
} | ||
const mixin = (...args) => { | ||
// maybe allow only function, add use defineProperty to make them non enumerable ? | ||
args.forEach(arg => { | ||
let properties = typeof arg === "function" ? arg(action) : arg | ||
if (properties && typeof properties === "object") { | ||
Object.keys(properties).forEach(property => { | ||
if (action.hasOwnProperty(property)) { | ||
throw new Error(`action mixin error: ${property} property exists`) | ||
} | ||
action[property] = properties[property] | ||
}) | ||
} | ||
}) | ||
return action | ||
} | ||
return mixin(action, { | ||
mixin, | ||
return { | ||
getState, | ||
@@ -145,6 +150,12 @@ getResult, | ||
shortcircuit, | ||
then | ||
}) | ||
then, | ||
} | ||
} | ||
export const createAction = ({ unwrapThenable = true } = {}) => { | ||
return mixin(pure, () => ({ unwrapThenable }), actionTalent) | ||
} | ||
export const isAction = (value) => hasTalent(actionTalent, value) | ||
// passed("foo").then(console.log) | ||
@@ -151,0 +162,0 @@ |
@@ -0,4 +1,5 @@ | ||
import { createAction } from "./action.js" | ||
import { test } from "@dmail/test-cheap" | ||
import { createAction } from "./action.js" | ||
import { assert, assertPassed, assertFailed, assertResult } from "./assertions.js" | ||
import { mixin } from "@dmail/mixin" | ||
@@ -93,3 +94,3 @@ test("action.js", ({ ensure }) => { | ||
const resolvedThenable = { | ||
then: onPassed => onPassed(value) | ||
then: (onPassed) => onPassed(value), | ||
} | ||
@@ -105,3 +106,3 @@ const action = createAction() | ||
const resolvedThenable = { | ||
then: onPassed => onPassed(value) | ||
then: (onPassed) => onPassed(value), | ||
} | ||
@@ -117,3 +118,3 @@ const action = createAction() | ||
const rejectedThenable = { | ||
then: (onPassed, onFailed) => onFailed(value) | ||
then: (onPassed, onFailed) => onFailed(value), | ||
} | ||
@@ -129,3 +130,3 @@ const action = createAction() | ||
const rejectedThenable = { | ||
then: (onPassed, onFailed) => onFailed(value) | ||
then: (onPassed, onFailed) => onFailed(value), | ||
} | ||
@@ -138,2 +139,11 @@ const action = createAction() | ||
ensure("action.fail(failedAction), fail with action wrapped value", () => { | ||
const failedAction = createAction() | ||
failedAction.fail(10) | ||
const action = createAction() | ||
action.fail(failedAction) | ||
assertFailed(action) | ||
assertResult(action, 10) | ||
}) | ||
ensure("action.then(onPass) call onpass immediatly when passed", () => { | ||
@@ -144,3 +154,3 @@ const action = createAction() | ||
let passedValue | ||
action.then(value => { | ||
action.then((value) => { | ||
passedValue = value | ||
@@ -155,3 +165,3 @@ }) | ||
let passedValue | ||
action.then(value => { | ||
action.then((value) => { | ||
passedValue = value | ||
@@ -169,3 +179,3 @@ }) | ||
let failedValue | ||
action.then(null, value => { | ||
action.then(null, (value) => { | ||
failedValue = value | ||
@@ -180,3 +190,3 @@ }) | ||
let failedValue | ||
action.then(null, value => { | ||
action.then(null, (value) => { | ||
failedValue = value | ||
@@ -207,33 +217,17 @@ }) | ||
ensure("action.mixin add property to action", () => { | ||
ensure("pass on talentedAction", () => { | ||
const action = createAction() | ||
const foo = () => {} | ||
action.mixin({ foo }) | ||
assert.equal(action.foo, foo) | ||
}) | ||
ensure("action.mixin throw on existing property", () => { | ||
const action = createAction() | ||
assert.throws(() => action.mixin({ pass: () => {} })) | ||
}) | ||
ensure("action mixin with a function", () => { | ||
const action = createAction() | ||
let firstArg | ||
const foo = () => {} | ||
action.mixin(arg => { | ||
firstArg = arg | ||
return { foo } | ||
const passedValues = [] | ||
action.then((value) => { | ||
passedValues.push(value) | ||
}) | ||
assert.equal(firstArg, action) | ||
assert.equal(action.foo, foo) | ||
const talentedAction = mixin(action, () => ({ foo: true })) | ||
talentedAction.then((value) => { | ||
passedValues.push(value) | ||
}) | ||
talentedAction.pass("yo") | ||
assertPassed(action) | ||
assertPassed(talentedAction) | ||
assert.deepEqual(passedValues, ["yo", "yo"]) | ||
}) | ||
ensure("action mixin can return null", () => { | ||
createAction().mixin(() => null) | ||
}) | ||
ensure("action mixin returning non object are ignored", () => { | ||
createAction().mixin(() => true) | ||
}) | ||
}) |
import { isAction } from "../action.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
export const all = iterable => | ||
export const all = (iterable) => | ||
fromFunction(({ fail, pass }) => { | ||
@@ -19,3 +19,3 @@ let callCount = 0 | ||
} | ||
const compositeOnFailed = result => { | ||
const compositeOnFailed = (result) => { | ||
if (failedOrPassed === false) { | ||
@@ -28,3 +28,3 @@ failedOrPassed = true | ||
if (isAction(value)) { | ||
value.then(result => compositeOnPassed(result, index), compositeOnFailed) | ||
value.then((result) => compositeOnPassed(result, index), compositeOnFailed) | ||
} else { | ||
@@ -31,0 +31,0 @@ compositeOnPassed(value, index) |
@@ -0,4 +1,4 @@ | ||
import { all } from "./all.js" | ||
import { test } from "@dmail/test-cheap" | ||
import { createAction } from "../action.js" | ||
import { all } from "./all.js" | ||
import { assert, assertPassed, assertFailed, assertResult } from "../assertions.js" | ||
@@ -5,0 +5,0 @@ |
import { isAction } from "../action.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
export const any = iterable => | ||
export const any = (iterable) => | ||
fromFunction(({ fail, pass }) => { | ||
@@ -11,3 +11,3 @@ let running = true | ||
let endedCount = 0 | ||
const compositePass = value => { | ||
const compositePass = (value) => { | ||
endedCount++ | ||
@@ -19,3 +19,3 @@ if (running) { | ||
} | ||
const compositeFail = value => { | ||
const compositeFail = (value) => { | ||
endedCount++ | ||
@@ -22,0 +22,0 @@ if (running) { |
export const aroundAction = (before, actionCreator, after) => { | ||
before() | ||
return actionCreator().then( | ||
result => { | ||
(result) => { | ||
after(result, true) | ||
return result | ||
}, | ||
result => { | ||
(result) => { | ||
after(result, false) | ||
return result | ||
} | ||
}, | ||
) | ||
} |
@@ -0,4 +1,4 @@ | ||
import { aroundAction } from "./aroundAction.js" | ||
import { test } from "@dmail/test-cheap" | ||
import { createAction } from "../action.js" | ||
import { aroundAction } from "./aroundAction.js" | ||
import { assert, assertPassed, assertFailed, assertResult } from "../assertions.js" | ||
@@ -24,3 +24,3 @@ | ||
}, | ||
after | ||
after, | ||
) | ||
@@ -51,3 +51,3 @@ | ||
}, | ||
after | ||
after, | ||
) | ||
@@ -54,0 +54,0 @@ |
import assert from "assert" | ||
export { assert } | ||
export const assertPassed = action => assert.equal(action.getState(), "passed") | ||
export const assertFailed = action => assert.equal(action.getState(), "failed") | ||
export const assertPassed = (action) => assert.equal(action.getState(), "passed") | ||
export const assertFailed = (action) => assert.equal(action.getState(), "failed") | ||
export const assertResult = (action, expectedResult) => | ||
assert.equal(action.getResult(), expectedResult) | ||
export const assertRunning = action => assert.equal(action.getState(), "unknown") | ||
export const assertPassing = action => assert.equal(action.getState(), "passing") | ||
export const assertFailing = action => assert.equal(action.getState(), "failing") | ||
export const assertRunning = (action) => assert.equal(action.getState(), "unknown") | ||
export const assertPassing = (action) => assert.equal(action.getState(), "passing") | ||
export const assertFailing = (action) => assert.equal(action.getState(), "failing") |
@@ -1,53 +0,73 @@ | ||
import { isAction } from "../action.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
import { allocableMsTalent, failureIsOutOfMs } from "../allocableMsTalent/allocableMsTalent.js" | ||
import { mixin } from "@dmail/mixin" | ||
import { createAction } from "../action" | ||
import { passed } from "../passed/passed.js" | ||
import { createIterator, compose } from "../compose/compose.js" | ||
export const collect = iterable => | ||
fromFunction(({ fail, pass }) => { | ||
const results = [] | ||
let callCount = 0 | ||
let passedOrFailedCount = 0 | ||
let someHasFailed = false | ||
export const collectSequence = (iterable, { failureIsCritical = () => false } = {}) => { | ||
const results = [] | ||
let someHasFailed = false | ||
const checkEnded = () => { | ||
passedOrFailedCount++ | ||
if (passedOrFailedCount === callCount) { | ||
return compose({ | ||
iterator: createIterator(iterable), | ||
composer: ({ value, state, index, nextValue, done, fail, pass }) => { | ||
if (index > -1) { | ||
results.push({ state, result: value }) | ||
} | ||
if (state === "failed") { | ||
if (failureIsCritical(value)) { | ||
return fail(value) | ||
} | ||
someHasFailed = true | ||
} | ||
if (done) { | ||
if (someHasFailed) { | ||
fail(results) | ||
} else { | ||
pass(results) | ||
return fail(results) | ||
} | ||
return pass(results) | ||
} | ||
} | ||
const compositeOnPassed = (result, index) => { | ||
results[index] = { | ||
state: "passed", | ||
result | ||
return nextValue | ||
}, | ||
}) | ||
} | ||
const createPassedActionWithAllocatedMs = (allocatedMs) => { | ||
const action = mixin(createAction(), allocableMsTalent) | ||
action.allocateMs(allocatedMs) | ||
action.pass() | ||
return action | ||
} | ||
export const collectSequenceWithAllocatedMs = (iterable, { allocatedMs = Infinity } = {}) => { | ||
const results = [] | ||
let someHasFailed = false | ||
return compose({ | ||
from: createPassedActionWithAllocatedMs(allocatedMs), | ||
iterator: createIterator(iterable), | ||
composer: ({ action, value, state, index, nextValue, done, fail, pass }) => { | ||
if (index > -1) { | ||
results.push({ state, result: value }) | ||
} | ||
checkEnded() | ||
} | ||
const compositeOnFailed = (result, index) => { | ||
results[index] = { | ||
state: "failed", | ||
result | ||
if (state === "failed") { | ||
if (failureIsOutOfMs(value)) { | ||
return fail(value) | ||
} | ||
someHasFailed = true | ||
} | ||
checkEnded() | ||
} | ||
const run = (value, index) => { | ||
if (isAction(value)) { | ||
value.then( | ||
result => compositeOnPassed(result, index), | ||
result => compositeOnFailed(result, index) | ||
) | ||
} else { | ||
compositeOnPassed(value, index) | ||
if (done) { | ||
if (someHasFailed) { | ||
return fail(results) | ||
} | ||
return pass(results) | ||
} | ||
} | ||
let index = 0 | ||
for (const value of iterable) { | ||
run(value, index) | ||
callCount++ | ||
index++ | ||
} | ||
checkEnded() | ||
const nextActionWithAllocableMs = mixin(passed(nextValue), allocableMsTalent) | ||
nextActionWithAllocableMs.allocateMs(action.getRemainingMs()) | ||
return nextActionWithAllocableMs | ||
}, | ||
}) | ||
} | ||
// export const collectConcurrent = (iterable, allocatedMs = Infinity) | ||
// export const collectConcurrentWithAllocatedMs = (iterable, allocatedMs = Infinity) |
@@ -1,37 +0,94 @@ | ||
import { isAction, createAction } from "../action.js" | ||
import { all } from "../all/all.js" | ||
import { sequence } from "../sequence/sequence.js" | ||
import { passed } from "../passed/passed.js" | ||
import { failed } from "../failed/failed.js" | ||
import { mutateAction } from "../fromFunction/fromFunction.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
import { mapIterable } from "../mapIterable.js" | ||
export const createIterator = (iterable) => { | ||
const iterator = iterable[Symbol.iterator]() | ||
let currentIndex = 0 | ||
const defaultHandle = (_, value) => passed(value) | ||
const iterate = () => { | ||
const next = iterator.next() | ||
const index = currentIndex | ||
currentIndex++ | ||
return { | ||
done: next.done, | ||
value: next.value, | ||
index, | ||
iterable, | ||
} | ||
} | ||
const compose = ( | ||
iterable, | ||
{ handle = defaultHandle, composer, failureIsCritical = () => false } | ||
) => { | ||
const map = (value, index) => | ||
mutateAction(isAction(value) ? value : createAction(), action => | ||
handle(action, value, index, iterable) | ||
).then( | ||
result => ({ state: "passed", result }), | ||
// transform failed into passed so that sequence & all does not stop on first failure | ||
result => (failureIsCritical(result) ? result : passed({ state: "failed", result })) | ||
) | ||
return { | ||
iterate, | ||
iterable, | ||
} | ||
} | ||
iterable = mapIterable(iterable, map) | ||
export const compose = ({ from, iterator, composer }) => { | ||
return fromFunction(({ fail, pass }) => { | ||
const { iterable, iterate } = iterator | ||
return composer(iterable).then( | ||
// but once are done, refails it when needed | ||
reports => (reports.some(({ state }) => state === "failed") ? failed(reports) : passed(reports)) | ||
) | ||
} | ||
let pending = true | ||
export const composeSequence = (iterable, params) => | ||
compose(iterable, Object.assign({ composer: sequence }, params)) | ||
const breakAndPass = (value) => { | ||
pending = false | ||
pass(value) | ||
} | ||
export const composeTogether = (iterable, params) => | ||
compose(iterable, Object.assign({ composer: all }, params)) | ||
const breakAndFail = (value) => { | ||
pending = false | ||
fail(value) | ||
} | ||
const unwrap = (value, handler) => { | ||
const action = passed(value) | ||
action.then( | ||
(value) => handler(action, value, "passed"), | ||
(value) => handler(action, value, "failed"), | ||
) | ||
} | ||
const handleUnknown = (action, value, state) => { | ||
const { done, value: nextValue, index: nextIndex } = iterate() | ||
const composerResult = composer({ | ||
index: nextIndex - 1, | ||
nextIndex, | ||
value, | ||
nextValue, | ||
action, | ||
state, | ||
iterable, | ||
done, | ||
pass: breakAndPass, | ||
fail: breakAndFail, | ||
}) | ||
if (pending) { | ||
if (done) { | ||
const handleLast = (action, value, state) => { | ||
composer({ | ||
index: nextIndex, | ||
nextIndex: nextIndex + 1, | ||
value, | ||
nextValue: undefined, | ||
action, | ||
state, | ||
iterable, | ||
done, | ||
pass: breakAndPass, | ||
fail: breakAndFail, | ||
}) | ||
if (pending) { | ||
throw new Error("composer must fail or pass when iteration is done") | ||
} | ||
} | ||
unwrap(composerResult, handleLast) | ||
} else { | ||
unwrap(composerResult, handleUnknown) | ||
} | ||
} | ||
} | ||
unwrap(from, handleUnknown) | ||
}) | ||
} |
@@ -0,88 +1,24 @@ | ||
import { createIterator, compose } from "./compose.js" | ||
import { test } from "@dmail/test-cheap" | ||
import { createAction } from "../action.js" | ||
import { passed } from "../passed/passed.js" | ||
import { failed } from "../failed/failed.js" | ||
import { composeSequence, composeTogether } from "./compose.js" | ||
import { assert, assertPassed, assertFailed, assertResult } from "../assertions.js" | ||
import assert from "assert" | ||
test("compose.js", ({ ensure }) => { | ||
ensure("composeSequence with values", () => { | ||
const action = composeSequence([0, 1]) | ||
assertPassed(action) | ||
assert.deepEqual(action.getResult(), [ | ||
{ state: "passed", result: 0 }, | ||
{ state: "passed", result: 1 } | ||
]) | ||
ensure("composer must call fail or pass on last iteration", () => { | ||
assert.throws(() => { | ||
compose({ | ||
iterator: createIterator([]), | ||
composer: () => {}, | ||
}) | ||
}, (e) => e.message === "composer must fail or pass when iteration is done") | ||
}) | ||
ensure("composeSequence collect passed action", () => { | ||
const action = composeSequence([passed(0), passed(1)]) | ||
assertPassed(action) | ||
assert.deepEqual(action.getResult(), [ | ||
{ state: "passed", result: 0 }, | ||
{ state: "passed", result: 1 } | ||
]) | ||
}) | ||
ensure("composeSequence collect failed action", () => { | ||
const action = composeSequence([failed(0), failed(1)]) | ||
assertFailed(action) | ||
assert.deepEqual(action.getResult(), [ | ||
{ state: "failed", result: 0 }, | ||
{ state: "failed", result: 1 } | ||
]) | ||
}) | ||
ensure("composeSequence with critical failure", () => { | ||
const action = composeSequence([failed(0), failed(1), passed(2)], { | ||
failureIsCritical: failure => failure === 1 | ||
ensure("composer calling fail or pass on last iteration", () => { | ||
const action = compose({ | ||
iterator: createIterator([]), | ||
composer: ({ pass }) => { | ||
pass(10) | ||
}, | ||
}) | ||
assertFailed(action) | ||
assertResult(action, 1) | ||
assert.equal(action.getResult(), 10) | ||
}) | ||
ensure("composeSequence complex example", () => { | ||
const action = composeSequence([0, 1, 2], { | ||
handle: (action, value, index) => { | ||
if (index === 0) { | ||
return passed(value) | ||
} | ||
if (index === 1) { | ||
return failed(value + 1) | ||
} | ||
return passed(value + 1) | ||
} | ||
}) | ||
assert.deepEqual(action.getResult(), [ | ||
{ state: "passed", result: 0 }, | ||
{ state: "failed", result: 2 }, | ||
{ state: "passed", result: 3 } | ||
]) | ||
}) | ||
ensure("composeSequence called in serie", () => { | ||
const firstAction = createAction() | ||
const secondAction = createAction() | ||
let callCount = 0 | ||
composeSequence([firstAction, secondAction], { | ||
handle: action => { | ||
callCount++ | ||
return action | ||
} | ||
}) | ||
assert.equal(callCount, 1) | ||
firstAction.pass() | ||
assert.equal(callCount, 2) | ||
}) | ||
ensure("composeTogether called concurrently", () => { | ||
let callCount = 0 | ||
composeTogether([0, 1], { | ||
handle: () => { | ||
callCount++ | ||
return createAction() | ||
} | ||
}) | ||
assert.equal(callCount, 2) | ||
}) | ||
}) |
import { isAction } from "../action.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
export const failed = value => (isAction(value) ? value : fromFunction(({ fail }) => fail(value))) | ||
export const failed = (value) => (isAction(value) ? value : fromFunction(({ fail }) => fail(value))) |
@@ -1,4 +0,5 @@ | ||
import { isAction, createAction } from "../action.js" | ||
import { isAction, isThenable, createAction } from "../action.js" | ||
export const mutateAction = (action, fn) => { | ||
export const fromFunction = (fn) => { | ||
const action = createAction() | ||
const returnValue = fn(action) | ||
@@ -10,6 +11,6 @@ if (returnValue === action) { | ||
returnValue.then(action.pass, action.fail) | ||
} else if (isThenable(returnValue)) { | ||
returnValue.then(action.pass, action.fail) | ||
} | ||
return action | ||
} | ||
export const fromFunction = fn => mutateAction(createAction(), fn) |
@@ -9,5 +9,5 @@ import { test } from "@dmail/test-cheap" | ||
const thenable = { | ||
then: onFulfill => { | ||
then: (onFulfill) => { | ||
onFulfill(value) | ||
} | ||
}, | ||
} | ||
@@ -24,3 +24,3 @@ const action = fromFunction(() => thenable) | ||
onReject(value) | ||
} | ||
}, | ||
} | ||
@@ -43,5 +43,25 @@ const action = fromFunction(() => thenable) | ||
throw exception | ||
}) | ||
}), | ||
) | ||
}) | ||
ensure("returning the action itself", () => { | ||
const action = fromFunction((act) => act) | ||
action.pass() | ||
assert.equal(action.getState(), "passed") | ||
}) | ||
ensure("returning an other passed action", () => { | ||
const passedWith10 = fromFunction(({ pass }) => pass(10)) | ||
const action = fromFunction(() => passedWith10) | ||
assert.equal(action.getState(), "passed") | ||
assert.equal(action.getResult(), 10) | ||
}) | ||
ensure("returning an other failed action", () => { | ||
const failedWith10 = fromFunction(({ fail }) => fail(10)) | ||
const action = fromFunction(() => failedWith10) | ||
assert.equal(action.getState(), "failed") | ||
assert.equal(action.getResult(), 10) | ||
}) | ||
}) |
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
export const fromNodeCallback = fn => (...args) => | ||
export const fromNodeCallback = (fn) => (...args) => | ||
fromFunction(({ pass }) => { | ||
@@ -5,0 +5,0 @@ fn(...args, (error, data) => { |
@@ -20,5 +20,5 @@ import { test } from "@dmail/test-cheap" | ||
() => fromNodeCallback(nodeCallbackError)(exception), | ||
error => error === exception | ||
(error) => error === exception, | ||
) | ||
}) | ||
}) |
@@ -19,5 +19,7 @@ import { test } from "@dmail/test-cheap" | ||
const recoverValue = 2 | ||
const action = fromNodeCallbackCatching(nodeCallbackError, e => e === exception, recoverValue)( | ||
exception | ||
) | ||
const action = fromNodeCallbackCatching( | ||
nodeCallbackError, | ||
(e) => e === exception, | ||
recoverValue, | ||
)(exception) | ||
assertPassed(action) | ||
@@ -31,3 +33,3 @@ assertResult(action, recoverValue) | ||
() => fromNodeCallbackCatching(nodeCallbackError, () => false)(exception), | ||
error => error === exception | ||
(error) => error === exception, | ||
) | ||
@@ -34,0 +36,0 @@ }) |
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
export const fromPromise = promise => | ||
export const fromPromise = (promise) => | ||
fromFunction(({ pass, fail }) => { | ||
promise.then(value => setTimeout(pass, 0, value), reason => setTimeout(fail, 0, reason)) | ||
promise.then((value) => setTimeout(pass, 0, value), (reason) => setTimeout(fail, 0, reason)) | ||
}) |
@@ -10,11 +10,11 @@ import { test } from "@dmail/test-cheap" | ||
let caughtException | ||
process.once("uncaughtException", e => { | ||
process.once("uncaughtException", (e) => { | ||
caughtException = e | ||
}) | ||
const thenableCatchingOnResolve = { | ||
then: onResolve => { | ||
then: (onResolve) => { | ||
try { | ||
onResolve() | ||
} catch (e) {} | ||
} | ||
}, | ||
} | ||
@@ -28,3 +28,3 @@ fromPromise(thenableCatchingOnResolve).then(() => { | ||
const failException = 2 | ||
process.once("uncaughtException", e => { | ||
process.once("uncaughtException", (e) => { | ||
caughtException = e | ||
@@ -39,3 +39,3 @@ }) | ||
} catch (e) {} | ||
} | ||
}, | ||
} | ||
@@ -49,3 +49,3 @@ fromPromise(thenableCatchingOnReject).then(null, () => { | ||
let result | ||
fromPromise(Promise.resolve(10)).then(arg => { | ||
fromPromise(Promise.resolve(10)).then((arg) => { | ||
result = arg | ||
@@ -52,0 +52,0 @@ }) |
@@ -1,10 +0,10 @@ | ||
const createIterable = createIterator => { | ||
const createIterable = (createIterator) => { | ||
return { | ||
[Symbol.iterator]: createIterator | ||
[Symbol.iterator]: createIterator, | ||
} | ||
} | ||
const createIterator = next => { | ||
const createIterator = (next) => { | ||
return { | ||
next | ||
next, | ||
} | ||
@@ -30,3 +30,3 @@ } | ||
done, | ||
value: mappedValue | ||
value: mappedValue, | ||
} | ||
@@ -72,5 +72,5 @@ }) | ||
done, | ||
value: accumulator | ||
value: accumulator, | ||
} | ||
}) | ||
}) |
import { isAction } from "../action.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
export const passed = value => (isAction(value) ? value : fromFunction(({ pass }) => pass(value))) | ||
export const passed = (value) => (isAction(value) ? value : fromFunction(({ pass }) => pass(value))) |
@@ -1,41 +0,26 @@ | ||
import { passed } from "../passed/passed.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
import { compose, createIterator } from "../compose/compose.js" | ||
export const reduce = (iterable, reducer, initialValue) => | ||
fromFunction(() => { | ||
const iterator = iterable[Symbol.iterator]() | ||
let index = 0 | ||
let reducedValue | ||
let { done, value } = iterator.next() | ||
export const reduce = (iterable, reducer, initialValue) => { | ||
const iterator = createIterator(iterable) | ||
if (initialValue === undefined) { | ||
const { done, value } = iterator.iterate() | ||
if (done) { | ||
if (initialValue === undefined) { | ||
throw new Error("reduce called on empty iterable without initialValue") | ||
} | ||
return passed(initialValue) | ||
throw new Error("reduce called on empty iterable without initialValue") | ||
} | ||
if (initialValue === undefined) { | ||
reducedValue = passed(value) | ||
initialValue = value | ||
} | ||
const nextResult = iterator.next() | ||
if (nextResult.done) { | ||
return reducedValue | ||
return compose({ | ||
from: initialValue, | ||
iterator, | ||
composer: ({ state, value, nextValue, nextIndex, iterable, done, fail, pass }) => { | ||
if (done) { | ||
return state === "passed" ? pass(value) : fail(value) | ||
} | ||
value = nextResult.value | ||
index++ | ||
} else { | ||
reducedValue = passed(initialValue) | ||
} | ||
const iterate = currentValue => | ||
reducedValue.then(result => { | ||
reducedValue = passed(reducer(result, currentValue, index, iterable)) | ||
index++ | ||
const { value, done } = iterator.next() | ||
if (done) { | ||
return reducedValue | ||
} | ||
return iterate(value) | ||
}) | ||
return iterate(value) | ||
if (state === "passed") { | ||
return reducer(value, nextValue, nextIndex, iterable) | ||
} | ||
return fail(value) | ||
}, | ||
}) | ||
} |
import { test } from "@dmail/test-cheap" | ||
import { createAction } from "../action.js" | ||
// import { passed } from "../passed/passed.js" | ||
// import { failed } from "../failed/failed.js" | ||
import { passed } from "../passed/passed.js" | ||
import { failed } from "../failed/failed.js" | ||
import { reduce } from "./reduce.js" | ||
@@ -42,7 +42,3 @@ import { assert, assertPassed, assertResult, assertRunning, assertFailed } from "../assertions.js" | ||
}) | ||
assert.equal(calledWith.length, 4) | ||
assert.equal(calledWith[0], firstValue) | ||
assert.equal(calledWith[1], secondValue) | ||
assert.equal(calledWith[2], 1) | ||
assert.equal(calledWith[3], iterable) | ||
assert.deepEqual(calledWith, [firstValue, secondValue, 1, iterable]) | ||
}) | ||
@@ -60,3 +56,3 @@ | ||
}, | ||
initialValue | ||
initialValue, | ||
) | ||
@@ -104,12 +100,8 @@ assert.equal(calledWith[0], initialValue) | ||
ensure("when reducer returns a failed action, reduced action fails", () => { | ||
const value = 1 | ||
const action = reduce([0, 1], () => { | ||
const failedAction = createAction() | ||
failedAction.fail(value) | ||
return failedAction | ||
}) | ||
ensure("when reducer returns an intermediate failed action, reduced action fails", () => { | ||
const failure = 1 | ||
const action = reduce([passed(), failed(failure), passed()], (acc, value) => value) | ||
assertFailed(action) | ||
assertResult(action, value) | ||
assertResult(action, failure) | ||
}) | ||
}) |
import { isAction } from "../action.js" | ||
import { fromFunction } from "../fromFunction/fromFunction.js" | ||
import { passed } from "../passed/passed.js" | ||
import { createIterator } from "../compose/compose.js" | ||
// ptet supprimer fn, maintenant qu'on a mapIterable non? | ||
// surtout qu'on utilisera surement composeSequence et pas sequence directement du coup | ||
export const sequence = (iterable, fn = v => v) => | ||
export const sequence = (iterable, fn = (v) => v) => | ||
fromFunction(({ pass, fail }) => { | ||
const iterator = iterable[Symbol.iterator]() | ||
const { iterate } = createIterator(iterable) | ||
const results = [] | ||
const iterate = () => { | ||
const { done, value } = iterator.next() | ||
const visit = () => { | ||
const { done, value, index } = iterate() | ||
if (done) { | ||
return pass(results) | ||
} | ||
const valueModified = fn(value) | ||
const valueModified = fn(value, index, iterable) | ||
if (isAction(valueModified)) { | ||
valueModified.then( | ||
result => { | ||
(result) => { | ||
results.push(result) | ||
iterate() | ||
visit() | ||
}, | ||
result => { | ||
(result) => { | ||
fail(result) | ||
} | ||
}, | ||
) | ||
} else { | ||
results.push(valueModified) | ||
iterate() | ||
visit() | ||
} | ||
} | ||
iterate() | ||
visit() | ||
}) | ||
@@ -35,0 +37,0 @@ |
@@ -39,3 +39,3 @@ import { test } from "@dmail/test-cheap" | ||
const value = 1 | ||
const action = sequence([value], v => v + 1) | ||
const action = sequence([value], (v) => v + 1) | ||
@@ -47,3 +47,3 @@ assertPassed(action) | ||
ensure("chainFunctions calls function with previous result", () => { | ||
const action = chainFunctions(() => passed(10), previous => passed(previous + 1)) | ||
const action = chainFunctions(() => passed(10), (previous) => passed(previous + 1)) | ||
assertPassed(action) | ||
@@ -54,3 +54,3 @@ assertResult(action, 11) | ||
ensure("chainFunctions first function can be called with an initialValue", () => { | ||
const action = chainFunctions(() => 10, value => passed(value)) | ||
const action = chainFunctions(() => 10, (value) => passed(value)) | ||
assertPassed(action) | ||
@@ -57,0 +57,0 @@ assertResult(action, 10) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
238922
2.61%15
-6.25%3816
2.77%1
Infinity%106
-2.75%8
-11.11%+ Added
+ Added