cs-bots 0.7.5 → 0.8.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 +108 -0
- package/README.md +47 -174
- package/docs/01-/346/236/266/346/236/204/346/226/207/346/241/243.md +14 -13
- package/docs/CONTRACT-/345/215/207/347/272/24709-Boss/344/275/223/351/252/214.md +280 -0
- package/docs//345/215/207/347/272/24708-/346/216/245/347/273/255/344/270/216/345/233/236/346/273/232.md +298 -0
- package/package.json +2 -2
- package/src/api.js +1005 -7
- package/src/board.js +43 -11
- package/src/client.js +537 -82
- package/src/settings.js +2 -2
- package/src/teams.js +34 -1
- package/src/tools.js +76 -1
package/src/board.js
CHANGED
|
@@ -415,6 +415,30 @@ function normalizeProgress(value, where) {
|
|
|
415
415
|
return value
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
+
/**
|
|
419
|
+
* 旧数据兼容读(契约 §9):补齐/抹平**新字段**,让老街机数据也能安全被读。
|
|
420
|
+
*
|
|
421
|
+
* 硬要求:**缺字段一律给默认值,绝不抛**。升级不丢任何既有任务/证据/历史,
|
|
422
|
+
* 所以这里只做「无副作用的正规化」,不猜测、不伪造来源(旧数据没有
|
|
423
|
+
* `progressBy` 就是「不知道谁设的」,不补一个假的 —— UI 会显示成总进度)。
|
|
424
|
+
*
|
|
425
|
+
* @param {object} t 从事件流/快照来的 Task(就地修改)
|
|
426
|
+
* @returns {object} 同一个 t
|
|
427
|
+
*/
|
|
428
|
+
function normalizeLegacyTask(t) {
|
|
429
|
+
if (!Array.isArray(t.blockedBy)) t.blockedBy = []
|
|
430
|
+
if (!Array.isArray(t.writeScopes)) t.writeScopes = []
|
|
431
|
+
if (!Array.isArray(t.labels)) t.labels = []
|
|
432
|
+
if (t.triaged !== true && t.triaged !== false) t.triaged = false
|
|
433
|
+
if (typeof t.progress !== 'number' || !Number.isFinite(t.progress)) t.progress = 0
|
|
434
|
+
// `progressBy`/`progressAt`(契约 §6 新增):旧数据没有 ⇒ 直接不设(视为 undefined)。
|
|
435
|
+
// 注意:**不给默认值**是对的 —— 给了就会把「旧任务」伪造成「某人设过进度」。
|
|
436
|
+
// 只在字段存在但类型坏了时才抹掉,避免 UI/导出拿到脏值。
|
|
437
|
+
if (t.progressBy !== undefined && typeof t.progressBy !== 'string') delete t.progressBy
|
|
438
|
+
if (t.progressAt !== undefined && !Number.isFinite(t.progressAt)) delete t.progressAt
|
|
439
|
+
return t
|
|
440
|
+
}
|
|
441
|
+
|
|
418
442
|
/** triaged 归一:严格布尔。 */
|
|
419
443
|
function normalizeTriaged(value, where) {
|
|
420
444
|
if (value === undefined || value === null) return undefined
|
|
@@ -748,11 +772,7 @@ export function createBoard(ctx, config = {}) {
|
|
|
748
772
|
for (const raw of snapTasks) {
|
|
749
773
|
if (!raw || typeof raw.id !== 'string') continue
|
|
750
774
|
const t = clone(raw)
|
|
751
|
-
|
|
752
|
-
if (!Array.isArray(t.writeScopes)) t.writeScopes = []
|
|
753
|
-
if (!Array.isArray(t.labels)) t.labels = []
|
|
754
|
-
if (t.triaged !== true && t.triaged !== false) t.triaged = false
|
|
755
|
-
if (typeof t.progress !== 'number' || !Number.isFinite(t.progress)) t.progress = 0
|
|
775
|
+
normalizeLegacyTask(t)
|
|
756
776
|
tasks.set(t.id, t)
|
|
757
777
|
idCounter = Math.max(idCounter, idNumber(t.id))
|
|
758
778
|
if (t.sourceSeq) sourceSeqIndex.set(t.sourceSeq, t.id)
|
|
@@ -798,11 +818,7 @@ export function createBoard(ctx, config = {}) {
|
|
|
798
818
|
continue
|
|
799
819
|
}
|
|
800
820
|
const t = clone(ev.after)
|
|
801
|
-
|
|
802
|
-
if (!Array.isArray(t.writeScopes)) t.writeScopes = []
|
|
803
|
-
if (!Array.isArray(t.labels)) t.labels = []
|
|
804
|
-
if (t.triaged !== true && t.triaged !== false) t.triaged = false
|
|
805
|
-
if (typeof t.progress !== 'number' || !Number.isFinite(t.progress)) t.progress = 0
|
|
821
|
+
normalizeLegacyTask(t)
|
|
806
822
|
tasks.set(ev.taskId, t)
|
|
807
823
|
events.push(clone(ev))
|
|
808
824
|
idCounter = Math.max(idCounter, idNumber(ev.taskId))
|
|
@@ -1196,7 +1212,23 @@ export function createBoard(ctx, config = {}) {
|
|
|
1196
1212
|
if (src.estimate !== undefined) setOrDelete('estimate', normalizeEstimate(src.estimate, where))
|
|
1197
1213
|
if (src.assignee !== undefined) setOrDelete('assignee', normalizeOptionalString(src.assignee, 'assignee', where))
|
|
1198
1214
|
if (src.reviewer !== undefined) setOrDelete('reviewer', normalizeOptionalString(src.reviewer, 'reviewer', where))
|
|
1199
|
-
if (src.progress !== undefined)
|
|
1215
|
+
if (src.progress !== undefined) {
|
|
1216
|
+
const progressNorm = normalizeProgress(src.progress, where)
|
|
1217
|
+
if (progressNorm === undefined) {
|
|
1218
|
+
// `null` = 清除进度 ⇒ 来源字段一并清掉(没有进度就谈不上「谁设的」)
|
|
1219
|
+
delete nextTask.progress
|
|
1220
|
+
delete nextTask.progressBy
|
|
1221
|
+
delete nextTask.progressAt
|
|
1222
|
+
} else {
|
|
1223
|
+
nextTask.progress = progressNorm
|
|
1224
|
+
// 契约 §6:进度来源是**派生字段** —— 调用方不许传(不在 PATCH_FIELDS /
|
|
1225
|
+
// NEW_FIELD_NAMES 白名单里,传了会被拒成「未知字段」),由这里自动同写。
|
|
1226
|
+
// 为什么必须留痕:UI 要能说清「当前 40%(队长估算)」还是「(Boss 设定)」,
|
|
1227
|
+
// 而 `progress` 单一个数字根本分不出是谁定的。
|
|
1228
|
+
nextTask.progressBy = by
|
|
1229
|
+
nextTask.progressAt = at
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1200
1232
|
if (src.triaged !== undefined) setOrDelete('triaged', normalizeTriaged(src.triaged, where))
|
|
1201
1233
|
if (src.startedAt !== undefined) setOrDelete('startedAt', optionalNumber(src.startedAt, 'startedAt', where))
|
|
1202
1234
|
if (src.completedAt !== undefined) setOrDelete('completedAt', optionalNumber(src.completedAt, 'completedAt', where))
|