chore: 初始化项目骨架
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@md-to-pdf/core",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^4.1.13"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const EXPORT_CONFIG_VERSION = 1;
|
||||
|
||||
export const supportedPaperFormats = [
|
||||
"A3",
|
||||
"A4",
|
||||
"A5",
|
||||
"Letter",
|
||||
"Legal",
|
||||
"Tabloid",
|
||||
"Custom"
|
||||
] as const;
|
||||
|
||||
export const paperFormatLabels: Record<
|
||||
(typeof supportedPaperFormats)[number],
|
||||
string
|
||||
> = {
|
||||
A3: "A3",
|
||||
A4: "A4",
|
||||
A5: "A5",
|
||||
Letter: "Letter",
|
||||
Legal: "Legal",
|
||||
Tabloid: "Tabloid",
|
||||
Custom: "自定义"
|
||||
};
|
||||
|
||||
const lengthSchema = z
|
||||
.string()
|
||||
.regex(/^\d+(?:\.\d+)?(?:mm|cm|in)$/, "长度必须包含 mm、cm 或 in 单位");
|
||||
|
||||
const marginSchema = z.object({
|
||||
top: lengthSchema,
|
||||
right: lengthSchema,
|
||||
bottom: lengthSchema,
|
||||
left: lengthSchema
|
||||
});
|
||||
|
||||
const headerFooterSlotSchema = z.object({
|
||||
enabled: z.boolean(),
|
||||
content: z.string().max(500)
|
||||
});
|
||||
|
||||
const headerFooterSchema = z.object({
|
||||
enabled: z.boolean(),
|
||||
height: lengthSchema,
|
||||
showDivider: z.boolean(),
|
||||
fontSize: lengthSchema,
|
||||
color: z.string(),
|
||||
left: headerFooterSlotSchema,
|
||||
center: headerFooterSlotSchema,
|
||||
right: headerFooterSlotSchema
|
||||
});
|
||||
|
||||
const paperSchema = z
|
||||
.object({
|
||||
format: z.enum(supportedPaperFormats),
|
||||
orientation: z.enum(["portrait", "landscape"]),
|
||||
width: lengthSchema.optional(),
|
||||
height: lengthSchema.optional(),
|
||||
margins: marginSchema
|
||||
})
|
||||
.superRefine((paper, context) => {
|
||||
if (paper.format === "Custom" && (!paper.width || !paper.height)) {
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
message: "自定义纸张必须同时指定宽度和高度",
|
||||
path: ["width"]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export const pageNumberFormatSchema = z.enum([
|
||||
"page",
|
||||
"page-total",
|
||||
"chinese-page-total",
|
||||
"dash-page",
|
||||
"custom"
|
||||
]);
|
||||
|
||||
export const exportConfigSchema = z.object({
|
||||
version: z.literal(EXPORT_CONFIG_VERSION),
|
||||
name: z.string().min(1).max(100),
|
||||
themeId: z.string().min(1),
|
||||
paper: paperSchema,
|
||||
header: headerFooterSchema,
|
||||
footer: headerFooterSchema,
|
||||
pageNumber: z.object({
|
||||
enabled: z.boolean(),
|
||||
position: z.enum(["header", "footer"]),
|
||||
alignment: z.enum(["left", "center", "right"]),
|
||||
format: pageNumberFormatSchema,
|
||||
template: z.string().max(500).optional(),
|
||||
startFrom: z.number().int().positive()
|
||||
}),
|
||||
metadata: z.object({
|
||||
title: z.string().max(300),
|
||||
author: z.string().max(300),
|
||||
subject: z.string().max(500),
|
||||
keywords: z.array(z.string().max(100)).max(30),
|
||||
language: z.string().max(30)
|
||||
}),
|
||||
print: z.object({
|
||||
background: z.boolean(),
|
||||
scale: z.number().min(0.1).max(2),
|
||||
pageBreakBeforeH1: z.boolean()
|
||||
})
|
||||
});
|
||||
|
||||
export type ExportConfig = z.infer<typeof exportConfigSchema>;
|
||||
export type PaperFormat = ExportConfig["paper"]["format"];
|
||||
export type HeaderFooterConfig = ExportConfig["header"];
|
||||
|
||||
const disabledSlot = {
|
||||
enabled: false,
|
||||
content: ""
|
||||
} as const;
|
||||
|
||||
export const defaultExportConfig: ExportConfig = {
|
||||
version: EXPORT_CONFIG_VERSION,
|
||||
name: "默认 A4 技术文档",
|
||||
themeId: "typora-like",
|
||||
paper: {
|
||||
format: "A4",
|
||||
orientation: "portrait",
|
||||
margins: {
|
||||
top: "20mm",
|
||||
right: "18mm",
|
||||
bottom: "20mm",
|
||||
left: "18mm"
|
||||
}
|
||||
},
|
||||
header: {
|
||||
enabled: false,
|
||||
height: "8mm",
|
||||
showDivider: false,
|
||||
fontSize: "3mm",
|
||||
color: "#6b7280",
|
||||
left: disabledSlot,
|
||||
center: disabledSlot,
|
||||
right: disabledSlot
|
||||
},
|
||||
footer: {
|
||||
enabled: true,
|
||||
height: "8mm",
|
||||
showDivider: false,
|
||||
fontSize: "3mm",
|
||||
color: "#6b7280",
|
||||
left: disabledSlot,
|
||||
center: {
|
||||
enabled: true,
|
||||
content: "${page} / ${pages}"
|
||||
},
|
||||
right: disabledSlot
|
||||
},
|
||||
pageNumber: {
|
||||
enabled: true,
|
||||
position: "footer",
|
||||
alignment: "center",
|
||||
format: "page-total",
|
||||
startFrom: 1
|
||||
},
|
||||
metadata: {
|
||||
title: "",
|
||||
author: "",
|
||||
subject: "",
|
||||
keywords: [],
|
||||
language: "zh-CN"
|
||||
},
|
||||
print: {
|
||||
background: true,
|
||||
scale: 1,
|
||||
pageBreakBeforeH1: false
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./export-config.js";
|
||||
export * from "./theme.js";
|
||||
@@ -0,0 +1,31 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const THEME_MANIFEST_VERSION = 1;
|
||||
|
||||
export const themeFeatureSchema = z.enum([
|
||||
"code",
|
||||
"table",
|
||||
"task-list",
|
||||
"footnote",
|
||||
"katex",
|
||||
"mermaid"
|
||||
]);
|
||||
|
||||
export const themeManifestSchema = z.object({
|
||||
manifestVersion: z.literal(THEME_MANIFEST_VERSION),
|
||||
id: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
||||
name: z.string().min(1).max(100),
|
||||
version: z.string().min(1).max(30),
|
||||
description: z.string().max(500),
|
||||
author: z.string().max(100),
|
||||
license: z.string().max(100),
|
||||
entry: z.string().endsWith(".css"),
|
||||
print: z.string().endsWith(".css").optional(),
|
||||
domPreset: z.enum(["typora", "github", "generic"]),
|
||||
defaultFontSize: z.string(),
|
||||
supportedFeatures: z.array(themeFeatureSchema),
|
||||
bundled: z.boolean()
|
||||
});
|
||||
|
||||
export type ThemeManifest = z.infer<typeof themeManifestSchema>;
|
||||
export type ThemeFeature = z.infer<typeof themeFeatureSchema>;
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user