sinwan-compiler 0.2.7 → 0.2.8

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.
@@ -43,8 +43,17 @@ function isBuiltinReactiveProp(componentName, attrName) {
43
43
  return false;
44
44
  return entry.reactiveProps.has(attrName);
45
45
  }
46
- function isBuiltinControlFlowComponent(componentName) {
47
- return !!componentName && BUILTIN_REACTIVE_PROPS.has(componentName);
46
+ function isReactiveContainerPassThrough(expr, scope) {
47
+ let node = expr;
48
+ while (t.isTSNonNullExpression(node)) {
49
+ node = node.expression;
50
+ }
51
+ if (!t.isIdentifier(node))
52
+ return false;
53
+ const binding = scope.bindings.get(node.name);
54
+ if (!binding)
55
+ return false;
56
+ return binding.kind === "mutable" || binding.kind === "prop";
48
57
  }
49
58
  function trackReactiveImports2(ast) {
50
59
  const names = {
@@ -611,7 +620,8 @@ function createBindingDescriptor(expr, exprPath, options) {
611
620
  wrapExpression(expr)
612
621
  ]);
613
622
  }
614
- if (t.isIdentifier(expr, { name: "children" })) {
623
+ const compInfo = getComponentExpressionInfo(exprPath);
624
+ if (t.isIdentifier(expr, { name: "children" }) || compInfo.isComponent && compInfo.attributeName === null) {
615
625
  return wrapExpression(expr);
616
626
  }
617
627
  return t.callExpression(t.identifier("_$bindText"), [wrapExpression(expr)]);
@@ -1050,15 +1060,10 @@ function wrapReactiveExpressions2(ast, options = {}) {
1050
1060
  JSXExpressionContainer(exprPath) {
1051
1061
  const expr = exprPath.node.expression;
1052
1062
  const compInfo = getComponentExpressionInfo(exprPath);
1053
- if (compInfo.isComponent) {
1054
- if (compInfo.attributeName !== null) {
1055
- if (!compInfo.componentName || !isReactiveComponentProp(compInfo.componentName, compInfo.attributeName, componentNames, reactiveProps, importedReactiveProps)) {
1056
- return;
1057
- }
1058
- } else {
1059
- if (!isBuiltinControlFlowComponent(compInfo.componentName)) {
1060
- return;
1061
- }
1063
+ if (compInfo.isComponent && compInfo.attributeName !== null) {
1064
+ const knownProp = !!compInfo.componentName && isReactiveComponentProp(compInfo.componentName, compInfo.attributeName, componentNames, reactiveProps, importedReactiveProps);
1065
+ if (!knownProp && (!shouldWrap(expr, scope) || isReactiveContainerPassThrough(expr, scope))) {
1066
+ return;
1062
1067
  }
1063
1068
  }
1064
1069
  if (shouldWrap(expr, scope)) {
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  runAnalyzeCli2,
5
5
  runCliIfMain2
6
- } from "./chunk-edjqytm9.js";
6
+ } from "./chunk-v4zrz7j7.js";
7
7
  export {
8
8
  runAnalyzeCli2 as runAnalyzeCli,
9
9
  runCliIfMain2 as runCliIfMain
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  propagateReactiveProps2,
18
18
  wrapReactiveExpressions2,
19
19
  runAnalyzeCli2
20
- } from "./chunk-edjqytm9.js";
20
+ } from "./chunk-v4zrz7j7.js";
21
21
 
22
22
  // src/transform.ts
23
23
  import { parse } from "@babel/parser";
@@ -19,9 +19,9 @@ export interface TransformOptions {
19
19
  /**
20
20
  * Resolves an import source (e.g. "./Child") to an absolute file path,
21
21
  * relative to the file being transformed. Used to look up reactive-prop
22
- * metadata for components imported from other modules so reactive values
23
- * passed to them are wrapped at the call site. When omitted, cross-module
24
- * component call sites fall back to the conservative (non-wrapping) behavior.
22
+ * metadata for components imported from other modules. Derived reads
23
+ * (`title={n.value}`) wrap even without metadata; bare signal/store
24
+ * identifiers stay unwrapped.
25
25
  */
26
26
  resolveImport?: (source: string, fromFile: string) => string | null;
27
27
  }
package/docs/README.md CHANGED
@@ -19,6 +19,7 @@ autoWrapComponents() plain `export function App()` → cc(App)
19
19
  │
20
20
  ▼
21
21
  wrapReactiveExpressions() {count.value} → {() => count.value}
22
+ also wraps those reads as children/attrs of <Label>
22
23
  │
23
24
  ▼
24
25
  hoist templates <div class="card">…</div> → _$tmpl_N
package/docs/transform.md CHANGED
@@ -22,6 +22,8 @@ The compiler turns the child into a lazy getter:
22
22
  <p>{() => count.value}</p>
23
23
  ```
24
24
 
25
+ The same wrap applies to **user-component children**. `<Label>{checked.value ? "On" : "Off"}</Label>` becomes `{() => checked.value ? "On" : "Off"}` so a one-shot `cc()` parent does not snapshot the string.
26
+
25
27
  The runtime runs that function inside an effect and updates the text when `count` changes.
26
28
 
27
29
  ## Automatic `cc()` wrapping
@@ -83,9 +85,12 @@ Not wrapped:
83
85
 
84
86
  **Native elements** (`div`, `p`, `button`, …): wrap reactive children and attributes.
85
87
 
86
- **User components** (`<Child title={…} />`): wrap a prop only if that prop is reactive for `Child` (local call graph, analyzer metadata, or a conservative fallback for exported components). Children forwarded to a user component stay unwrapped so the child can read `children` itself.
88
+ **User components** (`<Label>`, `<Child title={…} />`):
89
+
90
+ - **Children:** wrap reactive reads the same way as DOM text (`{count.value}`, `{checked.value ? "On" : "Off"}`) so `cc()` parents do not snapshot the value. Use a getter (`() => …`), never `_$bindText`, because the child may render nodes as well as strings. Render-prop functions (`{(v) => …}`) stay untouched.
91
+ - **Props:** wrap a prop if it is known-reactive for that component (built-in registry, local call graph, analyzer metadata). For *unknown* imported components, still wrap **derived reads** (`htmlFor={id.value}`, `disabled={off.value}`) and leave **container pass-through** alone (`checked={checked}`, `user={user}`) so the child receives the signal or store proxy.
87
92
 
88
- **Built-in control-flow** components wrap specific props, and they *do* wrap reactive expression children (those children render directly):
93
+ **Built-in control-flow** components wrap specific props, and they wrap reactive expression children (those children render directly):
89
94
 
90
95
  | Component | Reactive props |
91
96
  | --------- | -------------- |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinwan-compiler",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Shared compiler core for Sinwan plugins",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",