@duplojs/agents-kit 0.0.0-stage → 0.1.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -2
- package/dist/bin/index.d.ts +2 -0
- package/dist/bin/index.mjs +7 -0
- package/dist/bin/install/index.d.ts +2 -0
- package/dist/bin/install/index.mjs +25 -0
- package/dist/bin/install/skill.d.ts +28 -0
- package/dist/bin/install/skill.mjs +58 -0
- package/dist/bin/packagePath.d.ts +2 -0
- package/dist/bin/packagePath.mjs +12 -0
- package/dist/bin/setup/index.d.ts +12 -0
- package/dist/bin/setup/index.mjs +33 -0
- package/dist/bin/setup/instructions.d.ts +8 -0
- package/dist/bin/setup/instructions.mjs +27 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +0 -0
- package/docs/API/10-lang/10-array/10-at.ts +65 -0
- package/docs/API/10-lang/10-array/10-chunk.ts +42 -0
- package/docs/API/10-lang/10-array/10-coalescing.ts +19 -0
- package/docs/API/10-lang/10-array/10-concat.ts +34 -0
- package/docs/API/10-lang/10-array/10-copyWithin.ts +34 -0
- package/docs/API/10-lang/10-array/10-every.ts +25 -0
- package/docs/API/10-lang/10-array/10-fill.ts +34 -0
- package/docs/API/10-lang/10-array/10-fillAll.ts +34 -0
- package/docs/API/10-lang/10-array/10-filter.ts +43 -0
- package/docs/API/10-lang/10-array/10-find.ts +33 -0
- package/docs/API/10-lang/10-array/10-findAndReplace.ts +35 -0
- package/docs/API/10-lang/10-array/10-findAndSpliceDelete.ts +35 -0
- package/docs/API/10-lang/10-array/10-findAndSpliceInsert.ts +35 -0
- package/docs/API/10-lang/10-array/10-findAndSpliceReplace.ts +24 -0
- package/docs/API/10-lang/10-array/10-findDuplicates.ts +19 -0
- package/docs/API/10-lang/10-array/10-findIndex.ts +25 -0
- package/docs/API/10-lang/10-array/10-findLast.ts +33 -0
- package/docs/API/10-lang/10-array/10-findLastIndex.ts +25 -0
- package/docs/API/10-lang/10-array/10-first.ts +21 -0
- package/docs/API/10-lang/10-array/10-flat.ts +22 -0
- package/docs/API/10-lang/10-array/10-flatMap.ts +24 -0
- package/docs/API/10-lang/10-array/10-from.ts +25 -0
- package/docs/API/10-lang/10-array/10-group.ts +27 -0
- package/docs/API/10-lang/10-array/10-groupOutput.ts +30 -0
- package/docs/API/10-lang/10-array/10-includes.ts +24 -0
- package/docs/API/10-lang/10-array/10-indexOf.ts +24 -0
- package/docs/API/10-lang/10-array/10-insert.ts +34 -0
- package/docs/API/10-lang/10-array/10-is.ts +15 -0
- package/docs/API/10-lang/10-array/10-isLastIndex.ts +24 -0
- package/docs/API/10-lang/10-array/10-last.ts +21 -0
- package/docs/API/10-lang/10-array/10-lastIndexOf.ts +24 -0
- package/docs/API/10-lang/10-array/10-length.ts +28 -0
- package/docs/API/10-lang/10-array/10-lengthEqual.ts +39 -0
- package/docs/API/10-lang/10-array/10-map.ts +34 -0
- package/docs/API/10-lang/10-array/10-maxElements.ts +44 -0
- package/docs/API/10-lang/10-array/10-minElements.ts +44 -0
- package/docs/API/10-lang/10-array/10-notIncludes.ts +24 -0
- package/docs/API/10-lang/10-array/10-pop.ts +23 -0
- package/docs/API/10-lang/10-array/10-prepend.ts +34 -0
- package/docs/API/10-lang/10-array/10-push.ts +34 -0
- package/docs/API/10-lang/10-array/10-reduce.ts +28 -0
- package/docs/API/10-lang/10-array/10-reduceFrom.ts +16 -0
- package/docs/API/10-lang/10-array/10-reduceRight.ts +28 -0
- package/docs/API/10-lang/10-array/10-reverse.ts +25 -0
- package/docs/API/10-lang/10-array/10-select.ts +26 -0
- package/docs/API/10-lang/10-array/10-set.ts +24 -0
- package/docs/API/10-lang/10-array/10-shift.ts +23 -0
- package/docs/API/10-lang/10-array/10-slice.ts +24 -0
- package/docs/API/10-lang/10-array/10-some.ts +25 -0
- package/docs/API/10-lang/10-array/10-sort.ts +34 -0
- package/docs/API/10-lang/10-array/10-spliceDelete.ts +34 -0
- package/docs/API/10-lang/10-array/10-spliceInsert.ts +34 -0
- package/docs/API/10-lang/10-array/10-spliceReplace.ts +24 -0
- package/docs/API/10-lang/10-array/10-unshift.ts +34 -0
- package/docs/API/10-lang/10-array/index.llms.md +220 -0
- package/docs/API/10-lang/10-array/index.md +3 -0
- package/docs/API/10-lang/10-chrono/10-addDays.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addHours.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addMilliseconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addMinutes.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addMonths.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addSeconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addTime.ts +38 -0
- package/docs/API/10-lang/10-chrono/10-addWeeks.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addYears.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-applyTimezone.ts +29 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanDate.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanOrEqualDate.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanOrEqualTime.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanTime.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-closestTo.ts +48 -0
- package/docs/API/10-lang/10-chrono/10-computeTime.ts +35 -0
- package/docs/API/10-lang/10-chrono/10-createDate.ts +122 -0
- package/docs/API/10-lang/10-chrono/10-createDateOrThrow.ts +39 -0
- package/docs/API/10-lang/10-chrono/10-createTime.ts +86 -0
- package/docs/API/10-lang/10-chrono/10-createTimeOrThrow.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-eachDate.ts +67 -0
- package/docs/API/10-lang/10-chrono/10-equalDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-equalTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-formatDate.ts +43 -0
- package/docs/API/10-lang/10-chrono/10-formatTime.ts +37 -0
- package/docs/API/10-lang/10-chrono/10-getDayOfMonth.ts +37 -0
- package/docs/API/10-lang/10-chrono/10-getDayOfWeek.ts +30 -0
- package/docs/API/10-lang/10-chrono/10-getDayOfYear.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-getDifference.ts +29 -0
- package/docs/API/10-lang/10-chrono/10-getFirstDayOfMonth.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getFirstDayOfWeek.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getHour.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-getLastDayOfMonth.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getLastDayOfWeek.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getMilliseconds.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getMinute.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getMonth.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getSecond.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getTimezoneOffset.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-getWeekOfYear.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getYear.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanOrEqualDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanOrEqualTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-isDate.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-isSafeTimeValue.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-isSafeTimestamp.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-isSerializedTheDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-isSerializedTheTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-isTime.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-lessThanDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-lessThanOrEqualDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-lessThanOrEqualTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-lessThanTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-makeSafeTimeValue.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-makeSafeTimestamp.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-maxDate.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-maxTime.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-minDate.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-minTime.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-now.ts +13 -0
- package/docs/API/10-lang/10-chrono/10-round.ts +41 -0
- package/docs/API/10-lang/10-chrono/10-serialize.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-sortDates.ts +32 -0
- package/docs/API/10-lang/10-chrono/10-sortTimes.ts +31 -0
- package/docs/API/10-lang/10-chrono/10-subtractDays.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractHours.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractMilliseconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractMinutes.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractMonths.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractSeconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractTime.ts +38 -0
- package/docs/API/10-lang/10-chrono/10-subtractWeeks.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractYears.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-toDateISOString.ts +17 -0
- package/docs/API/10-lang/10-chrono/10-toNative.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-toTimeValue.ts +17 -0
- package/docs/API/10-lang/10-chrono/10-toTimestamp.ts +17 -0
- package/docs/API/10-lang/10-chrono/10-today.ts +13 -0
- package/docs/API/10-lang/10-chrono/10-tomorrow.ts +13 -0
- package/docs/API/10-lang/10-chrono/10-yesterday.ts +13 -0
- package/docs/API/10-lang/10-chrono/index.llms.md +332 -0
- package/docs/API/10-lang/10-chrono/index.md +3 -0
- package/docs/API/10-lang/10-common/10-and.ts +45 -0
- package/docs/API/10-lang/10-common/10-asserts.ts +13 -0
- package/docs/API/10-lang/10-common/10-asyncInnerPipe.ts +23 -0
- package/docs/API/10-lang/10-common/10-asyncLoop.ts +25 -0
- package/docs/API/10-lang/10-common/10-asyncPipe.ts +21 -0
- package/docs/API/10-lang/10-common/10-callThen.ts +22 -0
- package/docs/API/10-lang/10-common/10-cast.ts +16 -0
- package/docs/API/10-lang/10-common/10-clone.ts +12 -0
- package/docs/API/10-lang/10-common/10-createAsyncRetry.ts +34 -0
- package/docs/API/10-lang/10-common/10-createBuilder.ts +19 -0
- package/docs/API/10-lang/10-common/10-createEnum.ts +25 -0
- package/docs/API/10-lang/10-common/10-createExternalPromise.ts +13 -0
- package/docs/API/10-lang/10-common/10-createFormData.ts +16 -0
- package/docs/API/10-lang/10-common/10-createInterpolation.ts +12 -0
- package/docs/API/10-lang/10-common/10-createQueue.ts +16 -0
- package/docs/API/10-lang/10-common/10-createTransformer.ts +16 -0
- package/docs/API/10-lang/10-common/10-detachObjectMethod.ts +20 -0
- package/docs/API/10-lang/10-common/10-equal.ts +31 -0
- package/docs/API/10-lang/10-common/10-escapeRegExp.ts +11 -0
- package/docs/API/10-lang/10-common/10-falsy.ts +12 -0
- package/docs/API/10-lang/10-common/10-forward.ts +11 -0
- package/docs/API/10-lang/10-common/10-forwardAsserts.ts +17 -0
- package/docs/API/10-lang/10-common/10-forwardLog.ts +11 -0
- package/docs/API/10-lang/10-common/10-infer.ts +16 -0
- package/docs/API/10-lang/10-common/10-innerPipe.ts +23 -0
- package/docs/API/10-lang/10-common/10-instanceOf.ts +23 -0
- package/docs/API/10-lang/10-common/10-isType.ts +29 -0
- package/docs/API/10-lang/10-common/10-justExec.ts +28 -0
- package/docs/API/10-lang/10-common/10-justReturn.ts +19 -0
- package/docs/API/10-lang/10-common/10-loop.ts +20 -0
- package/docs/API/10-lang/10-common/10-memo.ts +12 -0
- package/docs/API/10-lang/10-common/10-memoObject.ts +11 -0
- package/docs/API/10-lang/10-common/10-memoPromise.ts +16 -0
- package/docs/API/10-lang/10-common/10-or.ts +29 -0
- package/docs/API/10-lang/10-common/10-pipe.ts +21 -0
- package/docs/API/10-lang/10-common/10-pipeCall.ts +20 -0
- package/docs/API/10-lang/10-common/10-prepareAsyncPipe.ts +20 -0
- package/docs/API/10-lang/10-common/10-preparePipe.ts +20 -0
- package/docs/API/10-lang/10-common/10-promiseAll.ts +16 -0
- package/docs/API/10-lang/10-common/10-promiseObject.ts +22 -0
- package/docs/API/10-lang/10-common/10-removeConstraint.ts +13 -0
- package/docs/API/10-lang/10-common/10-shameOnYou.ts +20 -0
- package/docs/API/10-lang/10-common/10-simpleClone.ts +12 -0
- package/docs/API/10-lang/10-common/10-stringToBytes.ts +16 -0
- package/docs/API/10-lang/10-common/10-stringToMillisecond.ts +17 -0
- package/docs/API/10-lang/10-common/10-timeout.ts +11 -0
- package/docs/API/10-lang/10-common/10-toCurriedPredicate.ts +28 -0
- package/docs/API/10-lang/10-common/10-toJSON.ts +15 -0
- package/docs/API/10-lang/10-common/10-toNative.ts +15 -0
- package/docs/API/10-lang/10-common/10-toRegExp.ts +17 -0
- package/docs/API/10-lang/10-common/10-transformer.ts +21 -0
- package/docs/API/10-lang/10-common/10-truthy.ts +12 -0
- package/docs/API/10-lang/10-common/10-useAsyncRetry.ts +31 -0
- package/docs/API/10-lang/10-common/10-when.ts +27 -0
- package/docs/API/10-lang/10-common/10-whenElse.ts +28 -0
- package/docs/API/10-lang/10-common/10-whenNot.ts +26 -0
- package/docs/API/10-lang/10-common/index.llms.md +228 -0
- package/docs/API/10-lang/10-common/index.md +3 -0
- package/docs/API/10-lang/10-dataStructure/10-absolutePath.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-allowedCharacters.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-array.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-arrayLengthEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-betweenThan.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-betweenThanOrEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-bigint.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-boolean.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-createCodec.ts +45 -0
- package/docs/API/10-lang/10-dataStructure/10-createCodecs.ts +134 -0
- package/docs/API/10-lang/10-dataStructure/10-createErrorInterpreter.ts +74 -0
- package/docs/API/10-lang/10-dataStructure/10-date.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-email.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-endsWith.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-even.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-extend.ts +27 -0
- package/docs/API/10-lang/10-dataStructure/10-greaterThan.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-greaterThanOrEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-include.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-integer.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-isNullStructure.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-isNullable.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-isOptional.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-isUndefinedStructure.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-lazy.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-lessThan.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-lessThanOrEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-literal.ts +19 -0
- package/docs/API/10-lang/10-dataStructure/10-maxCharacters.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-maxElements.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-minCharacters.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-minElements.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-multipleOf.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-negative.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-notEmpty.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-notZero.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-null.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-nullable.ts +19 -0
- package/docs/API/10-lang/10-dataStructure/10-number.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-numberInString.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-object.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-odd.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-optional.ts +19 -0
- package/docs/API/10-lang/10-dataStructure/10-partial.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-path.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-positive.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-record.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-refine.ts +27 -0
- package/docs/API/10-lang/10-dataStructure/10-regex.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-required.ts +21 -0
- package/docs/API/10-lang/10-dataStructure/10-safe.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-segmentPath.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-startsWith.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-strictNegative.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-strictPositive.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-string.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-stringLengthEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-time.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-trimmed.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-typeStructureIdentifier.ts +33 -0
- package/docs/API/10-lang/10-dataStructure/10-undefined.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-union.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-unwrapLazy.ts +17 -0
- package/docs/API/10-lang/10-dataStructure/10-url.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-uuid.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/index.llms.md +264 -0
- package/docs/API/10-lang/10-dataStructure/index.md +3 -0
- package/docs/API/10-lang/10-either/10-asyncGroup.ts +44 -0
- package/docs/API/10-lang/10-either/10-asyncSafeCallback.ts +23 -0
- package/docs/API/10-lang/10-either/10-error.ts +12 -0
- package/docs/API/10-lang/10-either/10-expect.ts +13 -0
- package/docs/API/10-lang/10-either/10-fail.ts +12 -0
- package/docs/API/10-lang/10-either/10-forwardAssertsSelection.ts +28 -0
- package/docs/API/10-lang/10-either/10-group.ts +58 -0
- package/docs/API/10-lang/10-either/10-hasInformation.ts +24 -0
- package/docs/API/10-lang/10-either/10-isLeft.ts +16 -0
- package/docs/API/10-lang/10-either/10-isRight.ts +16 -0
- package/docs/API/10-lang/10-either/10-isSelected.ts +29 -0
- package/docs/API/10-lang/10-either/10-keepAsRightByInformation.ts +29 -0
- package/docs/API/10-lang/10-either/10-keepAsRightSelection.ts +23 -0
- package/docs/API/10-lang/10-either/10-left.ts +13 -0
- package/docs/API/10-lang/10-either/10-matchInformation.ts +26 -0
- package/docs/API/10-lang/10-either/10-matchInformationOtherwise.ts +27 -0
- package/docs/API/10-lang/10-either/10-none.ts +12 -0
- package/docs/API/10-lang/10-either/10-ok.ts +12 -0
- package/docs/API/10-lang/10-either/10-result.ts +18 -0
- package/docs/API/10-lang/10-either/10-rewriteInformation.ts +24 -0
- package/docs/API/10-lang/10-either/10-right.ts +13 -0
- package/docs/API/10-lang/10-either/10-rightAsyncPipe.ts +69 -0
- package/docs/API/10-lang/10-either/10-rightPipe.ts +72 -0
- package/docs/API/10-lang/10-either/10-safeCallback.ts +29 -0
- package/docs/API/10-lang/10-either/10-some.ts +12 -0
- package/docs/API/10-lang/10-either/10-success.ts +12 -0
- package/docs/API/10-lang/10-either/10-toMaybe.ts +53 -0
- package/docs/API/10-lang/10-either/10-unwrapByInformation.ts +20 -0
- package/docs/API/10-lang/10-either/10-unwrapByInformationOrThrow.ts +19 -0
- package/docs/API/10-lang/10-either/10-unwrapLeft.ts +14 -0
- package/docs/API/10-lang/10-either/10-unwrapLeftOrThrow.ts +17 -0
- package/docs/API/10-lang/10-either/10-unwrapOr.ts +17 -0
- package/docs/API/10-lang/10-either/10-unwrapOtherwise.ts +20 -0
- package/docs/API/10-lang/10-either/10-unwrapRight.ts +14 -0
- package/docs/API/10-lang/10-either/10-unwrapRightOrThrow.ts +17 -0
- package/docs/API/10-lang/10-either/10-unwrapSelection.ts +26 -0
- package/docs/API/10-lang/10-either/10-unwrapSelectionOrThrow.ts +19 -0
- package/docs/API/10-lang/10-either/10-whenHasInformation.ts +35 -0
- package/docs/API/10-lang/10-either/10-whenHasInformationOtherwise.ts +29 -0
- package/docs/API/10-lang/10-either/10-whenIsLeft.ts +20 -0
- package/docs/API/10-lang/10-either/10-whenIsLeftOtherwise.ts +27 -0
- package/docs/API/10-lang/10-either/10-whenIsRight.ts +20 -0
- package/docs/API/10-lang/10-either/10-whenIsRightOtherwise.ts +26 -0
- package/docs/API/10-lang/10-either/10-whenIsSelected.ts +33 -0
- package/docs/API/10-lang/10-either/10-whenIsSelectedOtherwise.ts +35 -0
- package/docs/API/10-lang/10-either/index.llms.md +184 -0
- package/docs/API/10-lang/10-either/index.md +3 -0
- package/docs/API/10-lang/10-generator/10-asyncChunk.ts +55 -0
- package/docs/API/10-lang/10-generator/10-asyncConcat.ts +46 -0
- package/docs/API/10-lang/10-generator/10-asyncFilter.ts +41 -0
- package/docs/API/10-lang/10-generator/10-asyncFlat.ts +37 -0
- package/docs/API/10-lang/10-generator/10-asyncGroup.ts +65 -0
- package/docs/API/10-lang/10-generator/10-asyncLoop.ts +59 -0
- package/docs/API/10-lang/10-generator/10-asyncMap.ts +48 -0
- package/docs/API/10-lang/10-generator/10-asyncReduce.ts +63 -0
- package/docs/API/10-lang/10-generator/10-chunk.ts +44 -0
- package/docs/API/10-lang/10-generator/10-concat.ts +37 -0
- package/docs/API/10-lang/10-generator/10-createExternalAsyncGenerator.ts +29 -0
- package/docs/API/10-lang/10-generator/10-execute.ts +44 -0
- package/docs/API/10-lang/10-generator/10-filter.ts +35 -0
- package/docs/API/10-lang/10-generator/10-flat.ts +25 -0
- package/docs/API/10-lang/10-generator/10-group.ts +44 -0
- package/docs/API/10-lang/10-generator/10-groupOutput.ts +48 -0
- package/docs/API/10-lang/10-generator/10-loop.ts +55 -0
- package/docs/API/10-lang/10-generator/10-map.ts +35 -0
- package/docs/API/10-lang/10-generator/10-reduce.ts +51 -0
- package/docs/API/10-lang/10-generator/10-reduceFrom.ts +30 -0
- package/docs/API/10-lang/10-generator/index.llms.md +84 -0
- package/docs/API/10-lang/10-generator/index.md +3 -0
- package/docs/API/10-lang/index.md +3 -0
- package/docs/API/index.md +3 -0
- package/docs/API.llms.md +31 -0
- package/docs/concepts/01-fundamental/01-constraint/01-use.ts +22 -0
- package/docs/concepts/01-fundamental/01-constraint/10-built-in-constraint.ts +37 -0
- package/docs/concepts/01-fundamental/01-constraint/20-manipulation.ts +38 -0
- package/docs/concepts/01-fundamental/01-constraint/30-cast.ts +62 -0
- package/docs/concepts/01-fundamental/01-constraint/40-custom-constraint.ts +45 -0
- package/docs/concepts/01-fundamental/01-constraint/index.md +3 -0
- package/docs/concepts/01-fundamental/02-currying/01-use.ts +33 -0
- package/docs/concepts/01-fundamental/02-currying/10-built-in-function.ts +178 -0
- package/docs/concepts/01-fundamental/02-currying/20-inner-pipe.ts +39 -0
- package/docs/concepts/01-fundamental/02-currying/30-async-pipe.ts +42 -0
- package/docs/concepts/01-fundamental/02-currying/index.md +3 -0
- package/docs/concepts/01-fundamental/03-either/01-use.ts +21 -0
- package/docs/concepts/01-fundamental/03-either/10-discrimination.ts +79 -0
- package/docs/concepts/01-fundamental/03-either/20-exhaustive-handling.ts +73 -0
- package/docs/concepts/01-fundamental/03-either/30-composition.ts +72 -0
- package/docs/concepts/01-fundamental/03-either/40-result-adaptation.ts +40 -0
- package/docs/concepts/01-fundamental/03-either/50-external-results.ts +59 -0
- package/docs/concepts/01-fundamental/03-either/60-contextual-state.ts +40 -0
- package/docs/concepts/01-fundamental/03-either/index.md +3 -0
- package/docs/concepts/01-fundamental/04-data-structure/01-use.ts +22 -0
- package/docs/concepts/01-fundamental/04-data-structure/10-structure.ts +193 -0
- package/docs/concepts/01-fundamental/04-data-structure/20-constraint.ts +78 -0
- package/docs/concepts/01-fundamental/04-data-structure/30-validation.ts +100 -0
- package/docs/concepts/01-fundamental/04-data-structure/40-codecs.ts +151 -0
- package/docs/concepts/01-fundamental/04-data-structure/50-recursive.ts +48 -0
- package/docs/concepts/01-fundamental/04-data-structure/60-interpret-error.ts +123 -0
- package/docs/concepts/01-fundamental/04-data-structure/index.md +3 -0
- package/docs/concepts/01-fundamental/05-chrono/01-use.ts +14 -0
- package/docs/concepts/01-fundamental/05-chrono/10-creation.ts +59 -0
- package/docs/concepts/01-fundamental/05-chrono/20-manipulation.ts +94 -0
- package/docs/concepts/01-fundamental/05-chrono/30-serialized.ts +73 -0
- package/docs/concepts/01-fundamental/05-chrono/40-timezone.ts +81 -0
- package/docs/concepts/01-fundamental/05-chrono/index.md +3 -0
- package/docs/concepts/01-fundamental/06-modeling/10-new-type.ts +42 -0
- package/docs/concepts/01-fundamental/06-modeling/20-entity.ts +204 -0
- package/docs/concepts/01-fundamental/06-modeling/30-tagged-object.ts +181 -0
- package/docs/concepts/01-fundamental/06-modeling/40-entity-lifecycle.ts +275 -0
- package/docs/concepts/01-fundamental/06-modeling/50-evidence.ts +94 -0
- package/docs/concepts/01-fundamental/06-modeling/60-signed-function.ts +26 -0
- package/docs/concepts/01-fundamental/06-modeling/index.md +3 -0
- package/docs/concepts/01-fundamental/07-discrimination/10-entity.ts +104 -0
- package/docs/concepts/01-fundamental/07-discrimination/20-fact.ts +142 -0
- package/docs/concepts/01-fundamental/07-discrimination/30-tagged-object.ts +105 -0
- package/docs/concepts/01-fundamental/07-discrimination/40-error.ts +57 -0
- package/docs/concepts/01-fundamental/07-discrimination/50-literal.ts +87 -0
- package/docs/concepts/01-fundamental/07-discrimination/60-shape.ts +152 -0
- package/docs/concepts/01-fundamental/07-discrimination/70-predicate.ts +89 -0
- package/docs/concepts/01-fundamental/07-discrimination/index.md +3 -0
- package/docs/concepts/01-fundamental/index.md +1 -0
- package/docs/concepts/02-server/10-file/10-manipulation.ts +40 -0
- package/docs/concepts/02-server/10-file/20-path.ts +56 -0
- package/docs/concepts/02-server/10-file/index.md +3 -0
- package/docs/concepts/02-server/20-http/10-init.ts +31 -0
- package/docs/concepts/02-server/20-http/20-route.ts +174 -0
- package/docs/concepts/02-server/20-http/30-routine.ts +195 -0
- package/docs/concepts/02-server/20-http/40-jwt.ts +137 -0
- package/docs/concepts/02-server/20-http/50-codegen.ts +29 -0
- package/docs/concepts/02-server/20-http/index.md +3 -0
- package/docs/concepts/02-server/30-environment/10-platform.ts +38 -0
- package/docs/concepts/02-server/30-environment/20-variable.ts +41 -0
- package/docs/concepts/02-server/30-environment/index.md +3 -0
- package/docs/concepts/02-server/40-command/10-use.ts +112 -0
- package/docs/concepts/02-server/40-command/20-sub-command.ts +48 -0
- package/docs/concepts/02-server/40-command/index.md +3 -0
- package/docs/concepts/02-server/index.md +1 -0
- package/docs/concepts/03-client/10-http/10-init.ts +64 -0
- package/docs/concepts/03-client/10-http/20-request.ts +244 -0
- package/docs/concepts/03-client/10-http/30-hook.ts +139 -0
- package/docs/concepts/03-client/10-http/index.md +3 -0
- package/docs/concepts/03-client/20-form/10-init.ts +95 -0
- package/docs/concepts/03-client/20-form/20-input.ts +96 -0
- package/docs/concepts/03-client/20-form/30-layout.ts +160 -0
- package/docs/concepts/03-client/20-form/40-template.ts +89 -0
- package/docs/concepts/03-client/20-form/index.md +3 -0
- package/docs/concepts/03-client/index.md +1 -0
- package/docs/concepts/04-tests/01-unit/10-either.ts +136 -0
- package/docs/concepts/04-tests/01-unit/20-server-mocking.ts +53 -0
- package/docs/concepts/04-tests/01-unit/index.md +3 -0
- package/docs/concepts/04-tests/02-e2e/10-init.ts +80 -0
- package/docs/concepts/04-tests/02-e2e/20-architecture.ts +76 -0
- package/docs/concepts/04-tests/02-e2e/30-testing.ts +90 -0
- package/docs/concepts/04-tests/02-e2e/index.md +3 -0
- package/docs/concepts/04-tests/index.md +1 -0
- package/docs/concepts/05-type-driven-design/01-architecture/10-boundaries.md +41 -0
- package/docs/concepts/05-type-driven-design/01-architecture/index.md +3 -0
- package/docs/concepts/05-type-driven-design/02-domains/10-entities.md +58 -0
- package/docs/concepts/05-type-driven-design/02-domains/20-aggregates.md +49 -0
- package/docs/concepts/05-type-driven-design/02-domains/30-repositories.md +41 -0
- package/docs/concepts/05-type-driven-design/02-domains/index.md +3 -0
- package/docs/concepts/05-type-driven-design/03-applications/10-use-case.md +69 -0
- package/docs/concepts/05-type-driven-design/03-applications/index.md +3 -0
- package/docs/concepts/05-type-driven-design/04-infrastructure/10-implementation.md +56 -0
- package/docs/concepts/05-type-driven-design/04-infrastructure/index.md +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/book.ts +10 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/client.ts +10 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/email.ts +7 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/clientGiveBackBook.ts +27 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/clientRentBook.ts +30 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/createBook.ts +32 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/clientGiveBackBook.ts +15 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/clientRentBook.ts +16 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/createBook.ts +21 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/create.ts +34 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/rental.ts +31 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/returnBook.ts +30 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/index.ts +87 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/facts/giveBackBook.ts +33 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/facts/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/facts/rentBook.ts +32 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/index.ts +82 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/book.ts +16 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/client.ts +7 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/email.ts +12 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/command/clientRentBook.ts +62 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/command/index.ts +11 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/checkers/bookExist.ts +19 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/checkers/clientExist.ts +19 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/checkers/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/main.ts +19 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/routes/clientGiveBackBook.ts +37 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/routes/clientRentBook.ts +50 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/routes/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/book.ts +25 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/client.ts +7 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/email.ts +10 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/useCases/index.ts +12 -0
- package/docs/concepts/05-type-driven-design/index.md +3 -0
- package/docs/concepts.llms.md +475 -0
- package/instructions/coding-conventions.md +8 -0
- package/package.json +96 -3
- package/skills/command/SKILL.md +63 -0
- package/skills/command/references/examples/cli.ts +22 -0
- package/skills/command/references/examples/options-only.ts +27 -0
- package/skills/command/references/examples/preview-command.ts +57 -0
- package/skills/command/references/execution.md +31 -0
- package/skills/command/references/inputs.md +27 -0
- package/skills/fundamental/SKILL.md +80 -0
- package/skills/fundamental/references/composition.md +35 -0
- package/skills/fundamental/references/constraints-and-validation.md +61 -0
- package/skills/fundamental/references/examples/async-composition.ts +15 -0
- package/skills/fundamental/references/examples/cast.ts +18 -0
- package/skills/fundamental/references/examples/composition.ts +40 -0
- package/skills/fundamental/references/examples/environment-initialization.ts +19 -0
- package/skills/fundamental/references/examples/error-propagation.ts +24 -0
- package/skills/fundamental/references/examples/generic-inference.ts +31 -0
- package/skills/fundamental/references/examples/guaranteed-array-access.ts +31 -0
- package/skills/fundamental/references/examples/independent-inputs.ts +18 -0
- package/skills/fundamental/references/examples/infer.ts +21 -0
- package/skills/fundamental/references/examples/input-validation.ts +37 -0
- package/skills/fundamental/references/examples/safe-declarations.ts +25 -0
- package/skills/fundamental/references/results-and-errors.md +59 -0
- package/skills/http-client/SKILL.md +50 -0
- package/skills/http-client/references/configuration.md +9 -0
- package/skills/http-client/references/examples/client-expectations.ts +84 -0
- package/skills/http-client/references/examples/client-streams.ts +74 -0
- package/skills/http-client/references/examples/external-client.ts +78 -0
- package/skills/http-client/references/hooks.md +7 -0
- package/skills/http-client/references/responses.md +39 -0
- package/skills/http-client/references/streams.md +10 -0
- package/skills/http-server/SKILL.md +66 -0
- package/skills/http-server/references/code-generation.md +31 -0
- package/skills/http-server/references/examples/authentication.ts +42 -0
- package/skills/http-server/references/examples/contracts.ts +19 -0
- package/skills/http-server/references/examples/generate-sdk.ts +36 -0
- package/skills/http-server/references/examples/initialize.ts +29 -0
- package/skills/http-server/references/examples/minimal-route.ts +18 -0
- package/skills/http-server/references/examples/protected-route.ts +31 -0
- package/skills/http-server/references/examples/rename-user-route.ts +54 -0
- package/skills/http-server/references/examples/user-checker.ts +26 -0
- package/skills/http-server/references/examples/user-route.ts +38 -0
- package/skills/http-server/references/initialization.md +33 -0
- package/skills/http-server/references/reusable-flows.md +40 -0
- package/skills/http-server/references/routes-and-floor.md +38 -0
- package/skills/modeling/SKILL.md +76 -0
- package/skills/modeling/references/domain.md +33 -0
- package/skills/modeling/references/orchestration.md +36 -0
- package/skills/server/SKILL.md +55 -0
- package/skills/server/references/environment.md +30 -0
- package/skills/server/references/examples/environment.ts +41 -0
- package/skills/server/references/examples/file-structure.ts +26 -0
- package/skills/server/references/examples/files.ts +52 -0
- package/skills/server/references/files.md +38 -0
- package/skills/server/references/structures.md +15 -0
- package/skills/test/SKILL.md +70 -0
- package/skills/test/references/examples/results.ts +95 -0
- package/skills/test/references/examples/server.ts +59 -0
- package/skills/test/references/results.md +21 -0
- package/skills/test/references/server.md +17 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Entités métier et hydratation.
|
|
3
|
+
*
|
|
4
|
+
* Déclarer les propriétés métier, hydrater les données externes et mettre à jour les valeurs typées.
|
|
5
|
+
*/
|
|
6
|
+
import * as DEither from "@duplojs/lang/either";
|
|
7
|
+
import * as DDataStructure from "@duplojs/lang/dataStructure";
|
|
8
|
+
import * as DModeling from "@duplojs/lang/modeling";
|
|
9
|
+
import * as DArray from "@duplojs/lang/array";
|
|
10
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
11
|
+
|
|
12
|
+
// Une Entity représente un objet métier doté d’une identité explicite.
|
|
13
|
+
// Ses valeurs primitives sont définies par des NewType qui associent un sens métier
|
|
14
|
+
// et des contraintes à leur représentation. Des collections, objets imbriqués,
|
|
15
|
+
// autres Entity ou TaggedObject peuvent également composer la shape.
|
|
16
|
+
export namespace User {
|
|
17
|
+
// Un namespace d'entité permet de regrouper la définition de l'entité
|
|
18
|
+
// et de ses `NewType`.
|
|
19
|
+
//
|
|
20
|
+
// Les noms des `NewType` créés avec ce namespace sont automatiquement
|
|
21
|
+
// préfixés par le nom de l'entité.
|
|
22
|
+
const namespace = DModeling.createEntityNamespace("User");
|
|
23
|
+
|
|
24
|
+
// string & DModeling.NewType<"UserId", DString.Uuid>
|
|
25
|
+
export const Id = namespace.createNewType(
|
|
26
|
+
"Id",
|
|
27
|
+
DDataStructure.string(),
|
|
28
|
+
[DDataStructure.uuid()],
|
|
29
|
+
);
|
|
30
|
+
export type Id = DDataStructure.StructureValue<typeof Id>;
|
|
31
|
+
|
|
32
|
+
// number & DModeling.NewType<"UserAge", Integer | Positive>
|
|
33
|
+
export const Age = namespace.createNewType(
|
|
34
|
+
"Age",
|
|
35
|
+
DDataStructure.number(),
|
|
36
|
+
[
|
|
37
|
+
DDataStructure.integer(),
|
|
38
|
+
DDataStructure.positive(),
|
|
39
|
+
],
|
|
40
|
+
);
|
|
41
|
+
export type Age = DDataStructure.StructureValue<typeof Age>;
|
|
42
|
+
|
|
43
|
+
// string & DModeling.NewType<"UserName", DString.Trimmed | DString.MinCharacters<3> | DString.MaxCharacters<45>>
|
|
44
|
+
export const Name = namespace.createNewType(
|
|
45
|
+
"Name",
|
|
46
|
+
DDataStructure.string(),
|
|
47
|
+
[
|
|
48
|
+
DDataStructure.trimmed(),
|
|
49
|
+
DDataStructure.minCharacters(3),
|
|
50
|
+
DDataStructure.maxCharacters(45),
|
|
51
|
+
],
|
|
52
|
+
);
|
|
53
|
+
export type Name = DDataStructure.StructureValue<typeof Name>;
|
|
54
|
+
|
|
55
|
+
// string & DModeling.NewType<"UserTag", DString.Trimmed | DString.MinCharacters<2> | DString.MaxCharacters<20>>
|
|
56
|
+
export const Tag = namespace.createNewType(
|
|
57
|
+
"Tag",
|
|
58
|
+
DDataStructure.string(),
|
|
59
|
+
[
|
|
60
|
+
DDataStructure.trimmed(),
|
|
61
|
+
DDataStructure.minCharacters(2),
|
|
62
|
+
DDataStructure.maxCharacters(20),
|
|
63
|
+
],
|
|
64
|
+
);
|
|
65
|
+
export type Tag = DDataStructure.StructureValue<typeof Tag>;
|
|
66
|
+
|
|
67
|
+
// L'entité est ensuite déclarée à partir de ses différentes propriétés.
|
|
68
|
+
//
|
|
69
|
+
// DModeling.Entity<"User"> & {
|
|
70
|
+
// readonly name: string
|
|
71
|
+
// & DModeling.NewType<"UserName", DString.Trimmed | DString.MinCharacters<3> | DString.MaxCharacters<45>>;
|
|
72
|
+
// readonly id: string
|
|
73
|
+
// & DModeling.NewType<"UserId", DString.Uuid>;
|
|
74
|
+
// readonly age: number & DModeling.NewType<"UserAge", DNumber.Integer | DNumber.Positive>;
|
|
75
|
+
// readonly tags: readonly (
|
|
76
|
+
// string & DModeling.NewType<"UserTag", DString.Trimmed | DString.MinCharacters<2> | DString.MaxCharacters<20>>
|
|
77
|
+
// )[];
|
|
78
|
+
// };
|
|
79
|
+
export const Entity = namespace.createEntity(
|
|
80
|
+
() => ({
|
|
81
|
+
id: Id,
|
|
82
|
+
age: Age,
|
|
83
|
+
name: Name,
|
|
84
|
+
tags: DDataStructure.array(Tag),
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
export type Entity = DDataStructure.StructureValue<typeof Entity>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// L’hydratation fait entrer dans le modèle métier des données de repository ou de base de données.
|
|
91
|
+
// Une donnée provenant d’un système externe possède généralement un typage
|
|
92
|
+
// amoindri par rapport au modèle métier.
|
|
93
|
+
//
|
|
94
|
+
// Les contraintes et les `NewType` ne sont plus présents, mais les types
|
|
95
|
+
// primitifs restent connus.
|
|
96
|
+
//
|
|
97
|
+
// `map` permet d'hydrater l'entité depuis cette représentation.
|
|
98
|
+
//
|
|
99
|
+
// Les contraintes sont vérifiées pendant cette opération.
|
|
100
|
+
// Le mapping pouvant échouer, son résultat est représenté par un `Either`.
|
|
101
|
+
|
|
102
|
+
// DEither.Left<"async-error", DDataStructure.ErrorPromise> | DEither.Left<"map-error", DDataStructure.Error>
|
|
103
|
+
// | DEither.Right<"map-success", DModeling.Entity<"User"> & {
|
|
104
|
+
// readonly name: string & DModeling.NewType<"UserName", Trimmed | MinCharacters<3> | MaxCharacters<45>>;
|
|
105
|
+
// readonly id: string & DModeling.NewType<"UserId", Uuid>;
|
|
106
|
+
// readonly age: number & DModeling.NewType<"UserAge", Integer | Positive>;
|
|
107
|
+
// readonly tags: readonly (
|
|
108
|
+
// DModeling.NewType<"UserTag", DString.Trimmed | DString.MinCharacters<2> | DString.MaxCharacters<20>>
|
|
109
|
+
// )[];
|
|
110
|
+
// }>
|
|
111
|
+
const maybeMapUser = User.Entity.map({
|
|
112
|
+
id: "invalid-id",
|
|
113
|
+
name: "SuperName",
|
|
114
|
+
age: 12,
|
|
115
|
+
tags: ["superTag"],
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// `decodeMap` applique le même principe à une donnée encodée.
|
|
119
|
+
//
|
|
120
|
+
// La représentation demandée en entrée dépend des codecs utilisés.
|
|
121
|
+
// Avec `codecsString`, les types fondamentaux qui possèdent une représentation
|
|
122
|
+
// string sont attendus sous cette forme.
|
|
123
|
+
//
|
|
124
|
+
// L'âge de l'entité est donc ici fourni dans sa représentation encodée
|
|
125
|
+
// plutôt que directement comme un `number`.
|
|
126
|
+
|
|
127
|
+
// DEither.Left<"async-error", DDataStructure.ErrorPromise> | DEither.Left<"map-error", DDataStructure.Error>
|
|
128
|
+
// | DEither.Right<"map-success", DModeling.Entity<"User"> & {
|
|
129
|
+
// readonly name: string & DModeling.NewType<"UserName", Trimmed | MinCharacters<3> | MaxCharacters<45>>;
|
|
130
|
+
// readonly id: string & DModeling.NewType<"UserId", Uuid>;
|
|
131
|
+
// readonly age: number & DModeling.NewType<"UserAge", Integer | Positive>;
|
|
132
|
+
// readonly tags: readonly (
|
|
133
|
+
// DModeling.NewType<"UserTag", DString.Trimmed | DString.MinCharacters<2> | DString.MaxCharacters<20>>
|
|
134
|
+
// )[];
|
|
135
|
+
// }>
|
|
136
|
+
const maybeDecodeMapUser = User.Entity.decodeMap(DDataStructure.codecsString, {
|
|
137
|
+
id: "550e8400-e29b-41d4-a716-446655440000",
|
|
138
|
+
name: "SuperName",
|
|
139
|
+
age: DCommon.cast("12"),
|
|
140
|
+
tags: ["superTag"],
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// `new` est utilisé lorsque les propriétés possèdent déjà leur typage métier.
|
|
144
|
+
//
|
|
145
|
+
// Ici, chaque `NewType` est d'abord hydraté individuellement avec `map`.
|
|
146
|
+
// `DEither.group` regroupe ensuite les différentes opérations avant de fournir
|
|
147
|
+
// leurs valeurs à `User.Entity.new`.
|
|
148
|
+
//
|
|
149
|
+
// `new` n'effectue donc pas lui-même le mapping des propriétés.
|
|
150
|
+
// Il construit l'entité à partir de valeurs déjà correctement typées.
|
|
151
|
+
//
|
|
152
|
+
// Le résultat du `rightPipe` conserve la monade `Success` produite après
|
|
153
|
+
// regroupement des différentes validations.
|
|
154
|
+
|
|
155
|
+
// DEither.Left<"async-error", DDataStructure.ErrorPromise> | DEither.Left<"map-error", DDataStructure.Error>
|
|
156
|
+
// | DEither.Success<DModeling.Entity<"User"> & {
|
|
157
|
+
// readonly id: string & DModeling.NewType<"UserId", Uuid>;
|
|
158
|
+
// readonly name: string & DModeling.NewType<"UserName", Trimmed | MinCharacters<3> | MaxCharacters<45>>;
|
|
159
|
+
// readonly age: number & DModeling.NewType<"UserAge", Integer | Positive>;
|
|
160
|
+
// readonly tags: readonly [
|
|
161
|
+
// DModeling.NewType<"UserTag", DString.Trimmed | DString.MinCharacters<2> | DString.MaxCharacters<20>>
|
|
162
|
+
// ];
|
|
163
|
+
// }>
|
|
164
|
+
const maybeUser = DEither.rightPipe(
|
|
165
|
+
DEither.group({
|
|
166
|
+
id: User.Id.map("550e8400-e29b-41d4-a716-446655440000"),
|
|
167
|
+
name: User.Name.map("SuperName"),
|
|
168
|
+
age: User.Age.map(24),
|
|
169
|
+
tags: DEither.rightPipe(
|
|
170
|
+
User.Tag.map("superTag"),
|
|
171
|
+
DArray.coalescing,
|
|
172
|
+
),
|
|
173
|
+
}),
|
|
174
|
+
User.Entity.new,
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
declare const user: User.Entity;
|
|
178
|
+
declare const maybeAge: User.Age | undefined;
|
|
179
|
+
|
|
180
|
+
// User.Entity
|
|
181
|
+
const updatedUser = User.Entity.update(
|
|
182
|
+
user,
|
|
183
|
+
{
|
|
184
|
+
age: maybeAge,
|
|
185
|
+
},
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// `update` retourne une nouvelle entité en remplaçant uniquement
|
|
189
|
+
// les propriétés dont la nouvelle valeur n'est pas `undefined`.
|
|
190
|
+
//
|
|
191
|
+
// Contrairement à un spread classique, une valeur `undefined`
|
|
192
|
+
// n'écrase donc pas la valeur déjà présente sur l'entité.
|
|
193
|
+
//
|
|
194
|
+
// Si `maybeAge` vaut `undefined`, `user.age` est conservé.
|
|
195
|
+
// Sinon, sa valeur remplace l'âge existant.
|
|
196
|
+
//
|
|
197
|
+
// Les nouvelles valeurs ne sont pas validées par `update` :
|
|
198
|
+
// elles doivent déjà posséder le typage métier attendu.
|
|
199
|
+
|
|
200
|
+
// `map` et `decodeMap` existent aussi sur les `NewType`.
|
|
201
|
+
// Ces opérations ne sont donc pas spécifiques aux entités.
|
|
202
|
+
//
|
|
203
|
+
// Les variantes `asyncMap` et `asyncDecodeMap` permettent la même hydratation
|
|
204
|
+
// lorsque la structure contient des traitements asynchrones.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Objets taggés et unions discriminées.
|
|
3
|
+
*
|
|
4
|
+
* Identité transportable, distinction des formes d’un objet et hydratation des données brutes.
|
|
5
|
+
*/
|
|
6
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
7
|
+
import * as DDataStructure from "@duplojs/lang/dataStructure";
|
|
8
|
+
import * as DModeling from "@duplojs/lang/modeling";
|
|
9
|
+
import * as DPattern from "@duplojs/lang/pattern";
|
|
10
|
+
import * as DEither from "@duplojs/lang/either";
|
|
11
|
+
|
|
12
|
+
// Sans `TaggedObject`, une union discriminée serait généralement construite
|
|
13
|
+
// en ajoutant soi-même une propriété comme `type` ou `kind`.
|
|
14
|
+
//
|
|
15
|
+
// `createTaggedObject` normalise cette identité.
|
|
16
|
+
// Le code métier n'a pas à choisir ni à manipuler la clé utilisée pour
|
|
17
|
+
// enregistrer le tag.
|
|
18
|
+
//
|
|
19
|
+
// DModeling.ObjectTag<"EmailNotification"> & {
|
|
20
|
+
// readonly email: string;
|
|
21
|
+
// readonly subject: string;
|
|
22
|
+
// }
|
|
23
|
+
const EmailNotification = DModeling.createTaggedObject(
|
|
24
|
+
"EmailNotification",
|
|
25
|
+
{
|
|
26
|
+
email: DDataStructure.string(),
|
|
27
|
+
subject: DDataStructure.string(),
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
type EmailNotification = DDataStructure.StructureValue<typeof EmailNotification>;
|
|
31
|
+
|
|
32
|
+
// Les propriétés peuvent être définies directement avec des `DataStructure`.
|
|
33
|
+
//
|
|
34
|
+
// Contrairement à une `Entity`, un `TaggedObject` n'impose pas que ses
|
|
35
|
+
// propriétés soient des `NewType`.
|
|
36
|
+
//
|
|
37
|
+
// DModeling.ObjectTag<"SmsNotification"> & {
|
|
38
|
+
// readonly phone: string;
|
|
39
|
+
// readonly message: string;
|
|
40
|
+
// readonly attempts: number;
|
|
41
|
+
// }
|
|
42
|
+
const SmsNotification = DModeling.createTaggedObject(
|
|
43
|
+
"SmsNotification",
|
|
44
|
+
{
|
|
45
|
+
phone: DDataStructure.string(),
|
|
46
|
+
message: DDataStructure.string(),
|
|
47
|
+
attempts: DDataStructure.number(),
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
type SmsNotification = DDataStructure.StructureValue<typeof SmsNotification>;
|
|
51
|
+
|
|
52
|
+
// Plusieurs `TaggedObject` peuvent former une union discriminée.
|
|
53
|
+
//
|
|
54
|
+
// Leur identité permet de retrouver précisément la forme correspondante
|
|
55
|
+
// sans ajouter manuellement une propriété discriminante au modèle.
|
|
56
|
+
type Notification =
|
|
57
|
+
| EmailNotification
|
|
58
|
+
| SmsNotification;
|
|
59
|
+
|
|
60
|
+
declare const notification: Notification;
|
|
61
|
+
|
|
62
|
+
// `matchWithTaggedObject` discrimine directement l'union à partir du tag.
|
|
63
|
+
//
|
|
64
|
+
// Chaque callback reçoit la forme exacte associée à son identité.
|
|
65
|
+
const destination = DPattern.matchWithTaggedObject(
|
|
66
|
+
notification,
|
|
67
|
+
{
|
|
68
|
+
EmailNotification: (emailNotification) => emailNotification.email,
|
|
69
|
+
SmsNotification: (smsNotification) => smsNotification.phone,
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// L'identité peut également être récupérée directement.
|
|
74
|
+
//
|
|
75
|
+
// "EmailNotification" | "SmsNotification"
|
|
76
|
+
const notificationType = DModeling.getTagValue(notification);
|
|
77
|
+
|
|
78
|
+
// `hasTagValue` permet de tester une identité et affine simultanément
|
|
79
|
+
// le type de la valeur.
|
|
80
|
+
//
|
|
81
|
+
// Dans cette branche, `notification` est précisément un `EmailNotification`.
|
|
82
|
+
if (DModeling.hasTagValue(notification, "EmailNotification")) {
|
|
83
|
+
const subject = notification.subject;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// `new` est utilisé lorsque les propriétés possèdent déjà le typage attendu.
|
|
87
|
+
//
|
|
88
|
+
// Il construit le `TaggedObject` et lui associe son identité.
|
|
89
|
+
//
|
|
90
|
+
// EmailNotification
|
|
91
|
+
const emailNotification = EmailNotification.new({
|
|
92
|
+
email: "user@example.com",
|
|
93
|
+
subject: "Account created",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// L'identité fait partie de la structure du `TaggedObject`.
|
|
97
|
+
//
|
|
98
|
+
// Les opérations génériques comme `check`, `is`, `encode` ou `decode`
|
|
99
|
+
// travaillent donc avec une valeur qui possède déjà cette identité.
|
|
100
|
+
//
|
|
101
|
+
// Une donnée brute provenant d'une base de données, d'une API externe
|
|
102
|
+
// ou d'un autre système ne la possède généralement pas encore.
|
|
103
|
+
declare const externalEmailNotification: {
|
|
104
|
+
email: string;
|
|
105
|
+
subject: string;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// `map` sert à hydrater cette donnée lorsqu'elle entre dans le domaine.
|
|
109
|
+
//
|
|
110
|
+
// Le mapping ajoute l'identité du `TaggedObject`, vérifie sa structure
|
|
111
|
+
// et ses contraintes, puis retourne la valeur correctement typée.
|
|
112
|
+
//
|
|
113
|
+
// Le type demandé en entrée est volontairement moins précis que le type
|
|
114
|
+
// métier final afin de représenter les données provenant de systèmes externes.
|
|
115
|
+
//
|
|
116
|
+
// L'hydratation peut échouer, son résultat est donc représenté par un `Either`.
|
|
117
|
+
|
|
118
|
+
// DEither.Left<"async-error", DDataStructure.ErrorPromise>
|
|
119
|
+
// | DEither.Left<"map-error", DDataStructure.Error>
|
|
120
|
+
// | DEither.Right<"map-success", EmailNotification>
|
|
121
|
+
const maybeEmailNotification = EmailNotification.map(
|
|
122
|
+
externalEmailNotification,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Une fois hydraté, le tag fait partie de la donnée.
|
|
126
|
+
//
|
|
127
|
+
// Si ce `TaggedObject` est ensuite sérialisé et transporté vers un autre
|
|
128
|
+
// consommateur, son identité est conservée.
|
|
129
|
+
// Il n'a donc pas besoin d'être hydraté une seconde fois simplement
|
|
130
|
+
// parce qu'il traverse une frontière entre deux services.
|
|
131
|
+
//
|
|
132
|
+
// DEither.Left<"async-error", DDataStructure.ErrorPromise>
|
|
133
|
+
// | DEither.Left<"map-error", DDataStructure.Error>
|
|
134
|
+
// | (DModeling.ObjectTag<"EmailNotification"> & {
|
|
135
|
+
// readonly email: string;
|
|
136
|
+
// readonly subject: string;
|
|
137
|
+
// })
|
|
138
|
+
const mappedEmailNotification = DCommon.pipe(
|
|
139
|
+
EmailNotification.map({
|
|
140
|
+
email: "user@example.com",
|
|
141
|
+
subject: "Account created",
|
|
142
|
+
}),
|
|
143
|
+
DEither.unwrapRight,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// `decodeMap` suit le même principe que `map`, mais commence par décoder
|
|
147
|
+
// la représentation externe avec les codecs fournis.
|
|
148
|
+
//
|
|
149
|
+
// Ici, `attempts` provient par exemple d'une représentation string avant
|
|
150
|
+
// de retrouver son type métier `number`.
|
|
151
|
+
|
|
152
|
+
// DEither.Left<"async-error", DDataStructure.ErrorPromise>
|
|
153
|
+
// | DEither.Left<"map-error", DDataStructure.Error>
|
|
154
|
+
// | DEither.Right<"map-success", SmsNotification>
|
|
155
|
+
const maybeSmsNotification = SmsNotification.decodeMap(
|
|
156
|
+
DDataStructure.codecsString,
|
|
157
|
+
{
|
|
158
|
+
phone: "+33600000000",
|
|
159
|
+
message: "Account created",
|
|
160
|
+
attempts: DCommon.cast("1"),
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// `update` reconstruit un `TaggedObject` possédant la même identité
|
|
165
|
+
// en remplaçant uniquement les propriétés fournies.
|
|
166
|
+
//
|
|
167
|
+
// Comme pour les autres structures de modeling, `undefined` ne remplace
|
|
168
|
+
// pas une propriété déjà présente.
|
|
169
|
+
const updatedSmsNotification = SmsNotification.update(
|
|
170
|
+
SmsNotification.new({
|
|
171
|
+
phone: "+33600000000",
|
|
172
|
+
message: "Account created",
|
|
173
|
+
attempts: 1,
|
|
174
|
+
}),
|
|
175
|
+
{
|
|
176
|
+
attempts: 2,
|
|
177
|
+
},
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// Les variantes `asyncMap` et `asyncDecodeMap` permettent la même
|
|
181
|
+
// hydratation lorsqu'une structure contient des traitements asynchrones.
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Cycle de vie des entités.
|
|
3
|
+
*
|
|
4
|
+
* États, préconditions et transitions métier représentés par des Flag et des Fact.
|
|
5
|
+
*/
|
|
6
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
7
|
+
import * as DDataStructure from "@duplojs/lang/dataStructure";
|
|
8
|
+
import * as DModeling from "@duplojs/lang/modeling";
|
|
9
|
+
import * as DChrono from "@duplojs/lang/chrono";
|
|
10
|
+
import * as DPattern from "@duplojs/lang/pattern";
|
|
11
|
+
import * as DEither from "@duplojs/lang/either";
|
|
12
|
+
|
|
13
|
+
// Le modèle et les signatures expriment les états possibles, leurs preuves et les événements
|
|
14
|
+
// qui font évoluer l’entité. Les préconditions deviennent des exigences de typage.
|
|
15
|
+
export namespace User {
|
|
16
|
+
const namespace = DModeling.createEntityNamespace("User");
|
|
17
|
+
|
|
18
|
+
export const Id = namespace.createNewType(
|
|
19
|
+
"Id",
|
|
20
|
+
DDataStructure.string(),
|
|
21
|
+
[DDataStructure.uuid()],
|
|
22
|
+
);
|
|
23
|
+
export type Id = DDataStructure.StructureValue<typeof Id>;
|
|
24
|
+
|
|
25
|
+
export const Age = namespace.createNewType(
|
|
26
|
+
"Age",
|
|
27
|
+
DDataStructure.number(),
|
|
28
|
+
[
|
|
29
|
+
DDataStructure.integer(),
|
|
30
|
+
DDataStructure.positive(),
|
|
31
|
+
],
|
|
32
|
+
);
|
|
33
|
+
export type Age = DDataStructure.StructureValue<typeof Age>;
|
|
34
|
+
|
|
35
|
+
export const Name = namespace.createNewType(
|
|
36
|
+
"Name",
|
|
37
|
+
DDataStructure.string(),
|
|
38
|
+
[
|
|
39
|
+
DDataStructure.trimmed(),
|
|
40
|
+
DDataStructure.minCharacters(3),
|
|
41
|
+
DDataStructure.maxCharacters(45),
|
|
42
|
+
],
|
|
43
|
+
);
|
|
44
|
+
export type Name = DDataStructure.StructureValue<typeof Name>;
|
|
45
|
+
|
|
46
|
+
// Les `TaggedObject` décrivent les propriétés propres à chaque état.
|
|
47
|
+
// Leur tag permet de discriminer ces formes ; leur fonctionnement est détaillé
|
|
48
|
+
// dans le concept consacré aux objets taggés.
|
|
49
|
+
export const AwaitingValidationState = DModeling.createTaggedObject(
|
|
50
|
+
"AwaitingValidationState",
|
|
51
|
+
{
|
|
52
|
+
sendValidationAt: DDataStructure.date(),
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
export type AwaitingValidationState = DDataStructure.StructureValue<typeof AwaitingValidationState>;
|
|
56
|
+
|
|
57
|
+
export const Address = namespace.createNewType("Address", DDataStructure.string());
|
|
58
|
+
export type Address = DDataStructure.StructureValue<typeof Address>;
|
|
59
|
+
|
|
60
|
+
export const ValidateState = DModeling.createTaggedObject(
|
|
61
|
+
"ValidateState",
|
|
62
|
+
{
|
|
63
|
+
address: Address,
|
|
64
|
+
validateAt: DDataStructure.date(),
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
export type ValidateState = DDataStructure.StructureValue<typeof ValidateState>;
|
|
68
|
+
|
|
69
|
+
// La shape de l'entité reste fixe pendant son cycle de vie.
|
|
70
|
+
// Les propriétés dont la forme varie sont modélisées par des unions : ici,
|
|
71
|
+
// `state` contient soit `AwaitingValidationState`, soit `ValidateState`.
|
|
72
|
+
export const Entity = namespace.createEntity(
|
|
73
|
+
() => ({
|
|
74
|
+
id: Id,
|
|
75
|
+
age: Age,
|
|
76
|
+
name: Name,
|
|
77
|
+
state: DDataStructure.union([
|
|
78
|
+
AwaitingValidationState,
|
|
79
|
+
ValidateState,
|
|
80
|
+
]),
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
export type Entity = DDataStructure.StructureValue<typeof Entity>;
|
|
84
|
+
|
|
85
|
+
// Un `Flag` certifie une condition sur l'entité actuelle : état, capacité ou relation.
|
|
86
|
+
// Plusieurs flags compatibles peuvent coexister, indépendamment des variantes de `state`.
|
|
87
|
+
// Ici, chacun porte au runtime la payload de l'état qu'il certifie.
|
|
88
|
+
// Une fonction exigeant `User.Entity & User.AwaitingValidationFlag` reçoit ainsi
|
|
89
|
+
// une entité dont l'état d'attente est prouvé, avec son `AwaitingValidationState`.
|
|
90
|
+
export type AwaitingValidationFlag = DModeling.Flag<
|
|
91
|
+
"AwaitingValidation",
|
|
92
|
+
AwaitingValidationState
|
|
93
|
+
>;
|
|
94
|
+
export const AwaitingValidationFlag = DModeling.createFlag<
|
|
95
|
+
AwaitingValidationFlag,
|
|
96
|
+
typeof Entity
|
|
97
|
+
>("AwaitingValidation");
|
|
98
|
+
|
|
99
|
+
export type ValidateFlag = DModeling.Flag<
|
|
100
|
+
"Validate",
|
|
101
|
+
ValidateState
|
|
102
|
+
>;
|
|
103
|
+
export const ValidateFlag = DModeling.createFlag<
|
|
104
|
+
ValidateFlag,
|
|
105
|
+
typeof Entity
|
|
106
|
+
>("Validate");
|
|
107
|
+
|
|
108
|
+
// Après hydratation, `state` reste typé comme l'union des états possibles.
|
|
109
|
+
// `refineState` inspecte sa valeur et ajoute le flag correspondant sans modifier
|
|
110
|
+
// les propriétés métier. Chaque branche retourne un Result : elle constate l'état,
|
|
111
|
+
// sans décider si celui-ci autorise l'opération envisagée par l'appelant.
|
|
112
|
+
export function refineState<
|
|
113
|
+
GenericEntity extends Entity,
|
|
114
|
+
>(entity: GenericEntity) {
|
|
115
|
+
return DPattern.matchWithTaggedObject(
|
|
116
|
+
entity.state,
|
|
117
|
+
{
|
|
118
|
+
AwaitingValidationState: (state) => DEither.result(
|
|
119
|
+
"AwaitingValidation",
|
|
120
|
+
AwaitingValidationFlag.append(entity, state),
|
|
121
|
+
),
|
|
122
|
+
ValidateState: (state) => DEither.result(
|
|
123
|
+
"Validate",
|
|
124
|
+
ValidateFlag.append(entity, state),
|
|
125
|
+
),
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Une `Fact` représente une création ou une modification métier de l'entité,
|
|
132
|
+
// y compris un changement de propriété qui conserve le même état nommé.
|
|
133
|
+
// Sa payload décrit l'événement et reste portée par l'entité après application du fait.
|
|
134
|
+
// Ici, la création place toujours l'utilisateur en attente de validation.
|
|
135
|
+
export type UserCreateFact = DModeling.Fact<
|
|
136
|
+
"UserCreated",
|
|
137
|
+
{
|
|
138
|
+
id: User.Id;
|
|
139
|
+
age: User.Age;
|
|
140
|
+
name: User.Name;
|
|
141
|
+
state: User.AwaitingValidationState;
|
|
142
|
+
}
|
|
143
|
+
>;
|
|
144
|
+
export const UserCreateFact = DModeling.createFact<
|
|
145
|
+
UserCreateFact,
|
|
146
|
+
typeof User.Entity
|
|
147
|
+
>("UserCreated")(
|
|
148
|
+
({ applyFact }) => (
|
|
149
|
+
params: {
|
|
150
|
+
id: User.Id;
|
|
151
|
+
age: User.Age;
|
|
152
|
+
name: User.Name;
|
|
153
|
+
},
|
|
154
|
+
) => {
|
|
155
|
+
// La payload décrit complètement le fait qui vient de se produire.
|
|
156
|
+
//
|
|
157
|
+
// Elle contient notamment l'état produit par cette étape du cycle de vie,
|
|
158
|
+
// ce qui permet de conserver cette information avec la `Fact`.
|
|
159
|
+
const payload: DModeling.GetFactPayload<UserCreateFact> = {
|
|
160
|
+
id: params.id,
|
|
161
|
+
age: params.age,
|
|
162
|
+
name: params.name,
|
|
163
|
+
state: User.AwaitingValidationState.new({
|
|
164
|
+
sendValidationAt: DChrono.now(),
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// La création exprime plusieurs propriétés métier en une seule opération :
|
|
169
|
+
//
|
|
170
|
+
// - l'entité est créée avec `AwaitingValidationState` ;
|
|
171
|
+
// - le `AwaitingValidationFlag` prouve immédiatement cet état ;
|
|
172
|
+
// - `UserCreated` est apposée comme fait courant sur l'entité.
|
|
173
|
+
return DCommon.pipe(
|
|
174
|
+
payload,
|
|
175
|
+
User.Entity.new,
|
|
176
|
+
User.AwaitingValidationFlag.append(payload.state),
|
|
177
|
+
applyFact(payload),
|
|
178
|
+
);
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Cette `Fact` représente la transition entre l'attente de validation
|
|
183
|
+
// et l'état validé.
|
|
184
|
+
//
|
|
185
|
+
// Sa signature fait elle-même partie de la règle métier :
|
|
186
|
+
// seules les entités possédant `AwaitingValidationFlag` peuvent effectuer
|
|
187
|
+
// cette transition.
|
|
188
|
+
export type ValidateUserFact = DModeling.Fact<
|
|
189
|
+
"ValidateUserFact",
|
|
190
|
+
{
|
|
191
|
+
state: User.ValidateState;
|
|
192
|
+
}
|
|
193
|
+
>;
|
|
194
|
+
export const ValidateUserFact = DModeling.createFact<
|
|
195
|
+
ValidateUserFact,
|
|
196
|
+
typeof User.Entity
|
|
197
|
+
>("ValidateUserFact")(
|
|
198
|
+
({ applyFact }) => (
|
|
199
|
+
user: User.Entity & User.AwaitingValidationFlag,
|
|
200
|
+
params: {
|
|
201
|
+
address: User.Address;
|
|
202
|
+
},
|
|
203
|
+
) => {
|
|
204
|
+
// Le nouvel état appartient à la payload du fait.
|
|
205
|
+
//
|
|
206
|
+
// Le fait `ValidateUserFact` conserve donc également les informations
|
|
207
|
+
// produites lors de cette transition.
|
|
208
|
+
const payload: DModeling.GetFactPayload<ValidateUserFact> = {
|
|
209
|
+
state: User.ValidateState.new({
|
|
210
|
+
address: params.address,
|
|
211
|
+
validateAt: DChrono.now(),
|
|
212
|
+
}),
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// `Entity.update` reconstruit l'entité à partir de sa shape déclarée.
|
|
216
|
+
//
|
|
217
|
+
// Les anciens `Flag` et la précédente `Fact` ne sont donc pas conservés.
|
|
218
|
+
// La transition repart de l'entité dans son nouvel état, puis :
|
|
219
|
+
//
|
|
220
|
+
// - ajoute `ValidateFlag` pour prouver ce nouvel état ;
|
|
221
|
+
// - applique `ValidateUserFact` comme nouveau fait courant.
|
|
222
|
+
return DCommon.pipe(
|
|
223
|
+
user,
|
|
224
|
+
User.Entity.update({ state: payload.state }),
|
|
225
|
+
User.ValidateFlag.append(payload.state),
|
|
226
|
+
applyFact(payload),
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
declare const id: User.Id;
|
|
232
|
+
declare const age: User.Age;
|
|
233
|
+
declare const name: User.Name;
|
|
234
|
+
|
|
235
|
+
const createdUser = DCommon.pipe(
|
|
236
|
+
UserCreateFact.run({
|
|
237
|
+
id,
|
|
238
|
+
age,
|
|
239
|
+
name,
|
|
240
|
+
}),
|
|
241
|
+
DEither.unwrapRight,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
declare const address: User.Address;
|
|
245
|
+
|
|
246
|
+
// Le type de `createdUser` prouve qu'il possède
|
|
247
|
+
// `AwaitingValidationFlag`.
|
|
248
|
+
//
|
|
249
|
+
// Cette preuve satisfait directement la précondition de `ValidateUserFact`.
|
|
250
|
+
// Aucun contrôle supplémentaire de l'état n'est nécessaire ici.
|
|
251
|
+
|
|
252
|
+
// Après la transition :
|
|
253
|
+
// - `state` est précisément `ValidateState` ;
|
|
254
|
+
// - `AwaitingValidationFlag` a disparu ;
|
|
255
|
+
// - `ValidateFlag` prouve le nouvel état ;
|
|
256
|
+
// - `UserCreated` a été remplacée par `ValidateUserFact`.
|
|
257
|
+
//
|
|
258
|
+
// & DModeling.Entity<"User">
|
|
259
|
+
// & {
|
|
260
|
+
// readonly name: string & DModeling.NewType<"UserName", Trimmed | MinCharacters<3> | MaxCharacters<45>>;
|
|
261
|
+
// readonly id: string & DModeling.NewType<"UserId", Uuid>;
|
|
262
|
+
// readonly age: number & DModeling.NewType<"UserAge", Integer | Positive>;
|
|
263
|
+
// readonly state: User.ValidateState;
|
|
264
|
+
// }
|
|
265
|
+
// & DModeling.Flag<"Validate", User.ValidateState>
|
|
266
|
+
// & DModeling.Fact<"ValidateUserFact", {
|
|
267
|
+
// state: User.ValidateState;
|
|
268
|
+
// }>
|
|
269
|
+
const validateUser = DCommon.pipe(
|
|
270
|
+
ValidateUserFact.run(
|
|
271
|
+
createdUser,
|
|
272
|
+
{ address },
|
|
273
|
+
),
|
|
274
|
+
DEither.unwrapRight,
|
|
275
|
+
);
|