-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from samzong/file-traverser
redesgin filewalker
- Loading branch information
Showing
3 changed files
with
137 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import matter from 'gray-matter' | ||
|
||
export interface BasePost { | ||
title: string | ||
date: string | ||
url: string | ||
} | ||
|
||
export interface FileProcessorOptions { | ||
contentDir: string | ||
fileFilter?: (file: string) => boolean | ||
processFile: (filePath: string, content: string, matter: matter.GrayMatterFile<string>) => any | ||
} | ||
|
||
export function walkFiles<T>({ contentDir, fileFilter, processFile }: FileProcessorOptions): T[] { | ||
const results: T[] = [] | ||
|
||
function walk(dir: string) { | ||
const files = fs.readdirSync(dir) | ||
|
||
files.forEach(file => { | ||
const filePath = path.join(dir, file) | ||
const stat = fs.statSync(filePath) | ||
|
||
if (stat.isDirectory()) { | ||
walk(filePath) | ||
} else if (path.extname(file) === '.md') { | ||
if (fileFilter && !fileFilter(file)) { | ||
return | ||
} | ||
|
||
const content = fs.readFileSync(filePath, 'utf-8') | ||
const matterResult = matter(content) | ||
const result = processFile(filePath, content, matterResult) | ||
|
||
if (result) { | ||
results.push(result) | ||
} | ||
} | ||
}) | ||
} | ||
|
||
walk(contentDir) | ||
return results | ||
} | ||
|
||
// 辅助函数:从文件名中提取日期 | ||
export function extractDateFromFilename(filename: string): string | null { | ||
const match = filename.match(/^(\d{4}-\d{2}-\d{2})/) | ||
return match ? match[1] : null | ||
} | ||
|
||
// 辅助函数:格式化日期 | ||
export function formatDate(date: string | Date): string { | ||
if (typeof date === 'string') { | ||
date = new Date(date) | ||
} | ||
return date.toISOString().split('T')[0] | ||
} | ||
|
||
// 辅助函数:生成URL | ||
export function generateUrl(filePath: string, baseDir: string): string { | ||
return '/' + path.relative(path.resolve(baseDir), filePath).replace(/\.md$/, '') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,63 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import matter from 'gray-matter' | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { BasePost, walkFiles, formatDate } from "./fileWalker"; | ||
|
||
interface Post { | ||
title: string | ||
date: string | ||
url: string | ||
tags: string[] | ||
interface Post extends BasePost { | ||
tags: string[]; | ||
} | ||
|
||
interface TagData { | ||
[key: string]: Post[] | ||
} | ||
|
||
// 格式化日期函数 | ||
function formatDate(date: string | Date): string { | ||
if (typeof date === 'string') { | ||
// 如果是ISO格式的字符串,先转换为Date对象 | ||
date = new Date(date) | ||
} | ||
return date.toISOString().split('T')[0] | ||
[key: string]: Post[]; | ||
} | ||
|
||
export function generateTags(): TagData { | ||
const posts: Post[] = [] | ||
const contentDir = path.resolve(__dirname, '../../blog') | ||
const tags: TagData = {} | ||
|
||
function findMarkdownFiles(dir: string) { | ||
const files = fs.readdirSync(dir) | ||
|
||
files.forEach(file => { | ||
const filePath = path.join(dir, file) | ||
const stat = fs.statSync(filePath) | ||
|
||
if (stat.isDirectory()) { | ||
findMarkdownFiles(filePath) | ||
} else if (path.extname(file) === '.md') { | ||
const content = fs.readFileSync(filePath, 'utf-8') | ||
const { data } = matter(content) | ||
|
||
if (data.tags && Array.isArray(data.tags)) { | ||
const url = '/' + path.relative(path.resolve(__dirname, '../..'), filePath).replace(/\.md$/, '') | ||
const post = { | ||
title: data.title || file.replace(/\.md$/, ''), | ||
date: formatDate(data.date || stat.birthtime), | ||
url, | ||
tags: data.tags | ||
} | ||
|
||
posts.push(post) | ||
|
||
data.tags.forEach((tag: string) => { | ||
if (!tags[tag]) { | ||
tags[tag] = [] | ||
} | ||
tags[tag].push(post) | ||
}) | ||
} | ||
const contentDir = path.resolve(__dirname, "../../blog"); | ||
const tags: TagData = {}; | ||
|
||
const posts = walkFiles<Post>({ | ||
contentDir, | ||
processFile: (filePath, content, { data }) => { | ||
if (!data.tags || !Array.isArray(data.tags)) { | ||
return null; | ||
} | ||
}) | ||
} | ||
|
||
findMarkdownFiles(contentDir) | ||
|
||
Object.keys(tags).forEach(tag => { | ||
tags[tag].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) | ||
}) | ||
|
||
const sortedTags: TagData = {} | ||
Object.keys(tags).sort().forEach(tag => { | ||
sortedTags[tag] = tags[tag] | ||
}) | ||
|
||
return sortedTags | ||
} | ||
|
||
const post = { | ||
title: data.title || path.basename(filePath).replace(/\.md$/, ""), | ||
date: formatDate(data.date || fs.statSync(filePath).birthtime), | ||
url: | ||
"/" + | ||
path | ||
.relative(path.resolve(__dirname, "../.."), filePath) | ||
.replace(/\.md$/, ""), | ||
tags: data.tags, | ||
}; | ||
|
||
// 将文章添加到对应的标签集合中 | ||
data.tags.forEach((tag: string) => { | ||
if (!tags[tag]) { | ||
tags[tag] = []; | ||
} | ||
tags[tag].push(post); | ||
}); | ||
|
||
return post; | ||
}, | ||
}); | ||
|
||
// 对每个标签下的文章按日期排序 | ||
Object.keys(tags).forEach((tag) => { | ||
tags[tag].sort( | ||
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime() | ||
); | ||
}); | ||
|
||
// 对标签进行字母顺序排序 | ||
const sortedTags: TagData = {}; | ||
Object.keys(tags) | ||
.sort() | ||
.forEach((tag) => { | ||
sortedTags[tag] = tags[tag]; | ||
}); | ||
|
||
return sortedTags; | ||
} |