@praxisjs/fsm 2.1.7 → 2.2.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,50 @@
1
1
  # @praxisjs/fsm
2
2
 
3
+ ## 2.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 75115a9: Decorated fields are defined by their innermost decorator. With `@praxisjs/vite-plugin`, `@State()`, `@Prop()`, every built-in field decorator and `createFieldDecorator` bindings install their property directly with the field's initial value instead of replacing a plain value, which kept every instance in V8's slow dictionary mode. New `addClaimableInitializer(context, init)` export for field decorators written against the TC39 API.
8
+ - 75115a9: Field decorators throw a `TypeError` when the class is defined if they decorate an `accessor`, naming the member to fix. Covers `@State()`, `@Prop()`, every built-in field decorator and `createFieldDecorator` bindings. New `assertFieldContext(context, label?)` export for field decorators written against the TC39 API directly.
9
+ - 75115a9: Published packages no longer contain their tests: package builds compile `src` without `src/**/__tests__` (through a `tsconfig.build.json`), and each package's `files` leaves test sources and stale compiled tests out of the tarball. `pnpm typecheck` still type-checks the tests.
10
+ - 75115a9: Performance pass and bug fixes across the feature packages.
11
+ - `@praxisjs/router`: static paths are matched through an index and dynamic ones with a single regex run; `RouterView` keeps a shared layout mounted across navigations; new `router.isActive(path)` (used by `Link`, so a navigation re-evaluates only the links whose state changed) and `router.destroy()`. Fixes regex characters in route paths (`.`, `(`, `+`...) being treated as patterns, and a router replaced by `createRouter()` still reacting to `popstate`. `@Route` no longer wraps the class, and the field decorators share one accessor.
12
+ - `@praxisjs/store`: plugin-wrapped actions keep their identity across reads, extensions are bound once, and writing a field inside an effect no longer subscribes the effect to it. `constructor` and inherited `Object.prototype` members are no longer reported as actions. `@Store` caches the singleton.
13
+ - `@praxisjs/motion`: `@Tween` and `@Spring` share one accessor per field and no longer start a frame loop at construction; `tween()`/`spring()` react to target writes without an effect. Fixes `reset()` leaving a tween marked as playing.
14
+ - `@praxisjs/di`: cached singletons and tokens resolve without allocating, `@Injectable` registers the class itself instead of a subclass, and a dependency cycle through `inject()` calls in constructors now reports `[DI] Circular dependency detected` instead of overflowing the stack.
15
+ - `@praxisjs/fsm`: `send()` and `reset()` no longer subscribe the calling effect to the machine state, transitions allocate nothing per send, and `@StateMachine` shares one accessor.
16
+ - `@praxisjs/head`: tag diffing without `JSON.stringify` or a full `<head>` query per update; updating or removing an entry below the top one leaves the document alone, and removing an unknown id no longer resets the title.
17
+ - `@praxisjs/content`: each entry is loaded, parsed and rendered once and shared by `getCollection`, `getPage` and `getEntry`; `getEntry` looks the slug up in an index; schema defaults are built once per class.
18
+
19
+ - 75115a9: Smaller production bundles. The framework and feature packages are marked `"sideEffects": false`, so bundlers leave out the modules an app does not use (`For`/`Index` and `selector()` were kept in every bundle by their shape keepers). `@praxisjs/core`'s graph gates its observer instrumentation on a boolean that minifiers fold away when no observer is ever installed. `@praxisjs/runtime` passes `Index`'s positional update to the list view, so `For`-only apps leave it out, and builds its event prop table from camel-case names. `@praxisjs/devtools` is built one file per module and its decorators check `process.env.NODE_ENV` inline, so `@Trace`/`@Debug` in production code no longer bundle the registry and the panel. `@praxisjs/vite-plugin` serves TypeScript's decorator helpers and the claimed fields' helper from one virtual module (`virtual:praxisjs/decorators`) instead of writing them into every decorated file, and replaces the identical copies `tsc` wrote into ES module libraries.
20
+ - Updated dependencies [75115a9]
21
+ - Updated dependencies [75115a9]
22
+ - Updated dependencies [75115a9]
23
+ - Updated dependencies [75115a9]
24
+ - Updated dependencies [75115a9]
25
+ - Updated dependencies [75115a9]
26
+ - Updated dependencies [75115a9]
27
+ - Updated dependencies [75115a9]
28
+ - Updated dependencies [75115a9]
29
+ - Updated dependencies [75115a9]
30
+ - Updated dependencies [75115a9]
31
+ - @praxisjs/decorators@2.0.0
32
+ - @praxisjs/core@2.3.0
33
+ - @praxisjs/shared@0.3.2
34
+
35
+ ## 2.2.0
36
+
37
+ ### Minor Changes
38
+
39
+ - 2d5bd45: New `historyLimit` option, defaulting to 100: `history` keeps only the most recent transitions (`0` disables it, `Infinity` keeps everything). A machine with more than 100 transitions no longer reports the oldest ones unless `historyLimit: Infinity` is set.
40
+
41
+ ### Patch Changes
42
+
43
+ - Updated dependencies [a97a37c]
44
+ - Updated dependencies [c7a5950]
45
+ - @praxisjs/core@2.2.0
46
+ - @praxisjs/decorators@1.7.0
47
+
3
48
  ## 2.1.7
4
49
 
5
50
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,KAAK,OAAO,EAAE,KAAK,iBAAiB,EAAG,MAAM,WAAW,CAAC;AAEjF,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAiB5B,CAC7B,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAEtC,OAAO,EAAE,2BAA2B,CAAC,GAAG,CAAC,KACtC,IAAI,CACV;AAED,wBAAgB,YAAY,CAC1B,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAEhB,CAAC,SAAS,MAAM,GAAG,GAAG,EAGtB,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAInE,CAAC,SAAS,MAAM,EAC/B,QAAQ,SAAS,EACjB,SAAS,0BAA0B,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KACpD,IAAI,CAsBR"}
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiB,KAAK,OAAO,EAAE,KAAK,iBAAiB,EAAG,MAAM,WAAW,CAAC;AAEjF,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAiB5B,CAC7B,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAEtC,OAAO,EAAE,2BAA2B,CAAC,GAAG,CAAC,KACtC,IAAI,CACV;AAED,wBAAgB,YAAY,CAC1B,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAEhB,CAAC,SAAS,MAAM,GAAG,GAAG,EAGtB,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAEnE,CAAC,SAAS,MAAM,EAC/B,QAAQ,SAAS,EACjB,SAAS,0BAA0B,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KACpD,IAAI,CA2BR"}
@@ -1,4 +1,4 @@
1
- import { createMethodDecorator, } from "@praxisjs/decorators";
1
+ import { createMethodDecorator, addClaimableInitializer, assertFieldContext, } from "@praxisjs/decorators";
2
2
  import { createMachine } from "./machine";
3
3
  export function Transition(machineProp, event) {
4
4
  const decorator = createMethodDecorator({
@@ -20,26 +20,31 @@ export function Transition(machineProp, event) {
20
20
  export function StateMachine(
21
21
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
22
  definition) {
23
- const machines = new WeakMap();
24
23
  return function (_value, context) {
25
- context.addInitializer(function () {
26
- const name = context.name;
27
- Object.defineProperty(this, name, {
28
- get() {
29
- const self = this;
30
- if (!machines.has(self)) {
31
- const def = typeof definition === "function"
32
- ? definition.call(self)
33
- : definition;
34
- machines.set(self, createMachine(def, self));
35
- }
36
- return machines.get(self);
37
- },
38
- // eslint-disable-next-line @typescript-eslint/no-empty-function
39
- set() { },
40
- enumerable: true,
41
- configurable: true,
42
- });
24
+ assertFieldContext(context);
25
+ const name = context.name;
26
+ // Each instance's machine lives under this symbol, created on first read; the accessor itself
27
+ // is shared by every instance.
28
+ const slot = Symbol(`praxis.fsm.${String(name)}`);
29
+ const descriptor = {
30
+ get() {
31
+ let machine = this[slot];
32
+ if (machine === undefined) {
33
+ const def = typeof definition === "function" ? definition.call(this) : definition;
34
+ machine = createMachine(def, this);
35
+ this[slot] = machine;
36
+ }
37
+ return machine;
38
+ },
39
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
40
+ set() { },
41
+ enumerable: true,
42
+ configurable: true,
43
+ };
44
+ addClaimableInitializer(context, function () {
45
+ // Reserving the slot up front keeps every instance of the class on the same shape.
46
+ this[slot] = undefined;
47
+ Object.defineProperty(this, name, descriptor);
43
48
  });
44
49
  };
45
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAyC,MAAM,WAAW,CAAC;AAEjF,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,CAEpD,CAAC;gBACd,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;oBACrB,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAY,CAAC;YACrD,CAAC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IACH,+DAA+D;IAC/D,OAAO,SAIE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,YAAY;AAM1B,8DAA8D;AAC9D,UAAoF;IAEpF,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAyB,CAAC;IAEtD,OAAO,UACL,MAAiB,EACjB,OAAqD;QAErD,OAAO,CAAC,cAAc,CAAC;YACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE;gBAChC,GAAG;oBACD,MAAM,IAAI,GAAG,IAAS,CAAC;oBACvB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxB,MAAM,GAAG,GACP,OAAO,UAAU,KAAK,UAAU;4BAC9B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;4BACvB,CAAC,CAAC,UAAU,CAAC;wBACjB,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC/C,CAAC;oBACD,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAkB,CAAC;gBAC7C,CAAC;gBACD,gEAAgE;gBAChE,GAAG,KAAU,CAAC;gBACd,UAAU,EAAE,IAAI;gBAChB,YAAY,EAAE,IAAI;aACnB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAyC,MAAM,WAAW,CAAC;AAEjF,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,CAEpD,CAAC;gBACd,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;oBACrB,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAY,CAAC;YACrD,CAAC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IACH,+DAA+D;IAC/D,OAAO,SAIE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,YAAY;AAM1B,8DAA8D;AAC9D,UAAoF;IAEpF,OAAO,UACL,MAAiB,EACjB,OAAqD;QAErD,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QAC1B,8FAA8F;QAC9F,+BAA+B;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,cAAc,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClD,MAAM,UAAU,GAAuB;YACrC,GAAG;gBACD,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC1B,MAAM,GAAG,GAAG,OAAO,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;oBAClF,OAAO,GAAG,aAAa,CAAC,GAAG,EAAE,IAAoB,CAAC,CAAC;oBACnD,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;gBACvB,CAAC;gBACD,OAAO,OAAO,CAAC;YACjB,CAAC;YACD,gEAAgE;YAChE,GAAG,KAAU,CAAC;YACd,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;SACnB,CAAC;QACF,uBAAuB,CAAC,OAAO,EAAE;YAC/B,mFAAmF;YAClF,IAAgC,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;YACpD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
package/dist/machine.d.ts CHANGED
@@ -19,6 +19,12 @@ export interface MachineDefinition<S extends string, E extends string, T extends
19
19
  initial: S;
20
20
  states: StateMap<S, E, T>;
21
21
  onTransition?: (from: S, event: E, to: S) => void;
22
+ /**
23
+ * Maximum number of entries kept in `history`; the oldest are dropped first. `0` disables the
24
+ * history and `Infinity` keeps everything. Defaults to 100: each transition copies the array,
25
+ * so an unbounded history makes a long-running machine slower and larger over time.
26
+ */
27
+ historyLimit?: number;
22
28
  }
23
29
  export interface Machine<S extends string, E extends string> {
24
30
  state: Computed<S>;
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IAC3E,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,OAAO,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,CAC1F,CAAC,EACD;IACE,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IACpD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,EAAE,EAAE,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAClD,CACF,CAAC;AAEF,MAAM,WAAW,iBAAiB,CAChC,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,GAAG,MAAM;IAEzB,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM;IACzD,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,EAAE,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACvB,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACtB,KAAK,IAAI,IAAI,CAAC;CACf;AAgBD,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,GAAG,MAAM,EACzB,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAE,CAAW,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CA4C9E"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IAC3E,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,OAAO,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,CAC1F,CAAC,EACD;IACE,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IACpD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,EAAE,EAAE,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAClD,CACF,CAAC;AAEF,MAAM,WAAW,iBAAiB,CAChC,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,GAAG,MAAM;IAEzB,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM;IACzD,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,EAAE,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACvB,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACtB,KAAK,IAAI,IAAI,CAAC;CACf;AAgBD,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,GAAG,MAAM,EACzB,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAE,CAAW,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAmD9E"}
package/dist/machine.js CHANGED
@@ -1,50 +1,54 @@
1
- import { signal, computed } from "@praxisjs/core/internal";
2
- function resolveTransition(config, instance) {
3
- if (config == null)
4
- return null;
5
- if (typeof config === "string")
6
- return { target: config };
7
- const { target, guard, action } = config;
8
- return {
9
- target,
10
- guard: guard ? () => guard(instance) : undefined,
11
- action: action ? () => { action(instance); } : undefined,
12
- };
1
+ import { computed, readSignal, SignalNode, writeSignal } from "@praxisjs/core/internal";
2
+ function normalize(config) {
3
+ return typeof config === "string" ? { target: config } : config;
13
4
  }
5
+ const DEFAULT_HISTORY_LIMIT = 100;
14
6
  export function createMachine(definition, instance = {}) {
15
- const _state = signal(definition.initial);
16
- const _history = signal([]);
7
+ const stateNode = new SignalNode(definition.initial);
8
+ const historyNode = new SignalNode([]);
9
+ const limit = definition.historyLimit ?? DEFAULT_HISTORY_LIMIT;
10
+ function transitionFor(state, event) {
11
+ const config = definition.states[state].on?.[event];
12
+ return config == null ? null : normalize(config);
13
+ }
14
+ // Reads the current state without tracking: sending is a write, so an effect that sends must not
15
+ // re-run because the state it just changed moved.
17
16
  function send(event) {
18
- const current = _state();
19
- const resolved = resolveTransition(definition.states[current].on?.[event], instance);
20
- if (!resolved)
17
+ const current = stateNode.value;
18
+ const transition = transitionFor(current, event);
19
+ if (!transition)
21
20
  return false;
22
- if (resolved.guard && !resolved.guard())
21
+ if (transition.guard && !transition.guard(instance))
23
22
  return false;
24
- const { target: nextState } = resolved;
23
+ const nextState = transition.target;
25
24
  definition.states[current].onExit?.({ event, to: nextState });
26
- _state.set(nextState);
27
- _history.update((h) => [...h, { from: current, event, to: nextState }]);
25
+ writeSignal(stateNode, nextState);
26
+ if (limit !== 0) {
27
+ const prev = historyNode.value;
28
+ const next = prev.length < limit ? prev.slice() : prev.slice(prev.length - limit + 1);
29
+ next.push({ from: current, event, to: nextState });
30
+ writeSignal(historyNode, next);
31
+ }
28
32
  definition.onTransition?.(current, event, nextState);
29
- resolved.action?.();
33
+ transition.action?.(instance);
30
34
  definition.states[nextState].onEnter?.({ event, from: current });
31
35
  return true;
32
36
  }
33
37
  return {
34
- state: computed(() => _state()),
35
- history: computed(() => _history()),
38
+ state: computed(() => readSignal(stateNode)),
39
+ history: computed(() => readSignal(historyNode)),
36
40
  send,
37
41
  can: (event) => {
38
- const resolved = resolveTransition(definition.states[_state()].on?.[event], instance);
39
- if (!resolved)
42
+ const transition = transitionFor(readSignal(stateNode), event);
43
+ if (!transition)
40
44
  return false;
41
- return !resolved.guard || resolved.guard();
45
+ return !transition.guard || transition.guard(instance);
42
46
  },
43
- is: (state) => _state() === state,
47
+ is: (state) => readSignal(stateNode) === state,
44
48
  reset: () => {
45
- definition.states[_state()].onExit?.(undefined);
46
- _state.set(definition.initial);
47
- _history.set([]);
49
+ definition.states[stateNode.value].onExit?.(undefined);
50
+ writeSignal(stateNode, definition.initial);
51
+ writeSignal(historyNode, []);
48
52
  definition.states[definition.initial].onEnter?.(undefined);
49
53
  },
50
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"machine.js","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"machine.js","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@praxisjs/fsm",
3
- "version": "2.1.7",
3
+ "version": "2.2.1",
4
4
  "type": "module",
5
+ "sideEffects": false,
5
6
  "main": "./dist/index.js",
6
7
  "types": "./dist/index.d.ts",
7
8
  "exports": {
@@ -10,16 +11,24 @@
10
11
  "types": "./dist/index.d.ts"
11
12
  }
12
13
  },
14
+ "files": [
15
+ "dist",
16
+ "src",
17
+ "!dist/**/__tests__",
18
+ "!src/**/__tests__",
19
+ "CHANGELOG.md"
20
+ ],
13
21
  "devDependencies": {
14
22
  "typescript": "^6.0.3"
15
23
  },
16
24
  "dependencies": {
17
- "@praxisjs/core": "2.1.0",
18
- "@praxisjs/decorators": "1.6.1",
19
- "@praxisjs/shared": "0.3.1"
25
+ "@praxisjs/core": "2.3.0",
26
+ "@praxisjs/decorators": "2.0.0",
27
+ "@praxisjs/shared": "0.3.2"
20
28
  },
21
29
  "scripts": {
22
- "build": "tsc",
23
- "dev": "tsc --watch"
30
+ "build": "tsc -p tsconfig.build.json",
31
+ "dev": "tsc -p tsconfig.build.json --watch",
32
+ "typecheck": "tsc --noEmit"
24
33
  }
25
34
  }
package/src/decorators.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  createMethodDecorator,
3
+ addClaimableInitializer,
4
+ assertFieldContext,
3
5
  } from "@praxisjs/decorators";
4
6
 
5
7
  import { createMachine, type Machine, type MachineDefinition } from "./machine";
@@ -37,31 +39,34 @@ export function StateMachine<
37
39
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
40
  definition: MachineDefinition<S, E, T> | ((this: any) => MachineDefinition<S, E, T>),
39
41
  ) {
40
- const machines = new WeakMap<object, Machine<S, E>>();
41
-
42
42
  return function <U extends object>(
43
43
  _value: undefined,
44
44
  context: ClassFieldDecoratorContext<U, Machine<S, E>>,
45
45
  ): void {
46
- context.addInitializer(function (this: object) {
47
- const name = context.name;
48
- Object.defineProperty(this, name, {
49
- get(): Machine<S, E> {
50
- const self = this as T;
51
- if (!machines.has(self)) {
52
- const def =
53
- typeof definition === "function"
54
- ? definition.call(self)
55
- : definition;
56
- machines.set(self, createMachine(def, self));
57
- }
58
- return machines.get(self) as Machine<S, E>;
59
- },
60
- // eslint-disable-next-line @typescript-eslint/no-empty-function
61
- set(): void {},
62
- enumerable: true,
63
- configurable: true,
64
- });
46
+ assertFieldContext(context);
47
+ const name = context.name;
48
+ // Each instance's machine lives under this symbol, created on first read; the accessor itself
49
+ // is shared by every instance.
50
+ const slot = Symbol(`praxis.fsm.${String(name)}`);
51
+ const descriptor: PropertyDescriptor = {
52
+ get(this: Record<symbol, Machine<S, E> | undefined>): Machine<S, E> {
53
+ let machine = this[slot];
54
+ if (machine === undefined) {
55
+ const def = typeof definition === "function" ? definition.call(this) : definition;
56
+ machine = createMachine(def, this as unknown as T);
57
+ this[slot] = machine;
58
+ }
59
+ return machine;
60
+ },
61
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
62
+ set(): void {},
63
+ enumerable: true,
64
+ configurable: true,
65
+ };
66
+ addClaimableInitializer(context, function () {
67
+ // Reserving the slot up front keeps every instance of the class on the same shape.
68
+ (this as Record<symbol, unknown>)[slot] = undefined;
69
+ Object.defineProperty(this, name, descriptor);
65
70
  });
66
71
  };
67
72
  }
package/src/machine.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { signal, computed } from "@praxisjs/core/internal";
1
+ import { computed, readSignal, SignalNode, writeSignal } from "@praxisjs/core/internal";
2
2
  import type { Computed } from "@praxisjs/shared";
3
3
 
4
4
  export interface TransitionTarget<S extends string, T extends object = object> {
@@ -24,6 +24,12 @@ export interface MachineDefinition<
24
24
  initial: S;
25
25
  states: StateMap<S, E, T>;
26
26
  onTransition?: (from: S, event: E, to: S) => void;
27
+ /**
28
+ * Maximum number of entries kept in `history`; the oldest are dropped first. `0` disables the
29
+ * history and `Infinity` keeps everything. Defaults to 100: each transition copies the array,
30
+ * so an unbounded history makes a long-running machine slower and larger over time.
31
+ */
32
+ historyLimit?: number;
27
33
  }
28
34
 
29
35
  export interface Machine<S extends string, E extends string> {
@@ -35,65 +41,72 @@ export interface Machine<S extends string, E extends string> {
35
41
  reset(): void;
36
42
  }
37
43
 
38
- function resolveTransition<S extends string, T extends object>(
39
- config: S | TransitionTarget<S, T> | undefined,
40
- instance: T,
41
- ): { target: S; guard?: () => boolean; action?: () => void } | null {
42
- if (config == null) return null;
43
- if (typeof config === "string") return { target: config };
44
- const { target, guard, action } = config;
45
- return {
46
- target,
47
- guard: guard ? () => guard(instance) : undefined,
48
- action: action ? () => { action(instance); } : undefined,
49
- };
44
+ interface HistoryEntry<S extends string, E extends string> {
45
+ from: S;
46
+ event: E;
47
+ to: S;
48
+ }
49
+
50
+ function normalize<S extends string, T extends object>(
51
+ config: S | TransitionTarget<S, T>,
52
+ ): TransitionTarget<S, T> {
53
+ return typeof config === "string" ? { target: config } : config;
50
54
  }
51
55
 
56
+ const DEFAULT_HISTORY_LIMIT = 100;
57
+
52
58
  export function createMachine<
53
59
  S extends string,
54
60
  E extends string,
55
61
  T extends object = object,
56
62
  >(definition: MachineDefinition<S, E, T>, instance: T = {} as T): Machine<S, E> {
57
- const _state = signal(definition.initial);
58
- const _history = signal<Array<{ from: S; event: E; to: S }>>([]);
63
+ const stateNode = new SignalNode(definition.initial);
64
+ const historyNode = new SignalNode<Array<HistoryEntry<S, E>>>([]);
65
+ const limit = definition.historyLimit ?? DEFAULT_HISTORY_LIMIT;
66
+
67
+ function transitionFor(state: S, event: E): TransitionTarget<S, T> | null {
68
+ const config = definition.states[state].on?.[event];
69
+ return config == null ? null : normalize(config);
70
+ }
59
71
 
72
+ // Reads the current state without tracking: sending is a write, so an effect that sends must not
73
+ // re-run because the state it just changed moved.
60
74
  function send(event: E): boolean {
61
- const current = _state();
62
- const resolved = resolveTransition(
63
- definition.states[current].on?.[event],
64
- instance,
65
- );
66
- if (!resolved) return false;
67
- if (resolved.guard && !resolved.guard()) return false;
75
+ const current = stateNode.value;
76
+ const transition = transitionFor(current, event);
77
+ if (!transition) return false;
78
+ if (transition.guard && !transition.guard(instance)) return false;
68
79
 
69
- const { target: nextState } = resolved;
80
+ const nextState = transition.target;
70
81
 
71
82
  definition.states[current].onExit?.({ event, to: nextState });
72
- _state.set(nextState);
73
- _history.update((h) => [...h, { from: current, event, to: nextState }]);
83
+ writeSignal(stateNode, nextState);
84
+ if (limit !== 0) {
85
+ const prev = historyNode.value;
86
+ const next = prev.length < limit ? prev.slice() : prev.slice(prev.length - limit + 1);
87
+ next.push({ from: current, event, to: nextState });
88
+ writeSignal(historyNode, next);
89
+ }
74
90
  definition.onTransition?.(current, event, nextState);
75
- resolved.action?.();
91
+ transition.action?.(instance);
76
92
  definition.states[nextState].onEnter?.({ event, from: current });
77
93
  return true;
78
94
  }
79
95
 
80
96
  return {
81
- state: computed(() => _state()),
82
- history: computed(() => _history()),
97
+ state: computed(() => readSignal(stateNode)),
98
+ history: computed(() => readSignal(historyNode)),
83
99
  send,
84
100
  can: (event) => {
85
- const resolved = resolveTransition(
86
- definition.states[_state()].on?.[event],
87
- instance,
88
- );
89
- if (!resolved) return false;
90
- return !resolved.guard || resolved.guard();
101
+ const transition = transitionFor(readSignal(stateNode), event);
102
+ if (!transition) return false;
103
+ return !transition.guard || transition.guard(instance);
91
104
  },
92
- is: (state) => _state() === state,
105
+ is: (state) => readSignal(stateNode) === state,
93
106
  reset: () => {
94
- definition.states[_state()].onExit?.(undefined);
95
- _state.set(definition.initial);
96
- _history.set([]);
107
+ definition.states[stateNode.value].onExit?.(undefined);
108
+ writeSignal(stateNode, definition.initial);
109
+ writeSignal(historyNode, []);
97
110
  definition.states[definition.initial].onEnter?.(undefined);
98
111
  },
99
112
  };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=decorators.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decorators.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":""}