@vsceasy/cli 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,3 +6,30 @@ export {
6
6
  webviewState,
7
7
  } from './rpc';
8
8
  export type { RpcClient, Handlers, Transport, RpcClientOptions, WebviewApi } from './rpc';
9
+
10
+ export { defineStore } from './store';
11
+ export type { Store } from './store';
12
+
13
+ import type { RpcClient, Handlers } from './rpc';
14
+
15
+ /**
16
+ * Listen for a change pushed from the host over the RPC event channel, and run a
17
+ * callback when it arrives. This is the webview side of the reactivity model —
18
+ * the host emits with `server.emit(topic, …)` (usually wired via `watch()` /
19
+ * `watchEntity()`), and your visual element reacts here. Returns an unsubscribe
20
+ * function; call it on unmount.
21
+ *
22
+ * const api = connectWebview<TodoStatsViewApi>();
23
+ * // re-read + re-render whenever todos change on the host:
24
+ * const off = listen(api, 'todos:changed', () => refresh());
25
+ *
26
+ * It's a thin, named wrapper over `api.on(topic, handler)` so the place you
27
+ * listen reads clearly in the UI code. The payload (if any) is passed through.
28
+ */
29
+ export function listen<H extends Handlers>(
30
+ api: RpcClient<H>,
31
+ topic: string,
32
+ handler: (payload?: unknown) => void,
33
+ ): () => void {
34
+ return api.on(topic, handler);
35
+ }
@@ -2,6 +2,18 @@ import type * as vscode from 'vscode';
2
2
  import type { Handlers } from './rpc';
3
3
  import type { CodiconName } from './codiconNames';
4
4
 
5
+ /**
6
+ * Push a change to this webview over the RPC event channel. The webview reacts
7
+ * with `listen(api, topic, …)`. Wire it to a data source with `watch()` /
8
+ * `watchEntity()` inside `rpc()`:
9
+ *
10
+ * rpc: (vscode, ctx, emit) => {
11
+ * watchEntity(Todos, () => emit('todos:changed'));
12
+ * return { stats: () => … };
13
+ * }
14
+ */
15
+ export type RpcEmit = (topic: string, payload?: unknown) => void;
16
+
5
17
  export interface PanelDef<H extends Handlers = Handlers> {
6
18
  /** Stable id. Default: file basename. Used as command suffix and webview key. */
7
19
  id?: string;
@@ -13,8 +25,11 @@ export interface PanelDef<H extends Handlers = Handlers> {
13
25
  column?: 'active' | 'beside' | 'one' | 'two' | 'three';
14
26
  /** Keep DOM alive when hidden. Default: true. */
15
27
  retainContext?: boolean;
16
- /** RPC handlers — receives vscode namespace + extension context. */
17
- rpc?: (vscode: typeof import('vscode'), ctx: vscode.ExtensionContext) => H;
28
+ /**
29
+ * RPC handlers — receives the vscode namespace, the extension context, and
30
+ * `emit` for pushing change events to this webview (see {@link RpcEmit}).
31
+ */
32
+ rpc?: (vscode: typeof import('vscode'), ctx: vscode.ExtensionContext, emit: RpcEmit) => H;
18
33
  /** Optional command palette entry that opens this panel. Default: true. */
19
34
  command?:
20
35
  | boolean
@@ -125,8 +140,11 @@ export interface SubpanelDef<H extends Handlers = Handlers> {
125
140
  ui?: string;
126
141
  /** Keep DOM alive when hidden. Default: true. */
127
142
  retainContext?: boolean;
128
- /** RPC handlers — receives vscode namespace + extension context. */
129
- rpc?: (vscode: typeof import('vscode'), ctx: vscode.ExtensionContext) => H;
143
+ /**
144
+ * RPC handlers — receives the vscode namespace, the extension context, and
145
+ * `emit` for pushing change events to this webview (see {@link RpcEmit}).
146
+ */
147
+ rpc?: (vscode: typeof import('vscode'), ctx: vscode.ExtensionContext, emit: RpcEmit) => H;
130
148
  }
131
149
 
132
150
  export function defineSubpanel<H extends Handlers = Handlers>(def: SubpanelDef<H>): SubpanelDef<H> {
@@ -228,6 +246,18 @@ export interface TreeViewDef {
228
246
  vscode: typeof import('vscode'),
229
247
  ctx: vscode.ExtensionContext,
230
248
  ) => TreeNode[] | Promise<TreeNode[]>;
249
+ /**
250
+ * Keep the tree live. Receives `refresh` — call it (directly or as a callback)
251
+ * to re-run `getChildren`. Subscribe to a data source here so the tree updates
252
+ * itself; return an unsubscribe to clean up.
253
+ *
254
+ * watch: (refresh) => watchEntity(Todos, refresh),
255
+ */
256
+ watch?: (
257
+ refresh: () => void,
258
+ vscode: typeof import('vscode'),
259
+ ctx: vscode.ExtensionContext,
260
+ ) => (() => void) | void;
231
261
  }
232
262
 
233
263
  export function defineTreeView(def: TreeViewDef): TreeViewDef {
@@ -1,5 +1,5 @@
1
1
  export { definePanel, defineCommand, defineMenu, defineStatusBar, defineSubpanel, defineTreeView, defineJob } from './define';
2
- export type { PanelDef, CommandDef, MenuDef, MenuItem, MenuIcon, StatusBarDef, StatusBarMenuItem, KeybindingDef, SubpanelDef, TreeViewDef, TreeNode, JobDef, JobSchedule, CodiconName } from './define';
2
+ export type { PanelDef, CommandDef, MenuDef, MenuItem, MenuIcon, StatusBarDef, StatusBarMenuItem, KeybindingDef, SubpanelDef, TreeViewDef, TreeNode, JobDef, JobSchedule, CodiconName, RpcEmit } from './define';
3
3
  export { bootstrap } from './bootstrap';
4
4
  export type { Registry, BootstrapOptions, ActivateHook } from './bootstrap';
5
5
  export {
@@ -11,3 +11,6 @@ export {
11
11
  webviewState,
12
12
  } from './rpc';
13
13
  export type { Transport, RpcClient, Handlers, RpcClientOptions, WebviewApi } from './rpc';
14
+ export { defineStore, watch } from './store';
15
+ export type { Store, Watchable } from './store';
16
+ export { listen } from './client';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Reactive stores — a tiny, framework-agnostic observable value.
3
+ *
4
+ * A store holds one value and notifies subscribers when it changes. It's the
5
+ * non-ORM half of the reactivity model: use it for arbitrary state (a counter,
6
+ * a flag, a selection) that a visual element should track.
7
+ *
8
+ * const counter = defineStore(0);
9
+ * counter.subscribe((v) => console.log('now', v));
10
+ * counter.set(1); // logs: now 1
11
+ * counter.update((n) => n + 1);
12
+ *
13
+ * Pair it with `watch()` on the host to push changes to a webview, and
14
+ * `listen()` on the webview to react — see those helpers below and in client.ts.
15
+ */
16
+ export interface Store<T> {
17
+ /** Read the current value. */
18
+ get(): T;
19
+ /** Replace the value and notify subscribers (no-op if `Object.is`-equal). */
20
+ set(next: T): void;
21
+ /** Derive the next value from the current one, then `set` it. */
22
+ update(fn: (current: T) => T): void;
23
+ /** Subscribe to changes. Returns an unsubscribe function. */
24
+ subscribe(cb: (value: T) => void): () => void;
25
+ }
26
+
27
+ export function defineStore<T>(initial: T): Store<T> {
28
+ let value = initial;
29
+ const subs = new Set<(value: T) => void>();
30
+
31
+ return {
32
+ get: () => value,
33
+ set(next) {
34
+ if (Object.is(value, next)) return;
35
+ value = next;
36
+ subs.forEach((cb) => {
37
+ try { cb(value); } catch { /* a bad subscriber must not break a set */ }
38
+ });
39
+ },
40
+ update(fn) {
41
+ this.set(fn(value));
42
+ },
43
+ subscribe(cb) {
44
+ subs.add(cb);
45
+ return () => { subs.delete(cb); };
46
+ },
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Anything that can be watched: it exposes a `subscribe(cb)` returning an
52
+ * unsubscribe function. Stores satisfy this directly. (ORM entities are watched
53
+ * with `watchEntity` from your generated `db.ts`, which has the same shape.)
54
+ */
55
+ export interface Watchable {
56
+ subscribe(cb: (...args: any[]) => void): () => void;
57
+ }
58
+
59
+ /**
60
+ * Bridge a watchable source to a side-effect — typically an RPC emit that pushes
61
+ * the change to a subscribed webview. Runs `effect` on every change. Returns an
62
+ * unsubscribe function; register it on the panel's `ctx.subscriptions` (wrapped
63
+ * in `{ dispose }`) so it's cleaned up when the extension deactivates.
64
+ *
65
+ * // host side, in a panel's rpc():
66
+ * watch(badgeCount, () => server.emit('badge:changed'));
67
+ *
68
+ * For ORM entities, use `watchEntity(Todos, () => server.emit('todos:changed'))`
69
+ * from your generated db.ts — same idea, same return.
70
+ */
71
+ export function watch(source: Watchable, effect: () => void): () => void {
72
+ return source.subscribe(() => effect());
73
+ }