Skip to content

Commit 6d4f1b6

Browse files
committed
chore: update gitignore and optimize stryker config for vitest
1 parent f241175 commit 6d4f1b6

File tree

12 files changed

+378
-235
lines changed

12 files changed

+378
-235
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,23 @@ _site/
3434

3535
# Coverage
3636
coverage/
37+
*.json
38+
*.txt
39+
*.ps1
40+
!package.json
41+
!package-lock.json
42+
!tsconfig.json
43+
!biome.json
44+
!stryker.config.json
45+
!knip.json
46+
!src/lib/categories.json
3747

3848
# Stryker
3949
.stryker-tmp/
4050
reports/
51+
stryker_output.txt
52+
53+
# Scripts
54+
*.cjs
55+
!*.config.cjs
56+
!.dependency-cruiser.cjs

biome.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,26 @@
3232
}
3333
},
3434
"overrides": [
35+
{
36+
"includes": ["**/*.test.ts", "tests/**/*.ts"],
37+
"linter": {
38+
"rules": {
39+
"suspicious": {
40+
"noExplicitAny": "off"
41+
}
42+
}
43+
}
44+
},
3545
{
3646
"includes": ["**/*.svelte"],
3747
"linter": {
3848
"rules": {
3949
"style": {
4050
"useConst": "off"
51+
},
52+
"correctness": {
53+
"noUnusedVariables": "off",
54+
"noUnusedImports": "off"
4155
}
4256
}
4357
}

src/lib/categories.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929
"icon": "📝"
3030
}
3131
},
32-
"defaultCategory": "general",
32+
"defaultCategory": "General",
3333
"autoAssignByFolder": true
3434
}

src/lib/glob.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const postFiles = import.meta.glob("../posts/**/*.md", {
2+
eager: true,
3+
query: "?raw",
4+
import: "default",
5+
}) as Record<string, string>;

src/lib/markdown.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import { marked } from "marked";
22
import mermaid from "mermaid";
3+
import { postFiles } from "./glob";
34
import { normalizeImageSrc, parseFrontMatter } from "./utils";
45

5-
const postFiles = import.meta.glob("../posts/**/*.md", {
6-
eager: true,
7-
query: "?raw",
8-
import: "default",
9-
});
10-
116
export async function loadPost(slug: string) {
127
const filePath = (postFiles as Record<string, string>)[slug];
138
if (!filePath) {

src/lib/postLoader.ts

Lines changed: 78 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import categoryConfig from "./categories.json";
2+
import { postFiles } from "./glob";
23
import { parseMarkdown } from "./markdown";
34
import { 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(

src/lib/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ export function parseFrontMatter(content: string) {
101101
}
102102

103103
if (key === "tags") {
104-
data[key] = value.split(/[,\s]+/).filter(Boolean);
104+
let tagValue = value;
105+
if (tagValue.startsWith("[") && tagValue.endsWith("]")) {
106+
tagValue = tagValue.slice(1, -1);
107+
}
108+
data[key] = tagValue.split(/[,\s]+/).filter(Boolean);
105109
} else if (value === "true") {
106110
data[key] = true;
107111
} else if (value === "false") {

stryker.config.json

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
{
2-
"$schema": "https://stryker-mutator.io/schema/stryker-schema.json",
2+
"$schema": "https://help.stryker-mutator.io/rs/stryker-config.schema.json",
33
"packageManager": "npm",
44
"reporters": ["html", "clear-text", "progress"],
55
"testRunner": "vitest",
6+
"coverageAnalysis": "off",
7+
"ignoreStatic": false,
8+
"concurrency": 4,
9+
"inPlace": true,
10+
"files": ["**/*", "!node_modules/**/*", "!.stryker-tmp/**/*", "!dist/**/*"],
11+
"mutate": [
12+
"src/lib/utils.ts",
13+
"src/lib/postLoader.ts",
14+
"src/lib/markdown.ts"
15+
],
616
"vitest": {
717
"configFile": "vite.config.ts"
818
},
9-
"checkers": [],
10-
"mutate": ["src/lib/utils.ts"],
11-
"ignorePatterns": ["**/*.svelte"],
12-
"thresholds": {
13-
"high": 80,
14-
"low": 60,
15-
"break": 50
16-
}
19+
"disableTypeChecks": false
1720
}

tests/Comments.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { render, waitFor } from "@testing-library/svelte";
2-
import { tick } from "svelte";
32
import { beforeEach, describe, expect, test, vi } from "vitest";
43
import Comments from "../src/components/Comments.svelte";
54

0 commit comments

Comments
 (0)