11import categoryConfig from "./categories.json" ;
2+ import { postFiles } from "./glob" ;
23import { parseMarkdown } from "./markdown" ;
34import { parseFrontMatter , slugify } from "./utils" ;
45
@@ -14,37 +15,50 @@ function determineCategoryFromPath(path: string) {
1415 return folderMapping [ folderName ] || ( categoryConfig as any ) . defaultCategory ;
1516}
1617
17- export async function loadAllPosts ( ) {
18- try {
19- const modules = import . meta. glob ( "../posts/**/*.md" , {
20- eager : true ,
21- query : "?raw" ,
22- import : "default" ,
23- } ) as Record < string , string > ;
18+ function processPostMetadata (
19+ path : string ,
20+ data : Record < string , any > ,
21+ markdownBody : string ,
22+ ) {
23+ const fileName = path . split ( "/" ) . pop ( ) ?. replace ( ".md" , "" ) || "" ;
24+ let category = data . category ;
25+ if ( ( categoryConfig as any ) . autoAssignByFolder && ! category ) {
26+ category = determineCategoryFromPath ( path ) ;
27+ }
28+
29+ const { html : htmlContent } = parseMarkdown ( markdownBody ) ;
30+
31+ return {
32+ fileName,
33+ slug : slugify ( data . title || fileName || "" ) ,
34+ title : data . title || fileName ,
35+ date : data . date || new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] ,
36+ category : category || ( categoryConfig as any ) . defaultCategory ,
37+ tags : data . tags || [ ] ,
38+ excerpt : data . excerpt || data . description || "" ,
39+ folder : path . split ( "/" ) [ path . split ( "/" ) . length - 2 ] ,
40+ html : htmlContent ,
41+ ...data ,
42+ } ;
43+ }
2444
45+ export async function loadAllPosts (
46+ modulesOverride ?: Record < string , string | null > ,
47+ ) {
48+ try {
49+ const modules = modulesOverride || postFiles ;
2550 const posts : any [ ] = [ ] ;
26- for ( const path in modules ) {
51+
52+ for ( const [ path , content ] of Object . entries ( modules ) ) {
2753 try {
28- const content = modules [ path ] ;
29- const fileName = path . split ( "/" ) . pop ( ) ?. replace ( ".md" , "" ) ;
30- const { data, content : markdownContent } = parseFrontMatter ( content ) ;
31- let category = ( data as any ) . category ;
32- if ( ( categoryConfig as any ) . autoAssignByFolder && ! category ) {
33- category = determineCategoryFromPath ( path ) ;
34- }
35- const post = {
36- fileName,
37- slug : slugify ( ( data as any ) . title || fileName || "" ) ,
38- title : ( data as any ) . title || fileName ,
39- date : ( data as any ) . date || new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] ,
40- category : category || ( categoryConfig as any ) . defaultCategory ,
41- tags : ( data as any ) . tags || [ ] ,
42- excerpt : ( data as any ) . excerpt || ( data as any ) . description || "" ,
43- content : markdownContent ,
44- folder : path . split ( "/" ) [ path . split ( "/" ) . length - 2 ] ,
45- ...data ,
46- } ;
47- posts . push ( post ) ;
54+ if ( ! content ) continue ;
55+
56+ const { data, content : markdownBody } = parseFrontMatter ( content ) ;
57+ const post = processPostMetadata ( path , data , markdownBody ) ;
58+ posts . push ( {
59+ ...post ,
60+ content : markdownBody ,
61+ } ) ;
4862 } catch ( postError ) {
4963 console . error ( `❌ [postLoader] 포스트 파싱 중 에러 발생 (${ path } ):` , {
5064 message :
@@ -58,10 +72,25 @@ export async function loadAllPosts() {
5872 }
5973 }
6074
61- return posts . sort (
62- ( a , b ) =>
63- new Date ( b . date as any ) . getTime ( ) - new Date ( a . date as any ) . getTime ( ) ,
64- ) ;
75+ return posts . sort ( ( a , b ) => {
76+ try {
77+ return (
78+ new Date ( b . date ) . getTime ( ) - new Date ( a . date ) . getTime ( ) ||
79+ b . slug . localeCompare ( a . slug )
80+ ) ;
81+ } catch ( sortError ) {
82+ console . error ( "❌ [postLoader] 포스트 정렬 중 에러 발생:" , {
83+ message :
84+ sortError instanceof Error ? sortError . message : String ( sortError ) ,
85+ stack :
86+ sortError instanceof Error
87+ ? sortError . stack
88+ : "Stack trace unavailable" ,
89+ error : sortError ,
90+ } ) ;
91+ return 0 ;
92+ }
93+ } ) ;
6594 } catch ( error ) {
6695 console . error ( "❌ [postLoader] 포스트 로딩 중 치명적 에러 발생:" , {
6796 message : error instanceof Error ? error . message : String ( error ) ,
@@ -72,50 +101,41 @@ export async function loadAllPosts() {
72101 }
73102}
74103
75- export async function loadPostBySlug ( slug : string ) {
104+ export async function loadPostBySlug (
105+ slug : string ,
106+ modulesOverride ?: Record < string , string | null > ,
107+ ) {
76108 try {
77- const modules = import . meta. glob ( "../posts/**/*.md" , {
78- eager : true ,
79- query : "?raw" ,
80- import : "default" ,
81- } ) as Record < string , string > ;
82-
83- let targetContent : string | null = null ;
84- let targetFileName : string | null = null ;
109+ const modules = ( modulesOverride || postFiles ) as Record < string , string > ;
110+ let target : { path : string ; content : string } | null = null ;
85111
86112 for ( const path in modules ) {
87113 const content = modules [ path ] ;
88- const fileName = path . split ( "/" ) . pop ( ) ?. replace ( ".md" , "" ) ?? "unknown" ;
114+ if ( content === null || content === undefined ) continue ;
115+
116+ const fileName = path . split ( "/" ) . pop ( ) ?. replace ( ".md" , "" ) || "" ;
89117 const { data } = parseFrontMatter ( content ) ;
90- const postSlug = slugify ( ( data as any ) . title || fileName || "" ) ;
118+ const postSlug = slugify ( data . title || fileName || "" ) ;
119+
91120 if ( postSlug === slug ) {
92- targetContent = content ;
93- targetFileName = fileName ;
121+ target = { path, content } ;
94122 break ;
95123 }
96124 }
97125
98- if ( ! targetContent || ! targetFileName ) {
126+ if ( target === null ) {
99127 console . warn (
100128 `⚠️ [postLoader] 해당 슬러그에 대한 포스트를 찾을 수 없음: ${ slug } ` ,
101129 ) ;
102130 return null ;
103131 }
104132
105- const { data, content : markdownContent } = parseFrontMatter ( targetContent ) ;
106- const { html : htmlContent } = parseMarkdown ( targetContent ) ;
133+ const { data, content : markdownBody } = parseFrontMatter ( target . content ) ;
134+ const post = processPostMetadata ( target . path , data , markdownBody ) ;
107135
108136 return {
109- fileName : targetFileName ,
110- slug,
111- title : ( data as any ) . title || targetFileName ,
112- date : ( data as any ) . date || new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] ,
113- category : ( data as any ) . category || "general" ,
114- tags : ( data as any ) . tags || [ ] ,
115- excerpt : ( data as any ) . excerpt || ( data as any ) . description || "" ,
116- content : markdownContent ,
117- html : htmlContent ,
118- ...data ,
137+ ...post ,
138+ content : markdownBody ,
119139 } ;
120140 } catch ( error ) {
121141 console . error (
0 commit comments