dsh-group-status 0.2.2 → 0.4.0
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 +65 -0
- package/README.en.md +42 -24
- package/README.md +45 -25
- package/lib/client.js +1781 -483
- package/lib/client.js.map +1 -1
- package/lib/index.js +22 -9
- package/lib/types/client/BadgeSettingsCard.d.ts +24 -0
- package/lib/types/client/BadgeSettingsCard.d.ts.map +1 -0
- package/lib/types/client/BadgeSettingsCard.js +73 -0
- package/lib/types/client/BadgeSettingsCard.js.map +1 -0
- package/lib/types/client/badge-field.d.ts +44 -0
- package/lib/types/client/badge-field.d.ts.map +1 -0
- package/lib/types/client/badge-field.js +77 -0
- package/lib/types/client/badge-field.js.map +1 -0
- package/lib/types/client/badge-labels.d.ts +92 -0
- package/lib/types/client/badge-labels.d.ts.map +1 -0
- package/lib/types/client/badge-labels.js +150 -0
- package/lib/types/client/badge-labels.js.map +1 -0
- package/lib/types/client/badge-settings.d.ts +31 -3
- package/lib/types/client/badge-settings.d.ts.map +1 -1
- package/lib/types/client/badge-settings.js +50 -6
- package/lib/types/client/badge-settings.js.map +1 -1
- package/lib/types/client/contract/slots.d.ts +39 -21
- package/lib/types/client/contract/slots.d.ts.map +1 -1
- package/lib/types/client/contract/slots.js.map +1 -1
- package/lib/types/client/contract/toast.d.ts +67 -0
- package/lib/types/client/contract/toast.d.ts.map +1 -0
- package/lib/types/client/contract/toast.js +2 -0
- package/lib/types/client/contract/toast.js.map +1 -0
- package/lib/types/client/facet-store.d.ts +46 -0
- package/lib/types/client/facet-store.d.ts.map +1 -0
- package/lib/types/client/facet-store.js +123 -0
- package/lib/types/client/facet-store.js.map +1 -0
- package/lib/types/client/facet-visibility.d.ts +17 -0
- package/lib/types/client/facet-visibility.d.ts.map +1 -0
- package/lib/types/client/facet-visibility.js +18 -0
- package/lib/types/client/facet-visibility.js.map +1 -0
- package/lib/types/client/facets.d.ts +265 -0
- package/lib/types/client/facets.d.ts.map +1 -0
- package/lib/types/client/facets.js +209 -0
- package/lib/types/client/facets.js.map +1 -0
- package/lib/types/client/group-status.d.ts +97 -45
- package/lib/types/client/group-status.d.ts.map +1 -1
- package/lib/types/client/group-status.js +148 -85
- package/lib/types/client/group-status.js.map +1 -1
- package/lib/types/client/index.d.ts +31 -3
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +107 -14
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/locales.d.ts +60 -4
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +60 -4
- package/lib/types/client/locales.js.map +1 -1
- package/lib/types/client/navigation.d.ts +45 -12
- package/lib/types/client/navigation.d.ts.map +1 -1
- package/lib/types/client/navigation.js +102 -26
- package/lib/types/client/navigation.js.map +1 -1
- package/lib/types/client/rows/GroupBadge.d.ts +19 -25
- package/lib/types/client/rows/GroupBadge.d.ts.map +1 -1
- package/lib/types/client/rows/GroupBadge.js +45 -106
- package/lib/types/client/rows/GroupBadge.js.map +1 -1
- package/lib/types/client/rows/Rows.d.ts +7 -3
- package/lib/types/client/rows/Rows.d.ts.map +1 -1
- package/lib/types/client/rows/Rows.js +9 -9
- package/lib/types/client/rows/Rows.js.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.d.ts +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.d.ts.map +1 -1
- package/lib/types/client/rows/WorkspaceBrowser.js +75 -71
- package/lib/types/client/rows/WorkspaceBrowser.js.map +1 -1
- package/lib/types/client/session-actions/ArchiveSession.js +1 -1
- package/lib/types/client/session-actions/ArchiveSession.js.map +1 -1
- package/lib/types/client/session-actions/ForkSession.d.ts +5 -4
- package/lib/types/client/session-actions/ForkSession.d.ts.map +1 -1
- package/lib/types/client/session-actions/ForkSession.js +7 -4
- package/lib/types/client/session-actions/ForkSession.js.map +1 -1
- package/lib/types/client/session-actions/PinSession.js +1 -1
- package/lib/types/client/session-actions/PinSession.js.map +1 -1
- package/lib/types/client/session-actions/RowActionToast.d.ts +5 -8
- package/lib/types/client/session-actions/RowActionToast.d.ts.map +1 -1
- package/lib/types/client/session-actions/RowActionToast.js +10 -49
- package/lib/types/client/session-actions/RowActionToast.js.map +1 -1
- package/lib/types/client/session-actions/SessionId.d.ts +8 -0
- package/lib/types/client/session-actions/SessionId.d.ts.map +1 -0
- package/lib/types/client/session-actions/SessionId.js +16 -0
- package/lib/types/client/session-actions/SessionId.js.map +1 -0
- package/lib/types/client/session-watermarks.d.ts +30 -0
- package/lib/types/client/session-watermarks.d.ts.map +1 -0
- package/lib/types/client/session-watermarks.js +54 -0
- package/lib/types/client/session-watermarks.js.map +1 -0
- package/lib/types/client/shortcuts.d.ts +2 -7
- package/lib/types/client/shortcuts.d.ts.map +1 -1
- package/lib/types/client/shortcuts.js +7 -11
- package/lib/types/client/shortcuts.js.map +1 -1
- package/lib/types/client/toast/Toast.d.ts +41 -0
- package/lib/types/client/toast/Toast.d.ts.map +1 -0
- package/lib/types/client/toast/Toast.js +44 -0
- package/lib/types/client/toast/Toast.js.map +1 -0
- package/lib/types/client/toast/register.d.ts +11 -0
- package/lib/types/client/toast/register.d.ts.map +1 -0
- package/lib/types/client/toast/register.js +162 -0
- package/lib/types/client/toast/register.js.map +1 -0
- package/lib/types/client/tree.d.ts +2 -5
- package/lib/types/client/tree.d.ts.map +1 -1
- package/lib/types/client/tree.js +0 -5
- package/lib/types/client/tree.js.map +1 -1
- package/lib/types/index.d.ts +31 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +13 -1
- package/lib/types/index.js.map +1 -1
- package/package.json +33 -34
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分组状态 **facet 协议**:本插件对外提供的唯一接入面。
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么是这个方向
|
|
5
|
+
*
|
|
6
|
+
* 折叠分组的徽标要把「组内有没有别的插件的状态」折成一个数字。此前是**本插件逐家
|
|
7
|
+
* 适配**:`require('dsh-later/client')`、`require('dsh-gitea-dispatch/client')`,再把
|
|
8
|
+
* 各家的字段翻成自己的类型。那个方向的代价已经实测过一次:提供方把 `deadline` /
|
|
9
|
+
* `waitMaxSec` / `prNumber` 发出来了,本插件的接收类型只声明了两个字段,于是信息
|
|
10
|
+
* **静默丢失**(编译不报错、运行不报错、测试不报错,见 CHANGELOG 0.2.3「适配只做了一半」)。
|
|
11
|
+
*
|
|
12
|
+
* 现在方向反过来:**状态的所有者把自己的事实注册进来**,本插件只认协议形状。
|
|
13
|
+
* 新增一个状态源,本插件一行都不改。
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* // provider 侧(在自己的 apply 里)
|
|
17
|
+
* const groupStatus = require('dsh-group-status/client')
|
|
18
|
+
* groupStatus?.registerGroupStatusFacet?.({
|
|
19
|
+
* protocol: 1,
|
|
20
|
+
* id: 'my-plugin.review',
|
|
21
|
+
* subscribe: store.subscribe,
|
|
22
|
+
* getSnapshot: store.getSnapshot,
|
|
23
|
+
* fold: (snapshot, sessionIds, now) => ({ count, tone, pulse, data }),
|
|
24
|
+
* merge: (a, b) => ({ ... }),
|
|
25
|
+
* label: (fold, now) => '等待评审(剩 3分钟) · #15',
|
|
26
|
+
* renderIcon: (fold) => h('svg', …),
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* ## 为什么用 `subscribe` / `getSnapshot` 而不是 React hook
|
|
31
|
+
*
|
|
32
|
+
* 上一版让每家导出一个 hook,本插件在同一个组件里 `useXxxHook?.()` 调。两条都不成立:
|
|
33
|
+
*
|
|
34
|
+
* 1. **hook 数量必须逐次渲染恒定**,而 facet 是运行时注册/注销的:注册面一变,同一个
|
|
35
|
+
* 组件的 hook 调用序列就变了,React 直接抛 "Rendered more hooks than during the
|
|
36
|
+
* previous render"。
|
|
37
|
+
* 2. 本插件因此必须知道"有几个 facet、各叫什么"——正是想消掉的那个耦合。
|
|
38
|
+
*
|
|
39
|
+
* `subscribe` / `getSnapshot` 是同一份能力的非 React 形态(宿主
|
|
40
|
+
* `useSyncExternalStore` 的外部存储面),一个通用订阅器就能覆盖任意多个 facet。
|
|
41
|
+
*
|
|
42
|
+
* ## 为什么 `fold` 返回 `data`,而不是返回可渲染文本
|
|
43
|
+
*
|
|
44
|
+
* 多层文件夹要把同一个 facet 在子树各层的折叠结果**再合并**一次。文本合并不了
|
|
45
|
+
* (「剩 3分钟」和「剩 5分钟」拼起来不是答案),结构化 `data` 能合并——合并规则归
|
|
46
|
+
* facet 自己({@link GroupStatusFacet.merge}),渲染时刻再由
|
|
47
|
+
* {@link GroupStatusFacet.label} 现算文案。本插件全程不解释 `data`。
|
|
48
|
+
*
|
|
49
|
+
* ## 兼容性
|
|
50
|
+
*
|
|
51
|
+
* 协议带 `protocol` 版本号。本插件只接受
|
|
52
|
+
* {@link GROUP_STATUS_FACET_PROTOCOL_VERSION} 的 facet,其它版本**拒绝注册**并在
|
|
53
|
+
* console 点名(静默忽略会让"我注册了为什么没显示"变成不可诊断的问题)。
|
|
54
|
+
*
|
|
55
|
+
* @module dsh-group-status/client/facets
|
|
56
|
+
*/
|
|
57
|
+
import type { ReactNode } from 'react';
|
|
58
|
+
/** 本协议文件的协议版本。provider 必须原样填这个常量。 */
|
|
59
|
+
export declare const GROUP_STATUS_FACET_PROTOCOL_VERSION = 1;
|
|
60
|
+
/** 徽标可用的三档语义色(本插件的色板;provider 选档,不选具体颜色)。 */
|
|
61
|
+
export type FacetTone = 'info' | 'warn' | 'error';
|
|
62
|
+
/** tone 之间的优先级(越大越紧急),用于多层合并时取更高档。 */
|
|
63
|
+
export declare const FACET_TONE_RANK: Readonly<Record<FacetTone, number>>;
|
|
64
|
+
/**
|
|
65
|
+
* 一个 facet 在**一组会话**上折出来的事实。
|
|
66
|
+
*
|
|
67
|
+
* 字段是本插件与 provider 之间唯一的运行时契约:`count` 进徽标数字,`tone` 选色,
|
|
68
|
+
* `pulse` 决定要不要脉冲,`data` 归 provider 自用(本插件从不读它)。
|
|
69
|
+
*/
|
|
70
|
+
export interface FacetFold<Data = unknown> {
|
|
71
|
+
/**
|
|
72
|
+
* 贡献给徽标数字的条数。`0` 表示这个来源此刻不参与徽标(本插件会跳过它,
|
|
73
|
+
* 不画图标、不进文案)。
|
|
74
|
+
*/
|
|
75
|
+
count: number;
|
|
76
|
+
/** 语义色档。 */
|
|
77
|
+
tone: FacetTone;
|
|
78
|
+
/** 是否脉冲。紧迫感由状态所有者判定,不由徽标反推。 */
|
|
79
|
+
pulse: boolean;
|
|
80
|
+
/** 合并与文案所需的原始事实,形状由 facet 自定。 */
|
|
81
|
+
data?: Data;
|
|
82
|
+
}
|
|
83
|
+
/** {@link GroupStatusFacet.label} / {@link GroupStatusFacet.renderIcon} 的渲染上下文。 */
|
|
84
|
+
export interface FacetRenderContext {
|
|
85
|
+
/** 渲染时刻(epoch ms)。用于把 `data` 里的截止时刻换算成「还剩多久」。 */
|
|
86
|
+
now: number;
|
|
87
|
+
/**
|
|
88
|
+
* 侧栏行的翻译位(本插件的 `workspace` 命名空间)。
|
|
89
|
+
*
|
|
90
|
+
* ⚠️ 这是**便利项,不是义务**:provider 若有自己的 locale 命名空间,应当闭包自己
|
|
91
|
+
* 的翻译函数、忽略这里。这个字段是为**代管方**(`origin: 'legacy'`)复用本插件的行
|
|
92
|
+
* 文案而存在的;内置适配器已删除(迁移史见 `docs/facet-protocol.md`),字段保留给下一次代管。
|
|
93
|
+
*/
|
|
94
|
+
t: (key: string, options?: Record<string, string | number>) => string;
|
|
95
|
+
}
|
|
96
|
+
/** 一个注册进来的状态源。 */
|
|
97
|
+
export interface GroupStatusFacet<Input = unknown, Data = unknown> {
|
|
98
|
+
/** 必须是 {@link GROUP_STATUS_FACET_PROTOCOL_VERSION}。 */
|
|
99
|
+
readonly protocol: number;
|
|
100
|
+
/**
|
|
101
|
+
* 全局唯一 id,建议 `'<包名>.<状态名>'`(如 `'dsh-gitea-dispatch.waiting-review'`)。
|
|
102
|
+
* 它同时是 React key、重复注册的判据,以及本插件设置项的挂钩键({@link settingKey})。
|
|
103
|
+
*/
|
|
104
|
+
readonly id: string;
|
|
105
|
+
/**
|
|
106
|
+
* 外部存储订阅面(宿主 `useSyncExternalStore` 的第一参数)。
|
|
107
|
+
*
|
|
108
|
+
* 必须在快照可能变化时被调用,并且**允许多个订阅者**;返回退订函数。
|
|
109
|
+
*/
|
|
110
|
+
subscribe(listener: () => void): () => void;
|
|
111
|
+
/** 当前快照;还没拿到数据时返回 `undefined`(本插件会把该 facet 当作无贡献)。 */
|
|
112
|
+
getSnapshot(): Input | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* 把快照折成这一组会话上的事实。
|
|
115
|
+
*
|
|
116
|
+
* 纯函数要求:同样的 `(snapshot, sessionIds, now)` 必须给出等价的折果——
|
|
117
|
+
* 它在每次渲染里被调用,不该有副作用。
|
|
118
|
+
* @param snapshot - {@link getSnapshot} 的结果。
|
|
119
|
+
* @param sessionIds - 组内会话 id(含前缀形态;口径归 provider 判定)。
|
|
120
|
+
* @param now - 本次折叠的时刻(epoch ms)。
|
|
121
|
+
*/
|
|
122
|
+
fold(snapshot: Input | undefined, sessionIds: readonly string[], now: number): FacetFold<Data>;
|
|
123
|
+
/**
|
|
124
|
+
* 合并同一 facet 在子树各层的折果(多层文件夹)。
|
|
125
|
+
*
|
|
126
|
+
* 缺省实现按 `count` 相加、`tone` 取更紧急的一档、`pulse` 取或;facet 若需要
|
|
127
|
+
* 合并自己的 `data`(例如 PR 号并集、最早截止时刻)就必须覆盖它。
|
|
128
|
+
*/
|
|
129
|
+
merge?(a: FacetFold<Data>, b: FacetFold<Data>): FacetFold<Data>;
|
|
130
|
+
/**
|
|
131
|
+
* 徽标 `aria-label` / `title` 与悬停明细里的那句话。
|
|
132
|
+
*
|
|
133
|
+
* 由 provider 自己本地化(用它自己的 locale 命名空间);本插件不参与措辞。
|
|
134
|
+
* 返回空串视为「这个 facet 没有可显示文案」,只保留数字贡献。
|
|
135
|
+
*/
|
|
136
|
+
label?(fold: FacetFold<Data>, context: FacetRenderContext): string;
|
|
137
|
+
/**
|
|
138
|
+
* 图标。provider 交出**已含配色**的 React 元素(它最懂自己的状态该怎么画,
|
|
139
|
+
* 包括"超时该静止还是该闪"这类视觉语义)。
|
|
140
|
+
*
|
|
141
|
+
* 不提供时,本插件退回一个按 `tone` 取色的通用点。
|
|
142
|
+
*/
|
|
143
|
+
renderIcon?(fold: FacetFold<Data>, context: FacetRenderContext): ReactNode;
|
|
144
|
+
/**
|
|
145
|
+
* 受本插件哪个设置项开关控制(如 `'showWaitingReviewInBadge'`)。
|
|
146
|
+
*
|
|
147
|
+
* 省略 = 不受开关控制,始终参与。开关的**语义**(关掉意味着什么)由本插件判定,
|
|
148
|
+
* provider 只声明挂钩键。
|
|
149
|
+
*/
|
|
150
|
+
settingKey?: string;
|
|
151
|
+
/**
|
|
152
|
+
* 渲染顺序(升序)。**缺省排在所有声明过 `order` 的来源之后**,彼此按注册先后,
|
|
153
|
+
* 这样新接入的陌生来源不会插到既有状态前面抢视觉位置。
|
|
154
|
+
*/
|
|
155
|
+
order?: number;
|
|
156
|
+
/**
|
|
157
|
+
* 来源标记。**provider 不用填**(缺省即 `provider`)。
|
|
158
|
+
*
|
|
159
|
+
* 代管某个来源的一方显式写 `'legacy'`,用它声明「我是在替状态所有者代管」,从而在
|
|
160
|
+
* 对方接入同名 facet 时自动让位。本插件目前不代管任何来源,这条规则为**下一次**迁移
|
|
161
|
+
* 保留。见 {@link FACET_ORIGIN_RANK}。
|
|
162
|
+
*/
|
|
163
|
+
origin?: FacetOrigin;
|
|
164
|
+
}
|
|
165
|
+
/** 协议来源:`provider` = 状态所有者自己注册;`legacy` = 替状态所有者代管的注册方(本插件目前不代管任何来源)。 */
|
|
166
|
+
export type FacetOrigin = 'provider' | 'legacy';
|
|
167
|
+
/**
|
|
168
|
+
* 同 id 冲突时**由来源决胜,与注册顺序无关**。
|
|
169
|
+
*
|
|
170
|
+
* 宿主不保证插件 apply 的先后。过渡期内"本插件代 provider 写的适配器"与"provider
|
|
171
|
+
* 自己注册的 facet"会撞同一个 id:若靠顺序决胜,同一份部署今天显示、明天不显示。
|
|
172
|
+
* `provider` 恒胜 `legacy`:所有者一接入,代管方立刻让位,且不重复计数。迁移因此
|
|
173
|
+
* 不需要协商发布顺序。
|
|
174
|
+
*/
|
|
175
|
+
export declare const FACET_ORIGIN_RANK: Readonly<Record<FacetOrigin, number>>;
|
|
176
|
+
/** 一个 facet 的来源;缺省按 `provider`(最保守的假设:别人主动注册就是所有者)。 */
|
|
177
|
+
export declare function facetOrigin(facet: {
|
|
178
|
+
readonly origin?: FacetOrigin;
|
|
179
|
+
}): FacetOrigin;
|
|
180
|
+
/** 任意来源的 facet / 折果:聚合与渲染侧使用的**非泛型**形态。
|
|
181
|
+
*
|
|
182
|
+
* 协议对 provider 是泛型的(它能拿到自己的 `data` 类型),但登记面、折果表、渲染层
|
|
183
|
+
* 都不关心 `data` 是什么,所以内部一律用这两个别名。方法用**方法语法**声明,于是
|
|
184
|
+
* 具体 facet 的 `fold` / `merge` 在这些位置上是可赋值的(双变),不需要 `as never`。
|
|
185
|
+
*/
|
|
186
|
+
export type AnyFacet = GroupStatusFacet<unknown, unknown>;
|
|
187
|
+
export type AnyFacetFold = FacetFold<unknown>;
|
|
188
|
+
/** 一个已登记 facet 及其排序位。 */
|
|
189
|
+
export interface RegisteredFacet {
|
|
190
|
+
facet: AnyFacet;
|
|
191
|
+
/** 注册序号,作为 `order` 相同时的稳定 tie-break。 */
|
|
192
|
+
sequence: number;
|
|
193
|
+
}
|
|
194
|
+
/** {@link registerGroupStatusFacet} 的失败原因。 */
|
|
195
|
+
export type FacetRejection = 'not-an-object' | 'protocol-mismatch' | 'missing-id' | 'missing-methods'
|
|
196
|
+
/** 同 id 上已有更高来源的登记(过渡期适配器被状态所有者顶掉) */
|
|
197
|
+
| 'superseded';
|
|
198
|
+
/** 注册结果:成功带 `id`,失败带原因(且**不**静默丢弃)。 */
|
|
199
|
+
export type FacetRegistration = {
|
|
200
|
+
ok: true;
|
|
201
|
+
id: string;
|
|
202
|
+
} | {
|
|
203
|
+
ok: false;
|
|
204
|
+
id: string;
|
|
205
|
+
reason: FacetRejection;
|
|
206
|
+
};
|
|
207
|
+
/** 退订/注销函数。 */
|
|
208
|
+
export type Unregister = () => void;
|
|
209
|
+
/**
|
|
210
|
+
* 检查一个 facet 是否符合协议 v1。
|
|
211
|
+
* @returns 拒绝原因;`undefined` 表示可用。
|
|
212
|
+
*/
|
|
213
|
+
export declare function facetRejection(facet: unknown): FacetRejection | undefined;
|
|
214
|
+
/**
|
|
215
|
+
* 缺省折果合并:数量相加、色档取更紧急的一档、脉冲取或。
|
|
216
|
+
*
|
|
217
|
+
* ⚠️ 它**不**合并 `data`(本插件不知道 `data` 是什么)。需要合并原始事实的 facet
|
|
218
|
+
* 必须自己实现 {@link GroupStatusFacet.merge}。
|
|
219
|
+
*/
|
|
220
|
+
export declare function defaultMergeFold(a: AnyFacetFold, b: AnyFacetFold): AnyFacetFold;
|
|
221
|
+
/**
|
|
222
|
+
* 登记表面:一个可订阅的 facet 列表。
|
|
223
|
+
*
|
|
224
|
+
* 用闭包工厂里的**模块级单例**,于是 provider 与本插件拿到的是同一张表:模块表行
|
|
225
|
+
* 只在首次 `require` 时 materialize,之后所有调用方共享同一实例。
|
|
226
|
+
*/
|
|
227
|
+
export interface FacetRegistry {
|
|
228
|
+
/**
|
|
229
|
+
* 登记一个 facet。
|
|
230
|
+
*
|
|
231
|
+
* 同 id 已存在时按**来源**决胜({@link FACET_ORIGIN_RANK}):更高来源保持原位,
|
|
232
|
+
* 同来源或更高者覆盖。返回失败而不静默丢弃,调用方能在 console 里查到原因。
|
|
233
|
+
*/
|
|
234
|
+
register(facet: AnyFacet): FacetRegistration;
|
|
235
|
+
/**
|
|
236
|
+
* 摘掉一个登记项。
|
|
237
|
+
*
|
|
238
|
+
* 给了 `facet` 时只摘"**当前登记的还是它**"的那一份:同 id 已被后来的实现替换后,
|
|
239
|
+
* 旧 provider 的 dispose 不该把新登记摘掉。
|
|
240
|
+
* @returns 是否真的摘掉了。
|
|
241
|
+
*/
|
|
242
|
+
remove(id: string, facet?: AnyFacet): boolean;
|
|
243
|
+
/** 当前登记项,按 `order` 再按注册先后排序。 */
|
|
244
|
+
list(): readonly RegisteredFacet[];
|
|
245
|
+
/** 订阅登记面变化(注册/注销时触发)。 */
|
|
246
|
+
subscribe(listener: () => void): () => void;
|
|
247
|
+
}
|
|
248
|
+
/** 创建一张登记表面(测试用;生产走模块级单例 {@link registry})。 */
|
|
249
|
+
export declare function createFacetRegistry(): FacetRegistry;
|
|
250
|
+
/**
|
|
251
|
+
* 生产用的模块级单例登记表面。
|
|
252
|
+
*
|
|
253
|
+
* 与 {@link createFacetRegistry} 分开,是为了让测试能对着一张干净的表断言协议行为,
|
|
254
|
+
* 而不会被别的用例或别的插件登记的 facet 污染。
|
|
255
|
+
*/
|
|
256
|
+
export declare const registry: FacetRegistry;
|
|
257
|
+
/**
|
|
258
|
+
* 本插件 client 入口对外的登记函数(provider 侧唯一需要认识的符号)。
|
|
259
|
+
*
|
|
260
|
+
* @param facet - 待登记的 facet。
|
|
261
|
+
* @returns 注销函数;**注册失败时返回一个空操作**,同时把原因写进 console——
|
|
262
|
+
* 返回值形状保持稳定,provider 的 dispose 路径不必区分成败。
|
|
263
|
+
*/
|
|
264
|
+
export declare function registerGroupStatusFacet(facet: AnyFacet): Unregister;
|
|
265
|
+
//# sourceMappingURL=facets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facets.d.ts","sourceRoot":"","sources":["../../../src/client/facets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/** 本协议文件的协议版本。provider 必须原样填这个常量。 */
|
|
2
|
+
export const GROUP_STATUS_FACET_PROTOCOL_VERSION = 1;
|
|
3
|
+
/** tone 之间的优先级(越大越紧急),用于多层合并时取更高档。 */
|
|
4
|
+
export const FACET_TONE_RANK = Object.freeze({
|
|
5
|
+
info: 0, warn: 1, error: 2,
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* 同 id 冲突时**由来源决胜,与注册顺序无关**。
|
|
9
|
+
*
|
|
10
|
+
* 宿主不保证插件 apply 的先后。过渡期内"本插件代 provider 写的适配器"与"provider
|
|
11
|
+
* 自己注册的 facet"会撞同一个 id:若靠顺序决胜,同一份部署今天显示、明天不显示。
|
|
12
|
+
* `provider` 恒胜 `legacy`:所有者一接入,代管方立刻让位,且不重复计数。迁移因此
|
|
13
|
+
* 不需要协商发布顺序。
|
|
14
|
+
*/
|
|
15
|
+
export const FACET_ORIGIN_RANK = Object.freeze({
|
|
16
|
+
legacy: 0, provider: 1,
|
|
17
|
+
});
|
|
18
|
+
/** 一个 facet 的来源;缺省按 `provider`(最保守的假设:别人主动注册就是所有者)。 */
|
|
19
|
+
export function facetOrigin(facet) {
|
|
20
|
+
return facet.origin === 'legacy' ? 'legacy' : 'provider';
|
|
21
|
+
}
|
|
22
|
+
// #25③:此处原有 `const TONE_ORDER = ['info','warn','error']`,与对外导出的
|
|
23
|
+
// `FACET_TONE_RANK` 是同一个事实的两份实现,且只有 `defaultMergeFold` 一个使用者。
|
|
24
|
+
// 现已统一到 `FACET_TONE_RANK`(见该函数),私有那份删除。
|
|
25
|
+
/**
|
|
26
|
+
* 检查一个 facet 是否符合协议 v1。
|
|
27
|
+
* @returns 拒绝原因;`undefined` 表示可用。
|
|
28
|
+
*/
|
|
29
|
+
export function facetRejection(facet) {
|
|
30
|
+
if (typeof facet !== 'object' || facet === null)
|
|
31
|
+
return 'not-an-object';
|
|
32
|
+
const candidate = facet;
|
|
33
|
+
if (candidate.protocol !== GROUP_STATUS_FACET_PROTOCOL_VERSION)
|
|
34
|
+
return 'protocol-mismatch';
|
|
35
|
+
if (typeof candidate.id !== 'string' || candidate.id === '')
|
|
36
|
+
return 'missing-id';
|
|
37
|
+
if (typeof candidate.subscribe !== 'function'
|
|
38
|
+
|| typeof candidate.getSnapshot !== 'function'
|
|
39
|
+
|| typeof candidate.fold !== 'function')
|
|
40
|
+
return 'missing-methods';
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 缺省折果合并:数量相加、色档取更紧急的一档、脉冲取或。
|
|
45
|
+
*
|
|
46
|
+
* ⚠️ 它**不**合并 `data`(本插件不知道 `data` 是什么)。需要合并原始事实的 facet
|
|
47
|
+
* 必须自己实现 {@link GroupStatusFacet.merge}。
|
|
48
|
+
*/
|
|
49
|
+
export function defaultMergeFold(a, b) {
|
|
50
|
+
// #25③:读对外导出的 `FACET_TONE_RANK`,不再另持一份私有 `TONE_ORDER`。两份表的顺序
|
|
51
|
+
// 逐项相同(`{info:0,warn:1,error:2}` 与 `['info','warn','error']` 的下标一致),所以对
|
|
52
|
+
// 合法色档这是**零行为变更**;收口的是「同一个事实两份实现」本身。
|
|
53
|
+
//
|
|
54
|
+
// ⚠️ `?? -1` **不是防御性冗余,是负载性的,别顺手删**。`facetRejection` 只校验
|
|
55
|
+
// protocol / id / 三个方法,**不校验 `fold()` 返回的 `tone`** —— 那是跨插件边界,坏
|
|
56
|
+
// provider 交回一个非法档位是真能到达这里的。旧的 `TONE_ORDER.indexOf(非法值)` 得到
|
|
57
|
+
// `-1`,于是另一侧的合法档位必胜(`2 > -1`);而 `FACET_TONE_RANK[非法值]` 得到
|
|
58
|
+
// `undefined`,任何比较都是 `false`,非法档位就会被**传播出去**。少了这个 `?? -1`,
|
|
59
|
+
// 本次重构会在坏输入下静默改变结果。
|
|
60
|
+
const toneA = FACET_TONE_RANK[a.tone] ?? -1;
|
|
61
|
+
const toneB = FACET_TONE_RANK[b.tone] ?? -1;
|
|
62
|
+
return {
|
|
63
|
+
count: a.count + b.count,
|
|
64
|
+
tone: toneB > toneA ? b.tone : a.tone,
|
|
65
|
+
pulse: a.pulse || b.pulse,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** 创建一张登记表面(测试用;生产走模块级单例 {@link registry})。 */
|
|
69
|
+
export function createFacetRegistry() {
|
|
70
|
+
const entries = new Map();
|
|
71
|
+
const listeners = new Set();
|
|
72
|
+
let sequence = 0;
|
|
73
|
+
let sorted = [];
|
|
74
|
+
const resort = () => {
|
|
75
|
+
sorted = [...entries.values()].sort((x, y) => {
|
|
76
|
+
// 排序键 = (有没有声明 order, order, 注册序号)。
|
|
77
|
+
// 没声明 order 的来源一律排在**所有声明过的之后**,彼此按注册先后:陌生新来者
|
|
78
|
+
// 不该插到既有状态前面抢视觉位置,而两两之间又没有可比的新排序键。
|
|
79
|
+
const declaredX = x.facet.order !== undefined;
|
|
80
|
+
const declaredY = y.facet.order !== undefined;
|
|
81
|
+
if (declaredX !== declaredY)
|
|
82
|
+
return declaredX ? -1 : 1;
|
|
83
|
+
if (declaredX && declaredY)
|
|
84
|
+
return x.facet.order - y.facet.order;
|
|
85
|
+
return x.sequence - y.sequence;
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
let notifying = false;
|
|
89
|
+
let pending = false;
|
|
90
|
+
/**
|
|
91
|
+
* 通知订阅者,并把**重入合并成一轮补跑**。
|
|
92
|
+
*
|
|
93
|
+
* 订阅者在自己的回调里登记/注销 facet 是完全合法的(消费方常在收到变更后立即
|
|
94
|
+
* 补登记一个派生来源)。直接递归会有两个问题:嵌套深度由订阅者数量决定(两个互相
|
|
95
|
+
* 触发的订阅者就是无界递归),而且中间那轮通知看到的登记面是**改到一半**的。
|
|
96
|
+
* 所以内层调用只置脏标志,外层跑完一轮后再补一轮,直到没有新的改动 —— 每个订阅者
|
|
97
|
+
* 都看得到最终状态,递归深度恒为 1。
|
|
98
|
+
*/
|
|
99
|
+
const notify = () => {
|
|
100
|
+
if (notifying) {
|
|
101
|
+
pending = true;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
notifying = true;
|
|
105
|
+
try {
|
|
106
|
+
do {
|
|
107
|
+
pending = false;
|
|
108
|
+
// 复制一份再遍历:订阅者可能在回调里退订自己。
|
|
109
|
+
for (const listener of [...listeners]) {
|
|
110
|
+
try {
|
|
111
|
+
listener();
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
/* 单个订阅者异常不影响其余订阅者 */
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} while (pending);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
notifying = false;
|
|
121
|
+
pending = false;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
register: (facet) => {
|
|
126
|
+
const reason = facetRejection(facet);
|
|
127
|
+
const id = typeof facet?.id === 'string' ? facet.id : '';
|
|
128
|
+
if (reason !== undefined)
|
|
129
|
+
return { ok: false, id, reason };
|
|
130
|
+
const existing = entries.get(id);
|
|
131
|
+
const nextRank = FACET_ORIGIN_RANK[facetOrigin(facet)];
|
|
132
|
+
if (existing !== undefined && FACET_ORIGIN_RANK[facetOrigin(existing.facet)] > nextRank) {
|
|
133
|
+
// 同 id 上站着更高来源的登记(状态所有者已经自己接入),低的一边让位。
|
|
134
|
+
return { ok: false, id, reason: 'superseded' };
|
|
135
|
+
}
|
|
136
|
+
sequence += 1;
|
|
137
|
+
// 同来源重复登记直接覆盖:provider 热替换实现不必先注销再登记。
|
|
138
|
+
entries.set(id, { facet, sequence });
|
|
139
|
+
resort();
|
|
140
|
+
notify();
|
|
141
|
+
return { ok: true, id };
|
|
142
|
+
},
|
|
143
|
+
remove: (id, facet) => {
|
|
144
|
+
const current = entries.get(id);
|
|
145
|
+
if (current === undefined)
|
|
146
|
+
return false;
|
|
147
|
+
if (facet !== undefined && current.facet !== facet)
|
|
148
|
+
return false;
|
|
149
|
+
entries.delete(id);
|
|
150
|
+
resort();
|
|
151
|
+
notify();
|
|
152
|
+
return true;
|
|
153
|
+
},
|
|
154
|
+
list: () => sorted,
|
|
155
|
+
subscribe: (listener) => {
|
|
156
|
+
listeners.add(listener);
|
|
157
|
+
return () => {
|
|
158
|
+
listeners.delete(listener);
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* 生产用的模块级单例登记表面。
|
|
165
|
+
*
|
|
166
|
+
* 与 {@link createFacetRegistry} 分开,是为了让测试能对着一张干净的表断言协议行为,
|
|
167
|
+
* 而不会被别的用例或别的插件登记的 facet 污染。
|
|
168
|
+
*/
|
|
169
|
+
export const registry = createFacetRegistry();
|
|
170
|
+
/**
|
|
171
|
+
* 本插件 client 入口对外的登记函数(provider 侧唯一需要认识的符号)。
|
|
172
|
+
*
|
|
173
|
+
* @param facet - 待登记的 facet。
|
|
174
|
+
* @returns 注销函数;**注册失败时返回一个空操作**,同时把原因写进 console——
|
|
175
|
+
* 返回值形状保持稳定,provider 的 dispose 路径不必区分成败。
|
|
176
|
+
*/
|
|
177
|
+
export function registerGroupStatusFacet(facet) {
|
|
178
|
+
const result = registry.register(facet);
|
|
179
|
+
if (!result.ok) {
|
|
180
|
+
// 过渡期适配器被状态所有者顶掉是**预期结果**,不是错误:报一条 warn 会让人以为
|
|
181
|
+
// 徽标坏了。除此之外的每一次失败都必须可见,否则"注册了却没显示"无从诊断。
|
|
182
|
+
if (!(result.reason === 'superseded' && facetOrigin(facet) === 'legacy'))
|
|
183
|
+
reportRejection(result);
|
|
184
|
+
return () => undefined;
|
|
185
|
+
}
|
|
186
|
+
// 只摘"还是自己"的那一份:同 id 已被后来的实现替换时,旧 dispose 不该动新登记。
|
|
187
|
+
return () => {
|
|
188
|
+
registry.remove(result.id, facet);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 把注册失败写成一条可诊断的日志。
|
|
193
|
+
*
|
|
194
|
+
* 刻意不抛错:状态显示是增强功能,一个插件协议填错不该把宿主界面渲染打断;
|
|
195
|
+
* 但也不静默——"注册了却没显示"必须能查出原因。
|
|
196
|
+
*/
|
|
197
|
+
function reportRejection(rejection) {
|
|
198
|
+
const detail = rejection.reason === 'protocol-mismatch'
|
|
199
|
+
? `本插件只接受 protocol: ${GROUP_STATUS_FACET_PROTOCOL_VERSION}`
|
|
200
|
+
: rejection.reason === 'missing-methods'
|
|
201
|
+
? 'subscribe / getSnapshot / fold 三个方法必须齐备'
|
|
202
|
+
: rejection.reason === 'missing-id'
|
|
203
|
+
? "id 必须是非空字符串,建议 '<包名>.<状态名>'"
|
|
204
|
+
: rejection.reason === 'superseded'
|
|
205
|
+
? '同 id 上已有更高来源的登记;两个不同插件用了同一个 id,请各自换名'
|
|
206
|
+
: 'facet 必须是一个对象';
|
|
207
|
+
console.warn(`dsh-group-status: 拒绝登记状态 facet "${rejection.id}"(${rejection.reason}):${detail}`);
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=facets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facets.js","sourceRoot":"","sources":["../../../src/client/facets.ts"],"names":[],"mappings":"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"}
|