@winkjs/composer 0.0.2 → 0.4.0
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/LICENSE +1 -1
- package/README.md +42 -103
- package/package.json +53 -29
- package/src/composer.js +75 -0
- package/src/core/batch/aoo-encoder.js +148 -0
- package/src/core/batch/index.js +12 -0
- package/src/core/batch/sliding-window.js +91 -0
- package/src/core/codec/index.js +137 -0
- package/src/core/emitter-manager/mqtt/constants.js +102 -0
- package/src/core/emitter-manager/mqtt/emitter.js +780 -0
- package/src/core/emitter-manager/mqtt/index.js +190 -0
- package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
- package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
- package/src/core/emitter-manager/terminal/formatters.js +160 -0
- package/src/core/emitter-manager/terminal/index.js +341 -0
- package/src/core/env-vars.js +245 -0
- package/src/core/mqtt-protocol.js +47 -0
- package/src/core/partition-manager/index.js +7 -0
- package/src/core/partition-manager/init.js +44 -0
- package/src/core/partition-manager/introspect.js +15 -0
- package/src/core/partition-manager/publish-to.js +6 -0
- package/src/core/partition-manager/recompute.js +5 -0
- package/src/core/partition-manager/reset.js +5 -0
- package/src/core/partition-manager/update.js +264 -0
- package/src/core/partition-manager/validate-flow.js +157 -0
- package/src/core/semantics/digest.js +128 -0
- package/src/core/semantics/index.js +83 -0
- package/src/core/semantics/loader.js +571 -0
- package/src/core/semantics/schemas/asset-class-schema.js +218 -0
- package/src/core/semantics/schemas/column-schema.js +651 -0
- package/src/core/semantics/schemas/enum-schema.js +153 -0
- package/src/core/semantics/schemas/index.js +51 -0
- package/src/core/semantics/warnings.js +141 -0
- package/src/core/shutdown-manager/index.js +289 -0
- package/src/core/source-manager/csv/index.js +171 -0
- package/src/core/source-manager/csv/start.js +456 -0
- package/src/core/source-manager/mqtt/client.js +406 -0
- package/src/core/source-manager/mqtt/constants.js +147 -0
- package/src/core/source-manager/mqtt/dedup.js +244 -0
- package/src/core/source-manager/mqtt/index.js +260 -0
- package/src/core/source-manager/mqtt/status.js +546 -0
- package/src/core/source-manager/test-harness/comparator.js +226 -0
- package/src/core/source-manager/test-harness/field-generator.js +85 -0
- package/src/core/source-manager/test-harness/fuzz.js +87 -0
- package/src/core/source-manager/test-harness/index.js +115 -0
- package/src/core/source-manager/test-harness/prng.js +57 -0
- package/src/core/source-manager/test-harness/start.js +232 -0
- package/src/core/source-manager/test-harness/validate.js +213 -0
- package/src/core/storage-manager/questdb/assert-columns.js +120 -0
- package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
- package/src/core/storage-manager/questdb/index.js +1251 -0
- package/src/core/storage-manager/questdb/persist-plan.js +488 -0
- package/src/core/storage-manager/questdb/writers.js +142 -0
- package/src/core/test-utils/sealed-record.js +80 -0
- package/src/core/test-utils/soak-signature.js +149 -0
- package/src/core/test-utils/tcp-proxy.js +106 -0
- package/src/core/tunable/helpers.js +254 -0
- package/src/core/tunable/index.js +87 -0
- package/src/core/utils/console-formatter/index.js +207 -0
- package/src/core/utils/create-smart-store-as/index.js +98 -0
- package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
- package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
- package/src/core/utils/flow/index.js +5 -0
- package/src/core/utils/flow/make-collision-checker.js +23 -0
- package/src/core/utils/flow/to-kebab.js +20 -0
- package/src/core/utils/half-life/index.js +111 -0
- package/src/core/utils/node/disable.js +11 -0
- package/src/core/utils/node/enable.js +11 -0
- package/src/core/utils/node/execute-triggers.js +40 -0
- package/src/core/utils/node/index.js +10 -0
- package/src/core/utils/node/pause.js +11 -0
- package/src/core/utils/node/populate-predicate-inputs.js +14 -0
- package/src/core/utils/node/publish-nan.js +19 -0
- package/src/core/utils/node/reset-predicate-inputs.js +11 -0
- package/src/core/utils/node/unpause.js +11 -0
- package/src/core/utils/node/validate-spec.js +22 -0
- package/src/core/utils/options/resolve-field-keyed.js +115 -0
- package/src/core/utils/quantize/index.js +75 -0
- package/src/core/utils/stats/formulas.js +67 -0
- package/src/core/utils/stats/index.js +3 -0
- package/src/core/utils/validate/composer-validators.js +141 -0
- package/src/core/utils/validate/helpers.js +206 -0
- package/src/core/utils/validate/index.js +12 -0
- package/src/core/utils/validate/type-validators.js +538 -0
- package/src/core/utils/validate/validate.js +107 -0
- package/src/core/utils/validate/validators.js +177 -0
- package/src/core/wiring/assert-handle.js +57 -0
- package/src/core/wiring/assert-module.js +63 -0
- package/src/core/wiring/index.js +5 -0
- package/src/core/wiring/node-type-to-module.js +17 -0
- package/src/core/wiring/wire-emitters.js +256 -0
- package/src/core/wiring/wire-linear-graph.js +25 -0
- package/src/core/wiring/wire-node.js +157 -0
- package/src/core/wiring/wire-semantics.js +173 -0
- package/src/core/wiring/wire-storages.js +344 -0
- package/src/flow/check-output-collisions.js +93 -0
- package/src/flow/consts.js +9 -0
- package/src/flow/deep-clone-spec.js +64 -0
- package/src/flow/driver.js +171 -0
- package/src/flow/expand-single-input-array.js +76 -0
- package/src/flow/expand-template-spec.js +93 -0
- package/src/flow/flow-api-schemas.js +300 -0
- package/src/flow/flow.js +658 -0
- package/src/flow/for-each.js +225 -0
- package/src/flow/get-signature-pattern.js +31 -0
- package/src/flow/get-target-array.js +46 -0
- package/src/flow/inspect.js +67 -0
- package/src/flow/load-node-module.js +81 -0
- package/src/flow/make-node-method.js +112 -0
- package/src/flow/resolve-pick-by-field.js +77 -0
- package/src/flow/resolve-tunables.js +76 -0
- package/src/flow/run.js +392 -0
- package/src/flow/serialize.js +161 -0
- package/src/flow/signatures-schema.js +222 -0
- package/src/flow/spec-builder.js +65 -0
- package/src/flow/validate-triggers.js +250 -0
- package/src/flow/validate.js +261 -0
- package/src/nodes/accumulate/index.js +21 -0
- package/src/nodes/accumulate/init.js +48 -0
- package/src/nodes/accumulate/introspect.js +123 -0
- package/src/nodes/accumulate/publish-to.js +34 -0
- package/src/nodes/accumulate/recompute.js +27 -0
- package/src/nodes/accumulate/reset.js +25 -0
- package/src/nodes/accumulate/update.js +42 -0
- package/src/nodes/appraise/calibrate.js +64 -0
- package/src/nodes/appraise/decision.js +66 -0
- package/src/nodes/appraise/deviation.js +140 -0
- package/src/nodes/appraise/index.js +23 -0
- package/src/nodes/appraise/init.js +165 -0
- package/src/nodes/appraise/integrate.js +45 -0
- package/src/nodes/appraise/introspect.js +352 -0
- package/src/nodes/appraise/publish-to.js +93 -0
- package/src/nodes/appraise/receptor.js +69 -0
- package/src/nodes/appraise/recompute.js +79 -0
- package/src/nodes/appraise/reset.js +53 -0
- package/src/nodes/appraise/update.js +130 -0
- package/src/nodes/archive/csv/index.js +6 -0
- package/src/nodes/archive/csv/init.js +36 -0
- package/src/nodes/archive/csv/load.js +70 -0
- package/src/nodes/archive/csv/reset.js +14 -0
- package/src/nodes/archive/csv/simple-parser.js +216 -0
- package/src/nodes/archive/csv/test.js +173 -0
- package/src/nodes/archive/csv/update.js +63 -0
- package/src/nodes/butterworth-filter/index.js +18 -0
- package/src/nodes/butterworth-filter/init.js +184 -0
- package/src/nodes/butterworth-filter/introspect.js +228 -0
- package/src/nodes/butterworth-filter/publish-to.js +21 -0
- package/src/nodes/butterworth-filter/recompute.js +13 -0
- package/src/nodes/butterworth-filter/reset.js +30 -0
- package/src/nodes/butterworth-filter/update.js +38 -0
- package/src/nodes/categorize/index.js +19 -0
- package/src/nodes/categorize/init.js +58 -0
- package/src/nodes/categorize/introspect.js +177 -0
- package/src/nodes/categorize/publish-to.js +29 -0
- package/src/nodes/categorize/recompute.js +14 -0
- package/src/nodes/categorize/reset.js +16 -0
- package/src/nodes/categorize/update.js +53 -0
- package/src/nodes/controller/index.js +9 -0
- package/src/nodes/controller/init.js +55 -0
- package/src/nodes/controller/introspect.js +91 -0
- package/src/nodes/controller/publish-to.js +8 -0
- package/src/nodes/controller/recompute.js +9 -0
- package/src/nodes/controller/reset.js +17 -0
- package/src/nodes/controller/update.js +63 -0
- package/src/nodes/diff/index.js +19 -0
- package/src/nodes/diff/init.js +37 -0
- package/src/nodes/diff/introspect.js +132 -0
- package/src/nodes/diff/publish-to.js +21 -0
- package/src/nodes/diff/recompute.js +12 -0
- package/src/nodes/diff/reset.js +12 -0
- package/src/nodes/diff/update.js +37 -0
- package/src/nodes/digest-moments/formulas.js +12 -0
- package/src/nodes/digest-moments/index.js +14 -0
- package/src/nodes/digest-moments/init.js +67 -0
- package/src/nodes/digest-moments/introspect.js +154 -0
- package/src/nodes/digest-moments/publish-to.js +34 -0
- package/src/nodes/digest-moments/recompute.js +14 -0
- package/src/nodes/digest-moments/reset.js +14 -0
- package/src/nodes/digest-moments/update.js +120 -0
- package/src/nodes/dwell-time-tracker/index.js +14 -0
- package/src/nodes/dwell-time-tracker/init.js +59 -0
- package/src/nodes/dwell-time-tracker/introspect.js +137 -0
- package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
- package/src/nodes/dwell-time-tracker/recompute.js +8 -0
- package/src/nodes/dwell-time-tracker/reset.js +23 -0
- package/src/nodes/dwell-time-tracker/update.js +103 -0
- package/src/nodes/emit-if/helpers.js +94 -0
- package/src/nodes/emit-if/index.js +16 -0
- package/src/nodes/emit-if/init.js +67 -0
- package/src/nodes/emit-if/introspect.js +102 -0
- package/src/nodes/emit-if/publish-to.js +13 -0
- package/src/nodes/emit-if/recompute.js +12 -0
- package/src/nodes/emit-if/reset.js +27 -0
- package/src/nodes/emit-if/update.js +93 -0
- package/src/nodes/es-correlation/index.js +19 -0
- package/src/nodes/es-correlation/init.js +73 -0
- package/src/nodes/es-correlation/introspect.js +176 -0
- package/src/nodes/es-correlation/publish-to.js +32 -0
- package/src/nodes/es-correlation/recompute.js +56 -0
- package/src/nodes/es-correlation/reset.js +27 -0
- package/src/nodes/es-correlation/update.js +110 -0
- package/src/nodes/es-mean/index.js +20 -0
- package/src/nodes/es-mean/init.js +58 -0
- package/src/nodes/es-mean/introspect.js +129 -0
- package/src/nodes/es-mean/publish-to.js +19 -0
- package/src/nodes/es-mean/recompute.js +16 -0
- package/src/nodes/es-mean/reset.js +24 -0
- package/src/nodes/es-mean/update.js +69 -0
- package/src/nodes/es-pairwise-correlation/index.js +19 -0
- package/src/nodes/es-pairwise-correlation/init.js +98 -0
- package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
- package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
- package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
- package/src/nodes/es-pairwise-correlation/reset.js +29 -0
- package/src/nodes/es-pairwise-correlation/update.js +89 -0
- package/src/nodes/es-stats/index.js +21 -0
- package/src/nodes/es-stats/init.js +105 -0
- package/src/nodes/es-stats/introspect.js +157 -0
- package/src/nodes/es-stats/publish-to.js +42 -0
- package/src/nodes/es-stats/recompute.js +74 -0
- package/src/nodes/es-stats/reset.js +49 -0
- package/src/nodes/es-stats/update-envelope.js +44 -0
- package/src/nodes/es-stats/update-welford.js +64 -0
- package/src/nodes/es-stats/update.js +59 -0
- package/src/nodes/index.js +83 -0
- package/src/nodes/invert-flag/index.js +20 -0
- package/src/nodes/invert-flag/init.js +36 -0
- package/src/nodes/invert-flag/introspect.js +115 -0
- package/src/nodes/invert-flag/publish-to.js +23 -0
- package/src/nodes/invert-flag/recompute.js +12 -0
- package/src/nodes/invert-flag/reset.js +12 -0
- package/src/nodes/invert-flag/update.js +32 -0
- package/src/nodes/kalman1d/index.js +20 -0
- package/src/nodes/kalman1d/init.js +103 -0
- package/src/nodes/kalman1d/introspect.js +250 -0
- package/src/nodes/kalman1d/publish-to.js +34 -0
- package/src/nodes/kalman1d/recompute.js +23 -0
- package/src/nodes/kalman1d/reset.js +29 -0
- package/src/nodes/kalman1d/update.js +144 -0
- package/src/nodes/kernel/index.js +18 -0
- package/src/nodes/kernel/init.js +66 -0
- package/src/nodes/kernel/introspect.js +163 -0
- package/src/nodes/kernel/presets.js +74 -0
- package/src/nodes/kernel/publish-to.js +25 -0
- package/src/nodes/kernel/recompute.js +14 -0
- package/src/nodes/kernel/reset.js +20 -0
- package/src/nodes/kernel/update.js +69 -0
- package/src/nodes/lag/index.js +21 -0
- package/src/nodes/lag/init.js +87 -0
- package/src/nodes/lag/introspect.js +202 -0
- package/src/nodes/lag/publish-to.js +64 -0
- package/src/nodes/lag/recompute.js +33 -0
- package/src/nodes/lag/reset.js +49 -0
- package/src/nodes/lag/update.js +133 -0
- package/src/nodes/median3/index.js +19 -0
- package/src/nodes/median3/init.js +40 -0
- package/src/nodes/median3/introspect.js +116 -0
- package/src/nodes/median3/publish-to.js +21 -0
- package/src/nodes/median3/recompute.js +12 -0
- package/src/nodes/median3/reset.js +15 -0
- package/src/nodes/median3/update.js +58 -0
- package/src/nodes/moments-digest/copy-from.js +12 -0
- package/src/nodes/moments-digest/flush.js +17 -0
- package/src/nodes/moments-digest/index.js +132 -0
- package/src/nodes/moments-digest/init.js +84 -0
- package/src/nodes/moments-digest/introspect.js +122 -0
- package/src/nodes/moments-digest/prelude.js +28 -0
- package/src/nodes/moments-digest/publish-to.js +31 -0
- package/src/nodes/moments-digest/recompute.js +9 -0
- package/src/nodes/moments-digest/reset.js +20 -0
- package/src/nodes/moments-digest/update.js +182 -0
- package/src/nodes/node-names.js +67 -0
- package/src/nodes/page-hinkley/index.js +20 -0
- package/src/nodes/page-hinkley/init.js +66 -0
- package/src/nodes/page-hinkley/introspect.js +193 -0
- package/src/nodes/page-hinkley/publish-to.js +28 -0
- package/src/nodes/page-hinkley/recompute.js +14 -0
- package/src/nodes/page-hinkley/reset.js +23 -0
- package/src/nodes/page-hinkley/update.js +105 -0
- package/src/nodes/pass-if/index.js +21 -0
- package/src/nodes/pass-if/init.js +37 -0
- package/src/nodes/pass-if/introspect.js +93 -0
- package/src/nodes/pass-if/publish-to.js +15 -0
- package/src/nodes/pass-if/recompute.js +15 -0
- package/src/nodes/pass-if/reset.js +18 -0
- package/src/nodes/pass-if/update.js +37 -0
- package/src/nodes/persist-if/helpers.js +111 -0
- package/src/nodes/persist-if/index.js +9 -0
- package/src/nodes/persist-if/init.js +98 -0
- package/src/nodes/persist-if/introspect.js +106 -0
- package/src/nodes/persist-if/publish-to.js +21 -0
- package/src/nodes/persist-if/recompute.js +20 -0
- package/src/nodes/persist-if/reset.js +35 -0
- package/src/nodes/persist-if/update.js +112 -0
- package/src/nodes/persistence-check/index.js +14 -0
- package/src/nodes/persistence-check/init.js +38 -0
- package/src/nodes/persistence-check/introspect.js +144 -0
- package/src/nodes/persistence-check/publish-to.js +11 -0
- package/src/nodes/persistence-check/recompute.js +7 -0
- package/src/nodes/persistence-check/reset.js +12 -0
- package/src/nodes/persistence-check/update.js +57 -0
- package/src/nodes/process-index/index.js +15 -0
- package/src/nodes/process-index/init.js +48 -0
- package/src/nodes/process-index/introspect.js +182 -0
- package/src/nodes/process-index/publish-to.js +29 -0
- package/src/nodes/process-index/recompute.js +8 -0
- package/src/nodes/process-index/reset.js +8 -0
- package/src/nodes/process-index/update.js +75 -0
- package/src/nodes/ratio/index.js +14 -0
- package/src/nodes/ratio/init.js +37 -0
- package/src/nodes/ratio/introspect.js +155 -0
- package/src/nodes/ratio/publish-to.js +15 -0
- package/src/nodes/ratio/recompute.js +7 -0
- package/src/nodes/ratio/reset.js +7 -0
- package/src/nodes/ratio/update.js +47 -0
- package/src/nodes/sanitize/index.js +82 -0
- package/src/nodes/sanitize/init.js +82 -0
- package/src/nodes/sanitize/introspect.js +194 -0
- package/src/nodes/sanitize/publish-to.js +15 -0
- package/src/nodes/sanitize/recompute.js +8 -0
- package/src/nodes/sanitize/reset.js +14 -0
- package/src/nodes/sanitize/update.js +102 -0
- package/src/nodes/spike-guard/index.js +14 -0
- package/src/nodes/spike-guard/init.js +47 -0
- package/src/nodes/spike-guard/introspect.js +130 -0
- package/src/nodes/spike-guard/publish-to.js +35 -0
- package/src/nodes/spike-guard/recompute.js +14 -0
- package/src/nodes/spike-guard/reset.js +19 -0
- package/src/nodes/spike-guard/update.js +89 -0
- package/src/nodes/sse-emitter/index.js +7 -0
- package/src/nodes/sse-emitter/init.js +105 -0
- package/src/nodes/sse-emitter/introspect.js +134 -0
- package/src/nodes/sse-emitter/publish-to.js +6 -0
- package/src/nodes/sse-emitter/recompute.js +16 -0
- package/src/nodes/sse-emitter/reset.js +19 -0
- package/src/nodes/sse-emitter/update.js +69 -0
- package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
- package/src/nodes/sse-emitter/utils/build-message.js +31 -0
- package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
- package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
- package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
- package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
- package/src/nodes/state-change-detector/helpers.js +35 -0
- package/src/nodes/state-change-detector/index.js +12 -0
- package/src/nodes/state-change-detector/init.js +56 -0
- package/src/nodes/state-change-detector/introspect.js +146 -0
- package/src/nodes/state-change-detector/publish-to.js +20 -0
- package/src/nodes/state-change-detector/recompute.js +6 -0
- package/src/nodes/state-change-detector/reset.js +20 -0
- package/src/nodes/state-change-detector/update.js +97 -0
- package/src/nodes/sw-stats/index.js +14 -0
- package/src/nodes/sw-stats/init.js +51 -0
- package/src/nodes/sw-stats/introspect.js +131 -0
- package/src/nodes/sw-stats/publish-to.js +45 -0
- package/src/nodes/sw-stats/recompute.js +33 -0
- package/src/nodes/sw-stats/reset.js +15 -0
- package/src/nodes/sw-stats/update.js +39 -0
- package/src/nodes/swing-watch/index.js +17 -0
- package/src/nodes/swing-watch/init.js +144 -0
- package/src/nodes/swing-watch/introspect.js +188 -0
- package/src/nodes/swing-watch/publish-to.js +53 -0
- package/src/nodes/swing-watch/recompute.js +22 -0
- package/src/nodes/swing-watch/reset.js +55 -0
- package/src/nodes/swing-watch/update.js +767 -0
- package/src/nodes/tally/index.js +15 -0
- package/src/nodes/tally/init.js +32 -0
- package/src/nodes/tally/introspect.js +116 -0
- package/src/nodes/tally/publish-to.js +28 -0
- package/src/nodes/tally/recompute.js +10 -0
- package/src/nodes/tally/reset.js +10 -0
- package/src/nodes/tally/update.js +44 -0
- package/src/nodes/threshold/index.js +14 -0
- package/src/nodes/threshold/init.js +121 -0
- package/src/nodes/threshold/introspect.js +192 -0
- package/src/nodes/threshold/publish-to.js +11 -0
- package/src/nodes/threshold/recompute.js +8 -0
- package/src/nodes/threshold/reset.js +14 -0
- package/src/nodes/threshold/update.js +54 -0
- package/src/nodes/transform/helpers.js +39 -0
- package/src/nodes/transform/index.js +15 -0
- package/src/nodes/transform/init.js +35 -0
- package/src/nodes/transform/introspect.js +118 -0
- package/src/nodes/transform/publish-to.js +23 -0
- package/src/nodes/transform/recompute.js +12 -0
- package/src/nodes/transform/reset.js +11 -0
- package/src/nodes/transform/update.js +32 -0
- package/src/nodes/trend/compute-confidence.js +112 -0
- package/src/nodes/trend/index.js +14 -0
- package/src/nodes/trend/init.js +81 -0
- package/src/nodes/trend/introspect.js +151 -0
- package/src/nodes/trend/publish-to.js +22 -0
- package/src/nodes/trend/recompute.js +15 -0
- package/src/nodes/trend/reset.js +26 -0
- package/src/nodes/trend/update.js +93 -0
- package/src/nodes/tw-stats/copy-from.js +16 -0
- package/src/nodes/tw-stats/flush.js +12 -0
- package/src/nodes/tw-stats/index.js +41 -0
- package/src/nodes/tw-stats/init.js +92 -0
- package/src/nodes/tw-stats/introspect.js +171 -0
- package/src/nodes/tw-stats/publish-to.js +108 -0
- package/src/nodes/tw-stats/recompute.js +9 -0
- package/src/nodes/tw-stats/reset.js +16 -0
- package/src/nodes/tw-stats/update.js +113 -0
- package/src/nodes/unbalance/index.js +15 -0
- package/src/nodes/unbalance/init.js +59 -0
- package/src/nodes/unbalance/introspect.js +167 -0
- package/src/nodes/unbalance/publish-to.js +52 -0
- package/src/nodes/unbalance/recompute.js +11 -0
- package/src/nodes/unbalance/reset.js +10 -0
- package/src/nodes/unbalance/update.js +83 -0
- package/src/nodes/vector-distance/index.js +14 -0
- package/src/nodes/vector-distance/init.js +54 -0
- package/src/nodes/vector-distance/introspect.js +149 -0
- package/src/nodes/vector-distance/publish-to.js +35 -0
- package/src/nodes/vector-distance/recompute.js +11 -0
- package/src/nodes/vector-distance/reset.js +20 -0
- package/src/nodes/vector-distance/update.js +139 -0
- package/src/nodes/winnow/index.js +12 -0
- package/src/nodes/winnow/init.js +82 -0
- package/src/nodes/winnow/introspect.js +253 -0
- package/src/nodes/winnow/publish-to.js +51 -0
- package/src/nodes/winnow/recompute.js +14 -0
- package/src/nodes/winnow/reset.js +34 -0
- package/src/nodes/winnow/update.js +203 -0
- package/src/tools/training/features.js +227 -0
- package/src/tools/training/index.js +21 -0
- package/src/tools/training/logistic.js +238 -0
- package/src/tools/training/metrics.js +126 -0
- package/src/tools/training/scale.js +239 -0
- package/src/tools/training/validate.js +103 -0
- package/src/windowing/count-sliding/create.js +16 -0
- package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
- package/src/windowing/count-sliding/index.js +6 -0
- package/src/windowing/count-sliding/is-not-full.js +5 -0
- package/src/windowing/count-sliding/push.js +15 -0
- package/src/windowing/count-sliding/reset.js +11 -0
- package/src/windowing/count-sliding/size.js +5 -0
- package/src/windowing/time-sliding/create.js +25 -0
- package/src/windowing/time-sliding/push.js +42 -0
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -132
- package/docs/.nojekyll +0 -0
- package/docs/CONTRIBUTING.md +0 -134
- package/docs/README.md +0 -132
- package/docs/_coverpage.md +0 -26
- package/docs/_media/bg.png +0 -0
- package/docs/_media/wink-logo.png +0 -0
- package/docs/_navbar.md +0 -14
- package/docs/_sidebar.md +0 -2
- package/docs/index.html +0 -44
- package/eslint.config.js +0 -283
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { validators, composerValidators } from '../core/utils/validate/index.js';
|
|
2
|
+
import { SIGNATURE_PATTERNS } from './consts.js';
|
|
3
|
+
|
|
4
|
+
export const schemas = Object.create( null );
|
|
5
|
+
|
|
6
|
+
schemas[ SIGNATURE_PATTERNS.nameSugarOutputsOptions ] = [
|
|
7
|
+
{
|
|
8
|
+
name: 'nodeName',
|
|
9
|
+
type: 'string',
|
|
10
|
+
minLength: 1,
|
|
11
|
+
required: true,
|
|
12
|
+
description: 'Node\'s uniquely identifiable name'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'inputParams',
|
|
16
|
+
type: 'array',
|
|
17
|
+
minItems: 1,
|
|
18
|
+
required: true,
|
|
19
|
+
itemSchema: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
validator: validators.identifier,
|
|
22
|
+
error: 'It should be a valid parameter identifier'
|
|
23
|
+
},
|
|
24
|
+
description: 'Input parameters in an array format'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'outputs',
|
|
28
|
+
type: 'object',
|
|
29
|
+
required: false, // momentsDigest does not need it; all others do.
|
|
30
|
+
minProperties: 1,
|
|
31
|
+
error: '"outputs" should be an object with minimum 1 stats'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'options',
|
|
35
|
+
type: 'object',
|
|
36
|
+
required: false,
|
|
37
|
+
description: 'Node options'
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
schemas[ SIGNATURE_PATTERNS.nameLogic ] = [
|
|
42
|
+
{
|
|
43
|
+
name: 'nodeName',
|
|
44
|
+
type: 'string',
|
|
45
|
+
minLength: 1,
|
|
46
|
+
required: true,
|
|
47
|
+
description: 'Node\'s uniquely identifiable name'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'logic',
|
|
51
|
+
type: 'array',
|
|
52
|
+
required: true,
|
|
53
|
+
minItems: 1,
|
|
54
|
+
itemSchema: {
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: {
|
|
57
|
+
when: {
|
|
58
|
+
type: 'function',
|
|
59
|
+
required: true,
|
|
60
|
+
arity: 1,
|
|
61
|
+
error: '"when" must be a predicate function with one parameter'
|
|
62
|
+
},
|
|
63
|
+
triggers: {
|
|
64
|
+
type: 'array',
|
|
65
|
+
required: true,
|
|
66
|
+
minItems: 1,
|
|
67
|
+
itemSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
validator: composerValidators.trigger,
|
|
70
|
+
error: 'Invalid trigger specification'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
schemas[ SIGNATURE_PATTERNS.namePredicateOutputsOptions ] = [
|
|
79
|
+
{
|
|
80
|
+
name: 'nodeName',
|
|
81
|
+
type: 'string',
|
|
82
|
+
minLength: 1,
|
|
83
|
+
required: true,
|
|
84
|
+
description: 'Node\'s uniquely identifiable name'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'predicate',
|
|
88
|
+
type: 'function',
|
|
89
|
+
required: true,
|
|
90
|
+
error: '"predicate" must be a predicate function'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'outputs',
|
|
94
|
+
type: 'object',
|
|
95
|
+
required: true,
|
|
96
|
+
minProperties: 1,
|
|
97
|
+
error: '"outputs" should be an object with minimum 1 stats'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'options',
|
|
101
|
+
type: 'object',
|
|
102
|
+
required: false,
|
|
103
|
+
minProperties: 1,
|
|
104
|
+
error: '"options" should be an object with minimum 1 option/value pair'
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
schemas[ SIGNATURE_PATTERNS.namePredicateOptions ] = [
|
|
109
|
+
{
|
|
110
|
+
name: 'nodeName',
|
|
111
|
+
type: 'string',
|
|
112
|
+
minLength: 1,
|
|
113
|
+
required: true,
|
|
114
|
+
description: 'Node\'s uniquely identifiable name'
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'predicate',
|
|
118
|
+
type: 'function',
|
|
119
|
+
required: true,
|
|
120
|
+
error: '"predicate" must be a predicate function'
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'options',
|
|
124
|
+
type: 'object',
|
|
125
|
+
required: false,
|
|
126
|
+
minProperties: 1,
|
|
127
|
+
error: '"options" should be an object with minimum 1 option/value pair'
|
|
128
|
+
}
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
schemas[ SIGNATURE_PATTERNS.nameXOutputsOptions ] = [
|
|
132
|
+
{
|
|
133
|
+
name: 'nodeName',
|
|
134
|
+
type: 'string',
|
|
135
|
+
minLength: 1,
|
|
136
|
+
required: true,
|
|
137
|
+
description: 'Node\'s uniquely identifiable name'
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'x',
|
|
141
|
+
type: 'arrayOrString',
|
|
142
|
+
minLength: 1,
|
|
143
|
+
required: true,
|
|
144
|
+
description: 'x-input'
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'outputs',
|
|
148
|
+
type: 'object',
|
|
149
|
+
required: true,
|
|
150
|
+
minProperties: 1,
|
|
151
|
+
error: '"outputs" should be an object with minimum 1 stats'
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'options',
|
|
155
|
+
type: 'object',
|
|
156
|
+
required: false,
|
|
157
|
+
minProperties: 1,
|
|
158
|
+
error: '"options" should be an object with minimum 1 option/value pair'
|
|
159
|
+
}
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
schemas[ SIGNATURE_PATTERNS.nameXYOutputsOptions ] = [
|
|
163
|
+
{
|
|
164
|
+
name: 'nodeName',
|
|
165
|
+
type: 'string',
|
|
166
|
+
minLength: 1,
|
|
167
|
+
required: true,
|
|
168
|
+
description: 'Node\'s uniquely identifiable name'
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'x',
|
|
172
|
+
type: 'string',
|
|
173
|
+
minLength: 1,
|
|
174
|
+
required: true,
|
|
175
|
+
description: 'x-input'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'y',
|
|
179
|
+
type: 'string',
|
|
180
|
+
minLength: 1,
|
|
181
|
+
required: true,
|
|
182
|
+
description: 'x-input'
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: 'outputs',
|
|
186
|
+
type: 'object',
|
|
187
|
+
required: true,
|
|
188
|
+
minProperties: 1,
|
|
189
|
+
error: '"outputs" should be an object with minimum 1 stats'
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: 'options',
|
|
193
|
+
type: 'object',
|
|
194
|
+
required: false,
|
|
195
|
+
minProperties: 1,
|
|
196
|
+
error: '"options" should be an object with minimum 1 option/value pair'
|
|
197
|
+
}
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
schemas[ SIGNATURE_PATTERNS.nameXOptions ] = [
|
|
201
|
+
{
|
|
202
|
+
name: 'nodeName',
|
|
203
|
+
type: 'string',
|
|
204
|
+
minLength: 1,
|
|
205
|
+
required: true,
|
|
206
|
+
description: 'Node\'s uniquely identifiable name'
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'x',
|
|
210
|
+
type: 'arrayOrString',
|
|
211
|
+
minLength: 1,
|
|
212
|
+
required: true,
|
|
213
|
+
description: 'x-input'
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'options',
|
|
217
|
+
type: 'object',
|
|
218
|
+
required: false,
|
|
219
|
+
minProperties: 1,
|
|
220
|
+
error: '"options" should be an object with minimum 1 option/value pair'
|
|
221
|
+
}
|
|
222
|
+
];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const buildStatsFromOutputs = function ( outputs ) {
|
|
2
|
+
const stats = Object.create( null );
|
|
3
|
+
const seenStoreAs = Object.create( null );
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line guard-for-in
|
|
6
|
+
for ( const stat in outputs ) {
|
|
7
|
+
const storeAs = outputs[ stat ];
|
|
8
|
+
|
|
9
|
+
// A duplicate storeAs within one node is always a mistake (two stats fighting
|
|
10
|
+
// over one field), so it throws here. Duplicates ACROSS nodes on one path are the
|
|
11
|
+
// overwrite case, caught at build time by check-output-collisions.js.
|
|
12
|
+
if ( seenStoreAs[ storeAs ] ) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`WinkComposer/flow: Node has duplicate storeAs '${storeAs}' ` +
|
|
15
|
+
`for stats '${seenStoreAs[ storeAs ]}' and '${stat}'`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
seenStoreAs[ storeAs ] = stat;
|
|
20
|
+
|
|
21
|
+
stats[ stat ] = Object.create( null );
|
|
22
|
+
stats[ stat ].storeAs = storeAs;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return stats;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const specBuilder = function ( meta ) {
|
|
29
|
+
const patterns = Object.create( null );
|
|
30
|
+
|
|
31
|
+
patterns.NAME_PREDICATE_OPTIONS = function ( params ) {
|
|
32
|
+
const [ name, predicate, options ] = params;
|
|
33
|
+
return meta.buildSpec( name, predicate, options );
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
patterns.NAME_PREDICATE_OUTPUTS_OPTIONS = function ( params ) {
|
|
37
|
+
const [ name, predicate, outputs, options ] = params;
|
|
38
|
+
const stats = buildStatsFromOutputs( outputs );
|
|
39
|
+
return meta.buildSpec( name, predicate, stats, options );
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
patterns.NAME_LOGIC = function ( params ) {
|
|
43
|
+
const [ name, logic ] = params;
|
|
44
|
+
return meta.buildSpec( name, logic );
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
patterns.NAME_X_OUTPUTS_OPTIONS = function ( params ) {
|
|
48
|
+
const [ name, x, outputs, options ] = params;
|
|
49
|
+
const stats = buildStatsFromOutputs( outputs );
|
|
50
|
+
return meta.buildSpec( name, x, stats, options );
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
patterns.NAME_X_Y_OUTPUTS_OPTIONS = function ( params ) {
|
|
54
|
+
const [ name, x, y, outputs, options ] = params;
|
|
55
|
+
const stats = buildStatsFromOutputs( outputs );
|
|
56
|
+
return meta.buildSpec( name, x, y, stats, options );
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
patterns.NAME_X_OPTIONS = function ( params ) {
|
|
60
|
+
const [ name, x, options ] = params;
|
|
61
|
+
return meta.buildSpec( name, x, options );
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return patterns;
|
|
65
|
+
}; // specBuilder()
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Fail-fast trigger validation for Flow DSL.
|
|
3
|
+
*
|
|
4
|
+
* Validates trigger specifications at transpile/load time before runtime:
|
|
5
|
+
* - R1: Target node existence (all targets must reference existing nodes)
|
|
6
|
+
* - R2: Circular reference detection (no trigger cycles)
|
|
7
|
+
* - R3: Control method validation (method must be supported by target node)
|
|
8
|
+
*
|
|
9
|
+
* Design: Errors are accumulated (not fail-fast within validation) to report
|
|
10
|
+
* all issues at once. Runtime checks in partition-manager remain as second
|
|
11
|
+
* line of defense.
|
|
12
|
+
*
|
|
13
|
+
* Supports two trigger locations:
|
|
14
|
+
* - Direct: spec.triggers (inline triggers on any node)
|
|
15
|
+
* - Controller: spec.logic[].triggers (Controller node's logic array)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import nodeTypeToModule from '../core/wiring/node-type-to-module.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Extracts all triggers from a spec, handling both direct triggers
|
|
22
|
+
* and Controller node's nested logic[].triggers.
|
|
23
|
+
*
|
|
24
|
+
* @param {Object} spec - Node specification
|
|
25
|
+
* @returns {Array<Object>} Array of trigger objects
|
|
26
|
+
*/
|
|
27
|
+
const extractTriggers = function ( spec ) {
|
|
28
|
+
const triggers = [];
|
|
29
|
+
|
|
30
|
+
// Direct triggers (inline on any node)
|
|
31
|
+
if ( Array.isArray( spec.triggers ) ) {
|
|
32
|
+
triggers.push( ...spec.triggers );
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Controller node's nested triggers in logic array
|
|
36
|
+
if ( Array.isArray( spec.logic ) ) {
|
|
37
|
+
for ( let i = 0; i < spec.logic.length; i += 1 ) {
|
|
38
|
+
const logicItem = spec.logic[ i ];
|
|
39
|
+
if ( Array.isArray( logicItem.triggers ) ) {
|
|
40
|
+
triggers.push( ...logicItem.triggers );
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return triggers;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Builds an index of node names to their position and spec.
|
|
50
|
+
* @param {Array} specs - Node specifications
|
|
51
|
+
* @returns {Map<string, {index: number, spec: object}>} Node index map
|
|
52
|
+
*/
|
|
53
|
+
const buildNodeIndex = function ( specs ) {
|
|
54
|
+
const index = new Map();
|
|
55
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
56
|
+
index.set( specs[ i ].name, { index: i, spec: specs[ i ] } );
|
|
57
|
+
}
|
|
58
|
+
return index;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* R1: Validates that all trigger targets reference existing nodes.
|
|
63
|
+
* @param {Array} specs - Node specifications
|
|
64
|
+
* @param {Map} nodeIndex - Node name to index map
|
|
65
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
66
|
+
*/
|
|
67
|
+
const validateTargetExists = function ( specs, nodeIndex ) {
|
|
68
|
+
const errors = [];
|
|
69
|
+
|
|
70
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
71
|
+
const spec = specs[ i ];
|
|
72
|
+
const triggers = extractTriggers( spec );
|
|
73
|
+
|
|
74
|
+
for ( let t = 0; t < triggers.length; t += 1 ) {
|
|
75
|
+
const trigger = triggers[ t ];
|
|
76
|
+
const targets = trigger.targets || [];
|
|
77
|
+
|
|
78
|
+
for ( let j = 0; j < targets.length; j += 1 ) {
|
|
79
|
+
const targetName = targets[ j ];
|
|
80
|
+
if ( !nodeIndex.has( targetName ) ) {
|
|
81
|
+
errors.push(
|
|
82
|
+
`Node '${spec.name}' trigger[${t}] references unknown target '${targetName}'`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return errors;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* R2: Detects circular references in trigger graph.
|
|
94
|
+
* Uses DFS with coloring: 0=unvisited, 1=visiting, 2=visited.
|
|
95
|
+
* @param {Array} specs - Node specifications
|
|
96
|
+
* @param {Map} nodeIndex - Node name to index map
|
|
97
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
98
|
+
*/
|
|
99
|
+
const detectCycles = function ( specs, nodeIndex ) {
|
|
100
|
+
const errors = [];
|
|
101
|
+
const color = new Array( specs.length ).fill( 0 );
|
|
102
|
+
const path = [];
|
|
103
|
+
|
|
104
|
+
const dfs = function ( nodeIdx ) {
|
|
105
|
+
if ( color[ nodeIdx ] === 2 ) return false; // Already fully processed
|
|
106
|
+
if ( color[ nodeIdx ] === 1 ) return true; // Cycle detected
|
|
107
|
+
|
|
108
|
+
color[ nodeIdx ] = 1;
|
|
109
|
+
path.push( specs[ nodeIdx ].name );
|
|
110
|
+
|
|
111
|
+
const triggers = extractTriggers( specs[ nodeIdx ] );
|
|
112
|
+
for ( let t = 0; t < triggers.length; t += 1 ) {
|
|
113
|
+
const targets = triggers[ t ].targets || [];
|
|
114
|
+
for ( let j = 0; j < targets.length; j += 1 ) {
|
|
115
|
+
const targetEntry = nodeIndex.get( targets[ j ] );
|
|
116
|
+
if ( targetEntry && dfs( targetEntry.index ) ) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
path.pop();
|
|
123
|
+
color[ nodeIdx ] = 2;
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
128
|
+
if ( color[ i ] === 0 && dfs( i ) ) {
|
|
129
|
+
errors.push( `Circular trigger reference detected: ${path.join( ' → ' )}` );
|
|
130
|
+
// Reset for next potential cycle (though one is usually enough)
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return errors;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Validates a single trigger's control method against its target.
|
|
140
|
+
* @param {Object} sourceSpec - Source node spec
|
|
141
|
+
* @param {number} triggerIdx - Trigger index for error messages
|
|
142
|
+
* @param {string} controlMethod - Control method name
|
|
143
|
+
* @param {string} targetName - First target node name
|
|
144
|
+
* @param {Map} nodeIndex - Node name to index map
|
|
145
|
+
* @param {Object} nodeModules - Map of module name to node module
|
|
146
|
+
* @returns {string|null} Error message or null if valid
|
|
147
|
+
*/
|
|
148
|
+
const validateSingleTriggerMethod = function (
|
|
149
|
+
sourceSpec, triggerIdx, controlMethod, targetName, nodeIndex, nodeModules
|
|
150
|
+
) {
|
|
151
|
+
const targetEntry = nodeIndex.get( targetName );
|
|
152
|
+
if ( !targetEntry ) return null; // R1 will catch this
|
|
153
|
+
|
|
154
|
+
const targetSpec = targetEntry.spec;
|
|
155
|
+
const moduleName = nodeTypeToModule( targetSpec.nodeType );
|
|
156
|
+
const nodeModule = nodeModules[ moduleName ];
|
|
157
|
+
|
|
158
|
+
if ( !nodeModule ) {
|
|
159
|
+
return `Node '${sourceSpec.name}' trigger[${triggerIdx}] targets node type ` +
|
|
160
|
+
`'${targetSpec.nodeType}' but module '${moduleName}' not found`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const getSupportedControlMethods = nodeModule.getSupportedControlMethods;
|
|
164
|
+
if ( typeof getSupportedControlMethods !== 'function' ) {
|
|
165
|
+
return `Node module '${moduleName}' missing getSupportedControlMethods() introspection`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const supportedMethods = getSupportedControlMethods();
|
|
169
|
+
if ( !Object.prototype.hasOwnProperty.call( supportedMethods, controlMethod ) ) {
|
|
170
|
+
const validMethods = Object.keys( supportedMethods ).join( ', ' ) || '(none)';
|
|
171
|
+
return `Node '${sourceSpec.name}' trigger[${triggerIdx}] uses control method ` +
|
|
172
|
+
`'${controlMethod}' but '${targetSpec.nodeType}' only supports: ${validMethods}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return null;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* R3: Validates that control methods are supported by target nodes.
|
|
180
|
+
* @param {Array} specs - Node specifications
|
|
181
|
+
* @param {Map} nodeIndex - Node name to index map
|
|
182
|
+
* @param {Object} nodeModules - Map of module name to node module
|
|
183
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
184
|
+
*/
|
|
185
|
+
const validateControlMethod = function ( specs, nodeIndex, nodeModules ) {
|
|
186
|
+
const errors = [];
|
|
187
|
+
|
|
188
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
189
|
+
const spec = specs[ i ];
|
|
190
|
+
const triggers = extractTriggers( spec );
|
|
191
|
+
|
|
192
|
+
for ( let t = 0; t < triggers.length; t += 1 ) {
|
|
193
|
+
const trigger = triggers[ t ];
|
|
194
|
+
const targets = trigger.targets || [];
|
|
195
|
+
|
|
196
|
+
// Validate against first target (homogeneity enforced at runtime)
|
|
197
|
+
if ( targets.length > 0 ) {
|
|
198
|
+
const err = validateSingleTriggerMethod(
|
|
199
|
+
spec, t, trigger.control, targets[ 0 ], nodeIndex, nodeModules
|
|
200
|
+
);
|
|
201
|
+
if ( err ) {
|
|
202
|
+
errors.push( err );
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return errors;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Validates all trigger specifications in a flow.
|
|
213
|
+
*
|
|
214
|
+
* @param {Array} specs - Node specifications from flow DSL
|
|
215
|
+
* @param {Object} nodeModules - Map of module name to node module
|
|
216
|
+
* @returns {{valid: boolean, errors: Array<string>}} Validation result
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* const result = validateTriggers(specs, nodeModules);
|
|
220
|
+
* if (!result.valid) {
|
|
221
|
+
* console.error('Trigger validation failed:', result.errors);
|
|
222
|
+
* }
|
|
223
|
+
*/
|
|
224
|
+
export const validateTriggers = function ( specs, nodeModules ) {
|
|
225
|
+
const errors = [];
|
|
226
|
+
|
|
227
|
+
// Build node index for O(1) lookups
|
|
228
|
+
const nodeIndex = buildNodeIndex( specs );
|
|
229
|
+
|
|
230
|
+
// R1: Target existence
|
|
231
|
+
errors.push( ...validateTargetExists( specs, nodeIndex ) );
|
|
232
|
+
|
|
233
|
+
// R2: Circular references (only if R1 passed to avoid confusion)
|
|
234
|
+
if ( errors.length === 0 ) {
|
|
235
|
+
errors.push( ...detectCycles( specs, nodeIndex ) );
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// R3: Control method validation (only if R1 passed)
|
|
239
|
+
if ( errors.length === 0 ) {
|
|
240
|
+
errors.push( ...validateControlMethod( specs, nodeIndex, nodeModules ) );
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
valid: errors.length === 0,
|
|
245
|
+
errors
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Export helpers for testing
|
|
250
|
+
export { extractTriggers, buildNodeIndex, validateTargetExists, detectCycles, validateControlMethod };
|