@marimo-team/frontend 0.25.3-dev21 → 0.25.3-dev24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/frontend",
3
- "version": "0.25.3-dev21",
3
+ "version": "0.25.3-dev24",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -3,7 +3,7 @@
3
3
  import { describe, expect, it } from "vitest";
4
4
  import type { NotebookEvent } from "../events";
5
5
  import type { Resource } from "../resources/resource";
6
- import { createStream, type Stream, type StreamState } from "../stream";
6
+ import { createStream } from "../stream";
7
7
  import { fixtureEvents } from "./fixtures";
8
8
 
9
9
  interface CellIds {
@@ -54,17 +54,15 @@ const revisions: Resource<Revisions> = {
54
54
  },
55
55
  };
56
56
 
57
- interface Resources {
58
- cells: CellIds;
59
- revisions: Revisions;
57
+ function createTestStream() {
58
+ return createStream({ cells, revisions });
60
59
  }
61
- type State = StreamState<Resources>;
62
60
 
63
61
  function replay(
64
- stream: Stream<Resources>,
62
+ stream: ReturnType<typeof createTestStream>,
65
63
  events: readonly NotebookEvent[],
66
- from: State = stream.initial,
67
- ): State {
64
+ from = stream.initial,
65
+ ) {
68
66
  return events.reduce((state, event) => stream.reduce(state, event), from);
69
67
  }
70
68
 
@@ -77,7 +75,7 @@ if (cellEvent?.event !== "cell") {
77
75
 
78
76
  describe("notebook stream", () => {
79
77
  it("reads the snapshot, goes live at ready, and rebuilds after reset", () => {
80
- const stream = createStream({ cells, revisions });
78
+ const stream = createTestStream();
81
79
  const partial = replay(stream, snapshot.slice(0, ready));
82
80
  expect(partial).toMatchObject({
83
81
  phase: "snapshot",
@@ -105,7 +103,7 @@ describe("notebook stream", () => {
105
103
  });
106
104
 
107
105
  it("keeps resource state by reference when an event does not apply", () => {
108
- const stream = createStream({ cells, revisions });
106
+ const stream = createTestStream();
109
107
  const state = replay(stream, snapshot);
110
108
  const runtime = snapshot.find((event) => event.event === "runtime");
111
109
  const unhandled = stream.reduce(state, { ...runtime!, id: "100" });
@@ -121,7 +119,7 @@ describe("notebook stream", () => {
121
119
  });
122
120
 
123
121
  it("clears resources when its notebook is removed and ignores other notebooks", () => {
124
- const stream = createStream({ cells, revisions });
122
+ const stream = createTestStream();
125
123
  const state = replay(stream, snapshot);
126
124
  const time = "2026-10-01T09:30:00Z";
127
125
  expect(
@@ -141,7 +139,7 @@ describe("notebook stream", () => {
141
139
  });
142
140
 
143
141
  it("rejects objects from another notebook", () => {
144
- const stream = createStream({ cells, revisions });
142
+ const stream = createTestStream();
145
143
  const state = replay(stream, snapshot.slice(0, ready));
146
144
  const notebook = snapshot[0];
147
145
  if (notebook.event !== "notebook") {
@@ -162,7 +160,7 @@ describe("notebook stream", () => {
162
160
  });
163
161
 
164
162
  it("records each live event's cursor and resumes in place", () => {
165
- const stream = createStream({ cells, revisions });
163
+ const stream = createTestStream();
166
164
  const partial = replay(stream, snapshot.slice(0, ready));
167
165
  expect(stream.resume(partial)).toEqual({
168
166
  ...stream.initial,
@@ -195,7 +193,7 @@ describe("notebook stream", () => {
195
193
  });
196
194
 
197
195
  it("requires a cursor on live events other than reset and notifications", () => {
198
- const stream = createStream({ cells, revisions });
196
+ const stream = createTestStream();
199
197
  const state = replay(stream, snapshot);
200
198
  expect(() => stream.reduce(state, cellEvent)).toThrow("cursor");
201
199
  expect(
@@ -27,7 +27,7 @@ interface PendingDocument {
27
27
  * A snapshot's records are pending until `ready`. A live revision is pending
28
28
  * from its first cell until its `document` event.
29
29
  */
30
- export interface DocumentState {
30
+ interface DocumentState {
31
31
  readonly current: Document | null;
32
32
  readonly pending: PendingDocument | null;
33
33
  }
@@ -2,36 +2,24 @@
2
2
 
3
3
  import type * as Protocol from "../protocol";
4
4
 
5
- /** An event name from the protocol. */
6
- export type EventName = Protocol.EventOutput["event"];
7
-
8
- /** The decoded event with the given name. */
9
- export type EventOf<Name extends EventName> = Extract<
10
- Protocol.EventOutput,
11
- { event: Name }
12
- >;
13
-
14
5
  /**
15
6
  * Events the stream handles itself.
16
7
  *
17
8
  * They identify the notebook, discard state, or carry a native
18
9
  * notification. Resources do not receive them.
19
10
  */
20
- export type StreamEventName =
21
- | "reset"
22
- | "notebook"
23
- | "notebook.removed"
24
- | "marimo";
11
+ type StreamEventName = "reset" | "notebook" | "notebook.removed" | "marimo";
25
12
 
26
13
  /** Events a resource may handle. `ready` marks the end of the snapshot. */
27
- export type ResourceEventName = Exclude<EventName, StreamEventName>;
28
-
29
- /** `snapshot` until `ready` arrives and `live` after it. */
30
- export type StreamPhase = "snapshot" | "live";
14
+ export type ResourceEvent = Exclude<
15
+ Protocol.EventOutput,
16
+ { event: StreamEventName }
17
+ >;
31
18
 
32
19
  /** What a handler may know about the stream beyond the event. */
33
20
  export interface HandlerContext {
34
- readonly phase: StreamPhase;
21
+ /** `snapshot` until `ready` arrives and `live` after it. */
22
+ readonly phase: "snapshot" | "live";
35
23
  }
36
24
 
37
25
  /**
@@ -39,10 +27,10 @@ export interface HandlerContext {
39
27
  *
40
28
  * A handler returns `state` when the event does not apply to it.
41
29
  */
42
- export type EventHandlers<State> = {
43
- readonly [Name in ResourceEventName]?: (
30
+ type EventHandlers<State> = {
31
+ readonly [Name in ResourceEvent["event"]]?: (
44
32
  state: State,
45
- event: EventOf<Name>,
33
+ event: Extract<ResourceEvent, { event: Name }>,
46
34
  context: HandlerContext,
47
35
  ) => State;
48
36
  };
@@ -3,15 +3,13 @@
3
3
  import type { NotebookEvent } from "./events";
4
4
  import type * as Protocol from "./protocol";
5
5
  import type {
6
- EventOf,
7
6
  HandlerContext,
8
7
  Resource,
9
- ResourceEventName,
10
- StreamPhase,
8
+ ResourceEvent,
11
9
  } from "./resources/resource";
12
10
 
13
11
  /** A resource for each entry of a state map under the same name. */
14
- export type Resources<States> = {
12
+ type Resources<States> = {
15
13
  readonly [Name in keyof States]: Resource<States[Name]>;
16
14
  };
17
15
 
@@ -21,8 +19,8 @@ export type Resources<States> = {
21
19
  * Holds the phase, the notebook identity, the resume cursor, and the state
22
20
  * of each resource.
23
21
  */
24
- export interface StreamState<States> {
25
- readonly phase: StreamPhase;
22
+ interface StreamState<States> {
23
+ readonly phase: HandlerContext["phase"];
26
24
  /**
27
25
  * The notebook the stream describes.
28
26
  *
@@ -40,7 +38,7 @@ export interface StreamState<States> {
40
38
  }
41
39
 
42
40
  /** A reducer over the events of one notebook stream. */
43
- export interface Stream<States> {
41
+ interface Stream<States> {
44
42
  readonly initial: StreamState<States>;
45
43
  /**
46
44
  * Apply one event.
@@ -71,7 +69,7 @@ const UNCURSORED = new Set<NotebookEvent["event"]>([
71
69
  * Undefined for objects that do not name one.
72
70
  */
73
71
  function notebookIdOf(
74
- event: EventOf<ResourceEventName>,
72
+ event: ResourceEvent,
75
73
  ): Protocol.NotebookIdOutput | undefined {
76
74
  switch (event.event) {
77
75
  case "document":
@@ -127,7 +125,7 @@ export function createStream<States extends object>(
127
125
 
128
126
  function fanOut(
129
127
  state: StreamState<States>,
130
- event: EventOf<ResourceEventName>,
128
+ event: ResourceEvent,
131
129
  ): StreamState<States> {
132
130
  const context: HandlerContext = { phase: state.phase };
133
131
  let next = state.resources;
package/src/utils/once.ts CHANGED
@@ -2,36 +2,36 @@
2
2
 
3
3
  import { arrayShallowEquals } from "./arrays";
4
4
 
5
- // oxlint-disable-next-line typescript/no-explicit-any
6
- export function once<T extends (...args: any[]) => any>(fn: T): T {
7
- let result: ReturnType<T>;
5
+ export function once<F extends (...args: never[]) => unknown>(fn: F): F;
6
+ export function once<Args extends unknown[], Result, This>(
7
+ fn: (this: This, ...args: Args) => Result,
8
+ ): (this: This, ...args: Args) => Result {
9
+ let result: Result;
8
10
  let called = false;
9
- return function (
10
- this: ThisParameterType<T>,
11
- ...args: Parameters<T>
12
- ): ReturnType<T> {
11
+ return function (this: This, ...args: Args): Result {
13
12
  if (!called) {
14
13
  called = true;
15
- result = fn.apply(this, args) as ReturnType<T>;
14
+ result = fn.apply(this, args);
16
15
  }
17
16
  return result;
18
- } as T;
17
+ };
19
18
  }
20
19
 
21
- // oxlint-disable-next-line typescript/no-explicit-any
22
- export function memoizeLastValue<T extends (...args: any[]) => any>(fn: T): T {
23
- let result: ReturnType<T>;
24
- let lastArgs: Parameters<T> | undefined;
20
+ export function memoizeLastValue<F extends (...args: never[]) => unknown>(
21
+ fn: F,
22
+ ): F;
23
+ export function memoizeLastValue<Args extends unknown[], Result, This>(
24
+ fn: (this: This, ...args: Args) => Result,
25
+ ): (this: This, ...args: Args) => Result {
26
+ let result: Result;
27
+ let lastArgs: Args | undefined;
25
28
  let lastError: unknown;
26
29
  let hasError = false;
27
30
 
28
- return function (
29
- this: ThisParameterType<T>,
30
- ...args: Parameters<T>
31
- ): ReturnType<T> {
31
+ return function (this: This, ...args: Args): Result {
32
32
  if (lastArgs === undefined || !arrayShallowEquals(args, lastArgs)) {
33
33
  try {
34
- result = fn.apply(this, args) as ReturnType<T>;
34
+ result = fn.apply(this, args);
35
35
  hasError = false;
36
36
  lastError = undefined;
37
37
  } catch (error) {
@@ -45,5 +45,5 @@ export function memoizeLastValue<T extends (...args: any[]) => any>(fn: T): T {
45
45
  throw lastError;
46
46
  }
47
47
  return result;
48
- } as T;
48
+ };
49
49
  }