@almadar/std 17.0.3 → 17.1.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/behaviors/lolo/auth/atoms/std-dev-personas.lolo +27 -2
- package/behaviors/lolo/cli/atoms/std-orb-goldens.lolo +6 -3
- package/behaviors/lolo/cli/atoms/std-orb-lint-mem-handles.lolo +54 -34
- package/behaviors/lolo/cli/atoms/std-orb-lint-os-grants.lolo +4 -4
- package/behaviors/lolo/cli/atoms/std-orb-mcp.lolo +16 -21
- package/behaviors/lolo/cli/atoms/std-orb-serve.lolo +24 -4
- package/behaviors/lolo/codec/atoms/std-lolo-kotlin.lolo +26 -3
- package/behaviors/lolo/codec/atoms/std-lolo-python.lolo +15 -2
- package/behaviors/lolo/codec/atoms/std-lolo-rust.lolo +27 -2
- package/behaviors/lolo/codec/atoms/std-lolo-source.lolo +251 -60
- package/behaviors/lolo/codec/atoms/std-lolo-swift.lolo +24 -1
- package/behaviors/lolo/codec/atoms/std-lolo-typescript.lolo +24 -3
- package/behaviors/lolo/connect/atoms/std-meta-ads.lolo +4 -4
- package/behaviors/lolo/connect/atoms/std-stdio-lines.lolo +7 -4
- package/behaviors/lolo/connect/atoms/std-youtube.lolo +9 -9
- package/behaviors/lolo/dev/atoms/std-guest-session.lolo +122 -10
- package/behaviors/lolo/dev/atoms/std-mock-seed-marks.lolo +66 -0
- package/behaviors/lolo/dev/organisms/std-behavior-playground.lolo +5 -2
- package/behaviors/lolo/dev/organisms/std-launchpad.lolo +4 -3
- package/behaviors/lolo/gpu/atoms/std-gpu-compute.lolo +329 -0
- package/behaviors/lolo/net/atoms/std-http-client.lolo +4 -4
- package/behaviors/lolo/net/atoms/std-http-fetch.lolo +6 -6
- package/behaviors/lolo/net/atoms/std-npm-lookup.lolo +1 -1
- package/behaviors/lolo/net/atoms/std-npm-registry.lolo +2 -2
- package/behaviors/lolo/spec/auth/dev-personas.replay.goldens.json +263 -2
- package/behaviors/lolo/spec/cli/lint-all.lolo +1 -0
- package/behaviors/lolo/spec/cli/lint-item-action-event.replay.goldens.json +9 -9
- package/behaviors/lolo/spec/cli/lint-mem-handles.replay.goldens.json +3021 -1
- package/behaviors/lolo/spec/cli/lint-os-grants.replay.goldens.json +284 -12
- package/behaviors/lolo/spec/cli/mcp-server.replay.goldens.json +51 -55
- package/behaviors/lolo/spec/cli/orb-compile.replay.goldens.json +10 -4
- package/behaviors/lolo/spec/codec/lolo-kotlin.replay.goldens.json +7496 -7497
- package/behaviors/lolo/spec/codec/lolo-python.replay.goldens.json +341 -3
- package/behaviors/lolo/spec/codec/lolo-rust.replay.goldens.json +18931 -6142
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/compose-pair.lolo +44 -0
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/config-read.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/divide-default.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/divide-plain.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/get-past-end.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/list-call.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/list-plain.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/minus-binary.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/minus-unary.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/nested-let.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/no-machine.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/no-template.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/nth-past-end.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/nth-raw.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/ports-call.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/range-one.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/range-two.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/router-trio.lolo +88 -0
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/store-pair.lolo +62 -0
- package/behaviors/lolo/spec/codec/lolo-source.fixtures/string-literal.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.gen/knobs.py +27 -1
- package/behaviors/lolo/spec/codec/lolo-source.gen/src_assemble.in +54 -2
- package/behaviors/lolo/spec/codec/lolo-source.gen/src_finish.in +1 -1
- package/behaviors/lolo/spec/codec/lolo-source.gen/src_fold.in +24 -4
- package/behaviors/lolo/spec/codec/lolo-source.gen/src_head.in +8 -3
- package/behaviors/lolo/spec/codec/lolo-source.gen/src_prepare.in +6 -2
- package/behaviors/lolo/spec/codec/lolo-source.gen/src_trait.in +12 -2
- package/behaviors/lolo/spec/codec/lolo-source.parity/agent-step.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.parity/agent-step.server.lolo +1 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/chunk.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.parity/chunk.server.lolo +1 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/compose-pair.events.json +36 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/compose-pair.replay.goldens.json +91 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/cosine.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.parity/cosine.server.lolo +1 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/kotlin/compose-pair.kt +31 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/kotlin/router-trio.kt +31 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/kotlin/store-pair.kt +31 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/python/compose-pair.py +18 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/python/router-trio.py +18 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/python/store-pair.py +17 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/rust/compose-pair.rs +37 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/rust/router-trio.rs +37 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/rust/store-pair.rs +36 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/swift/compose-pair.swift +24 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/swift/router-trio.swift +24 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/swift/store-pair.swift +23 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/typescript/compose-pair.mts +24 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/typescript/router-trio.mts +24 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/drivers/typescript/store-pair.mts +22 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/recall-at-k.lolo +2 -1
- package/behaviors/lolo/spec/codec/lolo-source.parity/recall-at-k.server.lolo +1 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/router-trio.events.json +18 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/router-trio.replay.goldens.json +87 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/store-pair.events.json +58 -0
- package/behaviors/lolo/spec/codec/lolo-source.parity/store-pair.replay.goldens.json +238 -0
- package/behaviors/lolo/spec/codec/lolo-swift.replay.goldens.json +15599 -2204
- package/behaviors/lolo/spec/codec/lolo-typescript.replay.goldens.json +28930 -28929
- package/behaviors/lolo/spec/connect/bearer-api.replay.goldens.json +1 -1
- package/behaviors/lolo/spec/connect/esign.replay.goldens.json +3 -3
- package/behaviors/lolo/spec/connect/github.replay.goldens.json +13 -13
- package/behaviors/lolo/spec/connect/google-calendar.replay.goldens.json +2 -2
- package/behaviors/lolo/spec/connect/image.replay.goldens.json +1 -1
- package/behaviors/lolo/spec/connect/meta-ads.replay.goldens.json +2 -2
- package/behaviors/lolo/spec/connect/stdio-lines.replay.goldens.json +90 -0
- package/behaviors/lolo/spec/connect/twilio.replay.goldens.json +2 -2
- package/behaviors/lolo/spec/connect/youtube.replay.goldens.json +1 -1
- package/behaviors/lolo/spec/dev/guest-session.replay.goldens.json +824 -0
- package/behaviors/lolo/spec/dev/mock-seed-marks.replay.goldens.json +365 -0
- package/behaviors/lolo/spec/dev/verify-walk.replay.goldens.json +2 -1
- package/behaviors/lolo/spec/gpu/gpu-compute.replay.goldens.json +784 -0
- package/behaviors/lolo/spec/mem/mem-buffer.replay.goldens.json +97 -1
- package/behaviors/lolo/spec/ml/vector-write.goldens.json +1 -1
- package/behaviors/lolo/spec/ml/vector-write.replay.goldens.json +2 -2
- package/behaviors/lolo/spec/net/http-client-call-host.replay.goldens.json +3 -3
- package/behaviors/lolo/spec/net/http-client-env-host.replay.goldens.json +3 -3
- package/behaviors/lolo/spec/net/http-client.replay.goldens.json +56 -56
- package/behaviors/lolo/spec/net/http-fetch.replay.goldens.json +2 -2
- package/behaviors/lolo/spec/net/npm-lookup.replay.goldens.json +1 -1
- package/behaviors/lolo/spec/net/npm-registry.replay.goldens.json +2 -2
- package/behaviors/lolo/spec/net/server-declared-traits.replay.goldens.json +6 -3
- package/behaviors/lolo/spec/net/server-external-inputs.replay.goldens.json +16 -8
- package/behaviors/lolo/spec/net/server-retargeted-leg.replay.goldens.json +4 -2
- package/behaviors/lolo/spec/net/server-untargeted-discovery.replay.goldens.json +50 -45
- package/behaviors/lolo/spec/ops/llm-spend-board.replay.goldens.json +112 -16
- package/behaviors/lolo/spec/store/firestore-twin.replay.goldens.json +1 -1
- package/behaviors/lolo/spec/store/row-store-postgres.gen/record_real_sql.py +1 -1
- package/behaviors/lolo/spec/ui/game/fx-particles.replay.goldens.json +37 -0
- package/behaviors/lolo/ui/avl/atoms/std-avl-cosmic-zoom.lolo +2 -2
- package/behaviors/lolo/ui/game/atoms/std-fx-particles.lolo +10 -1
- package/behaviors/lolo/ui/game/atoms/ui-draw-fx-layer.lolo +4 -4
- package/behaviors/lolo/ui/game/organisms/std-arcade-board-3d.lolo +9 -9
- package/behaviors/lolo/ui/game/organisms/std-crew-board-2d.lolo +4 -4
- package/behaviors/lolo/ui/game/organisms/std-dungeon-board-2d.lolo +5 -5
- package/behaviors/lolo/ui/game/organisms/std-market-board-3d.lolo +9 -9
- package/behaviors/lolo/ui/game/organisms/std-objective-board-3d.lolo +9 -9
- package/behaviors/lolo/ui/game/organisms/std-platformer-board-2d.lolo +5 -5
- package/behaviors/lolo/ui/game/organisms/std-platformer-puzzle.lolo +4 -4
- package/behaviors/lolo/ui/game/organisms/std-survival-board-3d.lolo +9 -9
- package/behaviors/lolo/ui/game/organisms/std-tactics-board-2d.lolo +5 -5
- package/behaviors/lolo/ui/game/organisms/std-tactics-board-3d.lolo +9 -9
- package/behaviors/registry/auth/atoms/std-dev-personas.orb +1 -1
- package/behaviors/registry/cli/atoms/std-orb-goldens.orb +1 -1
- package/behaviors/registry/cli/atoms/std-orb-lint-mem-handles.orb +1 -1
- package/behaviors/registry/cli/atoms/std-orb-lint-os-grants.orb +1 -1
- package/behaviors/registry/cli/atoms/std-orb-mcp.orb +1 -1
- package/behaviors/registry/cli/atoms/std-orb-serve.orb +1 -1
- package/behaviors/registry/codec/atoms/std-lolo-kotlin.orb +1 -1
- package/behaviors/registry/codec/atoms/std-lolo-python.orb +1 -1
- package/behaviors/registry/codec/atoms/std-lolo-rust.orb +1 -1
- package/behaviors/registry/codec/atoms/std-lolo-source.orb +1 -1
- package/behaviors/registry/codec/atoms/std-lolo-swift.orb +1 -1
- package/behaviors/registry/codec/atoms/std-lolo-typescript.orb +1 -1
- package/behaviors/registry/connect/atoms/std-meta-ads.orb +1 -1
- package/behaviors/registry/connect/atoms/std-stdio-lines.orb +1 -1
- package/behaviors/registry/connect/atoms/std-youtube.orb +1 -1
- package/behaviors/registry/dev/atoms/std-guest-session.orb +1 -1
- package/behaviors/registry/dev/atoms/std-mock-seed-marks.orb +1 -0
- package/behaviors/registry/dev/organisms/std-behavior-playground.orb +37 -0
- package/behaviors/registry/dev/organisms/std-launchpad.orb +25 -0
- package/behaviors/registry/gpu/atoms/std-gpu-compute.orb +1 -0
- package/behaviors/registry/net/atoms/std-http-client.orb +1 -1
- package/behaviors/registry/net/atoms/std-http-fetch.orb +1 -1
- package/behaviors/registry/net/atoms/std-npm-lookup.orb +1 -1
- package/behaviors/registry/net/atoms/std-npm-registry.orb +1 -1
- package/behaviors/registry/spec/cli/lint-all.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/compose-pair.orb +1 -0
- package/behaviors/registry/spec/codec/lolo-source.fixtures/config-read.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/divide-default.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/divide-plain.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/get-past-end.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/list-call.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/list-plain.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/minus-binary.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/minus-unary.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/nested-let.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/no-machine.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/no-template.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/nth-past-end.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/nth-raw.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/ports-call.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/range-one.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/range-two.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.fixtures/router-trio.orb +1 -0
- package/behaviors/registry/spec/codec/lolo-source.fixtures/store-pair.orb +1 -0
- package/behaviors/registry/spec/codec/lolo-source.fixtures/string-literal.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/agent-step.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/agent-step.server.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/chunk.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/chunk.server.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/cosine.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/cosine.server.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/recall-at-k.orb +1 -1
- package/behaviors/registry/spec/codec/lolo-source.parity/recall-at-k.server.orb +1 -1
- package/behaviors/registry/ui/avl/atoms/std-avl-cosmic-zoom.orb +1 -1
- package/behaviors/registry/ui/game/atoms/std-fx-particles.orb +1 -1
- package/behaviors/registry/ui/game/atoms/ui-draw-fx-layer.orb +1 -1
- package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +20 -13
- package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +9 -5
- package/behaviors/registry/ui/game/organisms/std-dungeon-board-2d.orb +17 -7
- package/behaviors/registry/ui/game/organisms/std-market-board-3d.orb +19 -15
- package/behaviors/registry/ui/game/organisms/std-objective-board-3d.orb +15 -12
- package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +17 -7
- package/behaviors/registry/ui/game/organisms/std-platformer-puzzle.orb +4 -0
- package/behaviors/registry/ui/game/organisms/std-survival-board-3d.orb +15 -12
- package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +13 -6
- package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +14 -12
- package/canonical-operators.json +1426 -103
- package/dist/{chunk-EK22WRB6.js → chunk-2UGHBVU2.js} +2 -2
- package/dist/{chunk-GDMH5T4J.js → chunk-3DK7GI2C.js} +2 -2
- package/dist/chunk-3MDASC5C.js +26 -0
- package/dist/{chunk-K5ZI27PB.js → chunk-3PHO4RRF.js} +1 -1
- package/dist/{chunk-7IEMMYM6.js → chunk-4MJCLAZW.js} +1 -1
- package/dist/{chunk-W4IEV4BY.js → chunk-55JPIL7A.js} +2 -2
- package/dist/{chunk-RUGBZTV3.js → chunk-66BLZLFI.js} +1 -1
- package/dist/{chunk-YWFISV7L.js → chunk-66RAJFOD.js} +1 -1
- package/dist/{chunk-JWOWWGNZ.js → chunk-6ED4SUC6.js} +1 -1
- package/dist/{chunk-LL7P6EII.js → chunk-6KFCHNE2.js} +2 -2
- package/dist/{chunk-GFBL2TW6.js → chunk-A4QB3Y6L.js} +1 -1
- package/dist/chunk-BVWMLS32.js +123 -0
- package/dist/{chunk-5KQCGSNC.js → chunk-CRKVDCY7.js} +1 -1
- package/dist/{chunk-WHQDLLC3.js → chunk-EKWEY4OJ.js} +1 -1
- package/dist/{chunk-Y3BRVNYK.js → chunk-EU22GCGV.js} +2 -2
- package/dist/{chunk-XQPYTDZ4.js → chunk-FB6PKNRS.js} +1 -1
- package/dist/{chunk-UX3MDFX6.js → chunk-FSVOJQLP.js} +1 -1
- package/dist/{chunk-LDBD2FBQ.js → chunk-GAKLBWBR.js} +1 -1
- package/dist/{chunk-C3IEMPRZ.js → chunk-GO3FKBV2.js} +2 -2
- package/dist/{chunk-LZSPEHSM.js → chunk-GPDTJHYY.js} +1 -1
- package/dist/{chunk-W5ABMOXU.js → chunk-JQBWLH5V.js} +1 -1
- package/dist/{chunk-63X6RNY6.js → chunk-KKW3JHTC.js} +1 -1
- package/dist/{chunk-5PLJE42Q.js → chunk-LF2EZVAM.js} +1 -1
- package/dist/{chunk-RXWBYWQB.js → chunk-LGCKOZP3.js} +2 -2
- package/dist/{chunk-JJEADYP7.js → chunk-LMZ6XJFB.js} +2 -2
- package/dist/{chunk-CWYSQZJU.js → chunk-M2YQNSAZ.js} +2 -2
- package/dist/{chunk-GNCKJV3P.js → chunk-MKWHYBIS.js} +1 -1
- package/dist/{chunk-ZB2CLGEG.js → chunk-MXBGYTYF.js} +1 -1
- package/dist/{chunk-UN76TRSK.js → chunk-NH6MXHZR.js} +41 -41
- package/dist/{chunk-II2VW7T6.js → chunk-ODBIX4DB.js} +1 -1
- package/dist/{chunk-3F3CNWOG.js → chunk-OYDQR6DT.js} +2 -2
- package/dist/{chunk-FVL6BT6L.js → chunk-PD6POR44.js} +1 -1
- package/dist/{chunk-U6USXZ5M.js → chunk-PHFT3QNS.js} +2 -2
- package/dist/{chunk-RJYKIZMS.js → chunk-PQZ6PVKG.js} +2 -2
- package/dist/{chunk-TQPQXCSZ.js → chunk-Q6NHXIOZ.js} +2 -2
- package/dist/{chunk-KYGWVCTM.js → chunk-QMDVYTB7.js} +1 -1
- package/dist/{chunk-XKTATY45.js → chunk-RW2KMSG5.js} +4 -4
- package/dist/{chunk-UHNSPTFT.js → chunk-SA2ZS24W.js} +1 -1
- package/dist/{chunk-6YPUQK36.js → chunk-SFWP4UMK.js} +2 -2
- package/dist/{chunk-ZZYLFHBU.js → chunk-TLNEQA4D.js} +1 -1
- package/dist/{chunk-RGTBRWWA.js → chunk-TOODE5AD.js} +2 -2
- package/dist/{chunk-QGWAHOFR.js → chunk-U57GY7SM.js} +2 -2
- package/dist/{chunk-FDJZKB7J.js → chunk-UIDQQJSX.js} +1 -1
- package/dist/{chunk-LLH3WXM3.js → chunk-UVFP2B7I.js} +1 -1
- package/dist/{chunk-4OF7727E.js → chunk-VEGZPCTZ.js} +2 -2
- package/dist/{chunk-73YUPNIT.js → chunk-VXN4V7LC.js} +1 -1
- package/dist/{chunk-4D3W6AAE.js → chunk-YHQVZWPG.js} +1 -1
- package/dist/{chunk-XXYBHYLM.js → chunk-YQO3TO66.js} +2 -2
- package/dist/{chunk-YZAYFR5A.js → chunk-ZSJ3GEOJ.js} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +50 -50
- package/dist/modules/anim.js +2 -2
- package/dist/modules/array.js +2 -2
- package/dist/modules/auth.js +3 -3
- package/dist/modules/behavior.js +2 -2
- package/dist/modules/bit.js +2 -2
- package/dist/modules/browser.js +2 -2
- package/dist/modules/bytes.js +2 -2
- package/dist/modules/codec.js +3 -3
- package/dist/modules/composition.js +2 -2
- package/dist/modules/core.js +2 -2
- package/dist/modules/csv.js +2 -2
- package/dist/modules/ffi.js +3 -3
- package/dist/modules/format.js +2 -2
- package/dist/modules/geo.js +2 -2
- package/dist/modules/gpu.d.ts +12 -0
- package/dist/modules/gpu.js +3 -0
- package/dist/modules/grid.js +2 -2
- package/dist/modules/i18n.js +2 -2
- package/dist/modules/index.d.ts +1 -2
- package/dist/modules/index.js +45 -46
- package/dist/modules/json.js +2 -2
- package/dist/modules/kernel.js +3 -3
- package/dist/modules/kv.js +3 -3
- package/dist/modules/llm.js +2 -2
- package/dist/modules/math.js +2 -2
- package/dist/modules/mem.js +3 -3
- package/dist/modules/object.js +2 -2
- package/dist/modules/os-common.d.ts +1 -1
- package/dist/modules/os-common.js +2 -2
- package/dist/modules/os-desktop.js +3 -3
- package/dist/modules/os-dev.js +3 -3
- package/dist/modules/os-dir.js +3 -3
- package/dist/modules/os-env-stdio.js +3 -3
- package/dist/modules/os-fs.js +3 -3
- package/dist/modules/os-net.js +3 -3
- package/dist/modules/os-path.js +3 -3
- package/dist/modules/os-process.js +3 -3
- package/dist/modules/os-sys.js +3 -3
- package/dist/modules/os-time-users.js +3 -3
- package/dist/modules/os.js +13 -13
- package/dist/modules/path.js +2 -2
- package/dist/modules/prob.js +2 -2
- package/dist/modules/program.js +2 -2
- package/dist/modules/session.js +2 -2
- package/dist/modules/str.js +2 -2
- package/dist/modules/time.js +2 -2
- package/dist/modules/validate.js +2 -2
- package/dist/modules/vector.js +2 -2
- package/dist/modules/workspace.js +2 -2
- package/dist/modules/xml.js +2 -2
- package/dist/modules/yaml.js +2 -2
- package/dist/registry.d.ts +2 -2
- package/dist/registry.js +49 -49
- package/dist/{types-BA4LkhNJ.d.ts → types-CgiGhK6t.d.ts} +17 -3
- package/package.json +5 -5
- package/dist/chunk-F5TP25JA.js +0 -26
- package/dist/chunk-NE4WSTN7.js +0 -26
- package/dist/modules/trace.d.ts +0 -15
- package/dist/modules/trace.js +0 -2
- /package/dist/{chunk-SHSBTDDX.js → chunk-QUQ33UXH.js} +0 -0
|
@@ -3,10 +3,11 @@ app std-orb-serve [
|
|
|
3
3
|
inbound: ["cli-serve"],
|
|
4
4
|
env: ["HOME", "FIREBASE_AUTH_EMULATOR_HOST", "FIREBASE_PROJECT_ID"],
|
|
5
5
|
fs: { "~/.almadar/serve": [create], "~/.almadar/serve/**": [write, create, read], cwd: ".orbital": [create], cwd: ".orbital/serve": [create], cwd: ".orbital/serve/**": [write, create] },
|
|
6
|
-
description: "std-orb-serve — the `orb serve <file> [--port N] [--host H] [--no-mock] [--client-dir DIR] [--open] [--no-emulators]` command (spec/cli/orb-serve.lolo; port of orbital-cli program_command.rs serve_program and server_overrides). It resolves the app with program/read { resolve: true, path }. An app that declares its own http endpoint is composed alone, and --port, --host or --client-dir is refused (status 400): its server's options are set in the program. Without --client-dir the app gets a browser client prepared first: program/eval generate { mode: client, webClient: true } compiles it client-mode into <cwd>/.orbital/serve/<app> and lays the typescript shell's prebuilt web client, with the app's runtime files over it, out in .orbital/serve/<app>/web-client, which becomes the clientDir; when FIREBASE_AUTH_EMULATOR_HOST and FIREBASE_PROJECT_ID are both set, that folder's __/firebase/init.json names the Auth emulator for the page. Otherwise it writes ~/.almadar/serve/<app path with / as _>.server.lolo, which imports std-http-server's HttpServerOrbital with the serve options as its call-site config (host, port, portFromEnv false and, with --client-dir made absolute against the working directory and required to lie under it, clientDir relative to the working directory), resolves it with program/read so each knob reaches the trait bodies, and composes the app with std-http-server's resolved program (behavior/resolve, for its header grants) carrying that configured orbital, adding the listen grant for host:port and the anchored cwd read grant of the client dir. The compose, prepare-client and answer half is std-orb-serve-handoff's ServeHandoff, which std-orb-launchpad composes as well. The command never runs the program: it answers a hand-off the bootloader acts on, status 200 with headers orb-run: server, orb-app: the absolute app path, and the composed program's JSON as the body. --open and --no-emulators answer status 500 on stderr with the texts the Rust command bailed with; a port that is not an integer in 0..65535 answers status 400 on stderr; a client dir outside the working directory, an app that names no app or a program that does not resolve or compose answers status 500 on stderr `Error: <reason>`; a missing or second file or an unknown flag answers the usage (status 400, exit 2). Defaults: port 3030, host 127.0.0.1. The resolved app is written (with its catalogs and lazy behaviors) to ~/.almadar/serve/<app path with / as _>.orb, the directory read from the HOME env grant and written under the fs grant ~/.almadar/serve/**; orb-app names that file, so the bootloader finds the catalogs."
|
|
6
|
+
description: "std-orb-serve — the `orb serve <file> [--port N] [--host H] [--no-mock] [--client-dir DIR] [--open] [--no-emulators]` command (spec/cli/orb-serve.lolo; port of orbital-cli program_command.rs serve_program and server_overrides). It resolves the app with program/read { resolve: true, path }. An app that declares its own http endpoint is composed alone, and --port, --host or --client-dir is refused (status 400): its server's options are set in the program. Without --client-dir the app gets a browser client prepared first: program/eval generate { mode: client, webClient: true } compiles it client-mode into <cwd>/.orbital/serve/<app> and lays the typescript shell's prebuilt web client, with the app's runtime files over it, out in .orbital/serve/<app>/web-client, which becomes the clientDir; when FIREBASE_AUTH_EMULATOR_HOST and FIREBASE_PROJECT_ID are both set, that folder's __/firebase/init.json names the Auth emulator for the page. Otherwise it writes ~/.almadar/serve/<app path with / as _>.server.lolo, which imports std-http-server's HttpServerOrbital with the serve options as its call-site config (host, port, portFromEnv false and, with --client-dir made absolute against the working directory and required to lie under it, clientDir relative to the working directory), resolves it with program/read so each knob reaches the trait bodies, and composes the app with std-http-server's resolved program (behavior/resolve, for its header grants) carrying that configured orbital, adding the listen grant for host:port and the anchored cwd read grant of the client dir. The compose, prepare-client and answer half is std-orb-serve-handoff's ServeHandoff, which std-orb-launchpad composes as well. The command never runs the program: it answers a hand-off the bootloader acts on, status 200 with headers orb-run: server, orb-app: the absolute app path, and the composed program's JSON as the body. --open and --no-emulators answer status 500 on stderr with the texts the Rust command bailed with; a port that is not an integer in 0..65535 answers status 400 on stderr; a client dir outside the working directory, an app that names no app or a program that does not resolve or compose answers status 500 on stderr `Error: <reason>`; a missing or second file or an unknown flag answers the usage (status 400, exit 2). Defaults: port 3030, host 127.0.0.1. The resolved app is written (with its catalogs and lazy behaviors) to ~/.almadar/serve/<app path with / as _>.orb, the directory read from the HOME env grant and written under the fs grant ~/.almadar/serve/**; orb-app names that file, so the bootloader finds the catalogs. Unless --no-mock, and when the app does not already seed itself, the server program also composes std-mock-page-seed, and, when the app declares an [identity] entity no trait of it signs in, std-dev-personas over that entity (std-mock-seed-marks answers both texts), so the seeder can sign each owner in and the session starts as the first declared role."
|
|
7
7
|
]
|
|
8
8
|
uses Spec from "almadar-std/orb-serve"
|
|
9
9
|
uses Args from "std/behaviors/std-args"
|
|
10
|
+
uses Marks from "std/behaviors/std-mock-seed-marks"
|
|
10
11
|
uses Handoff from "std/behaviors/std-orb-serve-handoff"
|
|
11
12
|
type OrbCommandArgs = { argv : [string]!, cwd : string! }
|
|
12
13
|
type ArgFlag = { name : string!, aliases : [string]!, takesValue : boolean!, repeatable : boolean! }
|
|
@@ -47,6 +48,12 @@ orbital OrbServeOrbital {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
trait MarksCli = Marks.traits.MarksCheck {
|
|
52
|
+
listens {
|
|
53
|
+
ServeEngine.SERVE_SEED_ASK -> MARKS_CHECK
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
trait OrbServe -> ServeRun [optimistic] {
|
|
51
58
|
initial: ready
|
|
52
59
|
|
|
@@ -222,8 +229,12 @@ orbital OrbServeOrbital {
|
|
|
222
229
|
|
|
223
230
|
state writing {
|
|
224
231
|
INIT -> writing
|
|
225
|
-
SERVE_WRITE_SERVER -> writing
|
|
226
|
-
(emit SERVE_SEED_DECIDED { seed:
|
|
232
|
+
SERVE_WRITE_SERVER -> writing when (not @entity.mock)
|
|
233
|
+
(emit SERVE_SEED_DECIDED { seed: "" })
|
|
234
|
+
SERVE_WRITE_SERVER -> writing when @entity.mock
|
|
235
|
+
(emit SERVE_SEED_ASK { program: @entity.app })
|
|
236
|
+
SERVE_SEED_MARKED -> writing
|
|
237
|
+
(emit SERVE_SEED_DECIDED { seed: (if @payload.marked "" (str/concat "uses Seed from \"std/behaviors/std-mock-page-seed\"\norbital MockData = Seed.orbitals.MockData {}\n" @payload.personas)) })
|
|
227
238
|
SERVE_SEED_DECIDED -> resolving
|
|
228
239
|
(os/write-file (str/concat "~/.almadar/serve/" @entity.serverName) (bytes/from-string (str/concat
|
|
229
240
|
"app orb-served-server [version: \"1.0.0\"]\n"
|
|
@@ -286,6 +297,11 @@ orbital OrbServeOrbital {
|
|
|
286
297
|
SERVE_WRITE_SERVER { }
|
|
287
298
|
@description "Write the server program, std-http-server imported with the serve options as its call-site config."
|
|
288
299
|
@tier "internal"
|
|
300
|
+
SERVE_SEED_ASK {
|
|
301
|
+
program : ServeProgram!
|
|
302
|
+
}
|
|
303
|
+
@description "Ask std-mock-seed-marks whether the resolved app already declares the MockSeedMark store."
|
|
304
|
+
@tier "internal"
|
|
289
305
|
SERVE_SEED_DECIDED {
|
|
290
306
|
seed : string!
|
|
291
307
|
}
|
|
@@ -350,6 +366,10 @@ orbital OrbServeOrbital {
|
|
|
350
366
|
}
|
|
351
367
|
@description "Compose the app with std-http-server."
|
|
352
368
|
OrbServe.SERVE_START -> SERVE_START
|
|
369
|
+
MarksCli.MARKS_CHECKED -> SERVE_SEED_MARKED
|
|
370
|
+
SERVE_SEED_MARKED { marked : boolean! personas : string! }
|
|
371
|
+
@description "std-mock-seed-marks's MARKS_CHECKED: whether the app already declares the marks store, and the personas text that composes std-dev-personas onto the app's identity entity (empty when there is none)."
|
|
372
|
+
@tier "internal"
|
|
353
373
|
SERVE_SEED_DECIDED { seed : string! }
|
|
354
374
|
@description "The seed decision, which the server program write reads."
|
|
355
375
|
@tier "internal"
|
|
@@ -363,5 +383,5 @@ orbital OrbServeOrbital {
|
|
|
363
383
|
}
|
|
364
384
|
}
|
|
365
385
|
|
|
366
|
-
page boot as OrbServePage -> OrbServe, ArgsCli, ServeEngine, ServeHandoff
|
|
386
|
+
page boot as OrbServePage -> OrbServe, ArgsCli, MarksCli, ServeEngine, ServeHandoff
|
|
367
387
|
}
|
|
@@ -19,7 +19,7 @@ orbital LoloKotlinOrbital {
|
|
|
19
19
|
config {
|
|
20
20
|
language: "Kotlin"
|
|
21
21
|
requiresTypes: false
|
|
22
|
-
operators: { "/": "_div({{0}}, {{1}})", "%": "_mod({{0}}, {{1}})", "math/mod": "_mod({{0}}, {{1}})", "=": "_eq({{0}}, {{1}})", "==": "_eq({{0}}, {{1}})", "!=": "(!_eq({{0}}, {{1}}))", "default": "_default({{0}}, {{1}})", "as": "{{0}}", "list": "listOf({{*}})", "str/len": "_strLen({{0}}).toDouble()", "str/upper": "{{0}}.uppercase()", "str/lower": "{{0}}.lowercase()", "str/trim": "{{0}}.trim()", "str/trimStart": "{{0}}.trimStart()", "str/trimEnd": "{{0}}.trimEnd()", "str/capitalize": "_capitalize({{0}})", "str/split": "_split({{0}}, {{1}})", "str/join": "_join({{0}}, {{1}})", "str/concat": "_concat({{*}})", "str/includes": "{{0}}.contains({{1}})", "str/startsWith": "{{0}}.startsWith({{1}})", "str/endsWith": "{{0}}.endsWith({{1}})", "str/replace": "{{0}}.replaceFirst({{1}}, {{2}})", "str/replaceAll": "{{0}}.replace({{1}}, {{2}})", "str/repeat": "{{0}}.repeat(_count({{1}}))", "str/reverse": "StringBuilder({{0}}).reverse().toString()", "str/slice#2": "_strSlice({{0}}, {{1}})", "str/slice#3": "_strSlice({{0}}, {{1}}, {{2}})", "str/padStart#2": "_padStart({{0}}, {{1}})", "str/padStart#3": "_padStart({{0}}, {{1}}, {{2}})", "str/padEnd#2": "_padEnd({{0}}, {{1}})", "str/padEnd#3": "_padEnd({{0}}, {{1}}, {{2}})", "str/truncate#2": "_truncate({{0}}, {{1}})", "str/truncate#3": "_truncate({{0}}, {{1}}, {{2}})", "str/to-int": "_toInt({{0}})", "array/len": "{{0}}.size.toDouble()", "array/avg#1": "_avg({{0}})", "array/max#1": "_amax({{0}})", "array/min#1": "_amin({{0}})", "array/first": "_first({{0}})", "array/last": "_last({{0}})", "array/nth": "_nth({{0}}, {{1}})", "array/range#2": "_range({{0}}, {{1}})", "array/range#3": "_range({{0}}, {{1}}, {{2}})", "array/slice#2": "_slice({{0}}, {{1}})", "array/slice#3": "_slice({{0}}, {{1}}, {{2}})", "array/take": "{{0}}.take(_count({{1}}))", "array/drop": "{{0}}.drop(_count({{1}}))", "array/takeLast": "{{0}}.takeLast(_count({{1}}))", "array/dropLast": "{{0}}.dropLast(_count({{1}}))", "array/append": "_append({{0}}, {{1}})", "array/prepend": "_prepend({{0}}, {{1}})", "array/includes": "{{0}}.contains({{1}})", "array/indexOf": "_indexOf({{0}}, {{1}})", "array/reverse": "{{0}}.reversed()", "array/unique": "{{0}}.distinct()", "array/flatten": "{{0}}.flatten()", "array/zip": "{{0}}.zip({{1}}).map { listOf(it.first, it.second) }", "array/sort#1": "_sort({{0}})", "array/reduce": "{{0}}.fold({{1}}, {{2}})", "array/filter": "{{0}}.filter({{1}})", "array/reject": "{{0}}.filterNot({{1}})", "array/find": "{{0}}.firstOrNull({{1}})", "array/findIndex": "{{0}}.indexOfFirst({{1}}).toDouble()", "math/abs": "Math.abs(({{0}}).toDouble())", "math/max": "maxOf({{*}})", "math/min": "minOf({{*}})", "math/round#1": "_round({{0}})", "math/round#2": "_round({{0}}, {{1}})", "math/sqrt": "_sqrt({{0}})", "math/ln": "_ln({{0}})", "math/log10": "_log10({{0}})", "math/pow": "_pow({{0}}, {{1}})", "math/sign": "Math.signum(({{0}}).toDouble())", "math/clamp": "Math.min(Math.max(({{0}}).toDouble(), ({{1}}).toDouble()), ({{2}}).toDouble())", "math/ceil": "Math.ceil(({{0}}).toDouble())", "math/floor": "Math.floor(({{0}}).toDouble())", "math/sin": "Math.sin(({{0}}).toDouble())", "math/cos": "Math.cos(({{0}}).toDouble())", "math/tan": "Math.tan(({{0}}).toDouble())", "math/atan": "Math.atan(({{0}}).toDouble())", "math/atan2": "Math.atan2(({{0}}).toDouble(), ({{1}}).toDouble())", "math/hypot": "Math.hypot(({{0}}).toDouble(), ({{1}}).toDouble())", "validate/required": "_required({{0}})", "validate/length": "(_strLen({{0}}).toDouble() == ({{1}}).toDouble())", "validate/minLength": "(_strLen({{0}}).toDouble() >= ({{1}}).toDouble())", "validate/maxLength": "(_strLen({{0}}).toDouble() <= ({{1}}).toDouble())", "validate/min": "(({{0}}).toDouble() >= ({{1}}).toDouble())", "validate/max": "(({{0}}).toDouble() <= ({{1}}).toDouble())", "validate/range": "(({{0}}).toDouble() in ({{1}}).toDouble()..({{2}}).toDouble())", "validate/oneOf": "{{1}}.contains({{0}})", "validate/equals": "_eq({{0}}, {{1}})" }
|
|
22
|
+
operators: { "object/get#2": "_get({{0}}, {{1}})", "/": "_div({{0}}, {{1}})", "%": "_mod({{0}}, {{1}})", "math/mod": "_mod({{0}}, {{1}})", "=": "_eq({{0}}, {{1}})", "==": "_eq({{0}}, {{1}})", "!=": "(!_eq({{0}}, {{1}}))", "default": "_default({{0}}, {{1}})", "as": "{{0}}", "list": "listOf({{*}})", "str/len": "_strLen({{0}}).toDouble()", "str/upper": "{{0}}.uppercase()", "str/lower": "{{0}}.lowercase()", "str/trim": "{{0}}.trim()", "str/trimStart": "{{0}}.trimStart()", "str/trimEnd": "{{0}}.trimEnd()", "str/capitalize": "_capitalize({{0}})", "str/split": "_split({{0}}, {{1}})", "str/join": "_join({{0}}, {{1}})", "str/concat": "_concat({{*}})", "str/includes": "{{0}}.contains({{1}})", "str/startsWith": "{{0}}.startsWith({{1}})", "str/endsWith": "{{0}}.endsWith({{1}})", "str/replace": "{{0}}.replaceFirst({{1}}, {{2}})", "str/replaceAll": "{{0}}.replace({{1}}, {{2}})", "str/repeat": "{{0}}.repeat(_count({{1}}))", "str/reverse": "StringBuilder({{0}}).reverse().toString()", "str/slice#2": "_strSlice({{0}}, {{1}})", "str/slice#3": "_strSlice({{0}}, {{1}}, {{2}})", "str/padStart#2": "_padStart({{0}}, {{1}})", "str/padStart#3": "_padStart({{0}}, {{1}}, {{2}})", "str/padEnd#2": "_padEnd({{0}}, {{1}})", "str/padEnd#3": "_padEnd({{0}}, {{1}}, {{2}})", "str/truncate#2": "_truncate({{0}}, {{1}})", "str/truncate#3": "_truncate({{0}}, {{1}}, {{2}})", "str/to-int": "_toInt({{0}})", "array/len": "{{0}}.size.toDouble()", "array/avg#1": "_avg({{0}})", "array/max#1": "_amax({{0}})", "array/min#1": "_amin({{0}})", "array/first": "_first({{0}})", "array/last": "_last({{0}})", "array/nth": "_nth({{0}}, {{1}})", "array/range#2": "_range({{0}}, {{1}})", "array/range#3": "_range({{0}}, {{1}}, {{2}})", "array/slice#2": "_slice({{0}}, {{1}})", "array/slice#3": "_slice({{0}}, {{1}}, {{2}})", "array/take": "{{0}}.take(_count({{1}}))", "array/drop": "{{0}}.drop(_count({{1}}))", "array/takeLast": "{{0}}.takeLast(_count({{1}}))", "array/dropLast": "{{0}}.dropLast(_count({{1}}))", "array/append": "_append({{0}}, {{1}})", "array/prepend": "_prepend({{0}}, {{1}})", "array/includes": "{{0}}.contains({{1}})", "array/indexOf": "_indexOf({{0}}, {{1}})", "array/reverse": "{{0}}.reversed()", "array/unique": "{{0}}.distinct()", "array/flatten": "{{0}}.flatten()", "array/zip": "{{0}}.zip({{1}}).map { listOf(it.first, it.second) }", "array/sort#1": "_sort({{0}})", "array/reduce": "{{0}}.fold({{1}}, {{2}})", "array/filter": "{{0}}.filter({{1}})", "array/reject": "{{0}}.filterNot({{1}})", "array/find": "{{0}}.firstOrNull({{1}})", "array/findIndex": "{{0}}.indexOfFirst({{1}}).toDouble()", "math/abs": "Math.abs(({{0}}).toDouble())", "math/max": "maxOf({{*}})", "math/min": "minOf({{*}})", "math/round#1": "_round({{0}})", "math/round#2": "_round({{0}}, {{1}})", "math/sqrt": "_sqrt({{0}})", "math/ln": "_ln({{0}})", "math/log10": "_log10({{0}})", "math/pow": "_pow({{0}}, {{1}})", "math/sign": "Math.signum(({{0}}).toDouble())", "math/clamp": "Math.min(Math.max(({{0}}).toDouble(), ({{1}}).toDouble()), ({{2}}).toDouble())", "math/ceil": "Math.ceil(({{0}}).toDouble())", "math/floor": "Math.floor(({{0}}).toDouble())", "math/sin": "Math.sin(({{0}}).toDouble())", "math/cos": "Math.cos(({{0}}).toDouble())", "math/tan": "Math.tan(({{0}}).toDouble())", "math/atan": "Math.atan(({{0}}).toDouble())", "math/atan2": "Math.atan2(({{0}}).toDouble(), ({{1}}).toDouble())", "math/hypot": "Math.hypot(({{0}}).toDouble(), ({{1}}).toDouble())", "validate/required": "_required({{0}})", "validate/length": "(_strLen({{0}}).toDouble() == ({{1}}).toDouble())", "validate/minLength": "(_strLen({{0}}).toDouble() >= ({{1}}).toDouble())", "validate/maxLength": "(_strLen({{0}}).toDouble() <= ({{1}}).toDouble())", "validate/min": "(({{0}}).toDouble() >= ({{1}}).toDouble())", "validate/max": "(({{0}}).toDouble() <= ({{1}}).toDouble())", "validate/range": "(({{0}}).toDouble() in ({{1}}).toDouble()..({{2}}).toDouble())", "validate/oneOf": "{{1}}.contains({{0}})", "validate/equals": "_eq({{0}}, {{1}})" }
|
|
23
23
|
unary: { "-": "(-{{0}})", "not": "(!{{0}})", "array/range": "_range({{0}})", "array/sum": "_sum({{0}})", "array/count": "{{0}}.size.toDouble()", "array/sort": "_sort({{0}})", "math/round": "_round({{0}})", "array/concat": "{{0}}" }
|
|
24
24
|
infix: { "+": "+", "-": "-", "*": "*", "<": "<", "<=": "<=", ">": ">", ">=": ">=", "and": "&&", "or": "||", "array/concat": "+" }
|
|
25
25
|
infixForm: "({{*}})"
|
|
@@ -28,7 +28,7 @@ orbital LoloKotlinOrbital {
|
|
|
28
28
|
indexedSource: "{{src}}.mapIndexed { i_, x_ -> Pair(i_.toDouble(), x_) }"
|
|
29
29
|
indexedVars: "({{index}}, {{item}})"
|
|
30
30
|
unsupportedForm: "_unsupported({{op}})"
|
|
31
|
-
helpers: { "/": ["private fun _div(a: Number, b: Number): Double? = if (b.toDouble() == 0.0) null else a.toDouble() / b.toDouble()"], "%": ["private fun _mod(a: Number, b: Number): Double? = if (b.toDouble() == 0.0) null else a.toDouble() % b.toDouble()"], "math/mod": ["private fun _mod(a: Number, b: Number): Double? = if (b.toDouble() == 0.0) null else a.toDouble() % b.toDouble()"], "=": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "==": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "!=": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "default": ["private fun <T : Any> _default(v: T?, d: T): T = v ?: d"], "str/len": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "str/capitalize": ["private fun _capitalize(s: String): String {\n if (s.isEmpty()) return s\n val n = s.offsetByCodePoints(0, 1)\n return s.substring(0, n).uppercase() + s.substring(n).lowercase()\n}"], "str/split": ["private fun _split(s: String, d: String): List<String> =\n if (d == \"\") s.codePoints().toArray().map { String(Character.toChars(it)) } else s.split(d)"], "str/join": ["private fun _join(a: List<Any?>, d: String): String = a.joinToString(d) { _text(it) }", "private fun _text(v: Any?): String = when (v) {\n is String -> v\n is Boolean -> v.toString()\n is Long -> v.toString()\n is Int -> v.toString()\n is Double -> if (v.isFinite() && v == Math.floor(v)) java.math.BigDecimal(v).toBigInteger().toString() else v.toString()\n else -> throw IllegalArgumentException(\"expected string, number or boolean\")\n}"], "str/concat": ["private fun _concat(vararg v: Any?): String = v.joinToString(\"\") { _text(it) }", "private fun _text(v: Any?): String = when (v) {\n is String -> v\n is Boolean -> v.toString()\n is Long -> v.toString()\n is Int -> v.toString()\n is Double -> if (v.isFinite() && v == Math.floor(v)) java.math.BigDecimal(v).toBigInteger().toString() else v.toString()\n else -> throw IllegalArgumentException(\"expected string, number or boolean\")\n}"], "str/repeat": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "str/slice": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _strSlice(s: String, a: Number, b: Number? = null): String {\n val n = s.codePointCount(0, s.length)\n val x = _whole(a)\n val y = if (b == null) n else _whole(b)\n val from = if (x < 0) maxOf(n + x, 0) else minOf(x, n)\n val to = if (y < 0) maxOf(n + y, 0) else minOf(y, n)\n if (to <= from) return \"\"\n return s.substring(s.offsetByCodePoints(0, from), s.offsetByCodePoints(0, to))\n}"], "str/padStart": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}", "private fun _strLen(s: String): Int = s.codePointCount(0, s.length)", "private fun _padUnit(p: String): String {\n if (p.codePointCount(0, p.length) != 1) throw IllegalArgumentException(\"expected a single padding character, got \" + p)\n return p\n}", "private fun _padStart(s: String, n: Number, p: String = \" \"): String {\n val k = _count(n) - _strLen(s)\n return if (k <= 0) s else _padUnit(p).repeat(k) + s\n}"], "str/padEnd": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}", "private fun _strLen(s: String): Int = s.codePointCount(0, s.length)", "private fun _padUnit(p: String): String {\n if (p.codePointCount(0, p.length) != 1) throw IllegalArgumentException(\"expected a single padding character, got \" + p)\n return p\n}", "private fun _padEnd(s: String, n: Number, p: String = \" \"): String {\n val k = _count(n) - _strLen(s)\n return if (k <= 0) s else s + _padUnit(p).repeat(k)\n}"], "str/truncate": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}", "private fun _strLen(s: String): Int = s.codePointCount(0, s.length)", "private fun _strSlice(s: String, a: Number, b: Number? = null): String {\n val n = s.codePointCount(0, s.length)\n val x = _whole(a)\n val y = if (b == null) n else _whole(b)\n val from = if (x < 0) maxOf(n + x, 0) else minOf(x, n)\n val to = if (y < 0) maxOf(n + y, 0) else minOf(y, n)\n if (to <= from) return \"\"\n return s.substring(s.offsetByCodePoints(0, from), s.offsetByCodePoints(0, to))\n}", "private fun _truncate(s: String, n: Number, suffix: String = \"...\"): String =\n if (_strLen(s) <= _count(n)) s else _strSlice(s, 0.0, n) + suffix"], "str/to-int": ["private fun _toInt(s: String): Double? =\n if (Regex(\"[+-]?[0-9]+\").matches(s)) s.toLongOrNull()?.toDouble() else null"], "array/avg": ["private fun _avg(a: List<Number>): Double? = if (a.isEmpty()) null else a.sumOf { it.toDouble() } / a.size"], "array/max": ["private fun _amax(a: List<Number>): Double? = a.maxOfOrNull { it.toDouble() }"], "array/min": ["private fun _amin(a: List<Number>): Double? = a.minOfOrNull { it.toDouble() }"], "array/first": ["private fun <T> _first(a: List<T>): T? = a.firstOrNull()"], "array/last": ["private fun <T> _last(a: List<T>): T? = a.lastOrNull()"], "array/nth": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun <T> _nth(a: List<T>, i: Number): T? {\n val k = _whole(i)\n if (k < 0) throw IllegalArgumentException(\"nth: index \" + k + \" is not a whole number from 0\")\n return a.getOrNull(k)\n}"], "array/range": ["private fun _range(a: Number, b: Number? = null, step: Number = 1.0): List<Double> {\n val from = if (b == null) 0.0 else a.toDouble()\n val to = if (b == null) a.toDouble() else b.toDouble()\n val st = step.toDouble()\n if (st == 0.0 || st.isNaN() || st.isInfinite()) throw IllegalArgumentException(\"range: step 0 must be a non-zero finite number\")\n val out = mutableListOf<Double>()\n var x = from\n while (if (st > 0) x < to else x > to) {\n out.add(x)\n x += st\n }\n return out\n}"], "array/slice": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun <T> _slice(a: List<T>, s: Number, e: Number? = null): List<T> {\n val from = _whole(s)\n val to = if (e == null) a.size else _whole(e)\n if (from < 0 || to < 0) throw IllegalArgumentException(\"slice: not a whole number from 0\")\n val end = minOf(to, a.size)\n return if (from >= end) listOf() else a.subList(from, end).toList()\n}"], "array/take": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/drop": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/takeLast": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/dropLast": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/append": ["private fun <T> _append(a: List<T>, x: T): List<T> = a + listOf(x)"], "array/prepend": ["private fun <T> _prepend(a: List<T>, x: T): List<T> = listOf(x) + a"], "array/indexOf": ["private fun <T> _indexOf(a: List<T>, x: T): Double = a.indexOf(x).toDouble()"], "array/sort": ["private fun <T : Comparable<T>> _sort(a: List<T>): List<T> = a.sorted()"], "math/round": ["private fun _round(x: Number, d: Number = 0.0): Double {\n val m = Math.pow(10.0, d.toDouble())\n return Math.copySign(Math.floor(Math.abs(x.toDouble()) * m + 0.5) / m, x.toDouble())\n}"], "math/sqrt": ["private fun _sqrt(x: Number): Double? = if (x.toDouble() < 0.0) null else Math.sqrt(x.toDouble())"], "math/ln": ["private fun _ln(x: Number): Double? = if (x.toDouble() <= 0.0) null else Math.log(x.toDouble())"], "math/log10": ["private fun _log10(x: Number): Double? = if (x.toDouble() <= 0.0) null else Math.log10(x.toDouble())"], "math/pow": ["private fun _pow(a: Number, b: Number): Double? {\n val r = Math.pow(a.toDouble(), b.toDouble())\n return if (r.isNaN() || r.isInfinite()) null else r\n}"], "validate/required": ["private fun _required(v: Any?): Boolean = v != null && v != \"\""], "validate/length": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "validate/minLength": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "validate/maxLength": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "validate/equals": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "array/sum": ["private fun _sum(a: List<Number>): Double = a.sumOf { it.toDouble() }"], "unsupported": ["private fun _unsupported(name: String): Nothing = throw UnsupportedOperationException(\"no native template for operator \" + name)"] }
|
|
31
|
+
helpers: { "object/get": ["private fun <V> _get(o: Map<String, V>, p: String): V? {\n if (p.contains(\".\")) error(\"object/get: a dotted path is not supported on a typed map\")\n return o[p]\n}"], "store": ["class Answer(val ok: Boolean, val payload: Map<String, Any?>)\n\ninterface Store {\n fun persist(op: String, entity: String, data: Any?): Answer\n fun fetch(entity: String, keep: ((Map<String, Any?>) -> Boolean)?): Answer\n}\n\nprivate fun _codePoints(a: String, b: String): Int {\n val x = a.codePoints().toArray()\n val y = b.codePoints().toArray()\n for (i in 0 until minOf(x.size, y.size)) if (x[i] != y[i]) return x[i].compareTo(y[i])\n return x.size.compareTo(y.size)\n}\n\nprivate fun _stampOrder(a: Map<String, Any?>, b: Map<String, Any?>): Int {\n val sa = a[\"createdAt\"]\n val sb = b[\"createdAt\"]\n if ((sa == null) != (sb == null)) return if (sa != null) -1 else 1\n if (sa is Number && sb is Number && sa.toDouble() != sb.toDouble()) return sa.toDouble().compareTo(sb.toDouble())\n if (sa is String && sb is String && sa != sb) return _codePoints(sa, sb)\n return _codePoints(a[\"id\"].toString(), b[\"id\"].toString())\n}\n\nclass MemoryStore : Store {\n private val tables = mutableMapOf<String, MutableList<Pair<String, MutableMap<String, Any?>>>>()\n private var minted = 0\n\n override fun persist(op: String, entity: String, data: Any?): Answer {\n val rows = tables.getOrPut(entity) { mutableListOf() }\n if (op == \"create\" && data is Map<*, *>) {\n val row = data.entries.associate { (k, v) -> k.toString() to v }.toMutableMap()\n val given = row[\"id\"]\n val id = if (given is String && given.isNotEmpty()) given else {\n minted += 1\n entity + \"-\" + minted\n }\n row[\"id\"] = id\n rows.add(id to row)\n return Answer(true, row.toMap())\n }\n val key = when (data) {\n is String -> data\n is Map<*, *> -> data[\"id\"]?.toString() ?: \"\"\n else -> \"\"\n }\n val pos = rows.indexOfFirst { it.first == key }\n if (pos < 0) return Answer(false, mapOf(\"error\" to entity + \" \" + key + \" not found\", \"code\" to \"not-found\"))\n if (op == \"delete\") {\n rows.removeAt(pos)\n return Answer(true, mapOf(\"id\" to key, \"deleted\" to true))\n }\n if (data is Map<*, *>) for ((k, v) in data) rows[pos].second[k.toString()] = v\n return Answer(true, rows[pos].second.toMap())\n }\n\n override fun fetch(entity: String, keep: ((Map<String, Any?>) -> Boolean)?): Answer {\n val rows = (tables[entity] ?: mutableListOf()).map { it.second.toMap() }.filter { keep?.invoke(it) ?: true }.sortedWith(::_stampOrder)\n return Answer(true, mapOf(\"data\" to rows, \"totalCount\" to rows.size))\n }\n}"], "router": ["private val _routerJson = kotlinx.serialization.json.Json { encodeDefaults = true; ignoreUnknownKeys = true }\n\nprivate fun _json(value: Any?): kotlinx.serialization.json.JsonElement = when (value) {\n null -> kotlinx.serialization.json.JsonNull\n Unit -> kotlinx.serialization.json.JsonObject(emptyMap())\n is kotlinx.serialization.json.JsonElement -> value\n is String -> kotlinx.serialization.json.JsonPrimitive(value)\n is Number -> kotlinx.serialization.json.JsonPrimitive(value)\n is Boolean -> kotlinx.serialization.json.JsonPrimitive(value)\n is Map<*, *> -> kotlinx.serialization.json.JsonObject(value.entries.associate { (k, v) -> k.toString() to _json(v) })\n is List<*> -> kotlinx.serialization.json.JsonArray(value.map { _json(it) })\n else -> _routerJson.encodeToJsonElement(kotlinx.serialization.serializer(value.javaClass), value)\n}\n\nprivate inline fun <reified T> _decode(value: kotlinx.serialization.json.JsonElement): T =\n _routerJson.decodeFromJsonElement(kotlinx.serialization.serializer<T>(), value)\n\nclass _RouterEntry(\n val key: String,\n val trait: Any,\n val state: () -> String,\n val entity: () -> kotlinx.serialization.json.JsonElement,\n val count: () -> Int,\n val from: (Int) -> List<Triple<String, kotlinx.serialization.json.JsonElement, Boolean>>,\n)\n\nclass _RouterItem(\n val target: String,\n val event: String,\n val payload: kotlinx.serialization.json.JsonElement,\n val source: kotlinx.serialization.json.JsonElement,\n val guard: ((kotlinx.serialization.json.JsonElement) -> Boolean)?,\n val fans: Boolean,\n val completion: Boolean,\n)\n\nclass _RouterRow(\n val source: String,\n val event: String,\n val target: String,\n val trigger: String,\n val guard: ((kotlinx.serialization.json.JsonElement) -> Boolean)?,\n val mapping: ((kotlinx.serialization.json.JsonElement) -> kotlinx.serialization.json.JsonElement)?,\n)\n\nopen class _Router {\n val entries = mutableListOf<_RouterEntry>()\n val handles = mutableMapOf<String, Map<String, List<String>>>()\n val rows = mutableListOf<_RouterRow>()\n val log = mutableListOf<Triple<String, String, kotlinx.serialization.json.JsonElement>>()\n\n fun add(\n key: String,\n trait: Any,\n state: () -> String,\n entity: () -> kotlinx.serialization.json.JsonElement,\n count: () -> Int,\n from: (Int) -> List<Triple<String, kotlinx.serialization.json.JsonElement, Boolean>>,\n ) {\n entries.add(_RouterEntry(key, trait, state, entity, count, from))\n }\n\n fun row(\n source: String,\n event: String,\n target: String,\n trigger: String,\n guard: ((kotlinx.serialization.json.JsonElement) -> Boolean)?,\n mapping: ((kotlinx.serialization.json.JsonElement) -> kotlinx.serialization.json.JsonElement)?,\n ) {\n rows.add(_RouterRow(source, event, target, trigger, guard, mapping))\n }\n\n fun entry(key: String): _RouterEntry? = entries.firstOrNull { it.key == key }\n\n fun trait(key: String): Any? = entry(key)?.trait\n\n open fun deliver(target: String, event: String, payload: kotlinx.serialization.json.JsonElement) {}\n\n private fun targets(source: String, event: String, payload: kotlinx.serialization.json.JsonElement, completion: Boolean): List<_RouterItem> =\n rows.filter { it.source == source && it.event == event }.map {\n _RouterItem(it.target, it.trigger, it.mapping?.invoke(payload) ?: payload, payload, it.guard, false, completion)\n }\n\n fun dispatch(trait: String, event: String, payload: kotlinx.serialization.json.JsonElement) {\n val queue = ArrayDeque(listOf(_RouterItem(trait, event, payload, payload, null, true, false)))\n val seen = mutableSetOf<String>()\n var steps = 0\n while (queue.isNotEmpty()) {\n val item = queue.removeFirst()\n val e = entry(item.target) ?: continue\n val key = listOf(item.target, item.event, e.state(), item.payload.toString(), e.entity().toString()).joinToString(\"\\u001f\")\n if (!item.completion && key in seen) continue\n val g = item.guard\n if (g != null && !g(item.source)) continue\n if (steps >= 2000) break\n steps += 1\n seen.add(key)\n val n = e.count()\n deliver(item.target, item.event, item.payload)\n val fanned = if (item.fans) targets(item.target, item.event, item.payload, false).toMutableList() else mutableListOf()\n val own = mutableListOf<_RouterItem>()\n val newState = e.state()\n for ((ev, out, completion) in e.from(n)) {\n log.add(Triple(item.target, ev, out))\n if (handles[item.target]?.get(newState)?.contains(ev) == true) {\n own.add(_RouterItem(item.target, ev, out, out, null, false, completion))\n }\n fanned.addAll(targets(item.target, ev, out, completion))\n }\n queue.addAll(0, own)\n queue.addAll(fanned)\n }\n }\n}"], "/": ["private fun _div(a: Number, b: Number): Double? = if (b.toDouble() == 0.0) null else a.toDouble() / b.toDouble()"], "%": ["private fun _mod(a: Number, b: Number): Double? = if (b.toDouble() == 0.0) null else a.toDouble() % b.toDouble()"], "math/mod": ["private fun _mod(a: Number, b: Number): Double? = if (b.toDouble() == 0.0) null else a.toDouble() % b.toDouble()"], "=": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "==": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "!=": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "default": ["private fun <T : Any> _default(v: T?, d: T): T = v ?: d"], "str/len": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "str/capitalize": ["private fun _capitalize(s: String): String {\n if (s.isEmpty()) return s\n val n = s.offsetByCodePoints(0, 1)\n return s.substring(0, n).uppercase() + s.substring(n).lowercase()\n}"], "str/split": ["private fun _split(s: String, d: String): List<String> =\n if (d == \"\") s.codePoints().toArray().map { String(Character.toChars(it)) } else s.split(d)"], "str/join": ["private fun _join(a: List<Any?>, d: String): String = a.joinToString(d) { _text(it) }", "private fun _text(v: Any?): String = when (v) {\n is String -> v\n is Boolean -> v.toString()\n is Long -> v.toString()\n is Int -> v.toString()\n is Double -> if (v.isFinite() && v == Math.floor(v)) java.math.BigDecimal(v).toBigInteger().toString() else v.toString()\n else -> throw IllegalArgumentException(\"expected string, number or boolean\")\n}"], "str/concat": ["private fun _concat(vararg v: Any?): String = v.joinToString(\"\") { _text(it) }", "private fun _text(v: Any?): String = when (v) {\n is String -> v\n is Boolean -> v.toString()\n is Long -> v.toString()\n is Int -> v.toString()\n is Double -> if (v.isFinite() && v == Math.floor(v)) java.math.BigDecimal(v).toBigInteger().toString() else v.toString()\n else -> throw IllegalArgumentException(\"expected string, number or boolean\")\n}"], "str/repeat": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "str/slice": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _strSlice(s: String, a: Number, b: Number? = null): String {\n val n = s.codePointCount(0, s.length)\n val x = _whole(a)\n val y = if (b == null) n else _whole(b)\n val from = if (x < 0) maxOf(n + x, 0) else minOf(x, n)\n val to = if (y < 0) maxOf(n + y, 0) else minOf(y, n)\n if (to <= from) return \"\"\n return s.substring(s.offsetByCodePoints(0, from), s.offsetByCodePoints(0, to))\n}"], "str/padStart": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}", "private fun _strLen(s: String): Int = s.codePointCount(0, s.length)", "private fun _padUnit(p: String): String {\n if (p.codePointCount(0, p.length) != 1) throw IllegalArgumentException(\"expected a single padding character, got \" + p)\n return p\n}", "private fun _padStart(s: String, n: Number, p: String = \" \"): String {\n val k = _count(n) - _strLen(s)\n return if (k <= 0) s else _padUnit(p).repeat(k) + s\n}"], "str/padEnd": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}", "private fun _strLen(s: String): Int = s.codePointCount(0, s.length)", "private fun _padUnit(p: String): String {\n if (p.codePointCount(0, p.length) != 1) throw IllegalArgumentException(\"expected a single padding character, got \" + p)\n return p\n}", "private fun _padEnd(s: String, n: Number, p: String = \" \"): String {\n val k = _count(n) - _strLen(s)\n return if (k <= 0) s else s + _padUnit(p).repeat(k)\n}"], "str/truncate": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}", "private fun _strLen(s: String): Int = s.codePointCount(0, s.length)", "private fun _strSlice(s: String, a: Number, b: Number? = null): String {\n val n = s.codePointCount(0, s.length)\n val x = _whole(a)\n val y = if (b == null) n else _whole(b)\n val from = if (x < 0) maxOf(n + x, 0) else minOf(x, n)\n val to = if (y < 0) maxOf(n + y, 0) else minOf(y, n)\n if (to <= from) return \"\"\n return s.substring(s.offsetByCodePoints(0, from), s.offsetByCodePoints(0, to))\n}", "private fun _truncate(s: String, n: Number, suffix: String = \"...\"): String =\n if (_strLen(s) <= _count(n)) s else _strSlice(s, 0.0, n) + suffix"], "str/to-int": ["private fun _toInt(s: String): Double? =\n if (Regex(\"[+-]?[0-9]+\").matches(s)) s.toLongOrNull()?.toDouble() else null"], "array/avg": ["private fun _avg(a: List<Number>): Double? = if (a.isEmpty()) null else a.sumOf { it.toDouble() } / a.size"], "array/max": ["private fun _amax(a: List<Number>): Double? = a.maxOfOrNull { it.toDouble() }"], "array/min": ["private fun _amin(a: List<Number>): Double? = a.minOfOrNull { it.toDouble() }"], "array/first": ["private fun <T> _first(a: List<T>): T? = a.firstOrNull()"], "array/last": ["private fun <T> _last(a: List<T>): T? = a.lastOrNull()"], "array/nth": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun <T> _nth(a: List<T>, i: Number): T? {\n val k = _whole(i)\n if (k < 0) throw IllegalArgumentException(\"nth: index \" + k + \" is not a whole number from 0\")\n return a.getOrNull(k)\n}"], "array/range": ["private fun _range(a: Number, b: Number? = null, step: Number = 1.0): List<Double> {\n val from = if (b == null) 0.0 else a.toDouble()\n val to = if (b == null) a.toDouble() else b.toDouble()\n val st = step.toDouble()\n if (st == 0.0 || st.isNaN() || st.isInfinite()) throw IllegalArgumentException(\"range: step 0 must be a non-zero finite number\")\n val out = mutableListOf<Double>()\n var x = from\n while (if (st > 0) x < to else x > to) {\n out.add(x)\n x += st\n }\n return out\n}"], "array/slice": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun <T> _slice(a: List<T>, s: Number, e: Number? = null): List<T> {\n val from = _whole(s)\n val to = if (e == null) a.size else _whole(e)\n if (from < 0 || to < 0) throw IllegalArgumentException(\"slice: not a whole number from 0\")\n val end = minOf(to, a.size)\n return if (from >= end) listOf() else a.subList(from, end).toList()\n}"], "array/take": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/drop": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/takeLast": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/dropLast": ["private fun _whole(n: Number): Int {\n val d = n.toDouble()\n if (d != Math.floor(d) || d.isInfinite() || d < -2147483648.0 || d > 2147483647.0) throw IllegalArgumentException(\"expected a whole number, got \" + d)\n return d.toInt()\n}", "private fun _count(n: Number): Int {\n val k = _whole(n)\n if (k < 0) throw IllegalArgumentException(\"expected a whole number from 0, got \" + k)\n return k\n}"], "array/append": ["private fun <T> _append(a: List<T>, x: T): List<T> = a + listOf(x)"], "array/prepend": ["private fun <T> _prepend(a: List<T>, x: T): List<T> = listOf(x) + a"], "array/indexOf": ["private fun <T> _indexOf(a: List<T>, x: T): Double = a.indexOf(x).toDouble()"], "array/sort": ["private fun <T : Comparable<T>> _sort(a: List<T>): List<T> = a.sorted()"], "math/round": ["private fun _round(x: Number, d: Number = 0.0): Double {\n val m = Math.pow(10.0, d.toDouble())\n return Math.copySign(Math.floor(Math.abs(x.toDouble()) * m + 0.5) / m, x.toDouble())\n}"], "math/sqrt": ["private fun _sqrt(x: Number): Double? = if (x.toDouble() < 0.0) null else Math.sqrt(x.toDouble())"], "math/ln": ["private fun _ln(x: Number): Double? = if (x.toDouble() <= 0.0) null else Math.log(x.toDouble())"], "math/log10": ["private fun _log10(x: Number): Double? = if (x.toDouble() <= 0.0) null else Math.log10(x.toDouble())"], "math/pow": ["private fun _pow(a: Number, b: Number): Double? {\n val r = Math.pow(a.toDouble(), b.toDouble())\n return if (r.isNaN() || r.isInfinite()) null else r\n}"], "validate/required": ["private fun _required(v: Any?): Boolean = v != null && v != \"\""], "validate/length": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "validate/minLength": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "validate/maxLength": ["private fun _strLen(s: String): Int = s.codePointCount(0, s.length)"], "validate/equals": ["private fun _eq(a: Any?, b: Any?): Boolean = if (a is Number && b is Number) a.toDouble() == b.toDouble() else a == b"], "array/sum": ["private fun _sum(a: List<Number>): Double = a.sumOf { it.toDouble() }"], "unsupported": ["private fun _unsupported(name: String): Nothing = throw UnsupportedOperationException(\"no native template for operator \" + name)"] }
|
|
32
32
|
helperGap: "\n\n"
|
|
33
33
|
portEffects: ["persist", "fetch", "fetch-stream", "notify", "navigate", "navigate-back", "call-service", "cancel-call", "send-server", "spawn", "despawn", "log"]
|
|
34
34
|
portCall: "ports?.invoke(\"{{name}}\", listOf({{*}}))"
|
|
@@ -51,6 +51,24 @@ orbital LoloKotlinOrbital {
|
|
|
51
51
|
setStyle: "copy"
|
|
52
52
|
fieldCase: "split-camel"
|
|
53
53
|
voidPayload: "Unit"
|
|
54
|
+
programOpen: ["class Program({{entities}}{{store}}) : _Router() {", "{{i}}init {"]
|
|
55
|
+
programEntity: "e{{n}}: {{entity}}"
|
|
56
|
+
programEntitySep: ", "
|
|
57
|
+
programTrait: "{{i}}{{i}}val t{{n}} = {{class}}(e{{n}}); add({{key}}, t{{n}}, { t{{n}}.state }, { _json(t{{n}}.entity) }, { t{{n}}.emitted.size }, { n -> t{{n}}.emitted.drop(n).map { Triple(it.event, _json(it.payload), false) } })"
|
|
58
|
+
programHandles: "{{i}}{{i}}handles[{{key}}] = {{table}}"
|
|
59
|
+
programRow: "{{i}}{{i}}row({{source}}, {{event}}, {{target}}, {{trigger}}, {{guard}}, {{map}})"
|
|
60
|
+
deliverOpen: ["{{i}}}", "", "{{i}}override fun deliver(target: String, event: String, payload: kotlinx.serialization.json.JsonElement) {"]
|
|
61
|
+
deliverCase: "{{i}}{{i}}if (target == {{target}} && event == {{event}}) { (trait(target) as? {{class}})?.{{method}}({{arg}}); return }"
|
|
62
|
+
deliverCasePlain: "{{i}}{{i}}if (target == {{target}} && event == {{event}}) { (trait(target) as? {{class}})?.{{method}}(); return }"
|
|
63
|
+
deliverClose: ["{{i}}}"]
|
|
64
|
+
programClose: ["}"]
|
|
65
|
+
payloadDecode: "_decode<{{type}}>({{value}})"
|
|
66
|
+
guardForm: ["", "private fun {{name}}(payload_json: kotlinx.serialization.json.JsonElement): Boolean {", "{{i}}val payload = {{decode}}", "{{i}}return {{expr}}", "}"]
|
|
67
|
+
mapForm: ["", "private fun {{name}}(payload_json: kotlinx.serialization.json.JsonElement): kotlinx.serialization.json.JsonElement {", "{{i}}val payload = {{decode}}", "{{i}}return _json({{expr}})", "}"]
|
|
68
|
+
guardName: "_guard{{n}}"
|
|
69
|
+
mapName: "_map{{n}}"
|
|
70
|
+
guardRef: "::{{name}}"
|
|
71
|
+
mapRef: "::{{name}}"
|
|
54
72
|
recordForm: "{{type}}({{fields}})"
|
|
55
73
|
recordField: "{{name}} = {{value}}"
|
|
56
74
|
unionArmForm: "{{union}}.{{union}}{{arm}}({{inner}})"
|
|
@@ -59,9 +77,14 @@ orbital LoloKotlinOrbital {
|
|
|
59
77
|
methodCase: "pascal"
|
|
60
78
|
classOpen: "class {{class}}("
|
|
61
79
|
classEmpty: ""
|
|
62
|
-
constructor: ["{{i}}var entity: {{entity}},", "{{i}}val ports: ((String, List<Any?>) -> Unit)? = null,", "{{i}}val config: {{configType}} = {{configType}}(),", ") {", "{{i}}var state: String = {{initial}}", "{{i}}val emitted = mutableListOf<Emitted>()", "", "{{i}}data class Emitted(val event: String, val payload: Any)"]
|
|
80
|
+
constructor: ["{{i}}var entity: {{entity}},", "{{i}}val ports: ((String, List<Any?>) -> Unit)? = null,", "{{i}}val config: {{configType}} = {{configType}}(),", ") {", "{{i}}var state: String = {{initial}}", "{{i}}val emitted = mutableListOf<Emitted>()", "{{withStore}}{{i}}var store: Store? = null", "{{withStore}}{{i}}val completed = mutableSetOf<Int>()", "", "{{i}}data class Emitted(val event: String, val payload: Any)"]
|
|
63
81
|
configType: "{{trait}}Config"
|
|
64
82
|
emitMethod: ["{{i}}fun emit(event: String, payload: Any) {", "{{i}}{{i}}emitted.add(Emitted(event, payload))", "{{i}}}"]
|
|
83
|
+
completeMethod: ["", "{{i}}fun complete(answer: Answer, success: String?, failure: String?) {", "{{i}}{{i}}val route = (if (answer.ok) success else failure) ?: return", "{{i}}{{i}}completed.add(emitted.size)", "{{i}}{{i}}emitted.add(Emitted(route, answer.payload))", "{{i}}}", "", "{{i}}fun useStore(): Store = store ?: error(\"no store\")"]
|
|
84
|
+
routedEffects: {"persist": "complete(useStore().persist({{0}}, {{1}}, {{2}}), {{success}}, {{failure}})", "fetch": "complete(useStore().fetch({{entity}}, {{filter}}), {{success}}, {{failure}})"}
|
|
85
|
+
fetchAll: "null"
|
|
86
|
+
programStoreParam: ", store: Store"
|
|
87
|
+
programTraitStore: "{{i}}{{i}}val t{{n}} = {{class}}(e{{n}}); t{{n}}.store = store; add({{key}}, t{{n}}, { t{{n}}.state }, { _json(t{{n}}.entity) }, { t{{n}}.emitted.size }, { n -> t{{n}}.emitted.drop(n).mapIndexed { j, it -> Triple(it.event, _json(it.payload), (n + j) in t{{n}}.completed) } })"
|
|
65
88
|
entityNames: { "Any": "AnyEntity", "Array": "ArrayEntity", "Boolean": "BooleanEntity", "Box": "BoxEntity", "Button": "ButtonEntity", "Card": "CardEntity", "Char": "CharEntity", "Color": "ColorEntity", "Column": "ColumnEntity", "Double": "DoubleEntity", "Enum": "EnumEntity", "Exception": "ExceptionEntity", "Float": "FloatEntity", "Image": "ImageEntity", "Int": "IntEntity", "List": "ListEntity", "Long": "LongEntity", "Map": "MapEntity", "Modifier": "ModifierEntity", "Nothing": "NothingEntity", "Number": "NumberEntity", "Pair": "PairEntity", "Result": "ResultEntity", "Row": "RowEntity", "Set": "SetEntity", "Short": "ShortEntity", "State": "StateEntity", "String": "StringEntity", "Surface": "SurfaceEntity", "Text": "TextEntity", "Throwable": "ThrowableEntity", "Triple": "TripleEntity", "Unit": "UnitEntity" }
|
|
66
89
|
typeMap: { }
|
|
67
90
|
indent: " "
|
|
@@ -31,9 +31,9 @@ orbital LoloPythonOrbital {
|
|
|
31
31
|
calleeForm: "{{callee}}({{*}})"
|
|
32
32
|
unsupportedForm: "_unsupported({{op}})"
|
|
33
33
|
unsupportedWarn: "no {{language}} template for operator {{op}}"
|
|
34
|
-
helpers: { "/": ["def _div(a, b): return None if b == 0 else a / b"], "%": ["def _mod(a, b): return None if b == 0 else math.fmod(a, b)"], "math/mod": ["def _mod(a, b): return None if b == 0 else math.fmod(a, b)"], "default": ["def _default(v, d): return d if v is None else v"], "str/split": ["def _split(s, d): return list(s) if d == '' else s.split(d)"], "str/join": ["def _join(a, d): return d.join(_text(v) for v in a)", "def _text(v):\n if isinstance(v, bool): return 'true' if v else 'false'\n if isinstance(v, float) and v - v == 0 and v == int(v): return str(int(v))\n if isinstance(v, (int, float, str)): return str(v)\n raise TypeError('expected string, number or boolean')"], "str/concat": ["def _text(v):\n if isinstance(v, bool): return 'true' if v else 'false'\n if isinstance(v, float) and v - v == 0 and v == int(v): return str(int(v))\n if isinstance(v, (int, float, str)): return str(v)\n raise TypeError('expected string, number or boolean')"], "str/slice": ["def _str_slice(s, a, b=None):\n if a != int(a) or (b is not None and b != int(b)): raise ValueError('slice: not a whole number')\n return s[int(a):None if b is None else int(b)]"], "str/padStart": ["def _pad_start(s, n, p=' '):\n if len(p) != 1: raise ValueError('expected a single padding character')\n return s.rjust(int(n), p)"], "str/padEnd": ["def _pad_end(s, n, p=' '):\n if len(p) != 1: raise ValueError('expected a single padding character')\n return s.ljust(int(n), p)"], "str/truncate": ["def _truncate(s, n, suffix='...'): return s if len(s) <= n else s[:int(n)] + suffix"], "str/to-int": ["def _to_int(s):\n t = s[1:] if s[:1] in ('+', '-') else s\n return int(s) if t.isascii() and t.isdigit() and -2 ** 63 <= int(s) < 2 ** 63 else None"], "array/sum": ["def _sum(a, k=None): return sum(a) if k is None else sum(x[k] for x in a)"], "array/avg": ["def _avg(a, k=None):\n v = a if k is None else [x[k] for x in a]\n return sum(v) / len(v) if v else None"], "array/max": ["def _amax(a, k=None):\n v = a if k is None else [x[k] for x in a]\n return max(v) if v else None"], "array/min": ["def _amin(a, k=None):\n v = a if k is None else [x[k] for x in a]\n return min(v) if v else None"], "array/first": ["def _first(a): return a[0] if a else None"], "array/last": ["def _last(a): return a[-1] if a else None"], "array/nth": ["def _nth(a, i):\n if i != int(i) or i < 0: raise ValueError('nth: index is not a whole number from 0')\n return a[int(i)] if i < len(a) else None"], "array/range": ["def _range(a, b=None, step=1):\n start, end = (0, a) if b is None else (a, b)\n if step == 0: raise ValueError('range: step 0 must be a non-zero finite number')\n out = []\n x = start\n while (x < end) if step > 0 else (x > end):\n out.append(x)\n x += step\n return out"], "array/slice": ["def _slice(a, s, e=None):\n if s != int(s) or s < 0 or (e is not None and (e != int(e) or e < 0)): raise ValueError('slice: not a whole number from 0')\n return a[int(s):None if e is None else int(e)]"], "array/take": ["def _take(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[:int(n)]"], "array/drop": ["def _drop(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[int(n):]"], "array/takeLast": ["def _take_last(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[len(a) - int(n):] if n < len(a) else a[:]"], "array/dropLast": ["def _drop_last(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[:len(a) - int(n)] if n < len(a) else []"], "array/indexOf": ["def _index_of(a, x): return a.index(x) if x in a else -1"], "array/unique": ["def _unique(a):\n out = []\n for x in a:\n if x not in out: out.append(x)\n return out"], "array/sort": ["def _sort(a, k=None, o='asc'): return sorted(a, key=None if k is None else (lambda x: x[k]), reverse=(o == 'desc'))"], "object/get": ["def _get(o, p, d=None):\n for s in p.replace(chr(92) + '.', chr(0)).split('.'):\n s = s.replace(chr(0), '.')\n if isinstance(o, dict) and s in o: o = o[s]\n elif isinstance(o, list) and s.isdigit() and int(s) < len(o): o = o[int(s)]\n else: return d\n return o"], "object/has": ["def _has(o, p):\n for s in p.replace(chr(92) + '.', chr(0)).split('.'):\n s = s.replace(chr(0), '.')\n if isinstance(o, dict) and s in o: o = o[s]\n elif isinstance(o, list) and s.isdigit() and int(s) < len(o): o = o[int(s)]\n else: return False\n return True"], "object/set": ["def _set(o, p, v):\n out = dict(o)\n cur = out\n parts = [s.replace(chr(0), '.') for s in p.replace(chr(92) + '.', chr(0)).split('.')]\n for s in parts[:-1]:\n cur[s] = dict(cur[s]) if isinstance(cur.get(s), dict) else {}\n cur = cur[s]\n cur[parts[-1]] = v\n return out"], "object/pick": ["def _pick(o, ks): return {k: o[k] for k in ks if k in o}"], "object/omit": ["def _omit(o, ks): return {k: v for k, v in o.items() if k not in ks}"], "json/parse": ["def _json_parse(t):\n try: return json.loads(t)\n except ValueError: return None"], "json/stringify": ["def _json_dumps(v):\n def n(x):\n if isinstance(x, float) and x - x == 0 and x == int(x): return int(x)\n if isinstance(x, list): return [n(y) for y in x]\n if isinstance(x, dict): return {k: n(y) for k, y in x.items()}\n return x\n return json.dumps(n(v), separators=(',', ':'), ensure_ascii=False)"], "math/round": ["def _round(x, d=0):\n m = 10 ** d\n return math.copysign(math.floor(abs(x) * m + 0.5) / m, x)"], "math/sqrt": ["def _sqrt(x): return None if x < 0 else math.sqrt(x)"], "math/ln": ["def _ln(x): return None if x <= 0 else math.log(x)"], "math/log10": ["def _log10(x): return None if x <= 0 else math.log10(x)"], "math/pow": ["def _pow(a, b):\n try: return math.pow(a, b)\n except (ValueError, OverflowError, ZeroDivisionError): return None"], "math/sign": ["def _sign(x): return (x > 0) - (x < 0)"], "math/clamp": ["def _clamp(v, lo, hi): return min(max(v, lo), hi)"], "validate/required": ["def _required(v): return v is not None and v != ''"], "validate/number": ["def _is_number(v): return isinstance(v, (int, float)) and not isinstance(v, bool)"], "unsupported": ["def _unsupported(name): raise NotImplementedError('no native template for operator ' + name)"] }
|
|
34
|
+
helpers: { "store": ["class MemoryStore:\n def __init__(self):\n self.tables = {}\n self.minted = 0\n\n def persist(self, op, entity, data):\n rows = self.tables.setdefault(entity, {})\n if op == \"create\":\n row = dict(_plain(data))\n if not row.get(\"id\"):\n self.minted += 1\n row[\"id\"] = entity + \"-\" + str(self.minted)\n rows[row[\"id\"]] = row\n return True, dict(row)\n key = data if isinstance(data, str) else _plain(data).get(\"id\")\n if key not in rows:\n return False, {\"error\": entity + \" \" + str(key) + \" not found\", \"code\": \"not-found\"}\n if op == \"delete\":\n del rows[key]\n return True, {\"id\": key, \"deleted\": True}\n rows[key].update(_plain(data))\n return True, dict(rows[key])\n\n def fetch(self, entity, keep):\n rows = [dict(r) for r in self.tables.get(entity, {}).values() if keep is None or keep(dict(r))]\n rows.sort(key=lambda r: (0, r[\"createdAt\"], r[\"id\"]) if \"createdAt\" in r else (1, 0, r[\"id\"]))\n return True, {\"data\": rows, \"totalCount\": len(rows)}"], "router": ["def _plain(v):\n if dataclasses.is_dataclass(v):\n return dataclasses.asdict(v)\n return {} if v is None else v", "def _decode(cls, payload):\n names = {f.name for f in dataclasses.fields(cls)}\n return cls(**{k: v for k, v in (payload or {}).items() if k in names})", "class _Router:\n def __init__(self):\n self.traits = {}\n self.handles = {}\n self.rows = []\n self.log = []\n\n def add(self, key, trait):\n self.traits[key] = trait\n\n def row(self, source, event, target, trigger, guard, mapping):\n self.rows.append((source, event, target, trigger, guard, mapping))\n\n def targets(self, source, event, payload, completion):\n return [{\"trait\": target, \"event\": trigger, \"payload\": mapping(payload) if mapping else payload, \"source\": payload,\n \"guard\": guard, \"fans\": False, \"completion\": completion}\n for (s, e, target, trigger, guard, mapping) in self.rows if s == source and e == event]\n\n def dispatch(self, trait, event, payload):\n queue = deque([{\"trait\": trait, \"event\": event, \"payload\": payload, \"source\": payload, \"guard\": None, \"fans\": True, \"completion\": False}])\n seen = set()\n steps = 0\n while queue:\n item = queue.popleft()\n t = self.traits[item[\"trait\"]]\n key = json.dumps([item[\"trait\"], item[\"event\"], t.state, item[\"payload\"], _plain(t.entity)], sort_keys=True, default=str)\n if not item[\"completion\"] and key in seen:\n continue\n if item[\"guard\"] is not None and not item[\"guard\"](item[\"source\"]):\n continue\n if steps >= 2000:\n break\n steps += 1\n seen.add(key)\n n = len(t.emitted)\n self.deliver(item[\"trait\"], item[\"event\"], item[\"payload\"])\n own, fanned = [], []\n if item[\"fans\"]:\n fanned += self.targets(item[\"trait\"], item[\"event\"], item[\"payload\"], False)\n for emitted in t.emitted[n:]:\n ev, out = emitted[0], _plain(emitted[1])\n completion = len(emitted) > 2 and emitted[2]\n self.log.append((item[\"trait\"], ev, out))\n if ev in self.handles[item[\"trait\"]].get(t.state, ()):\n own.append({\"trait\": item[\"trait\"], \"event\": ev, \"payload\": out, \"source\": out, \"guard\": None, \"fans\": False, \"completion\": completion})\n fanned += self.targets(item[\"trait\"], ev, out, completion)\n queue.extendleft(reversed(own))\n queue.extend(fanned)"], "/": ["def _div(a, b): return None if b == 0 else a / b"], "%": ["def _mod(a, b): return None if b == 0 else math.fmod(a, b)"], "math/mod": ["def _mod(a, b): return None if b == 0 else math.fmod(a, b)"], "default": ["def _default(v, d): return d if v is None else v"], "str/split": ["def _split(s, d): return list(s) if d == '' else s.split(d)"], "str/join": ["def _join(a, d): return d.join(_text(v) for v in a)", "def _text(v):\n if isinstance(v, bool): return 'true' if v else 'false'\n if isinstance(v, float) and v - v == 0 and v == int(v): return str(int(v))\n if isinstance(v, (int, float, str)): return str(v)\n raise TypeError('expected string, number or boolean')"], "str/concat": ["def _text(v):\n if isinstance(v, bool): return 'true' if v else 'false'\n if isinstance(v, float) and v - v == 0 and v == int(v): return str(int(v))\n if isinstance(v, (int, float, str)): return str(v)\n raise TypeError('expected string, number or boolean')"], "str/slice": ["def _str_slice(s, a, b=None):\n if a != int(a) or (b is not None and b != int(b)): raise ValueError('slice: not a whole number')\n return s[int(a):None if b is None else int(b)]"], "str/padStart": ["def _pad_start(s, n, p=' '):\n if len(p) != 1: raise ValueError('expected a single padding character')\n return s.rjust(int(n), p)"], "str/padEnd": ["def _pad_end(s, n, p=' '):\n if len(p) != 1: raise ValueError('expected a single padding character')\n return s.ljust(int(n), p)"], "str/truncate": ["def _truncate(s, n, suffix='...'): return s if len(s) <= n else s[:int(n)] + suffix"], "str/to-int": ["def _to_int(s):\n t = s[1:] if s[:1] in ('+', '-') else s\n return int(s) if t.isascii() and t.isdigit() and -2 ** 63 <= int(s) < 2 ** 63 else None"], "array/sum": ["def _sum(a, k=None): return sum(a) if k is None else sum(x[k] for x in a)"], "array/avg": ["def _avg(a, k=None):\n v = a if k is None else [x[k] for x in a]\n return sum(v) / len(v) if v else None"], "array/max": ["def _amax(a, k=None):\n v = a if k is None else [x[k] for x in a]\n return max(v) if v else None"], "array/min": ["def _amin(a, k=None):\n v = a if k is None else [x[k] for x in a]\n return min(v) if v else None"], "array/first": ["def _first(a): return a[0] if a else None"], "array/last": ["def _last(a): return a[-1] if a else None"], "array/nth": ["def _nth(a, i):\n if i != int(i) or i < 0: raise ValueError('nth: index is not a whole number from 0')\n return a[int(i)] if i < len(a) else None"], "array/range": ["def _range(a, b=None, step=1):\n start, end = (0, a) if b is None else (a, b)\n if step == 0: raise ValueError('range: step 0 must be a non-zero finite number')\n out = []\n x = start\n while (x < end) if step > 0 else (x > end):\n out.append(x)\n x += step\n return out"], "array/slice": ["def _slice(a, s, e=None):\n if s != int(s) or s < 0 or (e is not None and (e != int(e) or e < 0)): raise ValueError('slice: not a whole number from 0')\n return a[int(s):None if e is None else int(e)]"], "array/take": ["def _take(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[:int(n)]"], "array/drop": ["def _drop(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[int(n):]"], "array/takeLast": ["def _take_last(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[len(a) - int(n):] if n < len(a) else a[:]"], "array/dropLast": ["def _drop_last(a, n):\n if n != int(n) or n < 0: raise ValueError('count is not a whole number from 0')\n return a[:len(a) - int(n)] if n < len(a) else []"], "array/indexOf": ["def _index_of(a, x): return a.index(x) if x in a else -1"], "array/unique": ["def _unique(a):\n out = []\n for x in a:\n if x not in out: out.append(x)\n return out"], "array/sort": ["def _sort(a, k=None, o='asc'): return sorted(a, key=None if k is None else (lambda x: x[k]), reverse=(o == 'desc'))"], "object/get": ["def _get(o, p, d=None):\n for s in p.replace(chr(92) + '.', chr(0)).split('.'):\n s = s.replace(chr(0), '.')\n if isinstance(o, dict) and s in o: o = o[s]\n elif isinstance(o, list) and s.isdigit() and int(s) < len(o): o = o[int(s)]\n else: return d\n return o"], "object/has": ["def _has(o, p):\n for s in p.replace(chr(92) + '.', chr(0)).split('.'):\n s = s.replace(chr(0), '.')\n if isinstance(o, dict) and s in o: o = o[s]\n elif isinstance(o, list) and s.isdigit() and int(s) < len(o): o = o[int(s)]\n else: return False\n return True"], "object/set": ["def _set(o, p, v):\n out = dict(o)\n cur = out\n parts = [s.replace(chr(0), '.') for s in p.replace(chr(92) + '.', chr(0)).split('.')]\n for s in parts[:-1]:\n cur[s] = dict(cur[s]) if isinstance(cur.get(s), dict) else {}\n cur = cur[s]\n cur[parts[-1]] = v\n return out"], "object/pick": ["def _pick(o, ks): return {k: o[k] for k in ks if k in o}"], "object/omit": ["def _omit(o, ks): return {k: v for k, v in o.items() if k not in ks}"], "json/parse": ["def _json_parse(t):\n try: return json.loads(t)\n except ValueError: return None"], "json/stringify": ["def _json_dumps(v):\n def n(x):\n if isinstance(x, float) and x - x == 0 and x == int(x): return int(x)\n if isinstance(x, list): return [n(y) for y in x]\n if isinstance(x, dict): return {k: n(y) for k, y in x.items()}\n return x\n return json.dumps(n(v), separators=(',', ':'), ensure_ascii=False)"], "math/round": ["def _round(x, d=0):\n m = 10 ** d\n return math.copysign(math.floor(abs(x) * m + 0.5) / m, x)"], "math/sqrt": ["def _sqrt(x): return None if x < 0 else math.sqrt(x)"], "math/ln": ["def _ln(x): return None if x <= 0 else math.log(x)"], "math/log10": ["def _log10(x): return None if x <= 0 else math.log10(x)"], "math/pow": ["def _pow(a, b):\n try: return math.pow(a, b)\n except (ValueError, OverflowError, ZeroDivisionError): return None"], "math/sign": ["def _sign(x): return (x > 0) - (x < 0)"], "math/clamp": ["def _clamp(v, lo, hi): return min(max(v, lo), hi)"], "validate/required": ["def _required(v): return v is not None and v != ''"], "validate/number": ["def _is_number(v): return isinstance(v, (int, float)) and not isinstance(v, bool)"], "unsupported": ["def _unsupported(name): raise NotImplementedError('no native template for operator ' + name)"] }
|
|
35
35
|
helperGap: "\n"
|
|
36
|
-
imports: { "Literal": "from typing import Literal", "Any": "from typing import Any", "field": "from dataclasses import field", "dataclass": "from dataclasses import dataclass", "%": "import math", "math/mod": "import math", "math/ceil": "import math", "math/floor": "import math", "math/sin": "import math", "math/cos": "import math", "math/tan": "import math", "math/atan": "import math", "math/atan2": "import math", "math/hypot": "import math", "math/round": "import math", "math/sqrt": "import math", "math/ln": "import math", "math/log10": "import math", "math/pow": "import math", "array/reduce": "import functools", "json/parse": "import json", "json/stringify": "import json" }
|
|
36
|
+
imports: { "router": "from collections import deque\nimport dataclasses\nimport json", "Literal": "from typing import Literal", "Any": "from typing import Any", "field": "from dataclasses import field", "dataclass": "from dataclasses import dataclass", "%": "import math", "math/mod": "import math", "math/ceil": "import math", "math/floor": "import math", "math/sin": "import math", "math/cos": "import math", "math/tan": "import math", "math/atan": "import math", "math/atan2": "import math", "math/hypot": "import math", "math/round": "import math", "math/sqrt": "import math", "math/ln": "import math", "math/log10": "import math", "math/pow": "import math", "array/reduce": "import functools", "json/parse": "import json", "json/stringify": "import json" }
|
|
37
37
|
portEffects: ["persist", "fetch", "fetch-stream", "notify", "navigate", "navigate-back", "call-service", "cancel-call", "send-server", "spawn", "despawn", "log"]
|
|
38
38
|
portCall: "self.ports.{{name}}({{*}})"
|
|
39
39
|
portCase: "lower"
|
|
@@ -77,6 +77,16 @@ orbital LoloPythonOrbital {
|
|
|
77
77
|
localCase: "keep"
|
|
78
78
|
methodCase: "lower"
|
|
79
79
|
methodName: "on_{{event}}"
|
|
80
|
+
programOpen: ["class Program(_Router):", "{{i}}def __init__(self, entities, ports=None):", "{{i}}{{i}}super().__init__()"]
|
|
81
|
+
programTrait: "{{i}}{{i}}self.add({{key}}, {{class}}(entities[{{key}}], ports))"
|
|
82
|
+
programHandles: "{{i}}{{i}}self.handles[{{key}}] = {{table}}"
|
|
83
|
+
programRow: "{{i}}{{i}}self.row({{source}}, {{event}}, {{target}}, {{trigger}}, {{guard}}, {{map}})"
|
|
84
|
+
deliverOpen: ["", "{{i}}def deliver(self, target, event, payload):"]
|
|
85
|
+
deliverCase: "{{i}}{{i}}if target == {{target}} and event == {{event}}:\n{{i}}{{i}}{{i}}return self.traits[target].{{method}}({{arg}})"
|
|
86
|
+
deliverCasePlain: "{{i}}{{i}}if target == {{target}} and event == {{event}}:\n{{i}}{{i}}{{i}}return self.traits[target].{{method}}()"
|
|
87
|
+
payloadDecode: "_decode({{type}}, {{value}})"
|
|
88
|
+
guardForm: ["", "", "def {{name}}(payload_json):", "{{i}}payload = {{decode}}", "{{i}}return {{expr}}"]
|
|
89
|
+
mapForm: ["", "", "def {{name}}(payload_json):", "{{i}}payload = {{decode}}", "{{i}}return {{expr}}"]
|
|
80
90
|
modelImports: { "entity": "from orbital_app.generated.entities import {{names}}", "payload": "from orbital_app.generated.events import {{names}}" }
|
|
81
91
|
modelImportEach: false
|
|
82
92
|
modelImportSep: ", "
|
|
@@ -86,6 +96,9 @@ orbital LoloPythonOrbital {
|
|
|
86
96
|
classEmpty: "{{i}}pass"
|
|
87
97
|
constructor: ["{{i}}def __init__(self, entity: {{entity}}, ports=None, config: {{configType}} | None = None):", "{{noConfig}}{{i}}def __init__(self, entity: {{entity}}, ports=None):", "{{i}}{{i}}self.state = {{initial}}", "{{i}}{{i}}self.entity = entity", "{{i}}{{i}}self.ports = ports", "{{i}}{{i}}self.config = config if config is not None else {{configType}}()", "{{i}}{{i}}self.emitted: list[tuple[str, object]] = []"]
|
|
88
98
|
emitMethod: ["{{i}}def emit(self, event, payload):", "{{i}}{{i}}self.emitted.append((event, payload))"]
|
|
99
|
+
completeMethod: ["", "{{i}}def complete(self, answer, success, failure):", "{{i}}{{i}}ok, payload = answer", "{{i}}{{i}}route = success if ok else failure", "{{i}}{{i}}if route is not None:", "{{i}}{{i}}{{i}}self.emitted.append((route, payload, True))"]
|
|
100
|
+
routedEffects: {"persist": "self.complete(self.ports.persist({{args}}), {{success}}, {{failure}})", "fetch": "self.complete(self.ports.fetch({{entity}}, {{filter}}), {{success}}, {{failure}})"}
|
|
101
|
+
fetchAll: "None"
|
|
89
102
|
methodOpen: "{{i}}def {{method}}(self, payload: {{payloadType}}) -> None:"
|
|
90
103
|
methodOpenPlain: "{{i}}def {{method}}(self, payload=None) -> None:"
|
|
91
104
|
methodClose: ""
|
|
@@ -29,7 +29,7 @@ orbital LoloRustOrbital {
|
|
|
29
29
|
indexedVars: "({{index}}, {{item}})"
|
|
30
30
|
unsupportedForm: "_unsupported(&{{op}})"
|
|
31
31
|
unsupportedWarn: "no {{language}} template for operator {{op}}"
|
|
32
|
-
helpers: { "/": ["fn _div(a: f64, b: f64) -> Option<f64> { if b == 0.0 { None } else { Some(a / b) } }"], "%": ["fn _mod(a: f64, b: f64) -> Option<f64> { if b == 0.0 { None } else { Some(a % b) } }"], "math/mod": ["fn _mod(a: f64, b: f64) -> Option<f64> { if b == 0.0 { None } else { Some(a % b) } }"], "default": ["trait _OrDefault<T> { fn _or_default(self, d: T) -> T; }\nimpl<T> _OrDefault<T> for Option<T> { fn _or_default(self, d: T) -> T { self.unwrap_or(d) } }\nimpl<T> _OrDefault<T> for T { fn _or_default(self, _d: T) -> T { self } }\nfn _default<T, V: _OrDefault<T>>(v: V, d: T) -> T { v._or_default(d) }"], "str/concat": ["fn _num_text(x: f64) -> String {\n if x.is_nan() { return \"NaN\".to_string(); }\n if x.is_infinite() { return (if x > 0.0 { \"Infinity\" } else { \"-Infinity\" }).to_string(); }\n if x == 0.0 { return \"0\".to_string(); }\n let a = x.abs();\n if a >= 1e21 || a < 1e-6 {\n let s = format!(\"{:e}\", x);\n return match s.split_once('e') {\n Some((m, e)) => if e.starts_with('-') { format!(\"{}e{}\", m, e) } else { format!(\"{}e+{}\", m, e) },\n None => s,\n };\n }\n format!(\"{}\", x)\n}", "trait _Text { fn _text(&self) -> String; }\nimpl _Text for String { fn _text(&self) -> String { self.clone() } }\nimpl _Text for bool { fn _text(&self) -> String { (if *self { \"true\" } else { \"false\" }).to_string() } }\nimpl _Text for f64 { fn _text(&self) -> String { _num_text(*self) } }", "macro_rules! _concat {\n ($($x:expr),+ $(,)?) => {{\n let mut s_ = String::new();\n $( s_.push_str(&_Text::_text(&$x)); )+\n s_\n }};\n}"], "str/join": ["fn _num_text(x: f64) -> String {\n if x.is_nan() { return \"NaN\".to_string(); }\n if x.is_infinite() { return (if x > 0.0 { \"Infinity\" } else { \"-Infinity\" }).to_string(); }\n if x == 0.0 { return \"0\".to_string(); }\n let a = x.abs();\n if a >= 1e21 || a < 1e-6 {\n let s = format!(\"{:e}\", x);\n return match s.split_once('e') {\n Some((m, e)) => if e.starts_with('-') { format!(\"{}e{}\", m, e) } else { format!(\"{}e+{}\", m, e) },\n None => s,\n };\n }\n format!(\"{}\", x)\n}", "trait _Text { fn _text(&self) -> String; }\nimpl _Text for String { fn _text(&self) -> String { self.clone() } }\nimpl _Text for bool { fn _text(&self) -> String { (if *self { \"true\" } else { \"false\" }).to_string() } }\nimpl _Text for f64 { fn _text(&self) -> String { _num_text(*self) } }", "fn _join<T: _Text>(a: &[T], d: &str) -> String { a.iter().map(|x| x._text()).collect::<Vec<_>>().join(d) }"], "str/split": ["fn _split(s: &str, d: &str) -> Vec<String> {\n if d.is_empty() { s.chars().map(|c| c.to_string()).collect() } else { s.split(d).map(|p| p.to_string()).collect() }\n}"], "str/slice": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _str_slice(s: &str, a: f64, b: Option<f64>) -> String {\n let c: Vec<char> = s.chars().collect();\n let n = c.len() as i64;\n let norm = |i: i64| -> i64 { if i < 0 { (n + i).max(0) } else { i.min(n) } };\n let st = norm(_whole(a));\n let en = match b { Some(v) => norm(_whole(v)), None => n };\n if en <= st { String::new() } else { c[st as usize..en as usize].iter().collect() }\n}"], "str/padStart": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _pad_start(s: &str, n: f64, p: &str) -> String {\n if p.chars().count() != 1 { panic!(\"expected a single padding character, got {:?}\", p); }\n let w = _whole(n);\n let len = s.chars().count() as i64;\n if w <= len { return s.to_string(); }\n let pad: String = std::iter::repeat(p).take((w - len) as usize).collect();\n format!(\"{}{}\", pad, s)\n}"], "str/padEnd": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _pad_end(s: &str, n: f64, p: &str) -> String {\n if p.chars().count() != 1 { panic!(\"expected a single padding character, got {:?}\", p); }\n let w = _whole(n);\n let len = s.chars().count() as i64;\n if w <= len { return s.to_string(); }\n let pad: String = std::iter::repeat(p).take((w - len) as usize).collect();\n format!(\"{}{}\", s, pad)\n}"], "str/truncate": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _truncate(s: &str, n: f64, suffix: &str) -> String {\n let w = _whole(n);\n if (s.chars().count() as i64) <= w { return s.to_string(); }\n let head: String = s.chars().take(w.max(0) as usize).collect();\n format!(\"{}{}\", head, suffix)\n}"], "str/repeat": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _repeat(s: &str, n: f64) -> String { s.repeat(_count(n)) }"], "str/capitalize": ["fn _capitalize(s: &str) -> String {\n let mut c = s.chars();\n match c.next() {\n Some(f) => f.to_uppercase().collect::<String>() + &c.as_str().to_lowercase(),\n None => String::new(),\n }\n}"], "str/to-int": ["fn _to_int(s: &str) -> Option<f64> { s.parse::<i64>().ok().map(|v| v as f64) }"], "array/sum": ["fn _sum(a: &[f64]) -> f64 { a.iter().fold(0.0_f64, |s, x| s + x) }"], "array/avg": ["fn _avg(a: &[f64]) -> Option<f64> { if a.is_empty() { None } else { Some(a.iter().fold(0.0_f64, |s, x| s + x) / a.len() as f64) } }"], "array/max": ["fn _amax(a: &[f64]) -> Option<f64> { a.iter().cloned().fold(None, |m, x| Some(match m { Some(y) => if x > y { x } else { y }, None => x })) }"], "array/min": ["fn _amin(a: &[f64]) -> Option<f64> { a.iter().cloned().fold(None, |m, x| Some(match m { Some(y) => if x < y { x } else { y }, None => x })) }"], "array/first": ["fn _first<T: Clone>(a: &[T]) -> Option<T> { a.first().cloned() }"], "array/last": ["fn _last<T: Clone>(a: &[T]) -> Option<T> { a.last().cloned() }"], "array/nth": ["fn _nth<T: Clone>(a: &[T], i: f64) -> Option<T> {\n if !i.is_finite() || i != i.trunc() || i < 0.0 { panic!(\"nth: index {} is not a whole number from 0\", i); }\n a.get(i as usize).cloned()\n}"], "array/range": ["fn _range(a: f64, b: f64, step: f64) -> Vec<f64> {\n if step == 0.0 || !step.is_finite() { panic!(\"range: step 0 must be a non-zero finite number\"); }\n let mut out = Vec::new();\n let mut x = a;\n while if step > 0.0 { x < b } else { x > b } { out.push(x); x += step; }\n out\n}"], "array/slice": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _slice<T: Clone>(a: &[T], s: f64, e: Option<f64>) -> Vec<T> {\n let st = _whole(s);\n let en = e.map(_whole);\n if st < 0 || en.map_or(false, |v| v < 0) { panic!(\"slice: not a whole number from 0\"); }\n let st = (st as usize).min(a.len());\n let en = en.map_or(a.len(), |v| (v as usize).min(a.len()));\n if en <= st { Vec::new() } else { a[st..en].to_vec() }\n}"], "array/take": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _take<T: Clone>(a: &[T], n: f64) -> Vec<T> { a.iter().take(_count(n)).cloned().collect() }"], "array/drop": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _drop<T: Clone>(a: &[T], n: f64) -> Vec<T> { a.iter().skip(_count(n)).cloned().collect() }"], "array/takeLast": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _take_last<T: Clone>(a: &[T], n: f64) -> Vec<T> { let k = _count(n).min(a.len()); a[a.len() - k..].to_vec() }"], "array/dropLast": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _drop_last<T: Clone>(a: &[T], n: f64) -> Vec<T> { let k = _count(n).min(a.len()); a[..a.len() - k].to_vec() }"], "array/append": ["fn _append<T: Clone>(a: &[T], x: T) -> Vec<T> { let mut v = a.to_vec(); v.push(x); v }"], "array/prepend": ["fn _prepend<T: Clone>(a: &[T], x: T) -> Vec<T> { let mut v = vec![x]; v.extend(a.iter().cloned()); v }"], "array/indexOf": ["fn _index_of<T: PartialEq>(a: &[T], x: &T) -> f64 { a.iter().position(|y| y == x).map_or(-1.0, |i| i as f64) }"], "array/unique": ["fn _unique<T: Clone + PartialEq>(a: &[T]) -> Vec<T> {\n let mut out: Vec<T> = Vec::new();\n for x in a { if !out.contains(x) { out.push(x.clone()); } }\n out\n}"], "array/flatten": ["fn _flatten<T: Clone>(a: &[Vec<T>]) -> Vec<T> { a.iter().flat_map(|v| v.iter().cloned()).collect() }"], "array/zip": ["fn _zip<T: Clone>(a: &[T], b: &[T]) -> Vec<Vec<T>> { a.iter().cloned().zip(b.iter().cloned()).map(|(x, y)| vec![x, y]).collect() }"], "array/concat": ["macro_rules! _vconcat {\n ($($x:expr),+ $(,)?) => {{\n let mut v_ = Vec::new();\n $( v_.extend($x.iter().cloned()); )+\n v_\n }};\n}"], "array/sort": ["fn _sort<T: Clone + PartialOrd>(a: &[T]) -> Vec<T> {\n let mut v = a.to_vec();\n v.sort_by(|x, y| x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal));\n v\n}"], "array/reduce": ["fn _reduce<T: Clone, A>(a: &[T], init: A, f: impl Fn(A, T) -> A) -> A { a.iter().cloned().fold(init, f) }"], "math/round": ["fn _round(x: f64, d: f64) -> f64 {\n let m = 10.0_f64.powf(d);\n let r = (x.abs() * m + 0.5).floor() / m;\n if x < 0.0 { -r } else { r }\n}"], "math/acos": ["fn _acos(x: f64) -> Option<f64> { if (-1.0..=1.0).contains(&x) { Some(x.acos()) } else { None } }"], "math/asin": ["fn _asin(x: f64) -> Option<f64> { if (-1.0..=1.0).contains(&x) { Some(x.asin()) } else { None } }"], "math/approach": ["fn _approach(c: f64, t: f64, d: f64) -> f64 { if (t - c).abs() <= d { t } else { c + (t - c).signum() * d } }"], "math/map": ["fn _map(v: f64, a: f64, b: f64, c: f64, d: f64) -> f64 { if b == a { c } else { c + (v - a) / (b - a) * (d - c) } }"], "math/wrap": ["fn _wrap(v: f64, lo: f64, hi: f64) -> f64 {\n let r = hi - lo;\n if r <= 0.0 { lo } else { ((v - lo) % r + r) % r + lo }\n}"], "array/insert": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _insert<T: Clone>(a: &[T], i: f64, x: T) -> Vec<T> {\n let k = _whole(i);\n if k < 0 || k as usize > a.len() { panic!(\"insert: index {} is not within a {}-item array\", k, a.len()); }\n let mut v = a.to_vec();\n v.insert(k as usize, x);\n v\n}"], "array/remove": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _remove<T: Clone>(a: &[T], i: f64) -> Vec<T> {\n let k = _whole(i);\n if k < 0 || k as usize >= a.len() { panic!(\"remove: index {} is outside a {}-item array\", k, a.len()); }\n let mut v = a.to_vec();\n v.remove(k as usize);\n v\n}"], "array/removeItem": ["fn _remove_item<T: Clone + PartialEq>(a: &[T], x: &T) -> Vec<T> {\n let mut v = a.to_vec();\n if let Some(p) = v.iter().position(|y| y == x) { v.remove(p); }\n v\n}"], "math/sqrt": ["fn _sqrt(x: f64) -> Option<f64> { if x < 0.0 { None } else { Some(x.sqrt()) } }"], "math/ln": ["fn _ln(x: f64) -> Option<f64> { if x <= 0.0 { None } else { Some(x.ln()) } }"], "math/log10": ["fn _log10(x: f64) -> Option<f64> { if x <= 0.0 { None } else { Some(x.log10()) } }"], "math/pow": ["fn _pow(a: f64, b: f64) -> Option<f64> { let r = a.powf(b); if r.is_finite() { Some(r) } else { None } }"], "math/sign": ["fn _sign(x: f64) -> f64 { if x > 0.0 { 1.0 } else if x < 0.0 { -1.0 } else { 0.0 } }"], "object/get": ["fn _get<V: Clone>(m: &std::collections::BTreeMap<String, V>, k: &str) -> Option<V> { m.get(k).cloned() }"], "object/merge": ["fn _merge<V: Clone>(a: &std::collections::BTreeMap<String, V>, b: &std::collections::BTreeMap<String, V>) -> std::collections::BTreeMap<String, V> {\n let mut m = a.clone();\n for (k, v) in b { m.insert(k.clone(), v.clone()); }\n m\n}"], "object/pick": ["fn _pick<V: Clone>(m: &std::collections::BTreeMap<String, V>, ks: &[String]) -> std::collections::BTreeMap<String, V> {\n m.iter().filter(|(k, _)| ks.contains(k)).map(|(k, v)| (k.clone(), v.clone())).collect()\n}"], "object/omit": ["fn _omit<V: Clone>(m: &std::collections::BTreeMap<String, V>, ks: &[String]) -> std::collections::BTreeMap<String, V> {\n m.iter().filter(|(k, _)| !ks.contains(k)).map(|(k, v)| (k.clone(), v.clone())).collect()\n}"], "unsupported": ["#[derive(Clone)]\nstruct _U;\nfn _unsupported(op: &str) -> _U { panic!(\"no native template for operator {}\", op) }\nimpl From<_U> for f64 { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for String { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for bool { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for Option<f64> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for Option<String> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for Option<bool> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<T> From<_U> for Vec<T> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<T> From<_U> for Option<Vec<T>> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<K: Ord, V> From<_U> for std::collections::BTreeMap<K, V> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<K: Ord, V> From<_U> for Option<std::collections::BTreeMap<K, V>> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }"] }
|
|
32
|
+
helpers: { "store": ["pub trait Store {\n fn persist(&mut self, op: &str, entity: &str, data: serde_json::Value) -> (bool, serde_json::Value);\n fn fetch(&mut self, entity: &str, keep: Option<&dyn Fn(&serde_json::Map<String, serde_json::Value>) -> bool>) -> (bool, serde_json::Value);\n}\n\nfn _order(a: &serde_json::Map<String, serde_json::Value>, b: &serde_json::Map<String, serde_json::Value>) -> std::cmp::Ordering {\n let (sa, sb) = (a.get(\"createdAt\").filter(|v| !v.is_null()), b.get(\"createdAt\").filter(|v| !v.is_null()));\n let by_stamp = match (sa, sb) {\n (Some(_), None) => std::cmp::Ordering::Less,\n (None, Some(_)) => std::cmp::Ordering::Greater,\n (Some(x), Some(y)) => match (x.as_f64(), y.as_f64(), x.as_str(), y.as_str()) {\n (Some(p), Some(q), _, _) => p.partial_cmp(&q).unwrap_or(std::cmp::Ordering::Equal),\n (_, _, Some(p), Some(q)) => p.cmp(q),\n _ => std::cmp::Ordering::Equal,\n },\n (None, None) => std::cmp::Ordering::Equal,\n };\n let id = |m: &serde_json::Map<String, serde_json::Value>| m.get(\"id\").and_then(|v| v.as_str()).unwrap_or(\"\").to_string();\n by_stamp.then_with(|| id(a).cmp(&id(b)))\n}\n\n#[derive(Default)]\npub struct MemoryStore {\n tables: std::collections::BTreeMap<String, Vec<(String, serde_json::Map<String, serde_json::Value>)>>,\n minted: u64,\n}\n\nimpl Store for MemoryStore {\n fn persist(&mut self, op: &str, entity: &str, data: serde_json::Value) -> (bool, serde_json::Value) {\n let rows = self.tables.entry(entity.to_string()).or_default();\n if op == \"create\" {\n let mut row = data.as_object().cloned().unwrap_or_default();\n let id = match row.get(\"id\").and_then(|v| v.as_str()).filter(|v| !v.is_empty()) {\n Some(v) => v.to_string(),\n None => {\n self.minted += 1;\n format!(\"{}-{}\", entity, self.minted)\n }\n };\n row.insert(\"id\".to_string(), serde_json::Value::String(id.clone()));\n rows.push((id, row.clone()));\n return (true, serde_json::Value::Object(row));\n }\n let key = match &data {\n serde_json::Value::String(v) => v.clone(),\n v => v.get(\"id\").and_then(|x| x.as_str()).unwrap_or(\"\").to_string(),\n };\n let Some(pos) = rows.iter().position(|(k, _)| *k == key) else {\n return (false, serde_json::json!({ \"error\": format!(\"{} {} not found\", entity, key), \"code\": \"not-found\" }));\n };\n if op == \"delete\" {\n rows.remove(pos);\n return (true, serde_json::json!({ \"id\": key, \"deleted\": true }));\n }\n if let Some(obj) = data.as_object() {\n for (k, v) in obj {\n rows[pos].1.insert(k.clone(), v.clone());\n }\n }\n (true, serde_json::Value::Object(rows[pos].1.clone()))\n }\n\n fn fetch(&mut self, entity: &str, keep: Option<&dyn Fn(&serde_json::Map<String, serde_json::Value>) -> bool>) -> (bool, serde_json::Value) {\n let mut rows: Vec<serde_json::Map<String, serde_json::Value>> = self.tables.get(entity).map_or_else(Vec::new, |t| t.iter().map(|(_, r)| r.clone()).collect());\n rows.retain(|r| keep.map_or(true, |k| k(r)));\n rows.sort_by(_order);\n let n = rows.len();\n (true, serde_json::json!({ \"data\": rows, \"totalCount\": n }))\n }\n}\n\nmacro_rules! _routed_store {\n ($t:ty) => {\n impl _Routed for $t {\n fn state(&self) -> String { self.state.clone() }\n fn entity_json(&self) -> serde_json::Value { serde_json::to_value(&self.entity).unwrap_or(serde_json::Value::Null) }\n fn emitted_len(&self) -> usize { self.emitted.len() }\n fn emitted_from(&self, n: usize) -> Vec<(String, serde_json::Value, bool)> {\n self.emitted[n..].iter().enumerate().map(|(j, (e, p))| (e.clone(), p.clone().unwrap_or_else(|| serde_json::json!({})), self.completed.contains(&(n + j)))).collect()\n }\n fn as_any(&mut self) -> &mut dyn std::any::Any { self }\n }\n };\n}"], "router": ["trait _Routed {\n fn state(&self) -> String;\n fn entity_json(&self) -> serde_json::Value;\n fn emitted_len(&self) -> usize;\n fn emitted_from(&self, n: usize) -> Vec<(String, serde_json::Value, bool)>;\n fn as_any(&mut self) -> &mut dyn std::any::Any;\n}\n\nmacro_rules! _routed {\n ($t:ty) => {\n impl _Routed for $t {\n fn state(&self) -> String { self.state.clone() }\n fn entity_json(&self) -> serde_json::Value { serde_json::to_value(&self.entity).unwrap_or(serde_json::Value::Null) }\n fn emitted_len(&self) -> usize { self.emitted.len() }\n fn emitted_from(&self, n: usize) -> Vec<(String, serde_json::Value, bool)> {\n self.emitted[n..].iter().map(|(e, p)| (e.clone(), p.clone().unwrap_or_else(|| serde_json::json!({})), false)).collect()\n }\n fn as_any(&mut self) -> &mut dyn std::any::Any { self }\n }\n };\n}\n\nfn _decode<T: serde::de::DeserializeOwned>(payload: &serde_json::Value) -> T {\n serde_json::from_value(payload.clone()).expect(\"a payload of the declared shape\")\n}\n\ntype _Guard = fn(&serde_json::Value) -> bool;\ntype _Map = fn(&serde_json::Value) -> serde_json::Value;\n\nstruct _Item {\n target: String,\n event: String,\n payload: serde_json::Value,\n source: serde_json::Value,\n guard: Option<_Guard>,\n fans: bool,\n completion: bool,\n}\n\n#[derive(Default)]\npub struct _Router {\n traits: Vec<(String, Box<dyn _Routed>)>,\n pub handles: std::collections::HashMap<String, std::collections::BTreeMap<String, Vec<String>>>,\n rows: Vec<(String, String, String, String, Option<_Guard>, Option<_Map>)>,\n pub log: Vec<(String, String, serde_json::Value)>,\n}\n\nimpl _Router {\n fn add(&mut self, key: String, trait_: Box<dyn _Routed>) {\n self.traits.push((key, trait_));\n }\n\n fn row(&mut self, source: String, event: String, target: String, trigger: String, guard: Option<_Guard>, mapping: Option<_Map>) {\n self.rows.push((source, event, target, trigger, guard, mapping));\n }\n\n fn find(&mut self, key: &str) -> Option<&mut Box<dyn _Routed>> {\n self.traits.iter_mut().find(|(k, _)| k == key).map(|(_, t)| t)\n }\n\n pub fn entity_of(&mut self, key: &str) -> serde_json::Value {\n self.find(key).map_or(serde_json::Value::Null, |t| t.entity_json())\n }\n\n fn get<T: 'static>(&mut self, key: &str) -> Option<&mut T> {\n self.find(key).and_then(|t| t.as_any().downcast_mut::<T>())\n }\n\n fn targets(&self, source: &str, event: &str, payload: &serde_json::Value, completion: bool) -> Vec<_Item> {\n self.rows\n .iter()\n .filter(|(s, e, ..)| s == source && e == event)\n .map(|(_, _, target, trigger, guard, mapping)| _Item {\n target: target.clone(),\n event: trigger.clone(),\n payload: mapping.map_or_else(|| payload.clone(), |m| m(payload)),\n source: payload.clone(),\n guard: *guard,\n fans: false,\n completion,\n })\n .collect()\n }\n}\n\ntrait _Program {\n fn router(&mut self) -> &mut _Router;\n fn deliver(&mut self, target: &str, event: &str, payload: &serde_json::Value);\n}\n\nfn _dispatch<P: _Program>(program: &mut P, trait_: &str, event: &str, payload: serde_json::Value) {\n let mut queue = std::collections::VecDeque::from(vec![_Item {\n target: trait_.to_string(),\n event: event.to_string(),\n payload: payload.clone(),\n source: payload,\n guard: None,\n fans: true,\n completion: false,\n }]);\n let mut seen = std::collections::HashSet::new();\n let mut steps = 0;\n while let Some(item) = queue.pop_front() {\n let Some((state, entity)) = program.router().find(&item.target).map(|t| (t.state(), t.entity_json())) else { continue };\n let key = serde_json::json!([item.target, item.event, state, item.payload, entity]).to_string();\n if !item.completion && seen.contains(&key) {\n continue;\n }\n if let Some(guard) = item.guard {\n if !guard(&item.source) {\n continue;\n }\n }\n if steps >= 2000 {\n break;\n }\n steps += 1;\n seen.insert(key);\n let n = program.router().find(&item.target).map_or(0, |t| t.emitted_len());\n program.deliver(&item.target, &item.event, &item.payload);\n let router = program.router();\n let mut fanned = if item.fans { router.targets(&item.target, &item.event, &item.payload, false) } else { Vec::new() };\n let (new_state, emits) = router.find(&item.target).map_or((String::new(), Vec::new()), |t| (t.state(), t.emitted_from(n)));\n let mut own = Vec::new();\n for (ev, out, completion) in emits {\n router.log.push((item.target.clone(), ev.clone(), out.clone()));\n if router.handles.get(&item.target).and_then(|h| h.get(&new_state)).is_some_and(|evs| evs.contains(&ev)) {\n own.push(_Item { target: item.target.clone(), event: ev.clone(), payload: out.clone(), source: out.clone(), guard: None, fans: false, completion });\n }\n fanned.extend(router.targets(&item.target, &ev, &out, completion));\n }\n for x in own.into_iter().rev() {\n queue.push_front(x);\n }\n queue.extend(fanned);\n }\n}"], "/": ["fn _div(a: f64, b: f64) -> Option<f64> { if b == 0.0 { None } else { Some(a / b) } }"], "%": ["fn _mod(a: f64, b: f64) -> Option<f64> { if b == 0.0 { None } else { Some(a % b) } }"], "math/mod": ["fn _mod(a: f64, b: f64) -> Option<f64> { if b == 0.0 { None } else { Some(a % b) } }"], "default": ["trait _OrDefault<T> { fn _or_default(self, d: T) -> T; }\nimpl<T> _OrDefault<T> for Option<T> { fn _or_default(self, d: T) -> T { self.unwrap_or(d) } }\nimpl<T> _OrDefault<T> for T { fn _or_default(self, _d: T) -> T { self } }\nfn _default<T, V: _OrDefault<T>>(v: V, d: T) -> T { v._or_default(d) }"], "str/concat": ["fn _num_text(x: f64) -> String {\n if x.is_nan() { return \"NaN\".to_string(); }\n if x.is_infinite() { return (if x > 0.0 { \"Infinity\" } else { \"-Infinity\" }).to_string(); }\n if x == 0.0 { return \"0\".to_string(); }\n let a = x.abs();\n if a >= 1e21 || a < 1e-6 {\n let s = format!(\"{:e}\", x);\n return match s.split_once('e') {\n Some((m, e)) => if e.starts_with('-') { format!(\"{}e{}\", m, e) } else { format!(\"{}e+{}\", m, e) },\n None => s,\n };\n }\n format!(\"{}\", x)\n}", "trait _Text { fn _text(&self) -> String; }\nimpl _Text for String { fn _text(&self) -> String { self.clone() } }\nimpl _Text for bool { fn _text(&self) -> String { (if *self { \"true\" } else { \"false\" }).to_string() } }\nimpl _Text for f64 { fn _text(&self) -> String { _num_text(*self) } }", "macro_rules! _concat {\n ($($x:expr),+ $(,)?) => {{\n let mut s_ = String::new();\n $( s_.push_str(&_Text::_text(&$x)); )+\n s_\n }};\n}"], "str/join": ["fn _num_text(x: f64) -> String {\n if x.is_nan() { return \"NaN\".to_string(); }\n if x.is_infinite() { return (if x > 0.0 { \"Infinity\" } else { \"-Infinity\" }).to_string(); }\n if x == 0.0 { return \"0\".to_string(); }\n let a = x.abs();\n if a >= 1e21 || a < 1e-6 {\n let s = format!(\"{:e}\", x);\n return match s.split_once('e') {\n Some((m, e)) => if e.starts_with('-') { format!(\"{}e{}\", m, e) } else { format!(\"{}e+{}\", m, e) },\n None => s,\n };\n }\n format!(\"{}\", x)\n}", "trait _Text { fn _text(&self) -> String; }\nimpl _Text for String { fn _text(&self) -> String { self.clone() } }\nimpl _Text for bool { fn _text(&self) -> String { (if *self { \"true\" } else { \"false\" }).to_string() } }\nimpl _Text for f64 { fn _text(&self) -> String { _num_text(*self) } }", "fn _join<T: _Text>(a: &[T], d: &str) -> String { a.iter().map(|x| x._text()).collect::<Vec<_>>().join(d) }"], "str/split": ["fn _split(s: &str, d: &str) -> Vec<String> {\n if d.is_empty() { s.chars().map(|c| c.to_string()).collect() } else { s.split(d).map(|p| p.to_string()).collect() }\n}"], "str/slice": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _str_slice(s: &str, a: f64, b: Option<f64>) -> String {\n let c: Vec<char> = s.chars().collect();\n let n = c.len() as i64;\n let norm = |i: i64| -> i64 { if i < 0 { (n + i).max(0) } else { i.min(n) } };\n let st = norm(_whole(a));\n let en = match b { Some(v) => norm(_whole(v)), None => n };\n if en <= st { String::new() } else { c[st as usize..en as usize].iter().collect() }\n}"], "str/padStart": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _pad_start(s: &str, n: f64, p: &str) -> String {\n if p.chars().count() != 1 { panic!(\"expected a single padding character, got {:?}\", p); }\n let w = _whole(n);\n let len = s.chars().count() as i64;\n if w <= len { return s.to_string(); }\n let pad: String = std::iter::repeat(p).take((w - len) as usize).collect();\n format!(\"{}{}\", pad, s)\n}"], "str/padEnd": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _pad_end(s: &str, n: f64, p: &str) -> String {\n if p.chars().count() != 1 { panic!(\"expected a single padding character, got {:?}\", p); }\n let w = _whole(n);\n let len = s.chars().count() as i64;\n if w <= len { return s.to_string(); }\n let pad: String = std::iter::repeat(p).take((w - len) as usize).collect();\n format!(\"{}{}\", s, pad)\n}"], "str/truncate": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _truncate(s: &str, n: f64, suffix: &str) -> String {\n let w = _whole(n);\n if (s.chars().count() as i64) <= w { return s.to_string(); }\n let head: String = s.chars().take(w.max(0) as usize).collect();\n format!(\"{}{}\", head, suffix)\n}"], "str/repeat": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _repeat(s: &str, n: f64) -> String { s.repeat(_count(n)) }"], "str/capitalize": ["fn _capitalize(s: &str) -> String {\n let mut c = s.chars();\n match c.next() {\n Some(f) => f.to_uppercase().collect::<String>() + &c.as_str().to_lowercase(),\n None => String::new(),\n }\n}"], "str/to-int": ["fn _to_int(s: &str) -> Option<f64> { s.parse::<i64>().ok().map(|v| v as f64) }"], "array/sum": ["fn _sum(a: &[f64]) -> f64 { a.iter().fold(0.0_f64, |s, x| s + x) }"], "array/avg": ["fn _avg(a: &[f64]) -> Option<f64> { if a.is_empty() { None } else { Some(a.iter().fold(0.0_f64, |s, x| s + x) / a.len() as f64) } }"], "array/max": ["fn _amax(a: &[f64]) -> Option<f64> { a.iter().cloned().fold(None, |m, x| Some(match m { Some(y) => if x > y { x } else { y }, None => x })) }"], "array/min": ["fn _amin(a: &[f64]) -> Option<f64> { a.iter().cloned().fold(None, |m, x| Some(match m { Some(y) => if x < y { x } else { y }, None => x })) }"], "array/first": ["fn _first<T: Clone>(a: &[T]) -> Option<T> { a.first().cloned() }"], "array/last": ["fn _last<T: Clone>(a: &[T]) -> Option<T> { a.last().cloned() }"], "array/nth": ["fn _nth<T: Clone>(a: &[T], i: f64) -> Option<T> {\n if !i.is_finite() || i != i.trunc() || i < 0.0 { panic!(\"nth: index {} is not a whole number from 0\", i); }\n a.get(i as usize).cloned()\n}"], "array/range": ["fn _range(a: f64, b: f64, step: f64) -> Vec<f64> {\n if step == 0.0 || !step.is_finite() { panic!(\"range: step 0 must be a non-zero finite number\"); }\n let mut out = Vec::new();\n let mut x = a;\n while if step > 0.0 { x < b } else { x > b } { out.push(x); x += step; }\n out\n}"], "array/slice": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _slice<T: Clone>(a: &[T], s: f64, e: Option<f64>) -> Vec<T> {\n let st = _whole(s);\n let en = e.map(_whole);\n if st < 0 || en.map_or(false, |v| v < 0) { panic!(\"slice: not a whole number from 0\"); }\n let st = (st as usize).min(a.len());\n let en = en.map_or(a.len(), |v| (v as usize).min(a.len()));\n if en <= st { Vec::new() } else { a[st..en].to_vec() }\n}"], "array/take": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _take<T: Clone>(a: &[T], n: f64) -> Vec<T> { a.iter().take(_count(n)).cloned().collect() }"], "array/drop": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _drop<T: Clone>(a: &[T], n: f64) -> Vec<T> { a.iter().skip(_count(n)).cloned().collect() }"], "array/takeLast": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _take_last<T: Clone>(a: &[T], n: f64) -> Vec<T> { let k = _count(n).min(a.len()); a[a.len() - k..].to_vec() }"], "array/dropLast": ["fn _count(x: f64) -> usize {\n if !x.is_finite() || x != x.trunc() || x < 0.0 { panic!(\"count is not a whole number from 0\"); }\n x as usize\n}", "fn _drop_last<T: Clone>(a: &[T], n: f64) -> Vec<T> { let k = _count(n).min(a.len()); a[..a.len() - k].to_vec() }"], "array/append": ["fn _append<T: Clone>(a: &[T], x: T) -> Vec<T> { let mut v = a.to_vec(); v.push(x); v }"], "array/prepend": ["fn _prepend<T: Clone>(a: &[T], x: T) -> Vec<T> { let mut v = vec![x]; v.extend(a.iter().cloned()); v }"], "array/indexOf": ["fn _index_of<T: PartialEq>(a: &[T], x: &T) -> f64 { a.iter().position(|y| y == x).map_or(-1.0, |i| i as f64) }"], "array/unique": ["fn _unique<T: Clone + PartialEq>(a: &[T]) -> Vec<T> {\n let mut out: Vec<T> = Vec::new();\n for x in a { if !out.contains(x) { out.push(x.clone()); } }\n out\n}"], "array/flatten": ["fn _flatten<T: Clone>(a: &[Vec<T>]) -> Vec<T> { a.iter().flat_map(|v| v.iter().cloned()).collect() }"], "array/zip": ["fn _zip<T: Clone>(a: &[T], b: &[T]) -> Vec<Vec<T>> { a.iter().cloned().zip(b.iter().cloned()).map(|(x, y)| vec![x, y]).collect() }"], "array/concat": ["macro_rules! _vconcat {\n ($($x:expr),+ $(,)?) => {{\n let mut v_ = Vec::new();\n $( v_.extend($x.iter().cloned()); )+\n v_\n }};\n}"], "array/sort": ["fn _sort<T: Clone + PartialOrd>(a: &[T]) -> Vec<T> {\n let mut v = a.to_vec();\n v.sort_by(|x, y| x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal));\n v\n}"], "array/reduce": ["fn _reduce<T: Clone, A>(a: &[T], init: A, f: impl Fn(A, T) -> A) -> A { a.iter().cloned().fold(init, f) }"], "math/round": ["fn _round(x: f64, d: f64) -> f64 {\n let m = 10.0_f64.powf(d);\n let r = (x.abs() * m + 0.5).floor() / m;\n if x < 0.0 { -r } else { r }\n}"], "math/acos": ["fn _acos(x: f64) -> Option<f64> { if (-1.0..=1.0).contains(&x) { Some(x.acos()) } else { None } }"], "math/asin": ["fn _asin(x: f64) -> Option<f64> { if (-1.0..=1.0).contains(&x) { Some(x.asin()) } else { None } }"], "math/approach": ["fn _approach(c: f64, t: f64, d: f64) -> f64 { if (t - c).abs() <= d { t } else { c + (t - c).signum() * d } }"], "math/map": ["fn _map(v: f64, a: f64, b: f64, c: f64, d: f64) -> f64 { if b == a { c } else { c + (v - a) / (b - a) * (d - c) } }"], "math/wrap": ["fn _wrap(v: f64, lo: f64, hi: f64) -> f64 {\n let r = hi - lo;\n if r <= 0.0 { lo } else { ((v - lo) % r + r) % r + lo }\n}"], "array/insert": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _insert<T: Clone>(a: &[T], i: f64, x: T) -> Vec<T> {\n let k = _whole(i);\n if k < 0 || k as usize > a.len() { panic!(\"insert: index {} is not within a {}-item array\", k, a.len()); }\n let mut v = a.to_vec();\n v.insert(k as usize, x);\n v\n}"], "array/remove": ["fn _whole(x: f64) -> i64 {\n if !x.is_finite() || x != x.trunc() { panic!(\"expected a whole number, got {}\", x); }\n x as i64\n}", "fn _remove<T: Clone>(a: &[T], i: f64) -> Vec<T> {\n let k = _whole(i);\n if k < 0 || k as usize >= a.len() { panic!(\"remove: index {} is outside a {}-item array\", k, a.len()); }\n let mut v = a.to_vec();\n v.remove(k as usize);\n v\n}"], "array/removeItem": ["fn _remove_item<T: Clone + PartialEq>(a: &[T], x: &T) -> Vec<T> {\n let mut v = a.to_vec();\n if let Some(p) = v.iter().position(|y| y == x) { v.remove(p); }\n v\n}"], "math/sqrt": ["fn _sqrt(x: f64) -> Option<f64> { if x < 0.0 { None } else { Some(x.sqrt()) } }"], "math/ln": ["fn _ln(x: f64) -> Option<f64> { if x <= 0.0 { None } else { Some(x.ln()) } }"], "math/log10": ["fn _log10(x: f64) -> Option<f64> { if x <= 0.0 { None } else { Some(x.log10()) } }"], "math/pow": ["fn _pow(a: f64, b: f64) -> Option<f64> { let r = a.powf(b); if r.is_finite() { Some(r) } else { None } }"], "math/sign": ["fn _sign(x: f64) -> f64 { if x > 0.0 { 1.0 } else if x < 0.0 { -1.0 } else { 0.0 } }"], "object/get": ["trait _Lookup {\n type Out;\n fn lookup(&self, k: &str) -> Self::Out;\n}\nimpl<V: Clone> _Lookup for std::collections::BTreeMap<String, V> {\n type Out = Option<V>;\n fn lookup(&self, k: &str) -> Option<V> { self.get(k).cloned() }\n}\nimpl _Lookup for serde_json::Map<String, serde_json::Value> {\n type Out = _Json;\n fn lookup(&self, k: &str) -> _Json { _Json(self.get(k).cloned().filter(|v| !v.is_null())) }\n}\nimpl<T: _Lookup + ?Sized> _Lookup for &T {\n type Out = T::Out;\n fn lookup(&self, k: &str) -> T::Out { (**self).lookup(k) }\n}\n#[derive(Clone, Debug)]\nstruct _Json(Option<serde_json::Value>);\nimpl PartialEq<String> for _Json {\n fn eq(&self, o: &String) -> bool { self.0.as_ref().and_then(|v| v.as_str()) == Some(o.as_str()) }\n}\nimpl PartialEq<f64> for _Json {\n fn eq(&self, o: &f64) -> bool { self.0.as_ref().and_then(|v| v.as_f64()) == Some(*o) }\n}\nimpl PartialEq<bool> for _Json {\n fn eq(&self, o: &bool) -> bool { self.0.as_ref().and_then(|v| v.as_bool()) == Some(*o) }\n}\nfn _get<M: _Lookup>(m: &M, k: &str) -> M::Out { m.lookup(k) }"], "object/merge": ["fn _merge<V: Clone>(a: &std::collections::BTreeMap<String, V>, b: &std::collections::BTreeMap<String, V>) -> std::collections::BTreeMap<String, V> {\n let mut m = a.clone();\n for (k, v) in b { m.insert(k.clone(), v.clone()); }\n m\n}"], "object/pick": ["fn _pick<V: Clone>(m: &std::collections::BTreeMap<String, V>, ks: &[String]) -> std::collections::BTreeMap<String, V> {\n m.iter().filter(|(k, _)| ks.contains(k)).map(|(k, v)| (k.clone(), v.clone())).collect()\n}"], "object/omit": ["fn _omit<V: Clone>(m: &std::collections::BTreeMap<String, V>, ks: &[String]) -> std::collections::BTreeMap<String, V> {\n m.iter().filter(|(k, _)| !ks.contains(k)).map(|(k, v)| (k.clone(), v.clone())).collect()\n}"], "unsupported": ["#[derive(Clone)]\nstruct _U;\nfn _unsupported(op: &str) -> _U { panic!(\"no native template for operator {}\", op) }\nimpl From<_U> for f64 { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for String { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for bool { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for Option<f64> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for Option<String> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl From<_U> for Option<bool> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<T> From<_U> for Vec<T> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<T> From<_U> for Option<Vec<T>> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<K: Ord, V> From<_U> for std::collections::BTreeMap<K, V> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }\nimpl<K: Ord, V> From<_U> for Option<std::collections::BTreeMap<K, V>> { fn from(_: _U) -> Self { panic!(\"unsupported\") } }"] }
|
|
33
33
|
helperGap: "\n"
|
|
34
34
|
portEffects: ["persist", "fetch", "fetch-stream", "notify", "navigate", "navigate-back", "call-service", "cancel-call", "send-server", "spawn", "despawn", "log"]
|
|
35
35
|
portCall: "(self.ports)(\"{{name}}\", serde_json::json!([{{*}}]))"
|
|
@@ -82,14 +82,39 @@ orbital LoloRustOrbital {
|
|
|
82
82
|
enumForm: "{{enum}}::{{member}}"
|
|
83
83
|
enumMemberCase: "split-pascal"
|
|
84
84
|
fieldNames: { "type": "type_" }
|
|
85
|
+
programOpen: ["pub struct Program {", "{{i}}pub router: _Router,", "}", "", "impl Program {", "{{i}}pub fn new(entities: ({{entities}},){{store}}) -> Self {", "{{i}}{{i}}let mut router = _Router::default();"]
|
|
86
|
+
programEntity: "{{entity}}"
|
|
87
|
+
programEntitySep: ", "
|
|
88
|
+
programTrait: "{{i}}{{i}}_routed!({{class}}); router.add({{key}}, Box::new({{class}}::new(entities.{{n}})));"
|
|
89
|
+
programHandles: "{{i}}{{i}}router.handles.insert({{key}}, {{table}});"
|
|
90
|
+
programRow: "{{i}}{{i}}router.row({{source}}, {{event}}, {{target}}, {{trigger}}, {{guard}}, {{map}});"
|
|
91
|
+
deliverOpen: ["{{i}}{{i}}Program { router }", "{{i}}}", "", "{{i}}pub fn dispatch(&mut self, trait_: &str, event: &str, payload: serde_json::Value) {", "{{i}}{{i}}_dispatch(self, trait_, event, payload)", "{{i}}}", "}", "", "impl _Program for Program {", "{{i}}fn router(&mut self) -> &mut _Router {", "{{i}}{{i}}&mut self.router", "{{i}}}", "", "{{i}}fn deliver(&mut self, target: &str, event: &str, payload: &serde_json::Value) {"]
|
|
92
|
+
deliverCase: "{{i}}{{i}}if target == {{target}} && event == {{event}} { if let Some(t) = self.router.get::<{{class}}>(target) { t.{{method}}({{arg}}); } return; }"
|
|
93
|
+
deliverCasePlain: "{{i}}{{i}}if target == {{target}} && event == {{event}} { if let Some(t) = self.router.get::<{{class}}>(target) { t.{{method}}(); } return; }"
|
|
94
|
+
deliverClose: ["{{i}}}", "}"]
|
|
95
|
+
programClose: []
|
|
96
|
+
payloadDecode: "&_decode::<{{type}}>({{value}})"
|
|
97
|
+
guardForm: ["", "fn {{name}}(payload_json: &serde_json::Value) -> bool {", "{{i}}let payload = {{decode}};", "{{i}}{{expr}}", "}"]
|
|
98
|
+
mapForm: ["", "fn {{name}}(payload_json: &serde_json::Value) -> serde_json::Value {", "{{i}}let payload = {{decode}};", "{{i}}serde_json::to_value({{expr}}).expect(\"a mapped payload\")", "}"]
|
|
99
|
+
guardName: "_guard_{{n}}"
|
|
100
|
+
mapName: "_map_{{n}}"
|
|
101
|
+
guardRef: "Some({{name}})"
|
|
102
|
+
mapRef: "Some({{name}})"
|
|
85
103
|
modelImportEach: true
|
|
86
104
|
fileHeader: "#![allow(dead_code, unused_macros, unused_parens, unused_variables)]"
|
|
87
105
|
sectionGap: "\n\n"
|
|
88
106
|
classOpen: "macro_rules! _list {\n ($($x:expr),* $(,)?) => { vec![$(($x).clone()),*] };\n}\n\npub struct {{class}} {"
|
|
89
107
|
classClose: "}"
|
|
90
108
|
classEmpty: ""
|
|
91
|
-
constructor: ["{{i}}pub state: String,", "{{i}}pub entity: {{entity}},", "{{i}}pub config: {{configType}},", "{{i}}pub ports: Box<dyn FnMut(&str, serde_json::Value)>,", "{{i}}pub emitted: Vec<(String, Option<serde_json::Value>)>,", "}", "", "impl {{class}} {", "{{i}}pub fn new(entity: {{entity}}) -> Self {", "{{i}}{{i}}Self { state: {{initial}}, entity, config: {{configType}}::default(), ports: Box::new(|_, _| {}), emitted: Vec::new() }", "{{noConfig}}{{i}}{{i}}Self { state: {{initial}}, entity, ports: Box::new(|_, _| {}), emitted: Vec::new() }", "{{i}}}", "", "{{i}}pub fn with_config(mut self, config: {{configType}}) -> Self {", "{{withConfig}}{{i}}{{i}}self.config = config;", "{{withConfig}}{{i}}{{i}}self", "{{withConfig}}{{i}}}", "{{withConfig}}", "{{i}}pub fn with_ports(mut self, ports: impl FnMut(&str, serde_json::Value) + 'static) -> Self {", "{{i}}{{i}}self.ports = Box::new(ports);", "{{i}}{{i}}self", "{{i}}}"]
|
|
109
|
+
constructor: ["{{i}}pub state: String,", "{{i}}pub entity: {{entity}},", "{{i}}pub config: {{configType}},", "{{i}}pub ports: Box<dyn FnMut(&str, serde_json::Value)>,", "{{i}}pub emitted: Vec<(String, Option<serde_json::Value>)>,", "{{withStore}}{{i}}pub store: Option<std::rc::Rc<std::cell::RefCell<dyn Store>>>,", "{{withStore}}{{i}}pub completed: Vec<usize>,", "}", "", "impl {{class}} {", "{{i}}pub fn new(entity: {{entity}}) -> Self {", "{{noStore}}{{i}}{{i}}Self { state: {{initial}}, entity, config: {{configType}}::default(), ports: Box::new(|_, _| {}), emitted: Vec::new() }", "{{noStore}}{{noConfig}}{{i}}{{i}}Self { state: {{initial}}, entity, ports: Box::new(|_, _| {}), emitted: Vec::new() }", "{{withStore}}{{i}}{{i}}Self { state: {{initial}}, entity, config: {{configType}}::default(), ports: Box::new(|_, _| {}), emitted: Vec::new(), store: None, completed: Vec::new() }", "{{withStore}}{{noConfig}}{{i}}{{i}}Self { state: {{initial}}, entity, ports: Box::new(|_, _| {}), emitted: Vec::new(), store: None, completed: Vec::new() }", "{{i}}}", "", "{{i}}pub fn with_config(mut self, config: {{configType}}) -> Self {", "{{withConfig}}{{i}}{{i}}self.config = config;", "{{withConfig}}{{i}}{{i}}self", "{{withConfig}}{{i}}}", "{{withConfig}}", "{{i}}pub fn with_ports(mut self, ports: impl FnMut(&str, serde_json::Value) + 'static) -> Self {", "{{i}}{{i}}self.ports = Box::new(ports);", "{{i}}{{i}}self", "{{i}}}"]
|
|
92
110
|
emitMethod: ["{{i}}fn emit(&mut self, event: String, payload: Option<serde_json::Value>) {", "{{i}}{{i}}self.emitted.push((event, payload));", "{{i}}}"]
|
|
111
|
+
completeMethod: ["", "{{i}}fn complete(&mut self, answer: (bool, serde_json::Value), success: Option<String>, failure: Option<String>) {", "{{i}}{{i}}let (ok, payload) = answer;", "{{i}}{{i}}if let Some(route) = if ok { success } else { failure } {", "{{i}}{{i}}{{i}}self.completed.push(self.emitted.len());", "{{i}}{{i}}{{i}}self.emitted.push((route, Some(payload)));", "{{i}}{{i}}}", "{{i}}}", "", "{{i}}fn use_store(&self) -> std::rc::Rc<std::cell::RefCell<dyn Store>> {", "{{i}}{{i}}self.store.clone().expect(\"no store\")", "{{i}}}"]
|
|
112
|
+
routedEffects: {"persist": "self.complete(self.use_store().borrow_mut().persist(&{{0}}, &{{1}}, serde_json::to_value(&{{2}}).expect(\"a row\")), {{success}}, {{failure}})", "fetch": "self.complete(self.use_store().borrow_mut().fetch(&{{entity}}, {{filter}}), {{success}}, {{failure}})"}
|
|
113
|
+
fetchAll: "None"
|
|
114
|
+
routeForm: "Some({{route}})"
|
|
115
|
+
filterForm: "Some(&({{lambda}}))"
|
|
116
|
+
programStoreParam: ", store: std::rc::Rc<std::cell::RefCell<dyn Store>>"
|
|
117
|
+
programTraitStore: "{{i}}{{i}}_routed_store!({{class}}); let mut t{{n}} = {{class}}::new(entities.{{n}}); t{{n}}.store = Some(store.clone()); router.add({{key}}, Box::new(t{{n}}));"
|
|
93
118
|
methodOpen: "{{i}}pub fn {{method}}(&mut self, payload: &{{payloadType}}) {"
|
|
94
119
|
methodOpenPlain: "{{i}}pub fn {{method}}(&mut self) {"
|
|
95
120
|
methodClose: "{{i}}}"
|