From a625e9ceb7700c6406c8834ddc821a66999dfeef Mon Sep 17 00:00:00 2001 From: tiye Date: Tue, 10 Nov 2026 09:56:15 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=8D=87=E7=BA=A7=20Guidebook=20=E5=88=B0?= =?UTF-8?q?=20Calcit=200.40.0=20=E5=B9=B6=E5=8C=BA=E5=88=86=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E5=92=8C=20Reel=20=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++----- calcit.cirru | 53 +++++++++++++++++++--------------------------------- deps.cirru | 6 +++--- package.json | 2 +- yarn.lock | 10 +++++----- 5 files changed, 31 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 82e651f..9702628 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Respo Guidebook -使用者注意:本轮将站点 Calcit CLI / `@calcit/procs` 从 **0.31.0** 配对正式 **0.32.1**,采用已发布 Docs Workflow **0.0.40**、Respo **0.17.1**、UI **0.9.0** 和 JS-FFI **0.2.9**。Reel **0.7.0-alpha.5**、Markdown **0.5.0-alpha.5**、Router **0.9.0-alpha.4** 仍为已发布 alpha,不声称完整依赖图均为正式版。升级后重新安装完整精确依赖图并刷新页面,UI 样式可能变化。源码仍仅使用 `calcit.cirru`,依赖以 `deps.cirru` 为准,不恢复 compact/package.cirru。 +开发使用配对的 Calcit CLI 和 `@calcit/procs` 0.40.0,并从正式标签解析 Docs Workflow 0.1.0 与 Reel 0.11.0。更新依赖后重新生成前端。 Guide 说明当前 Ref/watch、Option、event handler/app dispatch、名义 Store 和宿主边界。 旧 Beginner Guide、部分 Guide 实现说明和 API 仍有历史片段,尚未全部迁移或独立执行;站点构建通过不代表 @@ -9,7 +9,7 @@ Guide 说明当前 Ref/watch、Option、event handler/app dispatch、名义 Stor ## 开发与验收 -Node 24、Yarn 4.18.0、正式 0.32.1 CLI: +Node 24、Yarn 4.18.0、正式 0.40.0 CLI。 ```bash corepack enable @@ -26,9 +26,7 @@ yarn dev 并保存 PR 预览。当前 Guide 计数器与 DOM Events 数据解码示例由官方代码块检查覆盖;原项目没有定义附带测试,零个测试不等于业务覆盖;浏览器导航、 搜索与刷新需另行验收。页面 `hud!` 错误展示保留。 -默认 entry 的 dispatch-op 显式绑定原有 renderer 的 Dynamic 宿主入口; -非 Enum 输入仍被拒绝,业务 payload 仍受检后构造 Docs Workflow 的具名 Op。 -14 个定义的 schema 与 Store/Op 合同保持;官方 formatter 转换 renderer 的一处类型提示,业务表达式不变,不以关闭证明审计或增加断言绕过 strict。 +文档导航直接派发具名 `docs-workflow.schema/Op`。Reel 面板和快捷键通过独立回调接收 `reel.typed/Control`。 ## 部署边界 diff --git a/calcit.cirru b/calcit.cirru index 607e0d1..00c0c7e 100644 --- a/calcit.cirru +++ b/calcit.cirru @@ -34,35 +34,18 @@ 'dispatch! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn dispatch! (op) when config/dev? $ println |Dispatch: op - match (typed/decode-control op) - (:some control) - reset! *reel $ typed/apply-control updater @*reel control - (:none) - match op - (:states cursor data) - match - try-decode-map-as cursor $ List Tag - (:ok typed-cursor) - reset! *reel $ typed/record-op updater @*reel (docs-schema/Op :states typed-cursor data) (generate-id!) - :timestamp $ shared/date-now-snapshot - (:err message) (eprintln message) - (:hydrate-storage data) - match (try-decode-map-as data 'docs-workflow.schema/Store) - (:ok store) - reset! *reel $ typed/record-op updater @*reel (docs-schema/Op :hydrate-storage store) (generate-id!) - :timestamp $ shared/date-now-snapshot - (:err message) (eprintln message) - _ $ eprintln |Unknown-operation: op + reset! *reel $ typed/record-op updater @*reel op (generate-id!) + :timestamp $ shared/date-now-snapshot , &unit :examples $ [] - :schema $ quote $ Fn AnyEnum (-> Unit) (:features :js-ffi) (:open :decode) + :schema $ quote $ Fn docs-workflow.schema/Op (-> Unit) (:features :js-ffi) 'main! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn main! () (register-languages!) println "|Running mode:" $ if config/dev? |dev |release if config/dev? $ load-console-formatter! render-app! add-watch! *reel :changes $ fn (reel prev) (render-app!) - listen-devtools! |k dispatch! + listen-devtools-toggle! |k $ fn () $ on-control! (typed/Control :toggle) browser/set-before-unload! $ fn (event) (persist-storage!) browser/set-interval! persist-storage! 60000 println "|App started." @@ -70,11 +53,16 @@ :schema $ quote $ Fn (-> Unit) (:features :js-ffi) 'mount-target $ %{} 'CodeEntry (:doc |) :code $ quote $ defn mount-target () - .query-selector (js-cast js/document dom/DomDocument) |.app + .unwrap $ respo-browser/query-selector |.app :examples $ [] - :schema $ quote $ Fn - -> $ JsNullish respo.dom/DomElement - :features :js-ffi + :schema $ quote $ Fn (-> respo.dom/DomElement) (:features :js-ffi) + 'on-control! $ %{} 'CodeEntry (:doc |) + :code $ quote $ defn on-control! (control) + when config/dev? $ println |Dispatch: control + reset! *reel $ typed/apply-control updater @*reel control + , &unit + :examples $ [] + :schema $ quote $ Fn reel.typed/Control (-> Unit) (:features :js-ffi) 'persist-storage! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn persist-storage! () (js/console.log |persist) browser/storage-set! (:storage-key config/site) @@ -94,21 +82,19 @@ :schema $ quote $ Fn (-> Unit) (:features :js-ffi) 'render-app! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn render-app! () - render! (mount-target) (comp-container @*reel schema/docs) - fn (op) - hint-fn $ Fn Dynamic (-> Unit) (:features :js-ffi) - if (enum? op) (dispatch! op) (raise "|Expected an Enum render action") - , &unit + render-with! (mount-target) + fn () $ comp-container @*reel schema/docs on-control! + , dispatch! :examples $ [] :schema $ quote $ Fn (-> Unit) (:features :js-ffi) :ns $ %{} 'NsEntry (:doc |) :code $ quote $ ns app.main :require - respo.core :refer $ render! clear-cache! + respo.core :refer $ render-with! clear-cache! docs-workflow.comp.container :refer $ comp-container app.updater :refer $ updater app.schema :as schema - reel.util :refer $ listen-devtools! + reel.util :refer $ listen-devtools-toggle! app.config :as config |./calcit.build-errors :default build-errors |bottom-tip :default hud! @@ -116,8 +102,7 @@ reel.typed :as typed js-ffi.browser :as browser js-ffi.shared :as shared - respo.dom :as dom - docs-workflow.schema :as docs-schema + respo.ffi.browser :as respo-browser 'app.schema $ %{} 'FileEntry :defs $ {} 'docs $ %{} 'CodeEntry (:doc |) diff --git a/deps.cirru b/deps.cirru index 19e4da6..b573d6b 100644 --- a/deps.cirru +++ b/deps.cirru @@ -1,9 +1,9 @@ -{} (:calcit-version |0.38.0) +{} (:calcit-version |0.40.0) :version |0.0.4 - :dependencies $ {} (|Respo/reel.calcit |0.10.0) + :dependencies $ {} (|Respo/reel.calcit |0.11.0) |Respo/respo-markdown.calcit |0.8.2 |Respo/respo-router.calcit |0.12.2 |Respo/respo-ui.calcit |0.15.2 |Respo/respo.calcit |0.19.5 - |calcit-lang/docs-workflow |0.0.42 + |calcit-lang/docs-workflow |0.1.0 |calcit-lang/js-ffi |0.2.13 diff --git a/package.json b/package.json index 463f82c..1696be3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "packageManager": "yarn@4.18.0", "dependencies": { - "@calcit/procs": "0.38.0" + "@calcit/procs": "0.40.0" }, "devDependencies": { "bottom-tip": "^0.1.5", diff --git a/yarn.lock b/yarn.lock index 138711c..f916b16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,15 +12,15 @@ __metadata: languageName: node linkType: hard -"@calcit/procs@npm:0.38.0": - version: 0.38.0 - resolution: "@calcit/procs@npm:0.38.0" +"@calcit/procs@npm:0.40.0": + version: 0.40.0 + resolution: "@calcit/procs@npm:0.40.0" dependencies: "@calcit/finger-vec": "npm:0.1.1" "@calcit/ternary-tree": "npm:0.0.26" "@cirru/parser.ts": "npm:0.0.10" "@cirru/writer.ts": "npm:^0.1.9" - checksum: 10c0/8d1910cc739b1b23b5d5b549fb519053b2a578ab05f11814d28c09fbf4c18be5d3a14f52ff3b9bea4c9a3a42ab79d56a59021cd533d68ecc5e26e61da1e347ba + checksum: 10c0/4122eaa8d63fd57826d24c6c072dbd1cb6cdd2934dbfdb4fd0afc03f4aec73f07d71ccba246120c15e198134b7e92a324f1f1900b43c458b02e871354739cf84 languageName: node linkType: hard @@ -688,7 +688,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: - "@calcit/procs": "npm:0.38.0" + "@calcit/procs": "npm:0.40.0" bottom-tip: "npm:^0.1.5" cirru-color: "npm:^0.2.3" github-markdown-css: "npm:^5.3.0" From 14188b1519c0205ee2c1379aad3c4e591dc31cd7 Mon Sep 17 00:00:00 2001 From: tiye Date: Tue, 10 Nov 2026 12:19:57 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=90=8C=E6=AD=A5=20Respo=20Guidebook=20?= =?UTF-8?q?=E7=9A=84=E5=B7=A5=E5=85=B7=E9=93=BE=E5=92=8C=E5=85=B7=E5=90=8D?= =?UTF-8?q?=E6=B4=BE=E5=8F=91=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/guide.md | 23 +++++++++------- docs/guide/component-states.md | 48 +++++++++++++++++++--------------- docs/home.md | 2 +- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index 544d513..0f48e9a 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -1,6 +1,11 @@ -# Guide: Calcit 0.32.1 +# Guide: Calcit 0.40.0 -This site pairs formal Calcit CLI / `@calcit/procs` **0.32.1** with released Docs Workflow **0.0.40**, Respo **0.17.1** and JS-FFI **0.2.9**. The published UI graph still includes Reel **0.7.0-alpha.5**, Markdown **0.5.0-alpha.5** and Router **0.9.0-alpha.4**; it is not an entirely stable-release graph. Install it using Caps strict and keep runtime and CLI paired. Use `calcit.cirru` for source and `deps.cirru` for module versions; do not restore `compact.cirru` or `package.cirru`. +Use the published Calcit CLI and `@calcit/procs` **0.40.0** together. This site +uses Docs Workflow **0.1.0**, Respo **0.19.5**, Respo UI **0.15.2**, Reel +**0.11.0**, Markdown **0.8.2**, Router **0.12.2**, and JS-FFI **0.2.13**. +Docs Workflow also brings in Alerts **0.14.3**. Install with Caps strict and run +`caps verify --toolchain` to check the version pairing. The source and module +versions live in `calcit.cirru` and `deps.cirru`. For a new application, start with the maintained [Respo template](https://github.com/Respo/respo-calcit-workflow). Check its own @@ -36,14 +41,14 @@ not prove a JavaScript value has a Calcit schema. Keep JavaScript `bottom-tip` `respo.core/>>` selects a state branch and carries its cursor. A Respo event handler receives `(event, dispatch!)`; the dispatch function accepts exactly one value of the entry's `dispatch-op` type and returns Unit. For state changes, -package the cursor and new state in one application operation, then validate -its fields at the app boundary. A two-argument handler or custom +validate any raw cursor and payload where they enter the app, then construct +and dispatch one application operation. A two-argument handler or custom `on-select(path, d!)` callback does not make `d!` a two-argument dispatcher. Define an application Op enum and validate incoming state cursors/payloads before constructing it. With typed Reel, retain `State` in a Ref, -handle `typed/decode-control` separately, and use `typed/record-op` for domain -operations. `Date.now` is a host call, not a numeric constant; JS-FFI's +send `reel.typed/Control` to the separate `on-control!` callback, and use +`typed/record-op` for application operations. `Date.now` is a host call, not a numeric constant; JS-FFI's `date-now-snapshot` exposes a checked `:timestamp` value. This app uses Docs Workflow's **DocNode, Store and Op**, plus its @@ -55,8 +60,8 @@ interchangeable with that module's Store. Calcit's `get` returns an Option. Match `:some` / `:none`, or use `.unwrap-or` with a meaningful default; use `.unwrap` only for a real presence invariant. Do not insert arbitrary empty collections merely to silence checks. State -trees and browser event Maps remain heterogeneous boundaries: validate the -fields consumed rather than asserting every event is an unrelated Struct. +trees can hold heterogeneous values. Browser callbacks use `RespoEvent`, and +widget code validates the host fields it consumes. ## Verification and older chapters @@ -68,6 +73,6 @@ fragment or certify browser/WebSocket application behavior. The Beginner Guide, older implementation discussions under Guide, and several API chapters retain historical design notes. Their old macro expansions, direct JavaScript access and operation syntax are not -copy-ready 0.32.1 code. Consult the paired published module's `calcit query def` +copy-ready 0.40.0 code. Consult the paired published module's `calcit query def` and `query schema` views and the maintained template. Historical examples need section-by-section migration, not mechanical renaming without contract checks. diff --git a/docs/guide/component-states.md b/docs/guide/component-states.md index e5dcee3..4d5dcd9 100644 --- a/docs/guide/component-states.md +++ b/docs/guide/component-states.md @@ -6,7 +6,7 @@ boundary explicit; decode the fields a widget consumes before using them as a business model. A missing Map key returns `Option :none`, not an implicit nil. `respo.core/>>` selects a branch and extends its cursor. This small example uses -Tag keys, matching this documentation app's checked `List` operation path: +Tag keys. The published operation takes a `List`. ```cirru let @@ -21,22 +21,30 @@ present false, zero or empty string state with an arbitrary default. Match the Option returned by `get`; decode a present value according to the widget's actual state shape. -A Respo event handler receives two arguments: the event Map and the application -dispatch function. That dispatch function accepts **one** entry `dispatch-op` -value and returns Unit. Two handler arguments do not imply a two-argument -state dispatcher. Wrap the cursor and new state in the app's single operation: +A Respo event handler receives a `respo.schema/RespoEvent` and a dispatcher. +The dispatcher accepts one operation of the entry's `dispatch-op` type and +returns Unit. In this site, that operation is `docs-workflow.schema/Op`. +A custom callback such as `on-select(path, d!)` has two parameters, while each +call to `d!` still passes a single operation. + +Validate external data where it enters the app. For example, a widget that +stores a draft string can check an imported cursor and draft before +constructing the operation: ```cirru -fn (event d!) - d! $ :: :states cursor new-state - , &unit +let + raw-cursor $ parse-cirru-edn "|[] :task" + raw-draft $ parse-cirru-edn "|do |Edited" + cursor $ decode-map-as raw-cursor $ List respo.schema/CoordKey + draft $ decode-map-as raw-draft 'String + operation $ docs-workflow.schema/Op :states cursor draft + assert= (docs-workflow.schema/Op :states ([] :task) |Edited) operation ``` -This is a callback fragment in a context that already provides `cursor` and -`new-state`, not a standalone program. This site's application boundary checks -the raw Enum and payload before constructing the published nominal Op. -A custom callback such as `on-select(path, d!)` can also have two arguments; -that does not change the arity of the `d!` value passed to it. +Pass the validated operation to `d!` from the event handler. Use the +widget's own schema for its payload, such as a named Struct when it stores +several fields. To restore a saved store, decode the raw data against +`docs-workflow.schema/Store` before constructing `Op :hydrate-storage`. For the tree update itself, use the current three-argument helper: @@ -48,11 +56,9 @@ let `update-state-tree` and `respo.cursor/update-states` expose open boundaries; `update-states` also takes three arguments: store, cursor, new state. Their -results are not automatically proof of a nominal Store. This app's published -Docs Workflow updater checks the updated state Map before assigning it into -Store. Its app dispatcher validates cursors and hydrated stores before building -`docs-workflow.schema/Op`, then typed Reel records that operation. - -Use the actual checked `app.main/dispatch!` and `docs-workflow.updater/updater` -definitions as integration references. The removed `case-default` example and -the old two-argument `update-states` call are not current alternatives. +results require a check before assignment to a nominal Store. This site's +`app.main/dispatch!` takes an already constructed `Op` and records it in typed +Reel. The published `docs-workflow.updater/updater` checks the resulting state +Map before assigning it into Store. That Map check allows heterogeneous +payloads, so widget-specific validation belongs at the input boundary. +Reel controls enter through the separate `on-control!` callback. diff --git a/docs/home.md b/docs/home.md index de830ae..bfc04e2 100644 --- a/docs/home.md +++ b/docs/home.md @@ -4,7 +4,7 @@ Inspired by React and Reagent. -This site targets formal Calcit/procs **0.32.1**. Choose **Guide** in the sidebar +This site targets formal Calcit/procs **0.40.0**. Choose **Guide** in the sidebar for current migration notes. Beginner Guide and older API chapters retain historical material; not every snippet is ported or independently type-checked. From 7f0b9f38def767e95c0b8014d9d6a960c359007a Mon Sep 17 00:00:00 2001 From: tiye Date: Tue, 10 Nov 2026 12:54:06 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E7=9A=84=E7=8A=B6=E6=80=81=E9=94=AE=E7=B1=BB=E5=9E=8B=E5=92=8C?= =?UTF-8?q?=E8=8D=89=E7=A8=BF=E5=AF=BC=E5=85=A5=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/guide/component-states.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/guide/component-states.md b/docs/guide/component-states.md index 4d5dcd9..659ce6b 100644 --- a/docs/guide/component-states.md +++ b/docs/guide/component-states.md @@ -5,8 +5,9 @@ A component state branch is an open Map with a `:cursor` path and optional boundary explicit; decode the fields a widget consumes before using them as a business model. A missing Map key returns `Option :none`, not an implicit nil. -`respo.core/>>` selects a branch and extends its cursor. This small example uses -Tag keys. The published operation takes a `List`. +`respo.core/>>` takes one `respo.schema/CoordKey` and appends it to the +parent cursor. The resulting branch stores its path as a +`List`. ```cirru let @@ -27,15 +28,18 @@ returns Unit. In this site, that operation is `docs-workflow.schema/Op`. A custom callback such as `on-select(path, d!)` has two parameters, while each call to `d!` still passes a single operation. -Validate external data where it enters the app. For example, a widget that -stores a draft string can check an imported cursor and draft before -constructing the operation: +Validate external data where it enters the app. A widget that imports a +draft can check it as a String and use the cursor of its own state branch +when constructing the operation. ```cirru let - raw-cursor $ parse-cirru-edn "|[] :task" + states $ {} (:cursor $ []) + branch $ respo.core/>> states :task raw-draft $ parse-cirru-edn "|do |Edited" - cursor $ decode-map-as raw-cursor $ List respo.schema/CoordKey + cursor $ decode-map-as + .unwrap $ get branch :cursor + List respo.schema/CoordKey draft $ decode-map-as raw-draft 'String operation $ docs-workflow.schema/Op :states cursor draft assert= (docs-workflow.schema/Op :states ([] :task) |Edited) operation