feat: 实现 DOCX 可编辑字体嵌入

This commit is contained in:
SkyJourney
2026-07-31 16:18:30 +08:00
parent f3847f3e4b
commit 10bc62cee4
32 changed files with 2195 additions and 76 deletions
+68
View File
@@ -8,6 +8,73 @@ import {
} from "./export-config.js";
export const THEME_MANIFEST_VERSION = 1;
export const MAXIMUM_DOCX_FONT_FACE_COUNT = 16;
export const MAXIMUM_DOCX_FONT_SOURCE_BYTES = 8 * 1024 * 1024;
export const MAXIMUM_DOCX_FONT_TOTAL_SOURCE_BYTES =
32 * 1024 * 1024;
const docxFontNameSchema = z
.string()
.trim()
.min(1)
.max(100)
.regex(
/^[\p{L}\p{N}\s._-]+$/u,
"DOCX 字体名称包含不支持的字符"
);
const docxFontSourceSchema = z
.string()
.trim()
.min(1)
.max(500)
.refine(
(value) =>
!value.includes("\0") &&
!value.startsWith("/") &&
!value.startsWith("\\") &&
!/^[a-z]:[\\/]/iu.test(value) &&
!/^(?:https?:)?\/\//iu.test(value) &&
!value
.replace(/^theme-shared:/u, "")
.split(/[\\/]/u)
.includes(".."),
"DOCX 字体资源路径不安全"
)
.refine(
(value) => /\.(?:otf|ttf|woff2?)$/iu.test(value),
"DOCX 字体资源格式必须为 OTF、TTF、WOFF 或 WOFF2"
);
export const docxFontFaceSchema = z.object({
family: docxFontNameSchema,
aliases: z
.array(docxFontNameSchema)
.max(16)
.default([]),
source: docxFontSourceSchema,
weight: z
.number()
.int()
.min(100)
.max(900)
.multipleOf(100)
.default(400),
style: z.enum(["normal", "italic"]).default("normal"),
license: z.string().trim().min(1).max(200)
});
export const docxFontManifestSchema = z.object({
faces: z
.array(docxFontFaceSchema)
.min(1)
.max(MAXIMUM_DOCX_FONT_FACE_COUNT)
});
export type DocxFontFace = z.infer<typeof docxFontFaceSchema>;
export type DocxFontManifest = z.infer<
typeof docxFontManifestSchema
>;
export const themeFeatureSchema = z.enum([
"code",
@@ -51,6 +118,7 @@ export const themeManifestSchema = z.object({
footer: footerSchema.optional()
})
.optional(),
docxFonts: docxFontManifestSchema.optional(),
docxStyle: docxThemeStyleSchema.optional(),
bundled: z.boolean()
});