effectable 1.2.0-canary.10 → 1.2.0-canary.11

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.
@@ -5,6 +5,12 @@
5
5
  * Holds `state`, updates it via {@link Component.setState}, and after each update calls
6
6
  * {@link Component.onUpdate}.
7
7
  *
8
+ * **Single writer:** only {@link Component.setState} may change state after construction
9
+ * (triggers `onUpdate` and reconcile schedule). Direct `this.state = …` after init emits
10
+ * `console.warn` and does **not** change `#state`. Constructor init (`super(props, initial)`
11
+ * or `this.state = …` in the constructor body) is allowed without warning. If reconciliation
12
+ * is not needed, use a ref.
13
+ *
8
14
  * **Modes:**
9
15
  * - **Standalone** — `Component` as a lightweight stateful object without GraphRuntime: `setState`
10
16
  * immediately leads to `onUpdate`, with no “only after mount” restriction.
@@ -50,6 +56,7 @@ export type SetStateUpdate<S, P = unknown> = Partial<S> | ((prevState: S, props:
50
56
  * ```
51
57
  */
52
58
  export declare abstract class Component<S = unknown, P = unknown> implements Lifecycle {
59
+ #private;
53
60
  /**
54
61
  * Opt-in flag for HFT components: if `true`, {@link Component.setState} applies
55
62
  * updates **in-place** on the current `this.state` instead of creating a new object via spread.
@@ -66,10 +73,19 @@ export declare abstract class Component<S = unknown, P = unknown> implements Lif
66
73
  * ```
67
74
  */
68
75
  static readonly mutableState: boolean;
69
- /** Current instance state after the last assignment in {@link Component.setState}. */
70
- state: S;
71
76
  /** Instance inputs: filled by GraphRuntime, connect-HOC, or calling code. */
72
77
  props: P;
78
+ /**
79
+ * Current instance state after the last commit in {@link Component.setState}
80
+ * (or constructor init). Read freely; do not assign after construction — use `setState`.
81
+ */
82
+ get state(): S;
83
+ /**
84
+ * Direct assignment after construction is forbidden: emits {@link console.warn} and leaves
85
+ * `#state` unchanged (no write, no `onUpdate`, no reconcile). Prefer {@link Component.setState}.
86
+ * Allowed without warning during construction (`super(props, initial)` or subclass ctor body).
87
+ */
88
+ set state(value: S);
73
89
  /**
74
90
  * @param {P} props Props available in the {@link Component.setState} callback and in the subclass.
75
91
  * @param {S} [initialState] Initial state; if omitted, an empty object is used as `S`.
@@ -1 +1 @@
1
- {"version":3,"file":"Component.d.ts","sourceRoot":"","sources":["../../src/component/Component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,IACrC,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,8BAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,CACxD,YAAW,SAAS;IAClB;;;;;;;;;;;;;;OAcG;IACH,gBAAuB,YAAY,EAAE,OAAO,CAAS;IAErD,sFAAsF;IAC/E,KAAK,EAAE,CAAC,CAAC;IAEhB,6EAA6E;IACtE,KAAK,EAAE,CAAC,CAAC;IAEhB;;;OAGG;gBACU,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;IAKvC;;;;;;;;;OASG;IACI,QAAQ,CAAE,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAoCpD;;;;;;;;;OASG;IACI,QAAQ,CAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAI1C;;;;;;OAMG;IACH,OAAO,CAAC,IAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,SAAS,CAAC,IAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAK,kBAAkB,GAAG,kBAAkB,EAAE,GAAG,IAAI;CAC9D"}
1
+ {"version":3,"file":"Component.d.ts","sourceRoot":"","sources":["../../src/component/Component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,IACrC,OAAO,CAAC,CAAC,CAAC,GACV,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAQ7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,8BAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,CACxD,YAAW,SAAS;;IAClB;;;;;;;;;;;;;;OAcG;IACH,gBAAuB,YAAY,EAAE,OAAO,CAAS;IAWrD,6EAA6E;IACtE,KAAK,EAAE,CAAC,CAAC;IAEhB;;;OAGG;IACH,IAAW,KAAK,IAAK,CAAC,CAErB;IAED;;;;OAIG;IACH,IAAW,KAAK,CAAE,KAAK,EAAE,CAAC,EAMzB;IAED;;;OAGG;gBACU,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;IAWvC;;;;;;;;;OASG;IACI,QAAQ,CAAE,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAoCpD;;;;;;;;;OASG;IACI,QAAQ,CAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAI1C;;;;;;OAMG;IACH,OAAO,CAAC,IAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,SAAS,CAAC,IAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnC;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAK,kBAAkB,GAAG,kBAAkB,EAAE,GAAG,IAAI;CAC9D"}
@@ -6,6 +6,12 @@
6
6
  * Holds `state`, updates it via {@link Component.setState}, and after each update calls
7
7
  * {@link Component.onUpdate}.
8
8
  *
9
+ * **Single writer:** only {@link Component.setState} may change state after construction
10
+ * (triggers `onUpdate` and reconcile schedule). Direct `this.state = …` after init emits
11
+ * `console.warn` and does **not** change `#state`. Constructor init (`super(props, initial)`
12
+ * or `this.state = …` in the constructor body) is allowed without warning. If reconciliation
13
+ * is not needed, use a ref.
14
+ *
9
15
  * **Modes:**
10
16
  * - **Standalone** — `Component` as a lightweight stateful object without GraphRuntime: `setState`
11
17
  * immediately leads to `onUpdate`, with no “only after mount” restriction.
@@ -21,6 +27,10 @@
21
27
  Object.defineProperty(exports, "__esModule", { value: true });
22
28
  exports.Component = void 0;
23
29
  const types_1 = require("./types");
30
+ /** Warn text for forbidden direct `this.state =` after construction. */
31
+ const DIRECT_STATE_ASSIGNMENT_WARN = '[Effectable] Component: direct assignment to `state` is not supported. ' +
32
+ 'Use `setState(...)` so `onUpdate` and reconcile run. ' +
33
+ 'If you do not need reconciliation, store the value in a ref (`@UseRef`) instead of state.';
24
34
  /**
25
35
  * Abstract base class with state and lifecycle.
26
36
  * Implements the {@link Lifecycle} contract: `onMount` → `onUpdate*` → `onUnmount`.
@@ -60,17 +70,47 @@ class Component {
60
70
  * ```
61
71
  */
62
72
  static mutableState = false;
63
- /** Current instance state after the last assignment in {@link Component.setState}. */
64
- state;
73
+ /** Backing store for {@link Component.state}. Written only by init, setter, or {@link Component.setState}. */
74
+ #state;
75
+ /**
76
+ * When `true`, direct `this.state =` does not warn (constructor init window).
77
+ * Closed after the full `new` constructor chain finishes (microtask).
78
+ */
79
+ #allowDirectStateWrite;
65
80
  /** Instance inputs: filled by GraphRuntime, connect-HOC, or calling code. */
66
81
  props;
82
+ /**
83
+ * Current instance state after the last commit in {@link Component.setState}
84
+ * (or constructor init). Read freely; do not assign after construction — use `setState`.
85
+ */
86
+ get state() {
87
+ return this.#state;
88
+ }
89
+ /**
90
+ * Direct assignment after construction is forbidden: emits {@link console.warn} and leaves
91
+ * `#state` unchanged (no write, no `onUpdate`, no reconcile). Prefer {@link Component.setState}.
92
+ * Allowed without warning during construction (`super(props, initial)` or subclass ctor body).
93
+ */
94
+ set state(value) {
95
+ if (!this.#allowDirectStateWrite) {
96
+ console.warn(DIRECT_STATE_ASSIGNMENT_WARN);
97
+ return;
98
+ }
99
+ this.#state = value;
100
+ }
67
101
  /**
68
102
  * @param {P} props Props available in the {@link Component.setState} callback and in the subclass.
69
103
  * @param {S} [initialState] Initial state; if omitted, an empty object is used as `S`.
70
104
  */
71
105
  constructor(props, initialState) {
72
106
  this.props = props;
73
- this.state = (initialState ?? {});
107
+ this.#allowDirectStateWrite = true;
108
+ this.#state = (initialState ?? {});
109
+ // Subclass constructor bodies run synchronously after `super()` and may assign `this.state`.
110
+ // Close the gate once the full `new` constructor chain has finished.
111
+ queueMicrotask(() => {
112
+ this.#allowDirectStateWrite = false;
113
+ });
74
114
  }
75
115
  /**
76
116
  * Computes the next state as a shallow merge of `prev` with the update object or with the
@@ -83,7 +123,7 @@ class Component {
83
123
  * @returns {void}
84
124
  */
85
125
  setState(update) {
86
- const prev = this.state;
126
+ const prev = this.#state;
87
127
  const delta = typeof update === 'function'
88
128
  ? update(prev, this.props)
89
129
  : update;
@@ -107,7 +147,7 @@ class Component {
107
147
  }
108
148
  // Shallow-copy previous state and delta to avoid mutating the original state
109
149
  const next = { ...prev, ...delta };
110
- this.state = next;
150
+ this.#state = next;
111
151
  // State is already committed: always schedule even if onUpdate throws,
112
152
  // otherwise mounted compose/children stay stale after a successful write.
113
153
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"Component.js","sourceRoot":"","sources":["../../src/component/Component.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AAIH,mCAA+C;AAa/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAsB,SAAS;IAE7B;;;;;;;;;;;;;;OAcG;IACI,MAAM,CAAU,YAAY,GAAY,KAAK,CAAC;IAErD,sFAAsF;IAC/E,KAAK,CAAI;IAEhB,6EAA6E;IACtE,KAAK,CAAI;IAEhB;;;OAGG;IACH,YAAa,KAAQ,EAAE,YAAgB;QACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,CAAC,YAAY,IAAI,EAAE,CAAM,CAAC;IACzC,CAAC;IAED;;;;;;;;;OASG;IACI,QAAQ,CAAE,MAA4B;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,UAAU;YACxC,CAAC,CAAE,MAA4C,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;YACjE,CAAC,CAAC,MAAM,CAAC;QAEX,yEAAyE;QACzE,+DAA+D;QAC/D,IAAK,IAAI,CAAC,WAA0C,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAC3E,MAAM,MAAM,GAAG,IAA0C,CAAC;YAC1D,MAAM,GAAG,GAAG,KAA2C,CAAC;YACxD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;gBACpB,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACrB,CAAC;YACD,uEAAuE;YACvE,0EAA0E;YAC1E,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5B,CAAC;oBAAS,CAAC;gBACR,IAA2D,CAAC,4BAAoB,CAAC,EAAE,EAAE,CAAC;YACzF,CAAC;YACD,OAAO;QACT,CAAC;QAED,6EAA6E;QAC7E,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,IAAS,CAAC;QACvB,uEAAuE;QACvE,0EAA0E;QAC1E,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;gBAAS,CAAC;YACR,IAA2D,CAAC,4BAAoB,CAAC,EAAE,EAAE,CAAC;QACzF,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACI,QAAQ,CAAE,KAAQ,EAAE,KAAQ;QACjC,kDAAkD;IACpD,CAAC;;AA5FH,8BAyHC"}
1
+ {"version":3,"file":"Component.js","sourceRoot":"","sources":["../../src/component/Component.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAIH,mCAA+C;AAa/C,wEAAwE;AACxE,MAAM,4BAA4B,GAChC,yEAAyE;IACzE,uDAAuD;IACvD,2FAA2F,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAsB,SAAS;IAE7B;;;;;;;;;;;;;;OAcG;IACI,MAAM,CAAU,YAAY,GAAY,KAAK,CAAC;IAErD,8GAA8G;IAC9G,MAAM,CAAI;IAEV;;;OAGG;IACH,sBAAsB,CAAU;IAEhC,6EAA6E;IACtE,KAAK,CAAI;IAEhB;;;OAGG;IACH,IAAW,KAAK;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACH,IAAW,KAAK,CAAE,KAAQ;QACxB,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,YAAa,KAAQ,EAAE,YAAgB;QACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,CAAC,YAAY,IAAI,EAAE,CAAM,CAAC;QACxC,6FAA6F;QAC7F,qEAAqE;QACrE,cAAc,CAAC,GAAG,EAAE;YAClB,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;OASG;IACI,QAAQ,CAAE,MAA4B;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;QACzB,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,UAAU;YACxC,CAAC,CAAE,MAA4C,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;YACjE,CAAC,CAAC,MAAM,CAAC;QAEX,yEAAyE;QACzE,+DAA+D;QAC/D,IAAK,IAAI,CAAC,WAA0C,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAC3E,MAAM,MAAM,GAAG,IAA0C,CAAC;YAC1D,MAAM,GAAG,GAAG,KAA2C,CAAC;YACxD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;gBACpB,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACrB,CAAC;YACD,uEAAuE;YACvE,0EAA0E;YAC1E,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5B,CAAC;oBAAS,CAAC;gBACR,IAA2D,CAAC,4BAAoB,CAAC,EAAE,EAAE,CAAC;YACzF,CAAC;YACD,OAAO;QACT,CAAC;QAED,6EAA6E;QAC7E,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,IAAS,CAAC;QACxB,uEAAuE;QACvE,0EAA0E;QAC1E,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;gBAAS,CAAC;YACR,IAA2D,CAAC,4BAAoB,CAAC,EAAE,EAAE,CAAC;QACzF,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACI,QAAQ,CAAE,KAAQ,EAAE,KAAQ;QACjC,kDAAkD;IACpD,CAAC;;AA7HH,8BA0JC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effectable",
3
- "version": "1.2.0-canary.10",
3
+ "version": "1.2.0-canary.11",
4
4
  "description": "Declarative reactive runtime for Node.js: bootstrap, Redux-style RxJS store, Component lifecycle, class-based connect, and GraphRuntime.",
5
5
  "license": "MIT",
6
6
  "author": {