next-staticblog 0.1.4 → 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.ts CHANGED
@@ -1,25 +1,25 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import matter from "gray-matter";
3
+ import { matter } from "gray-matter-es";
4
4
 
5
- const postsDirectory = path.join(process.cwd(), "posts");
6
-
7
- export function getAllPostSlugs() {
5
+ export function getAllPostSlugs(directory: string = "posts/") {
6
+ const postsDirectory = path.join(process.cwd(), directory);
8
7
  return fs.readdirSync(postsDirectory);
9
8
  }
10
9
 
11
- export function getAllPosts() {
12
- const slugs = getAllPostSlugs();
13
- return slugs.map((slug) => getPostBySlug(slug));
10
+ export function getAllPosts(directory: string = "posts/") {
11
+ const slugs = getAllPostSlugs(directory);
12
+ return slugs.map((slug) => getPostBySlug(slug, directory));
14
13
  }
15
14
 
16
- export function getAllPostParams(){
17
- const slugs = getAllPostSlugs();
15
+ export function getAllPostParams(directory: string = "posts/") {
16
+ const slugs = getAllPostSlugs(directory);
18
17
  return slugs.map((slug) => ({ slug: slug.replace(/\.md$/, "") }));
19
18
  }
20
19
 
21
- export function getPostBySlug(slug: string) {
20
+ export function getPostBySlug(slug: string, directory: string = "posts/") {
22
21
  const realSlug = slug.replace(/\.md$/, "");
22
+ const postsDirectory = path.join(process.cwd(), directory);
23
23
  const fullPath = path.join(postsDirectory, `${realSlug}.md`);
24
24
  const fileContents = fs.readFileSync(fullPath, "utf8");
25
25
  const { data, content } = matter(fileContents);
package/package.json CHANGED
@@ -1,26 +1,29 @@
1
- {
2
- "name": "next-staticblog",
3
- "version": "0.1.4",
4
- "description": "Quickly configure the markdown component in the Next.js project and create a blog page!",
5
- "homepage": "https://github.com/yd-tw/next-staticblog",
6
- "license": "MIT",
7
- "author": "twyd",
8
- "type": "module",
9
- "main": "dist/index.js",
10
- "types": "dist/index.d.ts",
11
- "keywords": [
12
- "next.js",
13
- "markdown",
14
- "blog"
15
- ],
16
- "scripts": {
17
- "build": "tsc"
18
- },
19
- "dependencies": {
20
- "gray-matter": "^4.0.3"
21
- },
22
- "devDependencies": {
23
- "@types/node": "^22.13.1",
24
- "typescript": "^5.7.3"
25
- }
26
- }
1
+ {
2
+ "name": "next-staticblog",
3
+ "version": "0.2.0-beta.1",
4
+ "description": "Quickly configure the markdown component in the Next.js project and create a blog page!",
5
+ "homepage": "https://github.com/yd-tw/next-staticblog",
6
+ "license": "MIT",
7
+ "author": "twyd",
8
+ "type": "module",
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "keywords": [
12
+ "next.js",
13
+ "markdown",
14
+ "blog"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "test": "vitest run"
19
+ },
20
+ "dependencies": {
21
+ "gray-matter-es": "^0.2.1"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^24.10.13",
25
+ "@vitest/coverage-v8": "^4.0.18",
26
+ "typescript": "^5.9.3",
27
+ "vitest": "^4.0.18"
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: Custom Post
3
+ date: 2024-06-01
4
+ ---
5
+
6
+ Content from custom directory.
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: Hello World
3
+ date: 2024-01-01
4
+ ---
5
+
6
+ This is the content of the hello world post.
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: Second Post
3
+ date: 2024-01-02
4
+ tags:
5
+ - test
6
+ - blog
7
+ ---
8
+
9
+ This is the second post content.
@@ -0,0 +1,157 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+ import {
5
+ getAllPostSlugs,
6
+ getAllPosts,
7
+ getAllPostParams,
8
+ getPostBySlug,
9
+ } from "../index.ts";
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+
14
+ const FIXTURES_DIR = path.join(__dirname, "fixtures");
15
+
16
+ beforeEach(() => {
17
+ vi.spyOn(process, "cwd").mockReturnValue(FIXTURES_DIR);
18
+ });
19
+
20
+ afterEach(() => {
21
+ vi.restoreAllMocks();
22
+ });
23
+
24
+ describe("getAllPostSlugs", () => {
25
+ // 回傳預設 posts 目錄中的所有檔名
26
+ it("returns filenames from default posts directory", () => {
27
+ const slugs = getAllPostSlugs();
28
+ expect(slugs).toEqual(
29
+ expect.arrayContaining(["hello-world.md", "second-post.md"])
30
+ );
31
+ });
32
+
33
+ // 回傳自訂目錄中的所有檔名
34
+ it("returns filenames from custom directory", () => {
35
+ const slugs = getAllPostSlugs("custom-posts/");
36
+ expect(slugs).toEqual(["custom.md"]);
37
+ });
38
+
39
+ // 回傳目錄中所有檔案(數量正確)
40
+ it("returns all files in directory", () => {
41
+ const slugs = getAllPostSlugs();
42
+ expect(slugs).toHaveLength(2);
43
+ });
44
+ });
45
+
46
+ describe("getAllPostParams", () => {
47
+ // 回傳不含 .md 副檔名的 slug 參數物件
48
+ it("returns slug params without .md extension", () => {
49
+ const params = getAllPostParams();
50
+ expect(params).toEqual(
51
+ expect.arrayContaining([{ slug: "hello-world" }, { slug: "second-post" }])
52
+ );
53
+ });
54
+
55
+ // 回傳自訂目錄中的 slug 參數
56
+ it("returns slug params from custom directory", () => {
57
+ const params = getAllPostParams("custom-posts/");
58
+ expect(params).toEqual([{ slug: "custom" }]);
59
+ });
60
+
61
+ // 確保所有 slug 都已移除 .md 副檔名
62
+ it("strips .md extension from all slugs", () => {
63
+ const params = getAllPostParams();
64
+ for (const param of params) {
65
+ expect(param.slug).not.toMatch(/\.md$/);
66
+ }
67
+ });
68
+ });
69
+
70
+ describe("getPostBySlug", () => {
71
+ // 使用不含副檔名的 slug 取得文章資料
72
+ it("returns post data for slug without extension", () => {
73
+ const post = getPostBySlug("hello-world");
74
+ expect(post.slug).toBe("hello-world");
75
+ expect(post.metadata.title).toBe("Hello World");
76
+ expect(post.content).toContain("This is the content of the hello world post.");
77
+ });
78
+
79
+ // 使用含 .md 副檔名的 slug 取得文章資料
80
+ it("returns post data for slug with .md extension", () => {
81
+ const post = getPostBySlug("hello-world.md");
82
+ expect(post.slug).toBe("hello-world");
83
+ expect(post.metadata.title).toBe("Hello World");
84
+ });
85
+
86
+ // 正確解析 frontmatter 中的 metadata
87
+ it("parses frontmatter metadata correctly", () => {
88
+ const post = getPostBySlug("second-post");
89
+ expect(post.metadata.title).toBe("Second Post");
90
+ expect(post.metadata.tags).toEqual(["test", "blog"]);
91
+ });
92
+
93
+ // 回傳內容不包含 frontmatter 區塊
94
+ it("returns content without frontmatter", () => {
95
+ const post = getPostBySlug("second-post");
96
+ expect(post.content).toContain("This is the second post content.");
97
+ expect(post.content).not.toContain("---");
98
+ });
99
+
100
+ // 可從自訂目錄中取得文章
101
+ it("returns post from custom directory", () => {
102
+ const post = getPostBySlug("custom", "custom-posts/");
103
+ expect(post.slug).toBe("custom");
104
+ expect(post.metadata.title).toBe("Custom Post");
105
+ expect(post.content).toContain("Content from custom directory.");
106
+ });
107
+
108
+ // 回傳的 slug 永遠不包含 .md 副檔名
109
+ it("returned slug never has .md extension", () => {
110
+ const postWithExt = getPostBySlug("hello-world.md");
111
+ const postWithoutExt = getPostBySlug("hello-world");
112
+ expect(postWithExt.slug).toBe("hello-world");
113
+ expect(postWithoutExt.slug).toBe("hello-world");
114
+ });
115
+ });
116
+
117
+ describe("getAllPosts", () => {
118
+ // 回傳預設目錄中的所有文章
119
+ it("returns all posts from default directory", () => {
120
+ const posts = getAllPosts();
121
+ expect(posts).toHaveLength(2);
122
+ });
123
+
124
+ // 回傳的文章物件結構正確
125
+ it("returns posts with correct structure", () => {
126
+ const posts = getAllPosts();
127
+ for (const post of posts) {
128
+ expect(post).toHaveProperty("slug");
129
+ expect(post).toHaveProperty("metadata");
130
+ expect(post).toHaveProperty("content");
131
+ }
132
+ });
133
+
134
+ // 所有文章的 slug 都不包含 .md 副檔名
135
+ it("returns posts with slugs without .md extension", () => {
136
+ const posts = getAllPosts();
137
+ for (const post of posts) {
138
+ expect(post.slug).not.toMatch(/\.md$/);
139
+ }
140
+ });
141
+
142
+ // 可從自訂目錄取得文章列表
143
+ it("returns posts from custom directory", () => {
144
+ const posts = getAllPosts("custom-posts/");
145
+ expect(posts).toHaveLength(1);
146
+ expect(posts[0].slug).toBe("custom");
147
+ expect(posts[0].metadata.title).toBe("Custom Post");
148
+ });
149
+
150
+ // 所有回傳的文章內容都不是空字串
151
+ it("all returned posts have non-empty content", () => {
152
+ const posts = getAllPosts();
153
+ for (const post of posts) {
154
+ expect(post.content.trim().length).toBeGreaterThan(0);
155
+ }
156
+ });
157
+ });
package/tsconfig.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
+ "exclude": ["tests/**", "node_modules"],
2
3
  "compilerOptions": {
3
- "target": "es2016",
4
+ "target": "es2017",
4
5
  "module": "esnext",
5
6
  "moduleResolution": "bundler",
6
7
  "outDir": "./dist",
package/dist/index.d.ts DELETED
@@ -1,18 +0,0 @@
1
- export declare function getAllPostSlugs(): string[];
2
- export declare function getAllPosts(): {
3
- slug: string;
4
- metadata: {
5
- [key: string]: any;
6
- };
7
- content: string;
8
- }[];
9
- export declare function getAllPostParams(): {
10
- slug: string;
11
- }[];
12
- export declare function getPostBySlug(slug: string): {
13
- slug: string;
14
- metadata: {
15
- [key: string]: any;
16
- };
17
- content: string;
18
- };
package/dist/index.js DELETED
@@ -1,22 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import matter from "gray-matter";
4
- const postsDirectory = path.join(process.cwd(), "posts");
5
- export function getAllPostSlugs() {
6
- return fs.readdirSync(postsDirectory);
7
- }
8
- export function getAllPosts() {
9
- const slugs = getAllPostSlugs();
10
- return slugs.map((slug) => getPostBySlug(slug));
11
- }
12
- export function getAllPostParams() {
13
- const slugs = getAllPostSlugs();
14
- return slugs.map((slug) => ({ slug: slug.replace(/\.md$/, "") }));
15
- }
16
- export function getPostBySlug(slug) {
17
- const realSlug = slug.replace(/\.md$/, "");
18
- const fullPath = path.join(postsDirectory, `${realSlug}.md`);
19
- const fileContents = fs.readFileSync(fullPath, "utf8");
20
- const { data, content } = matter(fileContents);
21
- return { slug: realSlug, metadata: data, content };
22
- }