@jayyuen66/dsh-plugin-shared 0.1.9 → 0.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/README.md +73 -66
- package/README.zh-CN.md +98 -91
- package/config/tsconfig.client.base.json +1 -1
- package/dist/build/build-client.js +2 -2
- package/dist/build/build-host.js +1 -1
- package/dist/build/canonicalize-region-paths-DowoRhQK.js +1 -0
- package/dist/canonicalize-region-paths.js +1 -1
- package/dist/card-ui.js +105 -0
- package/dist/config/oxlint.base.js +1 -1
- package/dist/config/vitest.base.js +1 -1
- package/dist/jsonl.js +3 -3
- package/dist/project-key.js +1 -1
- package/dist/types/build-artifacts.d.ts +11 -11
- package/dist/types/build-client.d.ts +20 -20
- package/dist/types/build-host.d.ts +4 -4
- package/dist/types/build-types.d.ts +4 -4
- package/dist/types/canonicalize-region-paths.d.ts +1 -1
- package/dist/types/card-apply.d.ts +9 -9
- package/dist/types/card-ui/field.d.ts +33 -0
- package/dist/types/card-ui/hint.d.ts +11 -0
- package/dist/types/card-ui/inputs.d.ts +33 -0
- package/dist/types/card-ui/layout.d.ts +19 -0
- package/dist/types/card-ui/save-bar.d.ts +16 -0
- package/dist/types/card-ui/select.d.ts +15 -0
- package/dist/types/card-ui/styles.d.ts +2 -0
- package/dist/types/card-ui.d.ts +10 -0
- package/dist/types/config/oxlint.base.d.ts +118 -38
- package/dist/types/config/vitest.base.d.ts +3 -3
- package/dist/types/errors.d.ts +6 -6
- package/dist/types/job-outcome.d.ts +12 -12
- package/dist/types/jsonl.d.ts +6 -6
- package/dist/types/lesson-bus.d.ts +2 -2
- package/dist/types/locale.d.ts +9 -9
- package/dist/types/project-key.d.ts +6 -5
- package/dist/types/record.d.ts +16 -16
- package/dist/types/text.d.ts +4 -4
- package/dist/types/tool-events.d.ts +50 -21
- package/package.json +41 -22
- package/dist/build/canonicalize-region-paths-BxladpX3.js +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** 设置卡统一组件与样式。客户端专用的子模块,不进入根 barrel。 */
|
|
2
|
+
export { CARD_UI_CSS } from "./card-ui/styles.js";
|
|
3
|
+
export { splitHint } from "./card-ui/hint.js";
|
|
4
|
+
export { CardForm, FieldGrid, Section, StatusBar } from "./card-ui/layout.js";
|
|
5
|
+
export { Field, FieldLabel, InfoTip } from "./card-ui/field.js";
|
|
6
|
+
export type { FieldBase } from "./card-ui/field.js";
|
|
7
|
+
export { ListField, NumberField, TextField, ToggleField } from "./card-ui/inputs.js";
|
|
8
|
+
export { SelectField } from "./card-ui/select.js";
|
|
9
|
+
export type { SelectOption } from "./card-ui/select.js";
|
|
10
|
+
export { SaveBar } from "./card-ui/save-bar.js";
|
|
@@ -2,32 +2,32 @@ import type { OxlintConfig, OxlintOverride } from "oxlint";
|
|
|
2
2
|
export type RuleTable = NonNullable<OxlintConfig["rules"]>;
|
|
3
3
|
/**
|
|
4
4
|
* 一条规则能被关掉的**全部**合法理由。写不进这六类的,就不该有关掉它的选项。
|
|
5
|
-
*
|
|
5
|
+
* 每类的判断依据来自 oxlint/eslint 官方文档、上游 recommended 集合的归属,加上本仓的实测。
|
|
6
6
|
*/
|
|
7
7
|
export type OffReason =
|
|
8
|
-
/**
|
|
9
|
-
"
|
|
10
|
-
/**
|
|
11
|
-
| "
|
|
12
|
-
/**
|
|
13
|
-
| "
|
|
14
|
-
/**
|
|
15
|
-
| "
|
|
16
|
-
/**
|
|
8
|
+
/** 规则的判断标准与官方代码形态相反,开启等于判定官方写法违规。 */
|
|
9
|
+
"与官方形态冲突"
|
|
10
|
+
/** 与本仓已启用的另一条规则互相排除(开一侧就判另一侧全部违规)。 */
|
|
11
|
+
| "与已启用规则互斥"
|
|
12
|
+
/** 按它的意思改代码会把代码改坏,有实测的编译或运行后果。 */
|
|
13
|
+
| "实测有害"
|
|
14
|
+
/** 判断标准只在某类文件(用例文件、构建脚本)里成立,按文件种类收窄。 */
|
|
15
|
+
| "仅限特定文件"
|
|
16
|
+
/** 纯风格偏好类规则,上游不放进 recommended,开启只带来语义无关的重写。 */
|
|
17
17
|
| "上游不推荐"
|
|
18
|
-
/** 旧 `.oxlintrc.json`
|
|
19
|
-
| "
|
|
18
|
+
/** 旧 `.oxlintrc.json` 继承下来、实测开启后零命中——没有存在的理由,直接作废。 */
|
|
19
|
+
| "零命中作废";
|
|
20
20
|
export interface OffJustification {
|
|
21
21
|
/** 关它的理由类别。 */
|
|
22
22
|
kind: OffReason;
|
|
23
|
-
/**
|
|
23
|
+
/** 打开它在全仓产生的条数(测量方法见 OFF_JUSTIFICATIONS 的头注释)。 */
|
|
24
24
|
measured: number;
|
|
25
25
|
/** 一句话依据;配置加载只要求这个字段非空。 */
|
|
26
26
|
note: string;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
*
|
|
30
|
-
* 与基线取差数 `::error` 行,按路径分成 prod / test / scripts
|
|
29
|
+
* 实测方法:临时把基线里每条 `off`(rules 与 override 层都算)翻成 `error` 再跑 15 个成员、
|
|
30
|
+
* 与基线取差数 `::error` 行,按路径分成 prod / test / scripts 三类。`--deny=<rule>` 盖不住
|
|
31
31
|
* `off`,最早一轮用它在 13 个包目录上量出的数因此全偏小(`vitest/no-hooks` 用 `-D` 量出来是
|
|
32
32
|
* 0,实际是 181),整批作废重测。
|
|
33
33
|
*
|
|
@@ -37,8 +37,8 @@ export declare const OFF_JUSTIFICATIONS: Record<string, OffJustification>;
|
|
|
37
37
|
/**
|
|
38
38
|
* 基线里**不设豁免**的规则清单:这些规则必须保持开启,谁要关掉就得先给出依据。
|
|
39
39
|
*
|
|
40
|
-
*
|
|
41
|
-
* override 层的 off
|
|
40
|
+
* 方法是「按文件种类分别核对命中数」。`oxlint --deny=<rule>` 量的是整体,而 `--deny` 盖不住
|
|
41
|
+
* override 层的 off(这个测量方法见本文件头),所以一条规则可以同时是「TS 侧零命中、保持开启」
|
|
42
42
|
* 与「`scripts/` 的无类型 .mjs 里有命中、按文体收窄」——`eslint/no-continue` 正是这一类,
|
|
43
43
|
* 它的收窄在 SCRIPTS_OVERRIDES 里,不在这里。`eslint/no-await-in-loop` 则两侧都开着
|
|
44
44
|
* (实测探针对 .mjs 照样报),两边都按代码写到位,没有收窄层。
|
|
@@ -46,23 +46,23 @@ export declare const OFF_JUSTIFICATIONS: Record<string, OffJustification>;
|
|
|
46
46
|
export declare const RETIRED_OFFS: string[];
|
|
47
47
|
export declare const READONLY_SYNC_ALLOWLIST: string[];
|
|
48
48
|
/**
|
|
49
|
-
* 组装
|
|
49
|
+
* 组装 sonarjs 的入口:本包解析到的入口在前,调用方自带的在后并去重。
|
|
50
50
|
*
|
|
51
|
-
* 为什么要有这一层而不是直接 `[
|
|
52
|
-
*
|
|
51
|
+
* 为什么要有这一层而不是直接 `[resolvePluginEntry(SONARJS_PLUGIN), ...(jsPlugins ?? [])]`:
|
|
52
|
+
* 那写法无条件先求值,于是「调用方自带入口」这条官方预留的退路在缺 sonarjs 时**用不了**——
|
|
53
53
|
* 抛错发生在调用方的入口被用上之前,报错信息给的补救办法照做必然再报同一条。
|
|
54
|
-
*
|
|
54
|
+
* 分支规则:
|
|
55
55
|
* - 调用方带了**指向 sonarjs 的**入口 → 解析失败就跳过(它自备的就是 sonarjs),
|
|
56
56
|
* 成功则去重后前置;
|
|
57
57
|
* - 调用方只带了别家插件、或没带 → 解析失败照旧抛那条可操作的信息。SONARJS_RULES
|
|
58
|
-
* 无条件引用 sonarjs
|
|
59
|
-
* (`Plugin 'sonarjs' not found
|
|
58
|
+
* 无条件引用 sonarjs,只带别家插件满足不了它:那种失败会推迟到 oxlint 装载配置那一刻
|
|
59
|
+
* (`Plugin 'sonarjs' not found`),可操作的成因必须在这里先抛出来,而不是留到后面被掩盖。
|
|
60
60
|
* 「指向 sonarjs」按入口路径含 `sonarjs` 判定——调用方传的是自己解析到的插件路径,
|
|
61
|
-
*
|
|
61
|
+
* 这是能落进字符串判断的全部信号。
|
|
62
62
|
*
|
|
63
63
|
* 导出且把解析器做成入参,是为了「解析失败」那一支在**本仓**可测:本仓 devDependencies
|
|
64
|
-
* 装着 sonarjs
|
|
65
|
-
* `ProjectKeyOptions.realpath`
|
|
64
|
+
* 装着 sonarjs,真实的解析路径永远成功,那两个分支就只能靠注入 stub 走到(与 `LauncherLocator`、
|
|
65
|
+
* `ProjectKeyOptions.realpath` 同一套可注入选项的取舍)。生产侧的 consumer 是
|
|
66
66
|
* `definePluginConfig`,故这不是「只被测试养着的导出」。
|
|
67
67
|
*
|
|
68
68
|
* @param callerPlugins - 调用方经 `jsPlugins` 传入的入口;undefined / 空数组均可
|
|
@@ -70,37 +70,117 @@ export declare const READONLY_SYNC_ALLOWLIST: string[];
|
|
|
70
70
|
* @returns 交给 oxlint 的 jsPlugins 数组
|
|
71
71
|
*/
|
|
72
72
|
export declare function resolveJsPlugins(callerPlugins: NonNullable<OxlintConfig["jsPlugins"]> | undefined, resolve?: () => string): NonNullable<OxlintConfig["jsPlugins"]>;
|
|
73
|
+
/**
|
|
74
|
+
* 组装全部常挂插件的 `jsPlugins`:sonarjs 走 {@link resolveJsPlugins} 的退路语义,
|
|
75
|
+
* 其余三条在调用方没有自带入口时从本包解析并前置。
|
|
76
|
+
*
|
|
77
|
+
* 调用方自带入口的判定按路径/别名子串(`pointsAtPlugin`):这是能落进字符串判断的全部信号。
|
|
78
|
+
* 自带入口时**不再解析**本包那一份,避免同一个插件被挂两遍(两份插件对象会让同一条规则报两次)。
|
|
79
|
+
*
|
|
80
|
+
* 导出并把解析器做成可注入,是为了缺包分支在本仓可测:本仓 devDependencies 装着这四个包,
|
|
81
|
+
* 真实解析永远成功,失败支只能靠 stub 走到。
|
|
82
|
+
*
|
|
83
|
+
* @param callerPlugins - 调用方经 `jsPlugins` 传入的入口
|
|
84
|
+
* @param resolvers - 按插件 label 注入的入口解析器(生产用默认实现,测试注桩)
|
|
85
|
+
* @returns 交给 oxlint 的 jsPlugins 数组
|
|
86
|
+
*/
|
|
87
|
+
export declare function resolveBundledJsPlugins(callerPlugins: NonNullable<OxlintConfig["jsPlugins"]> | undefined, resolvers?: Record<string, () => string>): NonNullable<OxlintConfig["jsPlugins"]>;
|
|
88
|
+
/**
|
|
89
|
+
* `eslint-plugin-regexp` recommended 里带 `regexp/` 前缀的全部规则(63 条)。
|
|
90
|
+
*
|
|
91
|
+
* 不带它同 preset 的 4 条裸 eslint 规则(no-control-regex / no-misleading-character-class /
|
|
92
|
+
* no-regex-spaces / prefer-regex-literals):oxlint 的内建 eslint 插件已有同名规则,重复挂只会
|
|
93
|
+
* 把同一个缺陷报两遍。
|
|
94
|
+
*
|
|
95
|
+
* 实测(oxlint 1.90、9 包,含既有代码):95 条命中,prod 34 / test 56 / 其余 5;其中 56 条所属
|
|
96
|
+
* 规则带 fixer(实测 oxlint 会执行 JS plugin 的 fixer,用 prefer-w 验过)。剩余非 fixer 的
|
|
97
|
+
* `no-super-linear-backtracking` 在测试文件里由 TEST_OVERRIDES 收窄(理由见 OFF_JUSTIFICATIONS)。
|
|
98
|
+
*
|
|
99
|
+
* `no-obscure-range` 允许本仓刻意使用的两个 CJK 范围:把 `[一-鿿]` 改写成 `\u4e00-\u9fff` 只会
|
|
100
|
+
* 让中文正则更难读,而这两个范围的语义在项目里是明确的。
|
|
101
|
+
*/
|
|
102
|
+
export declare const REGEXP_RULES: RuleTable;
|
|
103
|
+
/**
|
|
104
|
+
* `eslint-plugin-zod` recommended 的 23 条里去掉 `consistent-schema-var-name` 后的 22 条
|
|
105
|
+
* (针对 zod 4)。
|
|
106
|
+
*
|
|
107
|
+
* 实测(oxlint 1.90、9 包):
|
|
108
|
+
* - `consistent-import` 默认要求 namespace import,与本仓统一的 `import { z } from "zod"` 冲突;
|
|
109
|
+
* 按参考仓的做法把 syntax 设成 named 后归零。
|
|
110
|
+
* - `no-number-schema-with-int` 5 条(`z.number().int()` → `z.int()`,fixer 可修)。
|
|
111
|
+
* - `require-error-message` 5 条待按代码补错误文案。
|
|
112
|
+
* - `consistent-schema-var-name` 71 条**不挂**:本仓的 schema 常量是大写词(`MAX_DENIES_SCHEMA`、
|
|
113
|
+
* `STATS_SNAPSHOT_SCHEMA`),规则的默认口径是把 `Schema` 后缀再拼一次,得到
|
|
114
|
+
* `MAX_DENIES_SCHEMASchema` 这类坏名字;把它当命名缺陷改 71 处只是风格迁移,不指向缺陷。
|
|
115
|
+
*
|
|
116
|
+
* 该插件只对真的 import zod 的文件生效;本仓九个包都声明了 zod,规则面不会空转。
|
|
117
|
+
*/
|
|
118
|
+
export declare const ZOD_RULES: RuleTable;
|
|
119
|
+
/**
|
|
120
|
+
* `@e18e/eslint-plugin` recommended 里**不与 oxlint 内建规则重复**的那一族。
|
|
121
|
+
*
|
|
122
|
+
* 刻意不挂的 9 条:
|
|
123
|
+
* - 实测与内建规则同义,挂上会把同一条缺陷报两遍:`prefer-array-at`(unicorn/prefer-at)、
|
|
124
|
+
* `prefer-array-some`(unicorn/prefer-array-some)、`prefer-date-now`(unicorn/prefer-date-now)、
|
|
125
|
+
* `prefer-includes`(unicorn/prefer-includes / typescript/prefer-includes)、
|
|
126
|
+
* `prefer-nullish-coalescing`(typescript/prefer-nullish-coalescing)、
|
|
127
|
+
* `prefer-object-has-own`(eslint/prefer-object-has-own)、`prefer-regex-test`
|
|
128
|
+
* (unicorn/prefer-regexp-test)、`prefer-spread-syntax`(unicorn/prefer-spread;某个消费方的
|
|
129
|
+
* sidecar 已为后者做过文件级 off,再挂本条会把那个冲突原样带回来)。
|
|
130
|
+
* - `prefer-string-fromcharcode` 与已启用的 `unicorn/prefer-code-point` **方向相反**:前者的
|
|
131
|
+
* fixer 把 `String.fromCodePoint` 改回 `String.fromCharCode`,后者要求反过来。实测在一个
|
|
132
|
+
* 消费方上执行 `--fix` 会把 15 处 `fromCodePoint` 改写成 `fromCharCode`,其中含非 BMP
|
|
133
|
+
* 码点时运行语义会变,故整条不挂(不是"重复",是互斥)。
|
|
134
|
+
*
|
|
135
|
+
* 实测非重复规则当前命中:`prefer-array-from-map` 25、`prefer-array-fill` 5(都带 fixer);
|
|
136
|
+
* `ban-dependencies` 唯一命中落在某个消费方的脚本,由 SCRIPTS_OVERRIDES 收窄(理由见
|
|
137
|
+
* OFF_JUSTIFICATIONS)。
|
|
138
|
+
*
|
|
139
|
+
* `prefer-static-regex` 全仓 1778 条(生产 78、测试 1672、其余 28),且没有 fixer:基线全局
|
|
140
|
+
* off,只在 PROD_OVERRIDES 的生产文件上开。测试里的内联正则不构成性能问题,生产侧按代码提到
|
|
141
|
+
* 模块作用域。
|
|
142
|
+
*/
|
|
143
|
+
export declare const E18E_RULES: RuleTable;
|
|
73
144
|
/**
|
|
74
145
|
* oxlint 认识的 vitest 规则全集(取自 `oxlint --rules` 的表格,73 条)。整族在基线 off,再由
|
|
75
146
|
* TEST_FILE_OVERRIDES 在用例文件上 on —— 理由见 OFF_JUSTIFICATIONS 里的 `vitest/*`。
|
|
76
147
|
*
|
|
77
148
|
* 这是一张**快照**,不是「上游新增规则自动落在生产文件之外」的机制:`categories` 是全局
|
|
78
149
|
* error 开关,上游在任一 category 里新增 vitest 规则,它就会先作用到每一个 host.ts。
|
|
79
|
-
* 拦这一步的是 test/config-oxlint.test.ts 的一致性用例——它拿 `oxlint --rules`
|
|
80
|
-
*
|
|
150
|
+
* 拦这一步的是 test/config-oxlint.test.ts 的一致性用例——它拿 `oxlint --rules` 的实际输出与
|
|
151
|
+
* 本数组逐条对照,上游新增/删除规则即失败,由人工同步名单(需要豁免的再补依据)。
|
|
81
152
|
*/
|
|
82
153
|
export declare const VITEST_ALL_RULES: string[];
|
|
83
154
|
export declare const BASE_RULES: RuleTable;
|
|
84
155
|
/**
|
|
85
|
-
* 用例文件(含 `test/*.ts`
|
|
86
|
-
*
|
|
87
|
-
* TEST_FILE_OVERRIDES 里开回来,所以 helper
|
|
156
|
+
* 用例文件(含 `test/*.ts` 测试数据与 helper)共享的豁免:规模类,以及「stub 要跨官方名义类型」
|
|
157
|
+
* 的类型类判断。vitest 的用例结构类判断不在这里 —— 它们在基线整族 off、只在
|
|
158
|
+
* TEST_FILE_OVERRIDES 里开回来,所以 helper 模块天然不在范围内,旧配置那份按目录豁免的
|
|
88
159
|
* TEST_HELPER_OVERRIDES 因此作废。
|
|
89
160
|
*/
|
|
90
161
|
export declare const TEST_OVERRIDES: OxlintOverride;
|
|
91
162
|
/**
|
|
92
|
-
*
|
|
163
|
+
* 生产代码面的 override:目前只有 `e18e/prefer-static-regex`。
|
|
164
|
+
*
|
|
165
|
+
* 该规则在全仓 1778 条(生产 78、测试 1672、其余 28),没有 fixer;全局 off、这里 on,
|
|
166
|
+
* 既保住「生产代码里的内联正则提到模块作用域」这条要求,又不把测试断言与构建脚本逼成
|
|
167
|
+
* 一堆模块级常量。`lib/**` 是各包的运行期模块(shared 的 build-* helper 也在 lib 下,
|
|
168
|
+
* 它们随包发布,按生产代码对待);`host.ts` / `cli-main.ts` 是包根的生产入口。
|
|
169
|
+
*/
|
|
170
|
+
export declare const PROD_OVERRIDES: OxlintOverride;
|
|
171
|
+
/**
|
|
172
|
+
* vitest 的用例结构类判断**只**在这里生效。
|
|
93
173
|
* `expect-expect` 的 `assertFunctionNames` 取 vitest flavor 的官方默认
|
|
94
174
|
* (`["expect", "expectTypeOf", "assert", "assertType"]`):本仓用例里有相当一部分用
|
|
95
175
|
* `node:assert/strict` 断言,那不是「缺断言」,而是这条规则在 jest flavor 默认值下漏判
|
|
96
176
|
* ——实测 17 条里 5 条属于这一族,补上默认值后就不报了。
|
|
97
177
|
*
|
|
98
|
-
*
|
|
178
|
+
* 剩下两族用规则自带的选项解决,不关规则、也不改判断方向:
|
|
99
179
|
* - 断言写在包内 helper 里(`assertSameLedger()` 一类):`assertFunctionNames` 就是
|
|
100
180
|
* "哪些函数算断言"的名单,走 {@link makeTestFileOverrides} 的 `assertionHelpers` 报名字。
|
|
101
|
-
* 名单只收**裸标识符**:带 `*` / `.` 的通配会把"任何调用都算断言"
|
|
181
|
+
* 名单只收**裸标识符**:带 `*` / `.` 的通配会把"任何调用都算断言"写进配置,等于让规则失去作用,直接抛。
|
|
102
182
|
* - 标题以大写术语开头(`PTC`、`W5`、`B1` 这类档位/模式名):`allowedPrefixes` 是
|
|
103
|
-
* prefer-lowercase-title
|
|
183
|
+
* prefer-lowercase-title 给的同一个选项(官方例子就是 HTTP 方法前缀)。走 `titlePrefixes` 报名字。
|
|
104
184
|
* 反过来的做法——把标题改成 `pTC` / `w5`——会把领域名字改成坏名字,本仓不采取。
|
|
105
185
|
*/
|
|
106
186
|
export declare const VITEST_ASSERTION_DEFAULTS: string[];
|
|
@@ -116,7 +196,7 @@ export interface TestFileOverridesOptions {
|
|
|
116
196
|
titlePrefixes?: string[];
|
|
117
197
|
}
|
|
118
198
|
/**
|
|
119
|
-
* 生成用例文件的 override(vitest
|
|
199
|
+
* 生成用例文件的 override(vitest 结构类判断的开与关都在这张表里)。
|
|
120
200
|
* @param opts - 本包需要用规则自带选项登记的名单(见文件头的两族说明)。
|
|
121
201
|
* @returns 可直接放进 `overrides` 的配置项。
|
|
122
202
|
*/
|
|
@@ -133,8 +213,8 @@ export interface PluginLintOptions {
|
|
|
133
213
|
offReasons?: Record<string, OffJustification>;
|
|
134
214
|
/**
|
|
135
215
|
* 本包"内部会断言"的用例 helper 名(如 `assertSameLedger`)。报进来的名字并入
|
|
136
|
-
* `vitest/expect-expect` 的 `assertFunctionNames`,规则本身保持 error ——
|
|
137
|
-
*
|
|
216
|
+
* `vitest/expect-expect` 的 `assertFunctionNames`,规则本身保持 error —— 这是规则自带的机制,
|
|
217
|
+
* 不是豁免。只收裸标识符,通配会让这条规则失去作用,直接抛。
|
|
138
218
|
*/
|
|
139
219
|
assertionHelpers?: string[];
|
|
140
220
|
/** 允许开头的用例标题大写术语(`PTC`/`W5`/`B1` 这类档位或模式名),进 allowedPrefixes。 */
|
|
@@ -9,12 +9,12 @@ type PackageConfig = ViteUserConfig;
|
|
|
9
9
|
type TestConfig = NonNullable<PackageConfig["test"]>;
|
|
10
10
|
type CoverageConfig = NonNullable<TestConfig["coverage"]>;
|
|
11
11
|
/**
|
|
12
|
-
* 覆盖率覆盖项的形状。`include`
|
|
12
|
+
* 覆盖率覆盖项的形状。`include` 不在其中:统计范围由 `coverageInclude` 单独供给,两处各写一份
|
|
13
13
|
* 必然漂移。覆盖率对象整块替换会让四项 100% 阈值与排除表静默消失,所以覆盖项不走 `test`
|
|
14
14
|
* 展开,而是逐键合并;`thresholds` 之内也逐键合并,单项可改、其余三项删不掉。
|
|
15
15
|
*/
|
|
16
16
|
type CoverageOverride = Omit<Partial<CoverageConfig>, "include">;
|
|
17
|
-
/**
|
|
17
|
+
/** 公共覆盖率配置与 test 块里真正因包而异的那一项。 */
|
|
18
18
|
export interface PackageVitestOptions {
|
|
19
19
|
/** `coverage.include` —— 本包该被统计的源文件(各包只有这里不同);空数组/空串在工厂即抛。 */
|
|
20
20
|
coverageInclude: string[];
|
|
@@ -24,7 +24,7 @@ export interface PackageVitestOptions {
|
|
|
24
24
|
test?: PackageConfig["test"];
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* 公共部分:各份配置里逐字相同的那部分,从今往后只有一处。
|
|
28
28
|
* `testTimeout: 20_000` 是各包共同值(vitest 默认 5000);继承它只会放宽不会收紧,
|
|
29
29
|
* 故不会把任何已过用例变成不稳定。
|
|
30
30
|
*/
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 把捕获到的值渲染成一段人读文本。
|
|
3
3
|
* `Error` 取 message(空串时回退 name)并接上 cause 链;`AggregateError` 附上成员;
|
|
4
|
-
* 非 Error 但带可读 message 属性的取该属性,其余按 `String()`
|
|
5
|
-
*
|
|
4
|
+
* 非 Error 但带可读 message 属性的取该属性,其余按 `String()` 处理。
|
|
5
|
+
* 全程不抛异常:恶意输入改用占位文本。
|
|
6
6
|
* @param error - 捕获到的值(catch 里的 `unknown`)。
|
|
7
7
|
* @returns 可直接进界面通知或日志的文本。
|
|
8
8
|
*/
|
|
9
9
|
export declare function errorText(error: unknown): string;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* 是不是「设置冲突」那一类失败(宿主在两个界面同时改同一份设置时抛出的那种失败)。
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
* `code`/`name` 是宿主两边都写的那两个值。经 `fieldOf`
|
|
15
|
-
* getter / Proxy
|
|
13
|
+
* 认两处痕迹而不是 `instanceof`:跨 realm 抛过来的错误类不是同一个构造函数,而
|
|
14
|
+
* `code`/`name` 是宿主两边都写的那两个值。经 `fieldOf` 读——它的带保护出口把恶意
|
|
15
|
+
* getter / Proxy trap 的抛错变成「取不到」,判定因此天然只回答是/否,不外抛。
|
|
16
16
|
* @param error 捕获到的值
|
|
17
17
|
* @returns 该失败是否应当按「设置已被别处改动」处理
|
|
18
18
|
*/
|
|
@@ -2,34 +2,34 @@ import type { ShellProcess } from "@deepseek-ai/dsh-shell";
|
|
|
2
2
|
import type { JobOutcome } from "@deepseek-ai/dsh-jobs";
|
|
3
3
|
/**
|
|
4
4
|
* 官方结局类型在这里再出一个具名出口。`jobOutcomeOf` 的返回类型就是它,消费方把它写进自己的
|
|
5
|
-
*
|
|
5
|
+
* 签名(生产者回调、测试断言)时若没有具名出口,只能把结构重述一遍——而重述正是本包要消除的。
|
|
6
6
|
*/
|
|
7
7
|
export type { JobOutcome } from "@deepseek-ai/dsh-jobs";
|
|
8
|
-
/** 映射只用得到的三个成员(不是整个 ShellProcess
|
|
8
|
+
/** 映射只用得到的三个成员(不是整个 ShellProcess:生产者句柄的其余成员与本函数无关)。 */
|
|
9
9
|
export type SettledProcess = Pick<ShellProcess, "status" | "exitCode" | "signal">;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @param proc
|
|
11
|
+
* 已结束进程 → 作业结局。
|
|
12
|
+
* @param proc 已结束的子进程句柄(`done` 已 resolve 之后再读,值才是终态)
|
|
13
13
|
* @returns 交给 {@link JobRegistry} 生产者的结局:killed / completed,理由在 detail
|
|
14
14
|
*/
|
|
15
15
|
export declare function jobOutcomeOf(proc: SettledProcess): JobOutcome;
|
|
16
16
|
/**
|
|
17
|
-
* 只用得到的那一个成员。**不按 `ShellProcess`
|
|
17
|
+
* 只用得到的那一个成员。**不按 `ShellProcess` 整个收**:官方的 `kill` 返回 `Promise<boolean>`,
|
|
18
18
|
* 把那个返回类型写进签名等于要求每个调用方(含测试替身)都得交回一个 Promise,
|
|
19
|
-
* 而这里真正需要的只是「有一个可以试着调的 kill
|
|
19
|
+
* 而这里真正需要的只是「有一个可以试着调的 kill」——返回值要么被丢弃,要么把拒绝接管下来。
|
|
20
20
|
*/
|
|
21
21
|
export interface KillableProcess {
|
|
22
22
|
kill: () => unknown;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* 终止子进程,**忽略失败**:进程可能已自然退出或已被系统回收,此时 kill 失败不是本包的失败。
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* 为什么不向调用方通报:调用点都在清理分支(卸载、被拒、超时)上,那里没有可行动的下一步;
|
|
28
|
+
* 把异常抛出去只会让清理链半途而废,留下更难处理的现场。
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
* 只拦得住前者,返回的 Promise
|
|
30
|
+
* 同步抛错与**异步拒绝**都要处理:官方句柄的 `kill` 返回 `Promise<boolean>`,同步 try/catch
|
|
31
|
+
* 只拦得住前者,返回的 Promise 拒绝最终会变成进程级 unhandledRejection——清理分支不该有能力
|
|
32
32
|
* 把宿主进程的未处理拒绝计数器推高。
|
|
33
|
-
* @param proc
|
|
33
|
+
* @param proc 待清理的句柄
|
|
34
34
|
*/
|
|
35
35
|
export declare function killProc(proc: KillableProcess): void;
|
package/dist/types/jsonl.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 反复保留后半行段直到 UTF-8 字节数 ≤ `maxBytes`;行数 ≤2 时停手(单条超限行原样保留,
|
|
3
|
-
*
|
|
3
|
+
* 防死循环也防清空文件)。未超限直接返回入参**同一引用**,调用方可据此跳过磁盘写入。
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* **配额必须是有限数**(这一点由调用方保证,本函数不代为归一):
|
|
6
6
|
* - `0` 与负数**照样收缩**到 ≤2 行为止——「0 = 永不截断」是某消费方在**调用前**
|
|
7
7
|
* `maxBytes > 0` 那道触发策略的承诺,不是本函数的语义(见它自己的 jsonl-fuse 头注)。
|
|
8
8
|
* 把 0 当成「不裁」会把这个承诺写成一个假象。
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
另一个在调用前就把非有限值与负数归一成 0。但那道归一在**消费方**,本包并不强制——
|
|
12
12
|
新增消费方时没有任何东西会提醒它。
|
|
13
13
|
*
|
|
14
|
-
* 为什么不在这种预算上抛错拒收:抛错会被两个消费方各自的 catch
|
|
14
|
+
* 为什么不在这种预算上抛错拒收:抛错会被两个消费方各自的 catch 接走(一个向外抛、一个内部捕获),
|
|
15
15
|
* 等于把一条清晰的预算错误变成一次静默跳过,排查方向反而更差。这里"不设限"只是「这次不裁」,
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* 不像读请求体那样会同时放开内存上限,所以没有必须拒收的那条失败方式。表现不同的同一种错,
|
|
17
|
+
* 各按各的失败方式处理。
|
|
18
18
|
*
|
|
19
19
|
* 两个消费方的具体调用点与配额归一位置记在 test/jsonl.test.ts 的同名用例里——这一段
|
|
20
20
|
* 不出现兄弟包标识符:声明上的 JSDoc 会被 tsc 抄进 dist/types/*.d.ts 一起发出去,
|
|
21
|
-
* 包名会让装了这个包的消费方以为存在一个并不存在的依赖(test/publish-manifest.test.ts
|
|
21
|
+
* 包名会让装了这个包的消费方以为存在一个并不存在的依赖(test/publish-manifest.test.ts 会判定失败)。
|
|
22
22
|
*
|
|
23
23
|
* @param text 整份 JSONL 文本
|
|
24
24
|
* @param maxBytes 字节上限;调用方须保证是有限数
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 执行一次 lesson bus 调用,并把两类失败归到同一个出口。
|
|
3
3
|
* @param call - 真正的调用(同步返回或返回 Promise 都接受)。
|
|
4
|
-
* @param onFailure -
|
|
5
|
-
* 返回类型写 `unknown` 而不是 `void`:签名不能让"
|
|
4
|
+
* @param onFailure - 失败处理:同步抛错与异步拒绝都会到这里,且各自只被调一次。
|
|
5
|
+
* 返回类型写 `unknown` 而不是 `void`:签名不能让"失败处理是 async 函数"变成类型错误,
|
|
6
6
|
* 而它返回的 Promise 由 report 接管(见该函数的注释),调用方不必也不该自己等它。
|
|
7
7
|
*/
|
|
8
8
|
export declare function settleLessonCall(call: () => unknown, onFailure: (reason: unknown) => unknown): void;
|
package/dist/types/locale.d.ts
CHANGED
|
@@ -8,10 +8,10 @@ export type Locale = BuiltInLocaleId;
|
|
|
8
8
|
/** 缺省语言。设置项未设或值不合语法时落到这里。 */
|
|
9
9
|
export declare const DEFAULT_LOCALE: Locale;
|
|
10
10
|
/**
|
|
11
|
-
* 官方 `@deepseek-ai/dsh-client-locale` 拥有的 settings
|
|
12
|
-
*
|
|
11
|
+
* 官方 `@deepseek-ai/dsh-client-locale` 拥有的 settings 命名空间与字段名。那两个常量官方
|
|
12
|
+
* 也导出(同包的根入口),这里**不引它而是抄字面量**:引它就得把 client 包变成宿主侧的运行期
|
|
13
13
|
* 依赖,而这两个值是纯字符串常量、不参与任何 client 行为。两侧必须逐字同名才读得到同一份偏好,
|
|
14
|
-
* 所以这条耦合是本包 README
|
|
14
|
+
* 所以这条耦合是本包 README 的登记项:官方那两个常量一旦改名,本包必须同步改。
|
|
15
15
|
*/
|
|
16
16
|
export declare const LOCALE_SETTINGS_NAMESPACE = "locale";
|
|
17
17
|
export declare const LOCALE_PREFERENCE_FIELD = "preference";
|
|
@@ -19,7 +19,7 @@ export declare const LOCALE_PREFERENCE_FIELD = "preference";
|
|
|
19
19
|
* 一个包的全部消息键值表(键名即语义,值是人读文案)。
|
|
20
20
|
*
|
|
21
21
|
* 键集绑 `Locale` 而不是手写 `{ zh; en }`:本文件的 `Locale` 已改成官方 `BuiltInLocaleId`
|
|
22
|
-
* 的别名,宿主哪天加一门语言,这两处必须**一起**响——只改 `Locale`
|
|
22
|
+
* 的别名,宿主哪天加一门语言,这两处必须**一起**响——只改 `Locale` 而把键集锁死成
|
|
23
23
|
* `{ zh; en }`,新增那门语言会静默取不到文案(`messagesFor` 的 else 分支落回 zh)。
|
|
24
24
|
* `Record` 与原 interface 在当前 `Locale`(恰为 `"zh"|"en"`)下结构等价,消费方字面量
|
|
25
25
|
* 无需改动;差别只在宿主扩宽那一刻,从「静默回落」变成「编译报错」。
|
|
@@ -27,7 +27,7 @@ export declare const LOCALE_PREFERENCE_FIELD = "preference";
|
|
|
27
27
|
* 值域收在 string 上,用**同构映射类型**而不是 `Record<string, string>`:实测(tsc)消费方
|
|
28
28
|
* 全部用 `interface Messages { readonly xxx: string }` 声明,而 interface **拿不到**隐式索引
|
|
29
29
|
* 签名——写成 `Messages extends Record<string, string>` 会让全部消费方 TS2322,那是外溢到
|
|
30
|
-
* 9 个包的破坏性变更。映射类型对 interface 与 type 都成立(test/type-guards.test.ts
|
|
30
|
+
* 9 个包的破坏性变更。映射类型对 interface 与 type 都成立(test/type-guards.test.ts 固定)。
|
|
31
31
|
* 收窄前实测到的缺口:`messagesFor({ zh: { g: 1 }, en: { g: "x" } }, "zh")` 零错误通过,即文件头
|
|
32
32
|
* 「值不是字符串都在 tsc 阶段就红」原本只在消费方自己声明 `Messages` 时才成立。
|
|
33
33
|
*/
|
|
@@ -37,15 +37,15 @@ export type MessagesCatalog<Messages> = Record<Locale, {
|
|
|
37
37
|
/**
|
|
38
38
|
* 把设置里的原始值归一成受支持的 locale:只取**主语言子标签**判定(`en-US`、`zh-Hans-CN`
|
|
39
39
|
* 都落位到 `en` / `zh`),没有「先按完整标签匹配」那一层——受支持的语言只有 `zh` 与 `en`
|
|
40
|
-
*
|
|
41
|
-
* DEFAULT_LOCALE
|
|
40
|
+
* 两个主标签,完整标签匹配不会多认出任何一个,反而要多维护一张表。判不出来一律回退到
|
|
41
|
+
* DEFAULT_LOCALE——文案语言不该成为报错来源。
|
|
42
42
|
* @param raw - 设置里的原始值,类型不可信(来自用户文档)。
|
|
43
43
|
* @returns 归一后的 locale。
|
|
44
44
|
*/
|
|
45
45
|
export declare function resolveLocale(raw: unknown): Locale;
|
|
46
46
|
/**
|
|
47
47
|
* 从 `ctx.settings.describe(LOCALE_SETTINGS_NAMESPACE)` 的返回值里取偏好并归一。
|
|
48
|
-
* describe
|
|
48
|
+
* describe 出来的结构由别的包拥有,所以入参按 unknown 处理:非对象、数组、缺字段
|
|
49
49
|
* 都走默认语言,不抛。
|
|
50
50
|
* @param described - describe 的原始返回值(可能 undefined)。
|
|
51
51
|
* @returns 归一后的 locale。
|
|
@@ -57,7 +57,7 @@ export declare function resolveLocalePreference(described: unknown): Locale;
|
|
|
57
57
|
* 按 `locale` 直接索引而不是 `locale === "en" ? … : …` 的二元分派:后者的 else 分支
|
|
58
58
|
* 把「非 en 即 zh」这个假设写死在运行期,`Locale` 扩宽时它**照样编译通过**,新增那门
|
|
59
59
|
* 语言静默拿不到文案。与 `MessagesCatalog` 的 `Record<Locale, …>` 合起来,
|
|
60
|
-
* 扩宽会在 `catalog[locale]`
|
|
60
|
+
* 扩宽会在 `catalog[locale]` 这一处报出 TS2322。
|
|
61
61
|
* @param catalog - 各语言齐全的消息表。
|
|
62
62
|
* @param locale - 已归一的语言。
|
|
63
63
|
* @returns 对应语言的消息表(引用返回,不做拷贝)。
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* 可注入的选项。`realpath` 是同步 fs 调用,`sep` 决定**整条**路径语义分支:分隔符字形与
|
|
3
|
+
* `resolve` 用的那套解析都由它选。两者注入是为了让两条分支在任何 runner 上都可判定——
|
|
4
|
+
* `path.sep` 在模块装载时就定死了,而只注入字形会让非 POSIX runner 上的 POSIX 用例拿到
|
|
5
|
+
* 原生解析结果,键随之漂移。
|
|
5
6
|
*/
|
|
6
7
|
export interface ProjectKeyOptions {
|
|
7
8
|
realpath?: (target: string) => string;
|
|
8
9
|
sep?: string;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
|
-
* cwd →
|
|
12
|
-
*
|
|
12
|
+
* cwd → 项目键。非字符串 / trim 后为空 / 归一后落到根目录 → `"default"`
|
|
13
|
+
* (与记忆网关的回退键名一致)。
|
|
13
14
|
*/
|
|
14
15
|
export declare function deriveProjectKey(cwd: unknown, opts?: ProjectKeyOptions): string;
|
package/dist/types/record.d.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
/** 对象类型守卫:非 `null` 的 `object` 且非数组(`Record` 索引签名投影的基础)。 */
|
|
2
2
|
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* 服务可用性校验:对象存在且**声明的每个方法**都可调用。
|
|
5
5
|
*
|
|
6
|
-
* 只做 `typeof value["shell"] === "object"`
|
|
7
|
-
*
|
|
6
|
+
* 只做 `typeof value["shell"] === "object"` 的话,检查声称的是「有这个服务」而实际证明的只是
|
|
7
|
+
* 「有个对象」——运行到一半才报错。逐个写出方法名,检查才名副其实。
|
|
8
8
|
*
|
|
9
9
|
* `Object.prototype` 的默认成员不算服务实现:`hasMethods({}, ["toString"])` 若照单全收,
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* cordis
|
|
10
|
+
* 一个普通对象就能冒充服务。判断是**身份**——解析到的函数正是 `Object.prototype` 上
|
|
11
|
+
* 那一个才排除,所以类/中间原型上的真实实现(包括对原型成员的重写)照常可识别,
|
|
12
|
+
* cordis 方法挂在原型上的读取不受影响。
|
|
13
13
|
* @param value 待验证的服务候选(来自 `ctx.get(...)` 的 unknown)
|
|
14
|
-
* @param methods
|
|
15
|
-
* @returns
|
|
14
|
+
* @param methods 该服务必须可调用的方法名
|
|
15
|
+
* @returns 是否为可用的服务
|
|
16
16
|
*/
|
|
17
17
|
export declare function hasMethods(value: unknown, methods: readonly string[]): boolean;
|
|
18
18
|
/**
|
|
19
19
|
* 从 `unknown` 投影单个字段;非 `Record` → `undefined`。
|
|
20
20
|
*
|
|
21
|
-
* ⚠
|
|
22
|
-
*
|
|
21
|
+
* ⚠ **取值走原型链,这是有意为之,不是疏忽**:`value[key]` 不做 `hasOwn` 判定,所以原型上的
|
|
22
|
+
* 方法照样取得到。消费方正靠这一条做**能力检查**——cordis 服务对象的方法挂在原型上、不是
|
|
23
23
|
* 自有键,形如 `typeof fieldOf(settings, "describe") === "function"`、
|
|
24
24
|
* `hasMethods(fieldOf(value, "timer"), ["timeout"])`、`typeof fieldOf(session,
|
|
25
25
|
* "snapshotEvents") === "function"`(消费包的调用点记在 test/record.test.ts)。
|
|
26
26
|
* 改成 `Object.hasOwn` 会让上面几处**一律判否**,那些包随即认不出合法的 cordis 服务——
|
|
27
|
-
*
|
|
27
|
+
* 而这类误判的表现是「能力检查静默返回 false」,不是报错,极难往这里归因。
|
|
28
28
|
*
|
|
29
29
|
* 代价是明写在这里:键名取到的是原型成员时(`fieldOf({}, "__proto__")` 交回
|
|
30
30
|
* `Object.prototype`、`fieldOf({}, "constructor")` 交回 `Object`)。这是本函数的取舍,
|
|
31
31
|
* 不是让消费方猜的属性——现存调用点的键名全是字面量,没有一处来自数据。
|
|
32
|
-
* test/record.test.ts
|
|
32
|
+
* test/record.test.ts 两侧都有用例固定:原型方法取得到(这是关键行为),自有键优先于原型键。
|
|
33
33
|
*
|
|
34
|
-
* ⚠
|
|
34
|
+
* ⚠ 本段刻意不写出兄弟包的名字:**声明上的 JSDoc 会被 tsc 抄进 dist/types/record.d.ts 一起
|
|
35
35
|
* 发出去**,包名会让装了这个包的消费方以为存在一个并不存在的依赖
|
|
36
|
-
*(test/publish-manifest.test.ts
|
|
36
|
+
*(test/publish-manifest.test.ts 的产物检查会判定失败)。要写具体调用点就写在 test/ 里。
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
* `undefined
|
|
38
|
+
* 读取走的是带保护的出口:被测对象带抛错 getter / Proxy trap 时按「取不到」交回
|
|
39
|
+
* `undefined`,异常不冒泡(能力检查不该打断流程)。
|
|
40
40
|
*/
|
|
41
41
|
export declare function fieldOf(value: unknown, key: string): unknown;
|
package/dist/types/text.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 保留前 `maxChars`
|
|
2
|
+
* 保留前 `maxChars` 个码元;截断位置切开代理对时丢掉尾部那个孤立高代理。
|
|
3
3
|
* `maxChars <= 0` 与 NaN ⇒ 空串。
|
|
4
4
|
*/
|
|
5
5
|
export declare function truncateEnd(text: string, maxChars: number): string;
|
|
6
6
|
/**
|
|
7
|
-
* 保留后 `minChars`
|
|
8
|
-
* `minChars`
|
|
9
|
-
*
|
|
7
|
+
* 保留后 `minChars` 个码元;截断位置切开代理对时丢掉首部那个孤立低代理。
|
|
8
|
+
* `minChars` 不足一个码元(含 `<= 0`、NaN、`0 < minChars < 1`)与 `truncateEnd(text, 0)`
|
|
9
|
+
* 相同,返回空串,不返回整串。
|
|
10
10
|
*/
|
|
11
11
|
export declare function truncateStart(text: string, minChars: number): string;
|