From 818f0bbacd2726303f3c465176c1eb63b9ab61c2 Mon Sep 17 00:00:00 2001 From: tiye Date: Sun, 8 Nov 2026 21:20:31 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=8D=87=E7=BA=A7=20Markup=20=E5=88=B0=20C?= =?UTF-8?q?alcit=200.38.0=20=E5=92=8C=E7=B1=BB=E5=9E=8B=E5=8C=96=20Reel=20?= =?UTF-8?q?=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/upload.yaml | 4 +-- README.md | 8 ++--- calcit.cirru | 56 +++++++++++------------------- deps.cirru | 4 +-- package.json | 2 +- scripts/typed-reel-render.test.mjs | 14 ++++---- yarn.lock | 10 +++--- 7 files changed, 42 insertions(+), 56 deletions(-) diff --git a/.github/workflows/upload.yaml b/.github/workflows/upload.yaml index 520d956..14c66db 100644 --- a/.github/workflows/upload.yaml +++ b/.github/workflows/upload.yaml @@ -33,7 +33,7 @@ jobs: corepack prepare yarn@4.18.0 --activate yarn --version - - uses: calcit-lang/setup-calcit@v1.5.0 + - uses: calcit-lang/setup-calcit@v1.5.1 with: tools: calcit,caps caps-version: "0.1.1" @@ -104,7 +104,7 @@ jobs: - name: Upload and verify frontend assets if: steps.cos-credentials.outputs.available == 'true' - uses: worktools/cos-upload-action@v1.2.0 + uses: worktools/cos-upload-action@v1.3.0 with: source-dir: dist bucket: ${{ secrets.COS_BUCKET }} diff --git a/README.md b/README.md index 43d62bd..03f1101 100644 --- a/README.md +++ b/README.md @@ -6,19 +6,19 @@ Demo http://repo.respo-mvc.org/markup/ . ### Usages -本次候选 **0.0.5** 配对正式 Calcit / `@calcit/procs` **0.37.0**。 +本次候选 **0.0.5** 配对正式 Calcit / `@calcit/procs` **0.38.0**。 消费者需重新安装完整依赖图、生成 JS 并完整刷新页面。Content 输入、Run、Reel 调试工具、 存档 key 和格式保持;Demo 不新增 Markdown 解析功能。UI/Reel 跨 minor 升级可能有样式差异。 0.0.5 尚未发布,正式 tag 出现前不要将本分支当作已发布依赖。 -依赖使用已发布的 Respo **0.19.5**、UI **0.15.2**、Reel **0.10.0**、JS-FFI **0.2.13**, +依赖使用已发布的 Respo **0.19.5**、UI **0.15.2**、Reel **0.11.0**、JS-FFI **0.2.13**, 传递 Router **0.12.2**;不再使用 Reel / Router 的旧 alpha 图。 -两个 DOM 回调使用真实 RespoEvent 和单 Enum dispatch,输入值由公开 `event-value` 检查为 String。 +编辑回调派发具体 `Op`,Reel 0.11.0 面板与快捷键通过独立回调传递 `Control`。输入值由公开 `event-value` 检查为 String。 原 Reel 的 `read-field` 已删除;此处直接读取数据,保留 Map/Struct 字段读取及缺失值语义。 两个间隔分别保持 8 / 8px,开发态子节点显式使用 Option。 根渲染和原 SSR 回归均按 Respo 的公开 managed memo frame 合同包住构造与渲染。 -应用 Op 与 Store 仍为原名义类型。开放 `AnyEnum` 分发入口必须检查后转为 Op;它也承载 Reel 控制事件。 +应用 Op 与 Store 仍为原名义类型。存档继续在构造 `Op :hydrate-storage` 前独立校验。 Store.states 是应用与 Reel 共用的真实异构状态树,继续保留 Map Dynamic Dynamic;不以含 Dynamic 的 union 或伪泛型隐藏该边界。固定 Site 已是具体 Struct,不为本次升级引入无实际需要的 union。 diff --git a/calcit.cirru b/calcit.cirru index d54634d..3279eaf 100644 --- a/calcit.cirru +++ b/calcit.cirru @@ -6,12 +6,12 @@ {} (:description |) (:init-fn 'app.main/main!) (:mode :js) (:reload-fn 'app.main/reload!) (:target :browser) :feature-policy $ {} :modules $ [] |respo.calcit/ |respo-ui.calcit/ |reel.calcit/ |js-ffi/ - :type-slots $ {} $ :dispatch-op 'app.schema/DispatchOp + :type-slots $ {} $ :dispatch-op 'app.schema/Op :files $ {} 'app.comp.container $ %{} 'FileEntry :defs $ {} $ 'comp-container %{} 'CodeEntry (:doc |) - :code $ quote $ defcomp comp-container (reel) + :code $ quote $ defcomp comp-container (reel on-control!) let store $ :store reel states $ :states store @@ -54,10 +54,12 @@ -> Unit println content if dev? - Option :some $ comp-typed-reel (>> states :reel) reel $ {} + Option :some $ comp-typed-reel (>> states :reel) reel ({}) on-control! Option :none :examples $ [] - :schema $ quote $ Fn (reel.typed/State app.schema/Op app.schema/Store) (-> respo.schema/Component) + :schema $ quote $ Fn (reel.typed/State app.schema/Op app.schema/Store) + Fn reel.typed/Control $ -> Unit + -> respo.schema/Component :ns $ %{} 'NsEntry (:doc |) :code $ quote $ ns app.comp.container :require (respo-ui.css :as css) @@ -93,14 +95,11 @@ 'dispatch! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn dispatch! (op) when config/dev? $ js/console.log |Dispatch: op - reset! *reel $ match (typed/decode-control op) - (:some action) (typed/apply-control updater @*reel action) - (:none) - typed/record-op updater @*reel (schema/decode-op op) (generate-id!) - :timestamp $ date-now-snapshot + reset! *reel $ typed/record-op updater @*reel op (generate-id!) + :timestamp $ date-now-snapshot , &unit :examples $ [] - :schema $ quote $ Fn AnyEnum (-> Unit) (:features :js-ffi) + :schema $ quote $ Fn app.schema/Op (-> Unit) (:features :js-ffi) 'main! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn main! () println "|Running mode:" $ if config/dev? |dev |release @@ -120,7 +119,7 @@ add-watch! *reel :changes $ fn (reel prev) hint-fn $ Fn (reel.typed/State app.schema/Op app.schema/Store) (reel.typed/State app.schema/Op app.schema/Store) (-> Unit) render-app! - listen-devtools! |k dispatch! + listen-devtools! |k on-control! set-before-unload! $ fn (event) hint-fn $ Fn js-ffi.browser/EventHost $ -> Unit persist-storage! @@ -138,6 +137,12 @@ .unwrap $ query-selector |.app :examples $ [] :schema $ quote respo.dom/DomElement + 'on-control! $ %{} 'CodeEntry (:doc |) + :code $ quote $ defn on-control! (control) + reset! *reel $ typed/apply-control updater @*reel control + , &unit + :examples $ [] + :schema $ quote $ Fn reel.typed/Control (-> Unit) 'persist-storage! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn persist-storage! () println "|Saved at" $ :iso $ date-now-snapshot @@ -160,16 +165,15 @@ :schema $ quote $ Fn (-> Unit) (:features :js-ffi) 'render-app! $ %{} 'CodeEntry (:doc |) :code $ quote $ defn render-app! () - with-memo-frame $ fn () $ render! mount-target (comp-container @*reel) - fn (op) - hint-fn $ Fn AnyEnum $ -> Unit - if (enum? op) (dispatch! op) (raise "|Expected Markup operation Enum") + render-with! mount-target + fn () $ comp-container @*reel 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! app.comp.container :refer $ comp-container app.updater :refer $ updater app.schema :as schema @@ -181,13 +185,8 @@ reel.typed :as typed js-ffi.browser :refer $ add-event-listener! set-before-unload! set-interval! storage-get storage-set! visibility-state respo.ffi.browser :refer $ query-selector - respo.memo :refer $ with-memo-frame 'app.schema $ %{} 'FileEntry :defs $ {} - 'DispatchOp $ %{} 'CodeEntry (:doc "|Respo 入口事件合同,容纳应用和 Reel 控制事件;代表值不发送。") - :code $ quote $ def DispatchOp (:: :unhandled) - :examples $ [] - :schema $ quote AnyEnum 'Op $ %{} 'CodeEntry (:doc |) :code $ quote $ defenum Op :states (List respo.schema/CoordKey) Dynamic @@ -199,21 +198,6 @@ :states $ Map Dynamic Dynamic :examples $ [] :schema $ quote StructDef - 'decode-op $ %{} 'CodeEntry - :doc "|将 Respo/Reel 传入的单 Enum 规范为应用 Op,检查游标列表与存档载荷;不直接断言 nominal 类型。" - :code $ quote $ defn decode-op (op) - match op - (:states cursor data) - Op :states - decode-map-as cursor $ List respo.schema/CoordKey - , data - (:hydrate-storage data) - match (decode-store data) - (:some stored) (Op :hydrate-storage stored) - (:none) (raise "|Invalid saved Markup state") - _ $ raise "|Unknown Markup operation" - :examples $ [] - :schema $ quote $ Fn AnyEnum (-> app.schema/Op) 'decode-store $ %{} 'CodeEntry :doc "|本地存档/旧存档的开放入口:已有 Store 保留身份,Map 验证后构造成 Store。states 是应用与 Reel 共用的异构 UI 状态树,不伪装成泛型关系。" :code $ quote $ defn decode-store (data) diff --git a/deps.cirru b/deps.cirru index bb608eb..f43b32c 100644 --- a/deps.cirru +++ b/deps.cirru @@ -1,7 +1,7 @@ -{} (:calcit-version |0.37.0) +{} (:calcit-version |0.38.0) :version |0.0.5 - :dependencies $ {} (|Respo/reel.calcit |0.10.0) + :dependencies $ {} (|Respo/reel.calcit |0.11.0) |Respo/respo-ui.calcit |0.15.2 |Respo/respo.calcit |0.19.5 |calcit-lang/js-ffi |0.2.13 diff --git a/package.json b/package.json index f97596f..731305a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "packageManager": "yarn@4.18.0", "dependencies": { - "@calcit/procs": "0.37.0" + "@calcit/procs": "0.38.0" }, "devDependencies": { "bottom-tip": "^0.1.5", diff --git a/scripts/typed-reel-render.test.mjs b/scripts/typed-reel-render.test.mjs index 189cbe4..44af14f 100644 --- a/scripts/typed-reel-render.test.mjs +++ b/scripts/typed-reel-render.test.mjs @@ -4,12 +4,12 @@ import test from 'node:test'; process.env.mode = 'dev'; const { comp_container } = await import('../js-out/app.comp.container.mjs'); -const { store, decode_op, decode_store } = await import('../js-out/app.schema.mjs'); +const { Op, store, decode_store } = await import('../js-out/app.schema.mjs'); const { updater } = await import('../js-out/app.updater.mjs'); const { new_reel, toggle_display, record_op, refresh } = await import('../js-out/reel.typed.mjs'); const { make_string } = await import('../js-out/respo.render.html.mjs'); const { with_memo_frame } = await import('../js-out/respo.memo.mjs'); -const renderHtml = (reel) => with_memo_frame(() => make_string(comp_container(reel))); +const renderHtml = (reel) => with_memo_frame(() => make_string(comp_container(reel, () => {}))); const clt = await import('../js-out/calcit.core.mjs'); // Fixed synthetic archive produced by the clean 0.27.0 tag's native formatter, @@ -31,8 +31,9 @@ test('renders the typed Reel devtools with an empty history', () => { test('content edits survive Reel replay and the existing saved-state format', () => { const field = (value, key) => clt.get(value, clt.init_tags([key])[key]).extra[0]; - const wire = clt.parse_cirru_edn(':: :states ([]) ({} (:content |中文🐈))'); - const reel = record_op(updater, new_reel(store), decode_op(wire), 'edit', 1); + const t = clt.init_tags(['states', 'content']); + const edit = clt._PCT__$o__$o_(Op, t.states, clt._$L_(), clt._$n__$M_(t.content, '中文🐈')); + const reel = record_op(updater, new_reel(store), edit, 'edit', 1); const current = field(reel, 'store'); assert.equal(field(field(field(current, 'states'), 'data'), 'content'), '中文🐈'); assert.match(renderHtml(reel), /中文🐈/); @@ -48,8 +49,9 @@ test('content edits survive Reel replay and the existing saved-state format', () test('hydrates the fixed pre-upgrade archive through the typed Reel update path', () => { const field = (value, key) => clt.get(value, clt.init_tags([key])[key]).extra[0]; const legacy = clt.parse_cirru_edn(PRE_031_ARCHIVE); - const hydrate = clt._$o__$o_(clt.init_tags(['hydrate-storage'])['hydrate-storage'], legacy); - const reel = record_op(updater, new_reel(store), decode_op(hydrate), 'legacy-archive', 1); + const stored = clt.option_$o_unwrap(decode_store(legacy)); + const hydrate = clt._PCT__$o__$o_(Op, clt.init_tags(['hydrate-storage'])['hydrate-storage'], stored); + const reel = record_op(updater, new_reel(store), hydrate, 'legacy-archive', 1); const restored = field(reel, 'store'); const expected = clt.assoc(store, clt.init_tags(['states']).states, field(legacy, 'states')); assert.equal(clt._$n__$e_(restored, expected), true); diff --git a/yarn.lock b/yarn.lock index ba23b81..66cb47e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,15 +12,15 @@ __metadata: languageName: node linkType: hard -"@calcit/procs@npm:0.37.0": - version: 0.37.0 - resolution: "@calcit/procs@npm:0.37.0" +"@calcit/procs@npm:0.38.0": + version: 0.38.0 + resolution: "@calcit/procs@npm:0.38.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/38efd6a08b096419d41aa1d502a573ecbb415867caa18ee69142010e5d6c285f36f47d4e4334c33eff15617b1eff980f29662176422acb1bbf4fac5fdca83178 + checksum: 10c0/8d1910cc739b1b23b5d5b549fb519053b2a578ab05f11814d28c09fbf4c18be5d3a14f52ff3b9bea4c9a3a42ab79d56a59021cd533d68ecc5e26e61da1e347ba languageName: node linkType: hard @@ -637,7 +637,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: - "@calcit/procs": "npm:0.37.0" + "@calcit/procs": "npm:0.38.0" bottom-tip: "npm:^0.1.5" vite: "npm:8.3.3" languageName: unknown From 0af56b08649db6d96a5c4d9de8b91e50bb28c4f2 Mon Sep 17 00:00:00 2001 From: tiye Date: Sun, 8 Nov 2026 21:26:59 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=AD=A3=E5=BC=8F=20Reel=20=E5=92=8C=20COS?= =?UTF-8?q?=20=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 03f1101..43a79bf 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,13 @@ yarn vite Frontend build uses `VITE_BASE_URL`, pointing to `https://cos-sh.tiye.me/Respo/markup/` on main and `https://cos-sh.tiye.me/Respo/markup/pr////` for PR previews. -COS action v1.2.0 uploads `dist` and verifies through `public-base-url`; +COS action v1.3.0 uploads `dist` and verifies through `public-base-url`; no separate upload verification script is needed. Production server deployment keeps its original source and destination; PRs do not deploy to the server. 同一 PR 的上传使用独立队列,生产上传使用另一个队列;保留排队任务, 不取消正在执行的上传。每次运行及重试使用不同预览路径,生产路径不变。 -Action 使用精确正式 tag v1.2.0,验证由 Action 内置能力完成。 +Action 使用精确正式 tag v1.3.0,验证由 Action 内置能力完成。 部署路径、COS 内置 verify 和前端/服务端边界不变。PR 不合并或自动部署生产。