@calcit/procs 0.12.14 → 0.12.15
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/.yarn/install-state.gz +0 -0
- package/editing-history/202504121453-map-to-record-rewrite.md +33 -0
- package/editing-history/2026-0326-2013-docs-frontmatter-and-module-search.md +1 -1
- package/editing-history/2026-0410-0011-snapshot-empty-version-pipe-marker.md +23 -0
- package/editing-history/202604121524-js-codegen-map-to-record.md +26 -0
- package/editing-history/202604121549-map-to-record-field-validation.md +29 -0
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/ts-src/calcit.procs.mts +1 -1
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 202504121453 - Automatic map-to-record rewrite in preprocessing
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
When a function parameter is typed as a struct type in its schema, but the caller passes a hashmap literal `{}`, the preprocessor now automatically rewrites the hashmap to a record construction `%{}` so that runtime gets a proper record with full type checking.
|
|
6
|
+
|
|
7
|
+
## Key implementation details
|
|
8
|
+
|
|
9
|
+
### type_annotation.rs
|
|
10
|
+
- Added `CalcitTypeAnnotation::resolve_to_struct()` — resolves `Struct`, `Record`, `TypeRef("ns/def")`, and `Optional(inner)` variants to concrete `CalcitStruct` definitions
|
|
11
|
+
- Added `resolve_struct_from_program(ns, def)` helper — looks up struct definitions from the program registry via `lookup_runtime_ready_registered` with fallback to `lookup_def_code_registered`
|
|
12
|
+
|
|
13
|
+
### preprocess.rs
|
|
14
|
+
- Added `try_rewrite_map_args_to_records()` — iterates processed args, checks each against `fn_info.arg_types[idx]`, calls `try_rewrite_single_map_to_record()` for potential rewrites
|
|
15
|
+
- Added `try_rewrite_single_map_to_record()` — validates arg is `List` with `Proc(NativeMap)` head, resolves expected type to struct, validates all keys are tags, builds `[Proc(NativeRecord), Struct(def), k1, v1, ...]`
|
|
16
|
+
- Integration point: `preprocess_list_call()` → `Calcit::Fn` match arm, between arg preprocessing and type checking
|
|
17
|
+
|
|
18
|
+
### AST transformation
|
|
19
|
+
- Input (hashmap literal): `[Proc(NativeMap), Tag(:x), 10, Tag(:y), 20]`
|
|
20
|
+
- Output (record literal): `[Proc(NativeRecord), Struct(Point2D), Tag(:x), 10, Tag(:y), 20]`
|
|
21
|
+
|
|
22
|
+
### Rewrite conditions
|
|
23
|
+
- Function has schema with `:args` referencing a struct type (TypeRef, Struct, or Record)
|
|
24
|
+
- Argument is a hashmap literal (`{}`) with tag keys
|
|
25
|
+
- Struct definition is resolvable at preprocess time
|
|
26
|
+
- If any condition fails, argument is left unchanged (safe fallback)
|
|
27
|
+
|
|
28
|
+
## Test
|
|
29
|
+
- Added `Point2D`, `sum-point`, `check-point-type`, `test-map-to-record` to `calcit/test-record.cirru`
|
|
30
|
+
- `check-point-type` uses `record?` to verify the rewrite produces actual records, not just maps
|
|
31
|
+
|
|
32
|
+
## Gotcha
|
|
33
|
+
- `cr tree insert-after` can create doubly-nested nodes — always verify with `tree show` after insertion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# 2026-0410-0011 — 修复 snapshot `configs.version` 对 `||` 空字符串的漏判
|
|
2
|
+
|
|
3
|
+
## 背景
|
|
4
|
+
|
|
5
|
+
PR `snapshot-format` 新增了空 `configs.version` 的回归测试,但 GitHub Actions 上加载 `compact.cirru` 时,`(:version ||)` 会解析成字符串 `"|"`,没有命中原先仅检查空白字符串的校验。
|
|
6
|
+
|
|
7
|
+
## 知识点
|
|
8
|
+
|
|
9
|
+
- Cirru 的空字符串字面量 `||` 在这条解析路径里会落成 `"|"`,不能只靠 `trim().is_empty()` 判断是否为空。
|
|
10
|
+
- `configs.version` 的校验要同时覆盖真正空串和这个 pipe marker,才能在加载阶段稳定报出 `configs.version cannot be empty`。
|
|
11
|
+
|
|
12
|
+
## 修改
|
|
13
|
+
|
|
14
|
+
- `src/snapshot.rs`
|
|
15
|
+
- 将 `parse_snapshot_config_string_field` 中 `version` 的空值判断扩展为:`text.trim().is_empty() || text == "|"`。
|
|
16
|
+
|
|
17
|
+
## 验证
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cargo fmt -- src/snapshot.rs
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
本地 `cargo test` 在当前机器仍受 macOS 链接器环境影响(`ld: library 'System' not found`),实际正确性改由 GitHub Actions 复核。
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# JS Codegen Fix for Map-to-Record Rewrite
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
The map-to-record rewrite (from previous commit) inserted `Calcit::Struct` directly into the AST. The interpreter handles this, but JS codegen (`emit_js.rs` line 319) has no arm for `Calcit::Struct` → panics with `unreachable!`.
|
|
5
|
+
|
|
6
|
+
## Key Insight
|
|
7
|
+
The `%{}` macro normally expands to `&%{}` with a **symbol/import reference** as the first arg (not a literal `Calcit::Struct`). JS codegen relies on this — it emits the symbol as a variable reference (e.g., `Element`), and the JS runtime `_$n__PCT__$M_` function accepts the struct object at runtime.
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
1. Added `resolve_to_struct_with_ref()` to `CalcitTypeAnnotation` — returns `Option<(CalcitStruct, Option<(Arc<str>, Arc<str>)>)>` with ns/def path from TypeRef annotations.
|
|
11
|
+
2. Modified `try_rewrite_single_map_to_record()` to emit `Calcit::Import(CalcitImport { ... })` instead of `Calcit::Struct`:
|
|
12
|
+
- `ImportInfo::SameFile` when struct is in same namespace (avoids self-import duplicate declaration)
|
|
13
|
+
- `ImportInfo::NsReferDef` when struct is in a different namespace (generates proper cross-ns import)
|
|
14
|
+
- Falls back to `Calcit::Struct` only when no ns/def path is available
|
|
15
|
+
|
|
16
|
+
## Pitfall: Self-Import Duplicate Declaration
|
|
17
|
+
First attempt used `NsReferDef` for all imports — caused `SyntaxError: Identifier 'Point2D' has already been declared` because a self-import was generated when struct is in same namespace. Fix: detect `ns == file_ns` and use `SameFile`.
|
|
18
|
+
|
|
19
|
+
## Verification in Respo
|
|
20
|
+
- Typed `element->string` as `'respo.schema/Element`, `make-string` as `'respo.schema/Component`
|
|
21
|
+
- Test passes `{}` map to `element->string` → auto-rewritten to `%{} Element ...` record construction
|
|
22
|
+
- Generated JS: `import { Element } from "./respo.schema.mjs"` + `$clt._$n__PCT__$M_(Element, ...)`
|
|
23
|
+
|
|
24
|
+
## Files Changed
|
|
25
|
+
- `src/calcit/type_annotation.rs`: Added `resolve_to_struct_with_ref()`
|
|
26
|
+
- `src/runner/preprocess.rs`: Emit Import reference in `try_rewrite_single_map_to_record()`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Map-to-Record Field Validation and Nil Fill
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
Map-to-record rewrite was passing through ALL map keys without validation, and emitting only
|
|
5
|
+
the keys present in the map. This caused:
|
|
6
|
+
1. Maps with keys not in the struct (e.g., `:x`) being incorrectly rewritten to records
|
|
7
|
+
2. "fields size does not match" runtime error when the map has fewer keys than struct fields
|
|
8
|
+
|
|
9
|
+
## Fix (preprocess.rs)
|
|
10
|
+
1. **Field validation**: Check each map key against `struct_def.fields`. If any key is not a
|
|
11
|
+
valid struct field, skip the rewrite entirely (stay as map).
|
|
12
|
+
2. **Nil fill**: Emit ALL struct fields in definition order. For fields not present in the map,
|
|
13
|
+
emit `Calcit::Nil`. This ensures the record always has the correct field count.
|
|
14
|
+
3. **HashMap tracking**: Build a `HashMap<EdnTag, &Calcit>` of provided fields for O(1) lookup
|
|
15
|
+
during emission.
|
|
16
|
+
|
|
17
|
+
## Key Types
|
|
18
|
+
- `struct_def.fields` is `Vec<EdnTag>` — compare with `EdnTag` directly, not `Arc<str>`
|
|
19
|
+
- `provided_fields` is `HashMap<EdnTag, &Calcit>` — avoids the `Arc<str>: Borrow<EdnTag>` issue
|
|
20
|
+
|
|
21
|
+
## Respo DomProps Design
|
|
22
|
+
- 29 fields with `(:: :optional <type>)` annotations
|
|
23
|
+
- Strings: class-name, id, type, href, src, placeholder, name, title, data-name, data-comp, target
|
|
24
|
+
- Dynamic: style (map), value, inner-text
|
|
25
|
+
- Bools: disabled, checked, spell-check, read-only, selected
|
|
26
|
+
- Number: tab-index
|
|
27
|
+
- Fns: on-click, on-input, on-focus, on-blur, on-keydown, on-keyup, on-change
|
|
28
|
+
- Maps: on, event
|
|
29
|
+
- `create-element`/`create-list-element` convert record props to map via `&record:to-map`
|
package/lib/package.json
CHANGED
package/package.json
CHANGED
package/ts-src/calcit.procs.mts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from "./calcit-data.mjs";
|
|
23
23
|
|
|
24
24
|
import { CalcitRef } from "./js-ref.mjs";
|
|
25
|
-
import {
|
|
25
|
+
import { CalcitRecord } from "./js-record.mjs";
|
|
26
26
|
import { CalcitImpl } from "./js-impl.mjs";
|
|
27
27
|
import { CalcitStruct } from "./js-struct.mjs";
|
|
28
28
|
import { CalcitEnum } from "./js-enum.mjs";
|