From 2b6578af921e442747fd6c067a77617b2965f90c Mon Sep 17 00:00:00 2001 From: seaHi Date: Fri, 11 Sep 2026 09:37:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E6=96=87?= =?UTF-8?q?=E7=AB=A0=E5=AF=BC=E5=85=A5=E5=8A=9F=E8=83=BD=E5=8F=8A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E8=A7=A3=E6=9E=90=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- pnpm-lock.yaml | 15 +-- src/lib/hugoParser.ts | 144 ----------------------- src/routes/admin/posts/[id]/+page.svelte | 115 ------------------ src/routes/admin/posts/new/+page.svelte | 114 ------------------ 5 files changed, 3 insertions(+), 389 deletions(-) delete mode 100644 src/lib/hugoParser.ts diff --git a/package.json b/package.json index 500c815..f907e18 100644 --- a/package.json +++ b/package.json @@ -54,8 +54,6 @@ "marked": "^18.0.9", "marked-highlight": "^2.2.4", "sanitize-html": "2.17.6", - "smol-toml": "^1.7.1", - "tocbot": "^4.36.8", - "yaml": "^2.9.0" + "tocbot": "^4.36.8" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5dd171..c31873b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,15 +45,9 @@ importers: sanitize-html: specifier: 2.17.6 version: 2.17.6 - smol-toml: - specifier: ^1.7.1 - version: 1.7.1 tocbot: specifier: ^4.36.8 version: 4.36.8 - yaml: - specifier: ^2.9.0 - version: 2.9.0 devDependencies: '@eslint/js': specifier: ^10.0.1 @@ -1631,10 +1625,6 @@ packages: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} - smol-toml@1.7.1: - resolution: {integrity: sha512-PPlsspAZ4jbMBu5DMFhfUGDQLu/vrL4SyBROVS37x8ynnVmFIs1VPBz1Co8Xks3TvpIaZXmU85y4DrQ+UyVFoQ==} - engines: {node: '>= 18'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3456,8 +3446,6 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 - smol-toml@1.7.1: {} - source-map-js@1.2.1: {} stackback@0.0.2: {} @@ -3679,7 +3667,8 @@ snapshots: yaml@1.10.3: {} - yaml@2.9.0: {} + yaml@2.9.0: + optional: true yocto-queue@0.1.0: {} diff --git a/src/lib/hugoParser.ts b/src/lib/hugoParser.ts deleted file mode 100644 index b1b59d7..0000000 --- a/src/lib/hugoParser.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { parse as parseToml } from 'smol-toml'; -import { parse as parseYaml } from 'yaml'; - -export interface HugoPostData { - title: string; - slug: string; - content: string; - cover: string; - published_at: string; - updated_at: string; - categories: string[]; - tags: string[]; - series: string[]; - series_weight: number | null; -} - -/** - * 解析并转换时间,一旦解析失败或空缺,严格使用当前系统时间 - */ -function parseOrCurrentDate(val: unknown): string { - if (!val) return new Date().toISOString(); - try { - const dateObj = new Date(val as string | number | Date); - if (isNaN(dateObj.getTime())) { - return new Date().toISOString(); - } - return dateObj.toISOString(); - } catch (err: any) { - return new Date().toISOString(); - } -} - -/** - * 清洗分类和标签列表(同时支持数组与单字符格式) - */ -function parseArrayField(val: unknown): string[] { - if (Array.isArray(val)) { - return val.map((item) => String(item).trim()).filter(Boolean); - } - if (typeof val === 'string' && val.trim() !== '') { - return [val.trim()]; - } - return []; -} - -function parseIntegerField(val: unknown): number | null { - if (val === null || val === undefined || val === '') return null; - const parsed = typeof val === 'number' ? val : Number(String(val).trim()); - return Number.isInteger(parsed) ? parsed : null; -} - -/** - * 去掉文件名结尾的格式拓展名,提供纯文件名基础 - */ -function stripExtension(filename: string): string { - return filename.replace(/\.(md|markdown|txt)$/i, '').trim(); -} - -/** - * Hugo Markdown 头部元数据及正文解析器 - * 同时原生兼容 TOML (+++) 与 YAML (---) 语法,自动过滤并丢弃本项目无端对应参数 - */ -export function parseHugoMarkdown(rawContent: string, fileName = ''): HugoPostData { - // 剔除可能存在的 UTF-8 BOM - const text = rawContent.replace(/^\uFEFF/, '').trim(); - const defaultName = fileName ? stripExtension(fileName) : '新文章'; - - let meta: Record = {}; - let bodyContent = text; - - try { - // 1. 优先检识 TOML (以 +++ 开头包络) - if (text.startsWith('+++')) { - const endIndex = text.indexOf('\n+++', 3); - if (endIndex !== -1) { - const frontmatter = text.substring(3, endIndex).trim(); - bodyContent = text.substring(endIndex + 4).trim(); - meta = parseToml(frontmatter) as Record; - } - } - // 2. 检识常规 YAML (以 --- 开头包络) - else if (text.startsWith('---')) { - const endIndex = text.indexOf('\n---', 3); - if (endIndex !== -1) { - const frontmatter = text.substring(3, endIndex).trim(); - bodyContent = text.substring(endIndex + 4).trim(); - meta = parseYaml(frontmatter) as Record; - } - } - } catch (err: any) { - console.error( - '解析 Markdown 头部参数时出现异常,直接回货底稿正文并对时差退回初始系统时刻:', - err - ); - // 当解析受卡出错,空字典依然不阻挠对下方日期与稿费正文字面的顺利捕拾 - } - - // 取值并完成映射:除以下对应参数处,诸如 draft/twemoji/lightgallery 等全在空载转储里随水蒸丢! - const title = - typeof meta.title === 'string' && meta.title.trim() !== '' ? meta.title.trim() : defaultName; - - let slug = typeof meta.slug === 'string' ? meta.slug.trim() : ''; - if (!slug) { - // 没有声明明确的 slug 时,由名目精简转化出基础链接字符串 - slug = defaultName - .toLowerCase() - .replace(/[^\w\u4e00-\u9fa5\s-]/g, '') - .replace(/\s+/g, '-'); - if (!slug) { - slug = 'post-' + Date.now(); - } - } - - // 特色图片字段识别(首挑 featuredImage,也兼备处理 cover/image) - const cover = - typeof meta.featuredImage === 'string' - ? meta.featuredImage.trim() - : typeof meta.cover === 'string' - ? meta.cover.trim() - : typeof meta.image === 'string' - ? meta.image.trim() - : ''; - - // 时间字段转化:严格按需求约定“一旦转换错漏或是全无,采用目前时刻填满” - const published_at = parseOrCurrentDate(meta.date || meta.published_at); - const updated_at = parseOrCurrentDate( - meta.lastmod || meta.updated_at || meta.date || meta.published_at - ); - - return { - title: title || '无名小贴', - slug, - content: bodyContent, - cover, - published_at, - updated_at, - categories: parseArrayField(meta.categories || meta.category), - tags: parseArrayField(meta.tags || meta.tag), - series: parseArrayField(meta.series), - series_weight: parseIntegerField(meta.series_weight) - }; -} diff --git a/src/routes/admin/posts/[id]/+page.svelte b/src/routes/admin/posts/[id]/+page.svelte index 9b49931..b7acb1e 100644 --- a/src/routes/admin/posts/[id]/+page.svelte +++ b/src/routes/admin/posts/[id]/+page.svelte @@ -1,6 +1,5 @@

编辑

-
- {#if form?.error} diff --git a/src/routes/admin/posts/new/+page.svelte b/src/routes/admin/posts/new/+page.svelte index f60ce60..c579802 100644 --- a/src/routes/admin/posts/new/+page.svelte +++ b/src/routes/admin/posts/new/+page.svelte @@ -9,7 +9,6 @@ import MarkdownEditor from '$lib/components/admin/MarkdownEditor.svelte'; import FeaturedImagePicker from '$lib/components/admin/FeaturedImagePicker.svelte'; import SelectDropdown from '$lib/components/admin/SelectDropdown.svelte'; - import { parseHugoMarkdown } from '$lib/hugoParser'; import TextInput from '$lib/components/admin/TextInput.svelte'; import Button from '$lib/components/admin/Button.svelte'; import Alert from '$lib/components/admin/Alert.svelte'; @@ -30,7 +29,6 @@ let selectedCategoryId = $state(''); let selectedSeriesId = $state(''); let seriesWeight = $state(''); - let fileInput: HTMLInputElement; let tagsList = $state(initialData.tags || []); let seriesList = $state(initialData.series || []); @@ -122,126 +120,14 @@ } } } - - async function handleImportMarkdown(e: Event) { - const target = e.target as HTMLInputElement; - const file = target.files?.[0]; - if (!file) return; - - try { - const rawText = await file.text(); - const imported = parseHugoMarkdown(rawText, file.name); - - title = imported.title; - slug = imported.slug; - content = imported.content; - if (imported.cover) cover = imported.cover; - publishedAt = imported.published_at; - updatedAt = imported.updated_at; - - // 1. 分类匹配:严格遵守“遇到全新未知的分类名跳过,由用户决定”的规范 - if (imported.categories.length > 0) { - const targetName = imported.categories[0].trim().toLowerCase(); - const matchedCat = data.categories.find((c) => c.name.trim().toLowerCase() === targetName); - if (matchedCat) { - selectedCategoryId = matchedCat.id; - } - } - - selectedSeriesId = ''; - seriesWeight = imported.series_weight ?? ''; - if (imported.series.length > 0) { - if (imported.series.length > 1) { - alert( - `检测到多个系列:${imported.series.join('、')}。BlogFlare 每篇文章只能属于一个系列,本次将选择第一个系列。` - ); - } - - const seriesName = imported.series[0].trim(); - let matchedSeries = seriesList.find( - (item) => item.name.trim().toLowerCase() === seriesName.toLowerCase() - ); - if (!matchedSeries && seriesName) { - const formData = new FormData(); - formData.append('name', seriesName); - const response = await fetch('/admin/series?/create', { - method: 'POST', - body: formData, - headers: { 'x-sveltekit-action': 'true' } - }); - - const actionResult = deserialize(await response.text()) as any; - if (actionResult.type === 'success' && actionResult.data?.series) { - const createdSeries = actionResult.data.series as { - id: number; - name: string; - slug: string; - }; - matchedSeries = createdSeries; - seriesList = [...seriesList, createdSeries]; - } else { - alert( - actionResult.data?.error || - `无法创建系列“${seriesName}”,请在系列管理中检查名称和 URL 别名。` - ); - } - } - if (matchedSeries) selectedSeriesId = matchedSeries.id; - } - - // 3. 标签匹配:库有即点取,不知则自主申请向库内补充建好 - for (const tagName of imported.tags) { - const val = tagName.trim(); - if (!val) continue; - const existingTag = tagsList.find((t) => t.name.toLowerCase() === val.toLowerCase()); - if (existingTag) { - if (!selectedTags.includes(existingTag.id)) { - selectedTags = [...selectedTags, existingTag.id]; - } - } else { - try { - const formData = new FormData(); - formData.append('name', val); - const res = await fetch('/admin/tags?/create', { - method: 'POST', - body: formData, - headers: { 'x-sveltekit-action': 'true' } - }); - - const actionRes = deserialize(await res.text()) as any; - if (actionRes.type === 'success' && actionRes.data?.tag) { - tagsList = [...tagsList, actionRes.data.tag]; - selectedTags = [...selectedTags, actionRes.data.tag.id]; - } - } catch (err: any) { - console.error('新建导入对应新标签时出错:', err); - } - } - } - target.value = ''; - } catch (err: any) { - console.error('导入转换出现错误:'); - alert('解析文档内容受困,请稍后检查所填文书'); - } - }

新{$page.data.aliases?.post || '文章'}

-
- {#if form?.error}