@xingwangzhe/stalux 1.41.3 → 1.41.4
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/package.json +1 -1
- package/src/schemas/collections.ts +35 -6
package/package.json
CHANGED
|
@@ -50,15 +50,42 @@ export interface CollectionPaths {
|
|
|
50
50
|
// 文章 Schema
|
|
51
51
|
// ---------------------------------------------------------------------------
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* 日期字段的严格格式:月/日/时/分/秒**必须补零**。
|
|
55
|
+
*
|
|
56
|
+
* 允许:`2025-07-04`、`"2025-07-04 18:44:32"`、`2025-05-10T12:00:00+08:00`。
|
|
57
|
+
* 拒绝:`2026-6-9 9:11:00` 这类未补零写法——站点时区解析器(dayjs.ts
|
|
58
|
+
* NAIVE_DATE_PATTERN)只认补零形式,未补零会静默回退到 new Date() 按
|
|
59
|
+
* **构建机器本地时区**解释,导致 RSS/页面时间整体平移(2026-10-24 事故)。
|
|
60
|
+
* 因此在 schema 层直接拒绝,让构建尽快失败,而不是产出错误时间。
|
|
61
|
+
*/
|
|
62
|
+
export const PADDED_DATETIME_PATTERN =
|
|
63
|
+
/^\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
64
|
+
|
|
65
|
+
const datetimeField = (label: string) =>
|
|
66
|
+
z
|
|
67
|
+
.string({ error: `${label} must be a string` })
|
|
68
|
+
.regex(
|
|
69
|
+
PADDED_DATETIME_PATTERN,
|
|
70
|
+
`${label} 月/日/时/分/秒必须补零,如 "2025-07-04 18:44:32"(拒绝 2026-6-9 9:11:00 这类未补零写法)`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
/** words 的日期字段:允许空串(模板预留),非空时必须补零 */
|
|
74
|
+
const paddedOrEmpty = (label: string) =>
|
|
75
|
+
z
|
|
76
|
+
.string()
|
|
77
|
+
.refine(
|
|
78
|
+
(value) => value === "" || PADDED_DATETIME_PATTERN.test(value),
|
|
79
|
+
`${label} 为空或月/日/时/分/秒必须补零,如 "2025-07-04 18:44:32"`,
|
|
80
|
+
);
|
|
81
|
+
|
|
53
82
|
const postSchema = z.object({
|
|
54
83
|
title: z.string().min(1, "title is required"),
|
|
55
84
|
abbrlink: z.union([z.string(), z.number().transform((num) => num.toString())], {
|
|
56
85
|
error: "abbrlink must be a string or number",
|
|
57
86
|
}),
|
|
58
|
-
date:
|
|
59
|
-
|
|
60
|
-
.min(1, "date is required, format: YYYY-MM-DD HH:mm:ss"),
|
|
61
|
-
updated: z.string().optional(),
|
|
87
|
+
date: datetimeField("date"),
|
|
88
|
+
updated: datetimeField("updated").optional(),
|
|
62
89
|
draft: z.boolean().optional().default(false),
|
|
63
90
|
tags: z.preprocess(
|
|
64
91
|
(val) => (typeof val === "string" ? [val] : val),
|
|
@@ -136,9 +163,11 @@ export function defineCollections(paths: CollectionPaths = {}) {
|
|
|
136
163
|
schema: z.object({
|
|
137
164
|
source: z.string().optional(),
|
|
138
165
|
link: z.url("words.link must be a valid URL").optional(),
|
|
166
|
+
// sourceDate 是自由文本(如 "1950"、"春秋"),不是机器时间,不做格式约束
|
|
139
167
|
sourceDate: z.string().optional(),
|
|
140
|
-
|
|
141
|
-
|
|
168
|
+
// words 允许空串(_template.md 预留字段),非空时必须补零
|
|
169
|
+
date: paddedOrEmpty("date").optional(),
|
|
170
|
+
updated: paddedOrEmpty("updated").optional(),
|
|
142
171
|
draft: z.boolean().optional().default(false),
|
|
143
172
|
title: z.string().optional(),
|
|
144
173
|
abbrlink: z.string().optional(),
|