@praxisjs/fsm 0.2.3 → 1.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # @praxisjs/fsm
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [029ef04]
8
+ - Updated dependencies [029ef04]
9
+ - Updated dependencies [029ef04]
10
+ - Updated dependencies [029ef04]
11
+ - Updated dependencies [029ef04]
12
+ - @praxisjs/core@1.1.0
13
+ - @praxisjs/decorators@0.6.0
14
+
15
+ ## 1.0.0
16
+
17
+ ### Major Changes
18
+
19
+ - 3372878: Migrate all packages from functional APIs to a decorator-first design.
20
+
21
+ **`@praxisjs/core`**
22
+
23
+ - Added `Composable` abstract base class for building class-based composables
24
+ - Removed `resource`, `createResource`, `Resource`, `ResourceStatus`, `ResourceOptions` from public exports — use `@Resource` from `@praxisjs/decorators` instead
25
+
26
+ **`@praxisjs/motion`**
27
+
28
+ - Replaced `useMotion`, `tween`, `spring`, `createTransition`, `Animate`, `easings`, `resolveEasing` with `@Tween` and `@Spring` decorators
29
+
30
+ **`@praxisjs/di`**
31
+
32
+ - Replaced `useService` and `createScope` with a `@Scope` decorator
33
+ - Renamed exported type `Scope` to `ScopeType` to free the name for the new decorator
34
+
35
+ **`@praxisjs/fsm`**
36
+
37
+ - Removed `createMachine` — use the `@StateMachine` and `@Transition` decorators directly
38
+
39
+ **`@praxisjs/router`**
40
+
41
+ - Removed `createRouter`, `lazy`, `useRouter`, `useParams`, `useQuery`, `useLocation`
42
+ - Added `@RouterConfig`, `@Lazy`, `@InjectRouter`, `@Params`, `@Query`, `@Location` decorators
43
+
44
+ **`@praxisjs/store`**
45
+
46
+ - Removed `createStore` — use the `@Store` and `@UseStore` decorators directly
47
+
48
+ **`@praxisjs/composables`**
49
+
50
+ - Replaced all `use*` composable functions with class-based composables extending `Composable`:
51
+ `WindowSize`, `ScrollPosition`, `ElementSize`, `Intersection`, `Focus`, `MediaQuery`, `ColorScheme`, `Mouse`, `KeyCombo`, `Idle`, `Clipboard`, `Geolocation`, `TimeAgo`, `Pagination`
52
+
53
+ **`@praxisjs/concurrent`**
54
+
55
+ - Removed `task`, `queue`, `pool` and their instance types — use `@Task`, `@Queue`, `@Pool` decorators instead
56
+
57
+ ### Patch Changes
58
+
59
+ - Updated dependencies [3372878]
60
+ - Updated dependencies [feaa478]
61
+ - @praxisjs/core@1.0.0
62
+ - @praxisjs/decorators@0.5.0
63
+
3
64
  ## 0.2.3
4
65
 
5
66
  ### Patch Changes
@@ -8,22 +8,36 @@ const TOGGLE_DEF = {
8
8
  on: { on: { toggle: "off" } },
9
9
  },
10
10
  };
11
+ // Helper to simulate TC39 method decorator context
12
+ function mockMethodContext(name) {
13
+ const initializers = [];
14
+ return {
15
+ name,
16
+ kind: "method",
17
+ addInitializer(fn) {
18
+ initializers.push(fn);
19
+ },
20
+ runInitializers(instance) {
21
+ initializers.forEach((fn) => { fn.call(instance); });
22
+ },
23
+ };
24
+ }
11
25
  // ── StateMachine ──────────────────────────────────────────────────────────────
12
26
  describe("StateMachine decorator", () => {
13
27
  it("adds a machine property via prototype", () => {
14
28
  class Light {
15
29
  }
16
- StateMachine(TOGGLE_DEF)(Light, {});
17
- const instance = new Light();
30
+ const Wrapped = StateMachine(TOGGLE_DEF)(Light, {});
31
+ const instance = new Wrapped();
18
32
  expect(instance.machine).toBeDefined();
19
33
  expect(instance.machine.state()).toBe("off");
20
34
  });
21
35
  it("returns a separate machine per instance", () => {
22
36
  class Bulb {
23
37
  }
24
- StateMachine(TOGGLE_DEF)(Bulb, {});
25
- const a = new Bulb();
26
- const b = new Bulb();
38
+ const Wrapped = StateMachine(TOGGLE_DEF)(Bulb, {});
39
+ const a = new Wrapped();
40
+ const b = new Wrapped();
27
41
  a.machine.send("toggle");
28
42
  expect(a.machine.state()).toBe("on");
29
43
  expect(b.machine.state()).toBe("off");
@@ -31,15 +45,15 @@ describe("StateMachine decorator", () => {
31
45
  it("uses a custom property key", () => {
32
46
  class Widget {
33
47
  }
34
- StateMachine(TOGGLE_DEF, "fsm")(Widget, {});
35
- const instance = new Widget();
48
+ const Wrapped = StateMachine(TOGGLE_DEF, "fsm")(Widget, {});
49
+ const instance = new Wrapped();
36
50
  expect(instance.fsm).toBeDefined();
37
51
  });
38
52
  it("returns the same instance on repeated access", () => {
39
53
  class Btn {
40
54
  }
41
- StateMachine(TOGGLE_DEF)(Btn, {});
42
- const instance = new Btn();
55
+ const Wrapped = StateMachine(TOGGLE_DEF)(Btn, {});
56
+ const instance = new Wrapped();
43
57
  expect(instance.machine).toBe(instance.machine);
44
58
  });
45
59
  });
@@ -47,38 +61,89 @@ describe("StateMachine decorator", () => {
47
61
  describe("Transition decorator", () => {
48
62
  it("calls the original method when send succeeds", () => {
49
63
  const original = vi.fn(() => "ran");
50
- const wrapped = Transition("machine", "toggle")(original, {});
51
- const instance = {
52
- machine: createMachine(TOGGLE_DEF),
53
- };
54
- wrapped.call(instance);
64
+ const ctx = mockMethodContext("doTransition");
65
+ Transition("machine", "toggle")(original, ctx);
66
+ const instance = { machine: createMachine(TOGGLE_DEF) };
67
+ ctx.runInitializers(instance);
68
+ const method = instance.doTransition;
69
+ method();
55
70
  expect(original).toHaveBeenCalled();
56
71
  });
57
72
  it("returns without calling method when machine is missing", () => {
58
73
  const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
59
74
  const original = vi.fn();
60
- const wrapped = Transition("machine", "toggle")(original, {});
61
- wrapped.call({});
75
+ const ctx = mockMethodContext("doTransition");
76
+ Transition("machine", "toggle")(original, ctx);
77
+ const instance = {};
78
+ ctx.runInitializers(instance);
79
+ const method = instance.doTransition;
80
+ method();
62
81
  expect(original).not.toHaveBeenCalled();
63
82
  expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Transition]"));
64
83
  warn.mockRestore();
65
84
  });
66
85
  it("does not call method when transition is invalid", () => {
67
86
  const original = vi.fn();
68
- const wrapped = Transition("machine", "toggle")(original, {});
87
+ const ctx = mockMethodContext("doTransition");
88
+ Transition("machine", "toggle")(original, ctx);
69
89
  const instance = {
70
90
  machine: createMachine({ initial: "on", states: { on: {} } }),
71
91
  };
92
+ ctx.runInitializers(instance);
93
+ const method = instance.doTransition;
72
94
  // "toggle" is not a valid event from "on" state
73
- wrapped.call(instance);
95
+ method();
74
96
  expect(original).not.toHaveBeenCalled();
75
97
  });
76
98
  it("passes through arguments to the original method", () => {
77
99
  const original = vi.fn((_x) => undefined);
78
- const wrapped = Transition("machine", "toggle")(original, {});
100
+ const ctx = mockMethodContext("doTransition");
101
+ Transition("machine", "toggle")(original, ctx);
79
102
  const instance = { machine: createMachine(TOGGLE_DEF) };
80
- wrapped.call(instance, 42);
103
+ ctx.runInitializers(instance);
104
+ const method = instance.doTransition;
105
+ method(42);
81
106
  expect(original).toHaveBeenCalledWith(42);
82
107
  });
108
+ it("@Transition on method in class without @StateMachine — warns and returns undefined", () => {
109
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => { });
110
+ const original = vi.fn(() => "ran");
111
+ const ctx = mockMethodContext("doTransition");
112
+ Transition("machine", "toggle")(original, ctx);
113
+ // Instance has no "machine" property at all
114
+ const instance = {};
115
+ ctx.runInitializers(instance);
116
+ const method = instance.doTransition;
117
+ const result = method();
118
+ expect(result).toBeUndefined();
119
+ expect(original).not.toHaveBeenCalled();
120
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Transition]"));
121
+ warn.mockRestore();
122
+ });
123
+ });
124
+ // ── StateMachine on subclass ───────────────────────────────────────────────────
125
+ describe("StateMachine decorator on subclass", () => {
126
+ it("machine is accessible on subclass instance", () => {
127
+ class Base {
128
+ }
129
+ class Child extends Base {
130
+ }
131
+ const Wrapped = StateMachine(TOGGLE_DEF)(Child, {});
132
+ const instance = new Wrapped();
133
+ expect(instance.machine).toBeDefined();
134
+ expect(instance.machine.state()).toBe("off");
135
+ });
136
+ it("instances of the decorated subclass are isolated", () => {
137
+ class Base {
138
+ }
139
+ class Child extends Base {
140
+ }
141
+ const Wrapped = StateMachine(TOGGLE_DEF)(Child, {});
142
+ const a = new Wrapped();
143
+ const b = new Wrapped();
144
+ a.machine.send("toggle");
145
+ expect(a.machine.state()).toBe("on");
146
+ expect(b.machine.state()).toBe("off");
147
+ });
83
148
  });
84
149
  //# sourceMappingURL=decorators.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.test.js","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decorators.test.js","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,UAAU,GAAG;IACjB,OAAO,EAAE,KAAc;IACvB,MAAM,EAAE;QACN,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAa,EAAE,EAAE;QACtC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAc,EAAE,EAAE;KACvC;CACO,CAAC;AAEX,mDAAmD;AACnD,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,YAAY,GAAkC,EAAE,CAAC;IACvD,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,QAAiB;QACvB,cAAc,CAAC,EAA0B;YACvC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,CAAC;QACD,eAAe,CAAC,QAAgB;YAC9B,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;KACF,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,KAAK;SAAG;QACd,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,EAA2B,CAA4B,CAAC;QACxG,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA6B,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,CAAE,QAAQ,CAAC,OAA4C,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,IAAI;SAAG;QACb,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,EAA2B,CAA2B,CAAC;QACtG,MAAM,CAAC,GAAG,IAAI,OAAO,EAA6B,CAAC;QACnD,MAAM,CAAC,GAAG,IAAI,OAAO,EAA6B,CAAC;QAClD,CAAC,CAAC,OAA4C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,CAAE,CAAC,CAAC,OAA4C,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,MAAM,CAAE,CAAC,CAAC,OAA4C,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,MAAM;SAAG;QACf,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,EAA2B,CAA6B,CAAC;QACjH,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA6B,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,GAAG;SAAG;QACZ,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,EAA2B,CAA0B,CAAC;QACpG,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA6B,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC9C,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,GAA6C,CAAC,CAAC;QAEzF,MAAM,QAAQ,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAA6B,CAAC;QACnF,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAI,QAA0C,CAAC,YAAY,CAAC;QAExE,MAAM,EAAE,CAAC;QACT,MAAM,CAAC,QAAQ,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC9C,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,GAA6C,CAAC,CAAC;QAEzF,MAAM,QAAQ,GAAG,EAA6B,CAAC;QAC/C,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAI,QAA0C,CAAC,YAAY,CAAC;QAExE,MAAM,EAAE,CAAC;QACT,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC9C,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,GAA6C,CAAC,CAAC;QAEzF,MAAM,QAAQ,GAAG;YACf,OAAO,EAAE,aAAa,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;SAC5C,CAAC;QAC7B,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAI,QAA0C,CAAC,YAAY,CAAC;QAExE,gDAAgD;QAChD,MAAM,EAAE,CAAC;QACT,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAW,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC9C,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,GAA6C,CAAC,CAAC;QAEzF,MAAM,QAAQ,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAA6B,CAAC;QACnF,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAI,QAAyD,CAAC,YAAY,CAAC;QAEvF,MAAM,CAAC,EAAE,CAAC,CAAC;QACX,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,GAAG,EAAE;QAC5F,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAC9C,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,GAA6C,CAAC,CAAC;QAEzF,4CAA4C;QAC5C,MAAM,QAAQ,GAAG,EAA6B,CAAC;QAC/C,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAI,QAA0C,CAAC,YAAY,CAAC;QAExE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;QAC/B,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,kFAAkF;AAElF,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI;SAAG;QACb,MAAM,KAAM,SAAQ,IAAI;SAAG;QAC3B,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,EAA2B,CAA4B,CAAC;QACxG,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA6B,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,CAAE,QAAQ,CAAC,OAA4C,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,IAAI;SAAG;QACb,MAAM,KAAM,SAAQ,IAAI;SAAG;QAC3B,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,EAA2B,CAA4B,CAAC;QACxG,MAAM,CAAC,GAAG,IAAI,OAAO,EAA6B,CAAC;QACnD,MAAM,CAAC,GAAG,IAAI,OAAO,EAA6B,CAAC;QAClD,CAAC,CAAC,OAA4C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,CAAE,CAAC,CAAC,OAA4C,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,MAAM,CAAE,CAAC,CAAC,OAA4C,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -141,5 +141,66 @@ describe("createMachine", () => {
141
141
  m.send("NEXT");
142
142
  expect(onTransition).toHaveBeenCalledWith("a", "NEXT", "b");
143
143
  });
144
+ it("state with on:{} — can() returns false for all events", () => {
145
+ const m = createMachine({
146
+ initial: "idle",
147
+ states: {
148
+ idle: { on: {} },
149
+ },
150
+ });
151
+ expect(m.can("START")).toBe(false);
152
+ expect(m.can("STOP")).toBe(false);
153
+ });
154
+ it("circular transition A→B→A — history contains correct entries", () => {
155
+ const m = createMachine({
156
+ initial: "a",
157
+ states: {
158
+ a: { on: { NEXT: "b" } },
159
+ b: { on: { NEXT: "a" } },
160
+ },
161
+ });
162
+ m.send("NEXT"); // a→b
163
+ m.send("NEXT"); // b→a
164
+ const h = m.history();
165
+ expect(h).toHaveLength(2);
166
+ expect(h[0]).toEqual({ from: "a", event: "NEXT", to: "b" });
167
+ expect(h[1]).toEqual({ from: "b", event: "NEXT", to: "a" });
168
+ });
169
+ it("send() with undefined event — does not crash, returns false", () => {
170
+ const m = trafficLight();
171
+ // Cast to bypass TypeScript — runtime guard should handle it gracefully
172
+ expect(m.send(undefined)).toBe(false);
173
+ });
174
+ it("onEnter callback is called AFTER the state has changed", () => {
175
+ let stateAtOnEnter;
176
+ const m = createMachine({
177
+ initial: "idle",
178
+ states: {
179
+ idle: { on: { START: "active" } },
180
+ active: {
181
+ onEnter() {
182
+ stateAtOnEnter = m.state();
183
+ },
184
+ },
185
+ },
186
+ });
187
+ m.send("START");
188
+ expect(stateAtOnEnter).toBe("active");
189
+ });
190
+ it("history not polluted by failed transitions (onExit throws)", () => {
191
+ const m = createMachine({
192
+ initial: "idle",
193
+ states: {
194
+ idle: {
195
+ on: { START: "active" },
196
+ onExit: () => { throw new Error("blocked"); },
197
+ },
198
+ active: {},
199
+ },
200
+ });
201
+ expect(() => m.send("START")).toThrow("blocked");
202
+ expect(m.history()).toHaveLength(0);
203
+ expect(m.state()).toBe("idle");
204
+ });
144
205
  });
145
206
  //# sourceMappingURL=machine.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"machine.test.js","sourceRoot":"","sources":["../../src/__tests__/machine.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"machine.test.js","sourceRoot":"","sources":["../../src/__tests__/machine.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import { type MachineDefinition } from "./machine";
2
- export declare function Transition(machineProp: string, event: string): (value: (...args: unknown[]) => unknown, _context: ClassMethodDecoratorContext) => (...args: unknown[]) => unknown;
3
- export declare function StateMachine<S extends string, E extends string>(definition: MachineDefinition<S, E>, propertyKey?: string): (value: abstract new (...args: unknown[]) => unknown, _context: ClassDecoratorContext) => void;
2
+ export declare function Transition(machineProp: string, event: string): (value: (...args: unknown[]) => unknown, context: ClassMethodDecoratorContext<any>) => void;
3
+ export declare function StateMachine<S extends string, E extends string>(definition: MachineDefinition<S, E>, propertyKey?: string): (value: abstract new (...args: unknown[]) => unknown, context: ClassDecoratorContext) => abstract new (...args: unknown[]) => unknown;
4
4
  //# sourceMappingURL=decorators.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEhF,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,IAEzD,OAAO,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACtC,UAAU,2BAA2B,KACpC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAUnC;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAC7D,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,EACnC,WAAW,SAAY,IAEN,OAAO,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,UAAU,qBAAqB,KAAG,IAAI,CAW7G"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAQA,OAAO,EAA+B,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEhF,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAe5B,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,2BAA2B,CAAC,GAAG,CAAC,KAAK,IAAI,CAC3H;AA6BD,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAC7D,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,EACnC,WAAW,SAAY,GAKQ,CAAC,KAAK,EAAE,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,qBAAqB,KAAK,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CACrK"}
@@ -1,21 +1,37 @@
1
+ import { createMethodDecorator, createClassDecorator, ClassBehavior, } from "@praxisjs/decorators";
1
2
  import { createMachine } from "./machine";
2
3
  export function Transition(machineProp, event) {
3
- return function (value, _context) {
4
- return function (...args) {
5
- const machine = this[machineProp];
6
- if (!machine) {
7
- console.warn(`[Transition] "${machineProp}" is not a state machine.`);
8
- return;
9
- }
10
- if (machine.send(event))
11
- return value.apply(this, args);
12
- };
13
- };
4
+ const decorator = createMethodDecorator({
5
+ wrap(original, instance) {
6
+ return (...args) => {
7
+ const machine = instance[machineProp];
8
+ if (!machine) {
9
+ console.warn(`[Transition] "${machineProp}" is not a state machine.`);
10
+ return;
11
+ }
12
+ if (machine.send(event))
13
+ return original.apply(instance, args);
14
+ };
15
+ },
16
+ });
17
+ // FSM decorators work on any class, not just StatefulComponent
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ return decorator;
14
20
  }
15
- export function StateMachine(definition, propertyKey = "machine") {
16
- return function (value, _context) {
21
+ class StateMachineBehavior extends ClassBehavior {
22
+ constructor(definition, propertyKey) {
23
+ super();
24
+ this.definition = definition;
25
+ this.propertyKey = propertyKey;
26
+ }
27
+ create(_instance) {
28
+ return {};
29
+ }
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ initialize(Enhanced) {
17
32
  const machines = new WeakMap();
18
- Object.defineProperty(value.prototype, propertyKey, {
33
+ const { definition, propertyKey } = this;
34
+ Object.defineProperty(Enhanced.prototype, propertyKey, {
19
35
  get() {
20
36
  if (!machines.has(this))
21
37
  machines.set(this, createMachine(definition));
@@ -24,6 +40,11 @@ export function StateMachine(definition, propertyKey = "machine") {
24
40
  enumerable: true,
25
41
  configurable: true,
26
42
  });
27
- };
43
+ }
44
+ }
45
+ export function StateMachine(definition, propertyKey = "machine") {
46
+ const decorator = createClassDecorator(new StateMachineBehavior(definition, propertyKey));
47
+ // FSM decorators work on any class, not just RootComponent
48
+ return decorator;
28
49
  }
29
50
  //# sourceMappingURL=decorators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAwC,MAAM,WAAW,CAAC;AAEhF,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,KAAa;IAC3D,OAAO,UACL,KAAsC,EACtC,QAAqC;QAErC,OAAO,UAAyC,GAAG,IAAe;YAChE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAwC,CAAC;YACzE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,iBAAiB,WAAW,2BAA2B,CAAC,CAAC;gBACtE,OAAO;YACT,CAAC;YACD,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,UAAmC,EACnC,WAAW,GAAG,SAAS;IAEvB,OAAO,UAAU,KAAmD,EAAE,QAA+B;QACnG,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAyB,CAAC;QACtD,MAAM,CAAC,cAAc,CAAE,KAA+B,CAAC,SAAS,EAAE,WAAW,EAAE;YAC7E,GAAG;gBACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;gBACvE,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAkB,CAAC;YAC7C,CAAC;YACD,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,GAEd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAwC,MAAM,WAAW,CAAC;AAEhF,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,KAAa;IAC3D,MAAM,SAAS,GAAG,qBAAqB,CAAC;QACtC,IAAI,CAAC,QAAQ,EAAE,QAAQ;YACrB,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE;gBAC5B,MAAM,OAAO,GAAI,QAAoC,CAAC,WAAW,CAAwC,CAAC;gBAC1G,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,CAAC,IAAI,CAAC,iBAAiB,WAAW,2BAA2B,CAAC,CAAC;oBACtE,OAAO;gBACT,CAAC;gBACD,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjE,CAAC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IACH,+DAA+D;IAC/D,8DAA8D;IAC9D,OAAO,SAAmH,CAAC;AAC7H,CAAC;AAED,MAAM,oBAAyD,SAAQ,aAAa;IAClF,YACmB,UAAmC,EACnC,WAAmB;QAEpC,KAAK,EAAE,CAAC;QAHS,eAAU,GAAV,UAAU,CAAyB;QACnC,gBAAW,GAAX,WAAW,CAAQ;IAGtC,CAAC;IAED,MAAM,CAAC,SAAwB;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8DAA8D;IAC9D,UAAU,CAAC,QAAyC;QAClD,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAyB,CAAC;QACtD,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;QACzC,MAAM,CAAC,cAAc,CAAE,QAAkC,CAAC,SAAS,EAAE,WAAW,EAAE;YAChF,GAAG;gBACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;gBACvE,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAkB,CAAC;YAC7C,CAAC;YACD,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAC1B,UAAmC,EACnC,WAAW,GAAG,SAAS;IAEvB,MAAM,SAAS,GAAG,oBAAoB,CAAC,IAAI,oBAAoB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IAC1F,2DAA2D;IAE3D,OAAO,SAA6J,CAAC;AACvK,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { createMachine } from "./machine";
2
1
  export type { Machine, MachineDefinition, StateMap } from "./machine";
3
2
  export { Transition, StateMachine } from "./decorators";
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,2 @@
1
- export { createMachine } from "./machine";
2
1
  export { Transition, StateMachine } from "./decorators";
3
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisjs/fsm",
3
- "version": "0.2.3",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -14,7 +14,8 @@
14
14
  "typescript": "^5.9.3"
15
15
  },
16
16
  "dependencies": {
17
- "@praxisjs/core": "0.4.2",
17
+ "@praxisjs/core": "1.1.0",
18
+ "@praxisjs/decorators": "0.6.0",
18
19
  "@praxisjs/shared": "0.2.0"
19
20
  },
20
21
  "scripts": {
@@ -11,22 +11,37 @@ const TOGGLE_DEF = {
11
11
  },
12
12
  } as const;
13
13
 
14
+ // Helper to simulate TC39 method decorator context
15
+ function mockMethodContext(name: string) {
16
+ const initializers: Array<(this: object) => void> = [];
17
+ return {
18
+ name,
19
+ kind: "method" as const,
20
+ addInitializer(fn: (this: object) => void) {
21
+ initializers.push(fn);
22
+ },
23
+ runInitializers(instance: object) {
24
+ initializers.forEach((fn) => { fn.call(instance); });
25
+ },
26
+ };
27
+ }
28
+
14
29
  // ── StateMachine ──────────────────────────────────────────────────────────────
15
30
 
16
31
  describe("StateMachine decorator", () => {
17
32
  it("adds a machine property via prototype", () => {
18
33
  class Light {}
19
- StateMachine(TOGGLE_DEF)(Light, {} as ClassDecoratorContext);
20
- const instance = new Light() as Record<string, unknown>;
34
+ const Wrapped = StateMachine(TOGGLE_DEF)(Light, {} as ClassDecoratorContext) as unknown as typeof Light;
35
+ const instance = new Wrapped() as Record<string, unknown>;
21
36
  expect(instance.machine).toBeDefined();
22
37
  expect((instance.machine as ReturnType<typeof createMachine>).state()).toBe("off");
23
38
  });
24
39
 
25
40
  it("returns a separate machine per instance", () => {
26
41
  class Bulb {}
27
- StateMachine(TOGGLE_DEF)(Bulb, {} as ClassDecoratorContext);
28
- const a = new Bulb() as Record<string, unknown>;
29
- const b = new Bulb() as Record<string, unknown>;
42
+ const Wrapped = StateMachine(TOGGLE_DEF)(Bulb, {} as ClassDecoratorContext) as unknown as typeof Bulb;
43
+ const a = new Wrapped() as Record<string, unknown>;
44
+ const b = new Wrapped() as Record<string, unknown>;
30
45
  (a.machine as ReturnType<typeof createMachine>).send("toggle");
31
46
  expect((a.machine as ReturnType<typeof createMachine>).state()).toBe("on");
32
47
  expect((b.machine as ReturnType<typeof createMachine>).state()).toBe("off");
@@ -34,15 +49,15 @@ describe("StateMachine decorator", () => {
34
49
 
35
50
  it("uses a custom property key", () => {
36
51
  class Widget {}
37
- StateMachine(TOGGLE_DEF, "fsm")(Widget, {} as ClassDecoratorContext);
38
- const instance = new Widget() as Record<string, unknown>;
52
+ const Wrapped = StateMachine(TOGGLE_DEF, "fsm")(Widget, {} as ClassDecoratorContext) as unknown as typeof Widget;
53
+ const instance = new Wrapped() as Record<string, unknown>;
39
54
  expect(instance.fsm).toBeDefined();
40
55
  });
41
56
 
42
57
  it("returns the same instance on repeated access", () => {
43
58
  class Btn {}
44
- StateMachine(TOGGLE_DEF)(Btn, {} as ClassDecoratorContext);
45
- const instance = new Btn() as Record<string, unknown>;
59
+ const Wrapped = StateMachine(TOGGLE_DEF)(Btn, {} as ClassDecoratorContext) as unknown as typeof Btn;
60
+ const instance = new Wrapped() as Record<string, unknown>;
46
61
  expect(instance.machine).toBe(instance.machine);
47
62
  });
48
63
  });
@@ -52,25 +67,28 @@ describe("StateMachine decorator", () => {
52
67
  describe("Transition decorator", () => {
53
68
  it("calls the original method when send succeeds", () => {
54
69
  const original = vi.fn(() => "ran");
55
- const wrapped = Transition("machine", "toggle")(
56
- original,
57
- {} as ClassMethodDecoratorContext,
58
- );
59
- const instance = {
60
- machine: createMachine(TOGGLE_DEF),
61
- } as Record<string, unknown>;
62
- wrapped.call(instance);
70
+ const ctx = mockMethodContext("doTransition");
71
+ Transition("machine", "toggle")(original, ctx as unknown as ClassMethodDecoratorContext);
72
+
73
+ const instance = { machine: createMachine(TOGGLE_DEF) } as Record<string, unknown>;
74
+ ctx.runInitializers(instance);
75
+ const method = (instance as Record<string, () => unknown>).doTransition;
76
+
77
+ method();
63
78
  expect(original).toHaveBeenCalled();
64
79
  });
65
80
 
66
81
  it("returns without calling method when machine is missing", () => {
67
82
  const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
68
83
  const original = vi.fn();
69
- const wrapped = Transition("machine", "toggle")(
70
- original,
71
- {} as ClassMethodDecoratorContext,
72
- );
73
- wrapped.call({} as Record<string, unknown>);
84
+ const ctx = mockMethodContext("doTransition");
85
+ Transition("machine", "toggle")(original, ctx as unknown as ClassMethodDecoratorContext);
86
+
87
+ const instance = {} as Record<string, unknown>;
88
+ ctx.runInitializers(instance);
89
+ const method = (instance as Record<string, () => unknown>).doTransition;
90
+
91
+ method();
74
92
  expect(original).not.toHaveBeenCalled();
75
93
  expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Transition]"));
76
94
  warn.mockRestore();
@@ -78,26 +96,72 @@ describe("Transition decorator", () => {
78
96
 
79
97
  it("does not call method when transition is invalid", () => {
80
98
  const original = vi.fn();
81
- const wrapped = Transition("machine", "toggle")(
82
- original,
83
- {} as ClassMethodDecoratorContext,
84
- );
99
+ const ctx = mockMethodContext("doTransition");
100
+ Transition("machine", "toggle")(original, ctx as unknown as ClassMethodDecoratorContext);
101
+
85
102
  const instance = {
86
103
  machine: createMachine({ initial: "on" as const, states: { on: {} } }),
87
104
  } as Record<string, unknown>;
105
+ ctx.runInitializers(instance);
106
+ const method = (instance as Record<string, () => unknown>).doTransition;
107
+
88
108
  // "toggle" is not a valid event from "on" state
89
- wrapped.call(instance);
109
+ method();
90
110
  expect(original).not.toHaveBeenCalled();
91
111
  });
92
112
 
93
113
  it("passes through arguments to the original method", () => {
94
114
  const original = vi.fn((_x: unknown) => undefined);
95
- const wrapped = Transition("machine", "toggle")(
96
- original,
97
- {} as ClassMethodDecoratorContext,
98
- );
115
+ const ctx = mockMethodContext("doTransition");
116
+ Transition("machine", "toggle")(original, ctx as unknown as ClassMethodDecoratorContext);
117
+
99
118
  const instance = { machine: createMachine(TOGGLE_DEF) } as Record<string, unknown>;
100
- wrapped.call(instance, 42);
119
+ ctx.runInitializers(instance);
120
+ const method = (instance as Record<string, (...a: unknown[]) => unknown>).doTransition;
121
+
122
+ method(42);
101
123
  expect(original).toHaveBeenCalledWith(42);
102
124
  });
125
+
126
+ it("@Transition on method in class without @StateMachine — warns and returns undefined", () => {
127
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
128
+ const original = vi.fn(() => "ran");
129
+ const ctx = mockMethodContext("doTransition");
130
+ Transition("machine", "toggle")(original, ctx as unknown as ClassMethodDecoratorContext);
131
+
132
+ // Instance has no "machine" property at all
133
+ const instance = {} as Record<string, unknown>;
134
+ ctx.runInitializers(instance);
135
+ const method = (instance as Record<string, () => unknown>).doTransition;
136
+
137
+ const result = method();
138
+ expect(result).toBeUndefined();
139
+ expect(original).not.toHaveBeenCalled();
140
+ expect(warn).toHaveBeenCalledWith(expect.stringContaining("[Transition]"));
141
+ warn.mockRestore();
142
+ });
143
+ });
144
+
145
+ // ── StateMachine on subclass ───────────────────────────────────────────────────
146
+
147
+ describe("StateMachine decorator on subclass", () => {
148
+ it("machine is accessible on subclass instance", () => {
149
+ class Base {}
150
+ class Child extends Base {}
151
+ const Wrapped = StateMachine(TOGGLE_DEF)(Child, {} as ClassDecoratorContext) as unknown as typeof Child;
152
+ const instance = new Wrapped() as Record<string, unknown>;
153
+ expect(instance.machine).toBeDefined();
154
+ expect((instance.machine as ReturnType<typeof createMachine>).state()).toBe("off");
155
+ });
156
+
157
+ it("instances of the decorated subclass are isolated", () => {
158
+ class Base {}
159
+ class Child extends Base {}
160
+ const Wrapped = StateMachine(TOGGLE_DEF)(Child, {} as ClassDecoratorContext) as unknown as typeof Child;
161
+ const a = new Wrapped() as Record<string, unknown>;
162
+ const b = new Wrapped() as Record<string, unknown>;
163
+ (a.machine as ReturnType<typeof createMachine>).send("toggle");
164
+ expect((a.machine as ReturnType<typeof createMachine>).state()).toBe("on");
165
+ expect((b.machine as ReturnType<typeof createMachine>).state()).toBe("off");
166
+ });
103
167
  });
@@ -162,4 +162,70 @@ describe("createMachine", () => {
162
162
  m.send("NEXT");
163
163
  expect(onTransition).toHaveBeenCalledWith("a", "NEXT", "b");
164
164
  });
165
+
166
+ it("state with on:{} — can() returns false for all events", () => {
167
+ const m = createMachine<"idle", "START" | "STOP">({
168
+ initial: "idle",
169
+ states: {
170
+ idle: { on: {} },
171
+ },
172
+ });
173
+ expect(m.can("START")).toBe(false);
174
+ expect(m.can("STOP")).toBe(false);
175
+ });
176
+
177
+ it("circular transition A→B→A — history contains correct entries", () => {
178
+ const m = createMachine<"a" | "b", "NEXT">({
179
+ initial: "a",
180
+ states: {
181
+ a: { on: { NEXT: "b" } },
182
+ b: { on: { NEXT: "a" } },
183
+ },
184
+ });
185
+ m.send("NEXT"); // a→b
186
+ m.send("NEXT"); // b→a
187
+ const h = m.history();
188
+ expect(h).toHaveLength(2);
189
+ expect(h[0]).toEqual({ from: "a", event: "NEXT", to: "b" });
190
+ expect(h[1]).toEqual({ from: "b", event: "NEXT", to: "a" });
191
+ });
192
+
193
+ it("send() with undefined event — does not crash, returns false", () => {
194
+ const m = trafficLight();
195
+ // Cast to bypass TypeScript — runtime guard should handle it gracefully
196
+ expect(m.send(undefined as unknown as TrafficEvent)).toBe(false);
197
+ });
198
+
199
+ it("onEnter callback is called AFTER the state has changed", () => {
200
+ let stateAtOnEnter: string | undefined;
201
+ const m = createMachine<"idle" | "active", "START">({
202
+ initial: "idle",
203
+ states: {
204
+ idle: { on: { START: "active" } },
205
+ active: {
206
+ onEnter() {
207
+ stateAtOnEnter = m.state();
208
+ },
209
+ },
210
+ },
211
+ });
212
+ m.send("START");
213
+ expect(stateAtOnEnter).toBe("active");
214
+ });
215
+
216
+ it("history not polluted by failed transitions (onExit throws)", () => {
217
+ const m = createMachine<"idle" | "active", "START">({
218
+ initial: "idle",
219
+ states: {
220
+ idle: {
221
+ on: { START: "active" },
222
+ onExit: () => { throw new Error("blocked"); },
223
+ },
224
+ active: {},
225
+ },
226
+ });
227
+ expect(() => m.send("START")).toThrow("blocked");
228
+ expect(m.history()).toHaveLength(0);
229
+ expect(m.state()).toBe("idle");
230
+ });
165
231
  });
package/src/decorators.ts CHANGED
@@ -1,28 +1,48 @@
1
+ import type { RootComponent } from "@praxisjs/core/internal";
2
+ import {
3
+ createMethodDecorator,
4
+ createClassDecorator,
5
+ ClassBehavior,
6
+ type ClassEnhancement,
7
+ } from "@praxisjs/decorators";
8
+
1
9
  import { createMachine, type Machine, type MachineDefinition } from "./machine";
2
10
 
3
11
  export function Transition(machineProp: string, event: string) {
4
- return function (
5
- value: (...args: unknown[]) => unknown,
6
- _context: ClassMethodDecoratorContext,
7
- ): (...args: unknown[]) => unknown {
8
- return function (this: Record<string, unknown>, ...args: unknown[]) {
9
- const machine = this[machineProp] as Machine<string, string> | undefined;
10
- if (!machine) {
11
- console.warn(`[Transition] "${machineProp}" is not a state machine.`);
12
- return;
13
- }
14
- if (machine.send(event)) return value.apply(this, args);
15
- };
16
- };
12
+ const decorator = createMethodDecorator({
13
+ wrap(original, instance) {
14
+ return (...args: unknown[]) => {
15
+ const machine = (instance as Record<string, unknown>)[machineProp] as Machine<string, string> | undefined;
16
+ if (!machine) {
17
+ console.warn(`[Transition] "${machineProp}" is not a state machine.`);
18
+ return;
19
+ }
20
+ if (machine.send(event)) return original.apply(instance, args);
21
+ };
22
+ },
23
+ });
24
+ // FSM decorators work on any class, not just StatefulComponent
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ return decorator as unknown as (value: (...args: unknown[]) => unknown, context: ClassMethodDecoratorContext<any>) => void;
17
27
  }
18
28
 
19
- export function StateMachine<S extends string, E extends string>(
20
- definition: MachineDefinition<S, E>,
21
- propertyKey = "machine",
22
- ) {
23
- return function (value: abstract new (...args: unknown[]) => unknown, _context: ClassDecoratorContext): void {
29
+ class StateMachineBehavior<S extends string, E extends string> extends ClassBehavior {
30
+ constructor(
31
+ private readonly definition: MachineDefinition<S, E>,
32
+ private readonly propertyKey: string,
33
+ ) {
34
+ super();
35
+ }
36
+
37
+ create(_instance: RootComponent): ClassEnhancement {
38
+ return {};
39
+ }
40
+
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ initialize(Enhanced: new (...args: any[]) => unknown): void {
24
43
  const machines = new WeakMap<object, Machine<S, E>>();
25
- Object.defineProperty((value as { prototype: object }).prototype, propertyKey, {
44
+ const { definition, propertyKey } = this;
45
+ Object.defineProperty((Enhanced as { prototype: object }).prototype, propertyKey, {
26
46
  get(this: object): Machine<S, E> {
27
47
  if (!machines.has(this)) machines.set(this, createMachine(definition));
28
48
  return machines.get(this) as Machine<S, E>;
@@ -30,5 +50,15 @@ export function StateMachine<S extends string, E extends string>(
30
50
  enumerable: true,
31
51
  configurable: true,
32
52
  });
33
- };
53
+ }
54
+ }
55
+
56
+ export function StateMachine<S extends string, E extends string>(
57
+ definition: MachineDefinition<S, E>,
58
+ propertyKey = "machine",
59
+ ) {
60
+ const decorator = createClassDecorator(new StateMachineBehavior(definition, propertyKey));
61
+ // FSM decorators work on any class, not just RootComponent
62
+
63
+ return decorator as unknown as (value: abstract new (...args: unknown[]) => unknown, context: ClassDecoratorContext) => abstract new (...args: unknown[]) => unknown;
34
64
  }
package/src/index.ts CHANGED
@@ -1,3 +1,2 @@
1
- export { createMachine } from "./machine";
2
1
  export type { Machine, MachineDefinition, StateMap } from "./machine";
3
2
  export { Transition, StateMachine } from "./decorators";