cs-bots 0.7.4 → 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/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
- if (!Array.isArray(t.blockedBy)) t.blockedBy = []
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
- if (!Array.isArray(t.blockedBy)) t.blockedBy = []
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) setOrDelete('progress', normalizeProgress(src.progress, where))
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))