@next-md-blog/core 1.0.0
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/README.md +242 -0
- package/dist/components/BlogPostSEO.d.ts +28 -0
- package/dist/components/BlogPostSEO.d.ts.map +1 -0
- package/dist/components/BlogPostSEO.js +22 -0
- package/dist/components/MarkdownContent.d.ts +48 -0
- package/dist/components/MarkdownContent.d.ts.map +1 -0
- package/dist/components/MarkdownContent.js +44 -0
- package/dist/components/OgImage.d.ts +35 -0
- package/dist/components/OgImage.d.ts.map +1 -0
- package/dist/components/OgImage.js +52 -0
- package/dist/components/markdown/a.d.ts +6 -0
- package/dist/components/markdown/a.d.ts.map +1 -0
- package/dist/components/markdown/a.js +7 -0
- package/dist/components/markdown/blockquote.d.ts +6 -0
- package/dist/components/markdown/blockquote.d.ts.map +1 -0
- package/dist/components/markdown/blockquote.js +7 -0
- package/dist/components/markdown/code.d.ts +6 -0
- package/dist/components/markdown/code.d.ts.map +1 -0
- package/dist/components/markdown/code.js +7 -0
- package/dist/components/markdown/defaults.d.ts +12 -0
- package/dist/components/markdown/defaults.d.ts.map +1 -0
- package/dist/components/markdown/defaults.js +59 -0
- package/dist/components/markdown/em.d.ts +6 -0
- package/dist/components/markdown/em.d.ts.map +1 -0
- package/dist/components/markdown/em.js +7 -0
- package/dist/components/markdown/h1.d.ts +6 -0
- package/dist/components/markdown/h1.d.ts.map +1 -0
- package/dist/components/markdown/h1.js +7 -0
- package/dist/components/markdown/h2.d.ts +6 -0
- package/dist/components/markdown/h2.d.ts.map +1 -0
- package/dist/components/markdown/h2.js +7 -0
- package/dist/components/markdown/h3.d.ts +6 -0
- package/dist/components/markdown/h3.d.ts.map +1 -0
- package/dist/components/markdown/h3.js +7 -0
- package/dist/components/markdown/h4.d.ts +6 -0
- package/dist/components/markdown/h4.d.ts.map +1 -0
- package/dist/components/markdown/h4.js +7 -0
- package/dist/components/markdown/h5.d.ts +6 -0
- package/dist/components/markdown/h5.d.ts.map +1 -0
- package/dist/components/markdown/h5.js +7 -0
- package/dist/components/markdown/h6.d.ts +6 -0
- package/dist/components/markdown/h6.d.ts.map +1 -0
- package/dist/components/markdown/h6.js +7 -0
- package/dist/components/markdown/hr.d.ts +6 -0
- package/dist/components/markdown/hr.d.ts.map +1 -0
- package/dist/components/markdown/hr.js +7 -0
- package/dist/components/markdown/img.d.ts +6 -0
- package/dist/components/markdown/img.d.ts.map +1 -0
- package/dist/components/markdown/img.js +9 -0
- package/dist/components/markdown/index.d.ts +29 -0
- package/dist/components/markdown/index.d.ts.map +1 -0
- package/dist/components/markdown/index.js +28 -0
- package/dist/components/markdown/li.d.ts +6 -0
- package/dist/components/markdown/li.d.ts.map +1 -0
- package/dist/components/markdown/li.js +7 -0
- package/dist/components/markdown/ol.d.ts +6 -0
- package/dist/components/markdown/ol.d.ts.map +1 -0
- package/dist/components/markdown/ol.js +7 -0
- package/dist/components/markdown/p.d.ts +6 -0
- package/dist/components/markdown/p.d.ts.map +1 -0
- package/dist/components/markdown/p.js +7 -0
- package/dist/components/markdown/pre.d.ts +6 -0
- package/dist/components/markdown/pre.d.ts.map +1 -0
- package/dist/components/markdown/pre.js +7 -0
- package/dist/components/markdown/strong.d.ts +6 -0
- package/dist/components/markdown/strong.d.ts.map +1 -0
- package/dist/components/markdown/strong.js +7 -0
- package/dist/components/markdown/table.d.ts +6 -0
- package/dist/components/markdown/table.d.ts.map +1 -0
- package/dist/components/markdown/table.js +7 -0
- package/dist/components/markdown/tbody.d.ts +6 -0
- package/dist/components/markdown/tbody.d.ts.map +1 -0
- package/dist/components/markdown/tbody.js +7 -0
- package/dist/components/markdown/td.d.ts +6 -0
- package/dist/components/markdown/td.d.ts.map +1 -0
- package/dist/components/markdown/td.js +7 -0
- package/dist/components/markdown/th.d.ts +6 -0
- package/dist/components/markdown/th.d.ts.map +1 -0
- package/dist/components/markdown/th.js +7 -0
- package/dist/components/markdown/thead.d.ts +6 -0
- package/dist/components/markdown/thead.d.ts.map +1 -0
- package/dist/components/markdown/thead.js +7 -0
- package/dist/components/markdown/tr.d.ts +6 -0
- package/dist/components/markdown/tr.d.ts.map +1 -0
- package/dist/components/markdown/tr.js +7 -0
- package/dist/components/markdown/ul.d.ts +6 -0
- package/dist/components/markdown/ul.d.ts.map +1 -0
- package/dist/components/markdown/ul.js +7 -0
- package/dist/components/markdown/utils.d.ts +6 -0
- package/dist/components/markdown/utils.d.ts.map +1 -0
- package/dist/components/markdown/utils.js +7 -0
- package/dist/core/config.d.ts +36 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +63 -0
- package/dist/core/constants.d.ts +36 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +44 -0
- package/dist/core/errors.d.ts +48 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +57 -0
- package/dist/core/file-utils.d.ts +22 -0
- package/dist/core/file-utils.d.ts.map +1 -0
- package/dist/core/file-utils.js +180 -0
- package/dist/core/seo-feeds.d.ts +16 -0
- package/dist/core/seo-feeds.d.ts.map +1 -0
- package/dist/core/seo-feeds.js +73 -0
- package/dist/core/seo-metadata.d.ts +17 -0
- package/dist/core/seo-metadata.d.ts.map +1 -0
- package/dist/core/seo-metadata.js +197 -0
- package/dist/core/seo-schema.d.ts +20 -0
- package/dist/core/seo-schema.d.ts.map +1 -0
- package/dist/core/seo-schema.js +131 -0
- package/dist/core/seo-utils.d.ts +66 -0
- package/dist/core/seo-utils.d.ts.map +1 -0
- package/dist/core/seo-utils.js +135 -0
- package/dist/core/seo.d.ts +11 -0
- package/dist/core/seo.d.ts.map +1 -0
- package/dist/core/seo.js +12 -0
- package/dist/core/type-guards.d.ts +58 -0
- package/dist/core/type-guards.d.ts.map +1 -0
- package/dist/core/type-guards.js +83 -0
- package/dist/core/types.d.ts +116 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/utils.d.ts +49 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +175 -0
- package/dist/core/validation.d.ts +22 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +50 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/package.json +80 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if a value is a non-empty string
|
|
3
|
+
*/
|
|
4
|
+
export function isString(value) {
|
|
5
|
+
return typeof value === 'string' && value.length > 0;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Type guard to check if a value is a string array
|
|
9
|
+
*/
|
|
10
|
+
export function isStringArray(value) {
|
|
11
|
+
return Array.isArray(value) && value.every(item => typeof item === 'string');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Type guard to check if a value is a number
|
|
15
|
+
*/
|
|
16
|
+
export function isNumber(value) {
|
|
17
|
+
return typeof value === 'number' && !isNaN(value);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Type guard to check if a value is an Author object
|
|
21
|
+
*/
|
|
22
|
+
export function isAuthorObject(value) {
|
|
23
|
+
return (typeof value === 'object' &&
|
|
24
|
+
value !== null &&
|
|
25
|
+
'name' in value &&
|
|
26
|
+
typeof value.name === 'string');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Type guard to check if a value is an Author
|
|
30
|
+
*/
|
|
31
|
+
export function isAuthor(value) {
|
|
32
|
+
return (typeof value === 'object' &&
|
|
33
|
+
value !== null &&
|
|
34
|
+
'name' in value &&
|
|
35
|
+
typeof value.name === 'string');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Gets a string field from frontmatter with fallback
|
|
39
|
+
* @param frontmatter - Blog post frontmatter object
|
|
40
|
+
* @param field - Field name to extract
|
|
41
|
+
* @param fallback - Optional fallback value if field is missing or invalid
|
|
42
|
+
* @returns String value or undefined
|
|
43
|
+
*/
|
|
44
|
+
export function getStringField(frontmatter, field, fallback) {
|
|
45
|
+
const value = frontmatter[field];
|
|
46
|
+
return isString(value) ? value : fallback;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Gets a number field from frontmatter with fallback
|
|
50
|
+
* @param frontmatter - Blog post frontmatter object
|
|
51
|
+
* @param field - Field name to extract
|
|
52
|
+
* @param fallback - Optional fallback value if field is missing or invalid
|
|
53
|
+
* @returns Number value or undefined
|
|
54
|
+
*/
|
|
55
|
+
export function getNumberField(frontmatter, field, fallback) {
|
|
56
|
+
const value = frontmatter[field];
|
|
57
|
+
return isNumber(value) ? value : fallback;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Resolves a frontmatter field from multiple possible field names
|
|
61
|
+
* Checks fields in order and returns the first valid value found
|
|
62
|
+
* @param fields - Array of field names to check (in priority order)
|
|
63
|
+
* @param frontmatter - Blog post frontmatter object
|
|
64
|
+
* @param fallback - Optional fallback value if no fields are found
|
|
65
|
+
* @returns First valid field value or fallback
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const title = resolveFrontmatterField<string>(
|
|
69
|
+
* ['seoTitle', 'title'],
|
|
70
|
+
* frontmatter,
|
|
71
|
+
* 'Default Title'
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function resolveFrontmatterField(fields, frontmatter, fallback) {
|
|
76
|
+
for (const field of fields) {
|
|
77
|
+
const value = frontmatter[field];
|
|
78
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return fallback;
|
|
83
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blog configuration
|
|
3
|
+
*/
|
|
4
|
+
export interface Config {
|
|
5
|
+
/** Site name */
|
|
6
|
+
siteName?: string;
|
|
7
|
+
/** Default site URL */
|
|
8
|
+
siteUrl?: string;
|
|
9
|
+
/** Default author name */
|
|
10
|
+
defaultAuthor?: string;
|
|
11
|
+
/** Array of author objects with detailed information */
|
|
12
|
+
authors?: Author[];
|
|
13
|
+
/** Twitter handle */
|
|
14
|
+
twitterHandle?: string;
|
|
15
|
+
/** Default OG image URL */
|
|
16
|
+
defaultOgImage?: string;
|
|
17
|
+
/** Default language code */
|
|
18
|
+
defaultLang?: string;
|
|
19
|
+
/** Alternate language URLs for hreflang (e.g., { 'en': 'https://example.com/blog/post', 'fr': 'https://example.com/fr/blog/post' }) */
|
|
20
|
+
alternateLanguages?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Author information
|
|
24
|
+
*/
|
|
25
|
+
export interface Author {
|
|
26
|
+
name: string;
|
|
27
|
+
email?: string;
|
|
28
|
+
bio?: string;
|
|
29
|
+
avatar?: string;
|
|
30
|
+
twitter?: string;
|
|
31
|
+
github?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Frontmatter metadata for blog posts
|
|
36
|
+
*/
|
|
37
|
+
export interface BlogPostFrontmatter {
|
|
38
|
+
title?: string;
|
|
39
|
+
date?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
/** Author can be a string, an object with name property (Quarto format), or an array of either */
|
|
42
|
+
author?: string | {
|
|
43
|
+
name: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
} | (string | {
|
|
46
|
+
name: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
})[];
|
|
49
|
+
/** Authors can be an array of strings or objects with name property */
|
|
50
|
+
authors?: (string | {
|
|
51
|
+
name: string;
|
|
52
|
+
[key: string]: unknown;
|
|
53
|
+
})[];
|
|
54
|
+
tags?: string[];
|
|
55
|
+
/** Custom OG image URL */
|
|
56
|
+
ogImage?: string;
|
|
57
|
+
/** Featured image URL (fallback for OG image) */
|
|
58
|
+
image?: string;
|
|
59
|
+
/** Robots meta directive (e.g., 'noindex, nofollow' or 'index, follow') */
|
|
60
|
+
robots?: string;
|
|
61
|
+
/** Whether to exclude from search engine indexing */
|
|
62
|
+
noindex?: boolean;
|
|
63
|
+
/** Whether to exclude from following links */
|
|
64
|
+
nofollow?: boolean;
|
|
65
|
+
/** Reading time in minutes (auto-calculated if not provided) */
|
|
66
|
+
readingTime?: number;
|
|
67
|
+
[key: string]: unknown;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Complete blog post with content and metadata
|
|
71
|
+
*/
|
|
72
|
+
export interface BlogPost {
|
|
73
|
+
/** The slug identifier for the post (filename without extension) */
|
|
74
|
+
slug: string;
|
|
75
|
+
/** The markdown content of the post */
|
|
76
|
+
content: string;
|
|
77
|
+
/** Frontmatter metadata parsed from the markdown file */
|
|
78
|
+
frontmatter: BlogPostFrontmatter;
|
|
79
|
+
/** Reading time in minutes (auto-calculated) */
|
|
80
|
+
readingTime: number;
|
|
81
|
+
/** Word count (auto-calculated) */
|
|
82
|
+
wordCount: number;
|
|
83
|
+
/** Normalized authors array (string or Author objects) */
|
|
84
|
+
authors: (string | Author)[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Blog post metadata without content (for listings)
|
|
88
|
+
*/
|
|
89
|
+
export interface BlogPostMetadata {
|
|
90
|
+
/** The slug identifier for the post */
|
|
91
|
+
slug: string;
|
|
92
|
+
/** Frontmatter metadata parsed from the markdown file */
|
|
93
|
+
frontmatter: BlogPostFrontmatter;
|
|
94
|
+
/** Normalized authors array (string or Author objects) */
|
|
95
|
+
authors: (string | Author)[];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Options for reading blog posts
|
|
99
|
+
*/
|
|
100
|
+
export interface GetBlogPostOptions {
|
|
101
|
+
/** Custom path to posts directory */
|
|
102
|
+
postsDir?: string;
|
|
103
|
+
/** Locale code for multi-language support (e.g., 'en', 'fr') */
|
|
104
|
+
locale?: string;
|
|
105
|
+
/** Blog configuration for author resolution */
|
|
106
|
+
config?: Config;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Result of file system operations
|
|
110
|
+
*/
|
|
111
|
+
export interface FileSystemResult<T> {
|
|
112
|
+
success: boolean;
|
|
113
|
+
data?: T;
|
|
114
|
+
error?: Error;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Author } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Calculates reading time in minutes from markdown content
|
|
4
|
+
* Assumes average reading speed of 200 words per minute
|
|
5
|
+
* @param content - The markdown content
|
|
6
|
+
* @returns Reading time in minutes (rounded up)
|
|
7
|
+
*/
|
|
8
|
+
export declare function calculateReadingTime(content: string): number;
|
|
9
|
+
/**
|
|
10
|
+
* Calculates word count from markdown content
|
|
11
|
+
* @param content - The markdown content
|
|
12
|
+
* @returns Word count
|
|
13
|
+
*/
|
|
14
|
+
export declare function calculateWordCount(content: string): number;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves author names to full Author objects from config
|
|
17
|
+
* Matches by full name only (case-insensitive)
|
|
18
|
+
* @param authorName - Author name to resolve
|
|
19
|
+
* @param configAuthors - Array of authors from config
|
|
20
|
+
* @returns Author object if found, otherwise returns the name as string
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveAuthorFromConfig(authorName: string, configAuthors?: Author[]): string | Author;
|
|
23
|
+
/**
|
|
24
|
+
* Normalizes authors to an array of strings or Author objects
|
|
25
|
+
* Supports:
|
|
26
|
+
* - author: "John Doe" (string)
|
|
27
|
+
* - author: { name: "John Doe", affiliation: "..." } (single object with name property - Quarto format)
|
|
28
|
+
* - author: ["John Doe", "Jane Smith"] (array of strings)
|
|
29
|
+
* - author: [{ name: "John Doe" }, { name: "Jane Smith" }] (array of objects with name)
|
|
30
|
+
* - authors: ["John Doe", "Jane Smith"] (array of strings)
|
|
31
|
+
* - authors: [{ name: "John Doe" }, { name: "Jane Smith" }] (array of objects with name)
|
|
32
|
+
* If configAuthors is provided, resolves author names to full Author objects by matching full name
|
|
33
|
+
* Falls back to string names if authors array is not configured (backward compatible)
|
|
34
|
+
* @param author - Author field from frontmatter (string, object with name, string[], or array of objects with name)
|
|
35
|
+
* @param authors - Authors field from frontmatter (string[] or array of objects with name)
|
|
36
|
+
* @param configAuthors - Optional array of authors from config to resolve against
|
|
37
|
+
* @returns Normalized array of author names or Author objects
|
|
38
|
+
*/
|
|
39
|
+
export declare function normalizeAuthors(author?: string | {
|
|
40
|
+
name: string;
|
|
41
|
+
[key: string]: unknown;
|
|
42
|
+
} | (string | {
|
|
43
|
+
name: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
})[], authors?: (string | {
|
|
46
|
+
name: string;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
})[], configAuthors?: Author[]): (string | Author)[];
|
|
49
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA+DzC;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAqB5D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAU1D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,MAAM,GAAG,MAAM,CAYjB;AAsBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,CAAC,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,EAAE,EAClH,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC,EAAE,EAC/D,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CA0CrB"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// Regex patterns for markdown stripping (compiled once at module level)
|
|
2
|
+
const CODE_BLOCK_REGEX = /```[\s\S]*?```/g;
|
|
3
|
+
const INLINE_CODE_REGEX = /`[^`]*`/g;
|
|
4
|
+
const LINK_REGEX = /\[([^\]]*)\]\([^\)]*\)/g;
|
|
5
|
+
const IMAGE_REGEX = /!\[([^\]]*)\]\([^\)]*\)/g;
|
|
6
|
+
const HTML_TAG_REGEX = /<[^>]*>/g;
|
|
7
|
+
const HEADER_REGEX = /#+\s+/g;
|
|
8
|
+
const HORIZONTAL_RULE_REGEX = /---+/g;
|
|
9
|
+
const LIST_MARKER_REGEX = /^[\s]*[-*+]\s+/gm;
|
|
10
|
+
const BLOCKQUOTE_REGEX = /^>\s+/gm;
|
|
11
|
+
const WHITESPACE_REGEX = /\s+/g;
|
|
12
|
+
// Constants
|
|
13
|
+
const WORDS_PER_MINUTE = 200;
|
|
14
|
+
const MIN_READING_TIME = 1;
|
|
15
|
+
/**
|
|
16
|
+
* Strips markdown syntax from content to get plain text
|
|
17
|
+
* @param content - The markdown content
|
|
18
|
+
* @param options - Options for what to strip
|
|
19
|
+
* @returns Plain text with markdown syntax removed
|
|
20
|
+
*/
|
|
21
|
+
function stripMarkdownSyntax(content, options = {}) {
|
|
22
|
+
let plainText = content
|
|
23
|
+
// Remove code blocks
|
|
24
|
+
.replace(CODE_BLOCK_REGEX, '')
|
|
25
|
+
// Remove inline code
|
|
26
|
+
.replace(INLINE_CODE_REGEX, '')
|
|
27
|
+
// Remove links but keep text
|
|
28
|
+
.replace(LINK_REGEX, '$1')
|
|
29
|
+
// Remove images
|
|
30
|
+
.replace(IMAGE_REGEX, '')
|
|
31
|
+
// Remove HTML tags
|
|
32
|
+
.replace(HTML_TAG_REGEX, '');
|
|
33
|
+
// Conditionally remove additional markdown elements
|
|
34
|
+
if (options.includeHeaders) {
|
|
35
|
+
plainText = plainText.replace(HEADER_REGEX, '');
|
|
36
|
+
}
|
|
37
|
+
if (options.includeHorizontalRules) {
|
|
38
|
+
plainText = plainText.replace(HORIZONTAL_RULE_REGEX, '');
|
|
39
|
+
}
|
|
40
|
+
if (options.includeLists) {
|
|
41
|
+
plainText = plainText.replace(LIST_MARKER_REGEX, '');
|
|
42
|
+
}
|
|
43
|
+
if (options.includeBlockquotes) {
|
|
44
|
+
plainText = plainText.replace(BLOCKQUOTE_REGEX, '');
|
|
45
|
+
}
|
|
46
|
+
// Remove extra whitespace
|
|
47
|
+
return plainText.replace(WHITESPACE_REGEX, ' ').trim();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Calculates reading time in minutes from markdown content
|
|
51
|
+
* Assumes average reading speed of 200 words per minute
|
|
52
|
+
* @param content - The markdown content
|
|
53
|
+
* @returns Reading time in minutes (rounded up)
|
|
54
|
+
*/
|
|
55
|
+
export function calculateReadingTime(content) {
|
|
56
|
+
if (!content || typeof content !== 'string') {
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
// Strip all markdown syntax including headers, lists, blockquotes, etc.
|
|
60
|
+
const plainText = stripMarkdownSyntax(content, {
|
|
61
|
+
includeHeaders: true,
|
|
62
|
+
includeLists: true,
|
|
63
|
+
includeBlockquotes: true,
|
|
64
|
+
includeHorizontalRules: true,
|
|
65
|
+
});
|
|
66
|
+
// Count words (split by whitespace)
|
|
67
|
+
const wordCount = plainText.split(/\s+/).filter((word) => word.length > 0).length;
|
|
68
|
+
// Calculate reading time
|
|
69
|
+
const readingTime = Math.ceil(wordCount / WORDS_PER_MINUTE);
|
|
70
|
+
// Minimum reading time is 1 minute
|
|
71
|
+
return Math.max(MIN_READING_TIME, readingTime);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Calculates word count from markdown content
|
|
75
|
+
* @param content - The markdown content
|
|
76
|
+
* @returns Word count
|
|
77
|
+
*/
|
|
78
|
+
export function calculateWordCount(content) {
|
|
79
|
+
if (!content || typeof content !== 'string') {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
// Strip basic markdown syntax (no headers, lists, etc. for word count)
|
|
83
|
+
const plainText = stripMarkdownSyntax(content);
|
|
84
|
+
// Count words (split by whitespace)
|
|
85
|
+
return plainText.split(/\s+/).filter((word) => word.length > 0).length;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Resolves author names to full Author objects from config
|
|
89
|
+
* Matches by full name only (case-insensitive)
|
|
90
|
+
* @param authorName - Author name to resolve
|
|
91
|
+
* @param configAuthors - Array of authors from config
|
|
92
|
+
* @returns Author object if found, otherwise returns the name as string
|
|
93
|
+
*/
|
|
94
|
+
export function resolveAuthorFromConfig(authorName, configAuthors) {
|
|
95
|
+
// If no config authors, return name as-is (backward compatibility)
|
|
96
|
+
if (!configAuthors || configAuthors.length === 0) {
|
|
97
|
+
return authorName;
|
|
98
|
+
}
|
|
99
|
+
// Match by full name (case-insensitive)
|
|
100
|
+
const found = configAuthors.find((a) => a.name.toLowerCase() === authorName.toLowerCase());
|
|
101
|
+
return found || authorName;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Extracts author name from various formats (string, object with name property, etc.)
|
|
105
|
+
* @param item - Author item that could be a string or object
|
|
106
|
+
* @returns Author name as string, or undefined if invalid
|
|
107
|
+
*/
|
|
108
|
+
function extractAuthorName(item) {
|
|
109
|
+
if (typeof item === 'string') {
|
|
110
|
+
return item.trim() || undefined;
|
|
111
|
+
}
|
|
112
|
+
if (typeof item === 'object' && item !== null) {
|
|
113
|
+
// Handle objects with name property: { name: "John Doe" }
|
|
114
|
+
if ('name' in item && typeof item.name === 'string') {
|
|
115
|
+
return item.name.trim() || undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Normalizes authors to an array of strings or Author objects
|
|
122
|
+
* Supports:
|
|
123
|
+
* - author: "John Doe" (string)
|
|
124
|
+
* - author: { name: "John Doe", affiliation: "..." } (single object with name property - Quarto format)
|
|
125
|
+
* - author: ["John Doe", "Jane Smith"] (array of strings)
|
|
126
|
+
* - author: [{ name: "John Doe" }, { name: "Jane Smith" }] (array of objects with name)
|
|
127
|
+
* - authors: ["John Doe", "Jane Smith"] (array of strings)
|
|
128
|
+
* - authors: [{ name: "John Doe" }, { name: "Jane Smith" }] (array of objects with name)
|
|
129
|
+
* If configAuthors is provided, resolves author names to full Author objects by matching full name
|
|
130
|
+
* Falls back to string names if authors array is not configured (backward compatible)
|
|
131
|
+
* @param author - Author field from frontmatter (string, object with name, string[], or array of objects with name)
|
|
132
|
+
* @param authors - Authors field from frontmatter (string[] or array of objects with name)
|
|
133
|
+
* @param configAuthors - Optional array of authors from config to resolve against
|
|
134
|
+
* @returns Normalized array of author names or Author objects
|
|
135
|
+
*/
|
|
136
|
+
export function normalizeAuthors(author, authors, configAuthors) {
|
|
137
|
+
const authorList = [];
|
|
138
|
+
// First, collect from authors field
|
|
139
|
+
if (Array.isArray(authors) && authors.length > 0) {
|
|
140
|
+
authors.forEach((a) => {
|
|
141
|
+
const name = extractAuthorName(a);
|
|
142
|
+
if (name) {
|
|
143
|
+
authorList.push(name);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// Then, collect from author field
|
|
148
|
+
if (author) {
|
|
149
|
+
if (Array.isArray(author)) {
|
|
150
|
+
author.forEach((a) => {
|
|
151
|
+
const name = extractAuthorName(a);
|
|
152
|
+
if (name) {
|
|
153
|
+
authorList.push(name);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (typeof author === 'string' && author.trim().length > 0) {
|
|
158
|
+
authorList.push(author.trim());
|
|
159
|
+
}
|
|
160
|
+
else if (typeof author === 'object' && author !== null && 'name' in author) {
|
|
161
|
+
// Handle single object: { name: "John Doe" }
|
|
162
|
+
const name = extractAuthorName(author);
|
|
163
|
+
if (name) {
|
|
164
|
+
authorList.push(name);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Remove duplicates while preserving order
|
|
169
|
+
const uniqueAuthors = authorList.filter((a, i, arr) => arr.indexOf(a) === i);
|
|
170
|
+
// Resolve authors from config if available
|
|
171
|
+
if (configAuthors && configAuthors.length > 0) {
|
|
172
|
+
return uniqueAuthors.map((name) => resolveAuthorFromConfig(name, configAuthors));
|
|
173
|
+
}
|
|
174
|
+
return uniqueAuthors;
|
|
175
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BlogPostFrontmatter } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Validates that a slug is safe and valid
|
|
4
|
+
* @param slug - The slug to validate
|
|
5
|
+
* @returns True if valid, throws error if invalid
|
|
6
|
+
* @throws {Error} If slug is invalid
|
|
7
|
+
*/
|
|
8
|
+
export declare function validateSlug(slug: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Validates frontmatter data
|
|
11
|
+
* @param frontmatter - The frontmatter to validate
|
|
12
|
+
* @returns Validated frontmatter
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateFrontmatter(frontmatter: unknown): BlogPostFrontmatter;
|
|
15
|
+
/**
|
|
16
|
+
* Validates markdown content
|
|
17
|
+
* @param content - The content to validate
|
|
18
|
+
* @returns True if valid
|
|
19
|
+
* @throws {Error} If content is invalid
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateContent(content: string): boolean;
|
|
22
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/core/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAoBlD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,OAAO,GAAG,mBAAmB,CAW7E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKxD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates that a slug is safe and valid
|
|
3
|
+
* @param slug - The slug to validate
|
|
4
|
+
* @returns True if valid, throws error if invalid
|
|
5
|
+
* @throws {Error} If slug is invalid
|
|
6
|
+
*/
|
|
7
|
+
export function validateSlug(slug) {
|
|
8
|
+
if (!slug || typeof slug !== 'string') {
|
|
9
|
+
throw new Error('Slug must be a non-empty string');
|
|
10
|
+
}
|
|
11
|
+
if (slug.trim().length === 0) {
|
|
12
|
+
throw new Error('Slug cannot be empty or whitespace');
|
|
13
|
+
}
|
|
14
|
+
// Prevent directory traversal and invalid characters
|
|
15
|
+
if (slug.includes('..') || slug.includes('/') || slug.includes('\\')) {
|
|
16
|
+
throw new Error('Slug cannot contain path separators or directory traversal sequences');
|
|
17
|
+
}
|
|
18
|
+
// Prevent null bytes
|
|
19
|
+
if (slug.includes('\0')) {
|
|
20
|
+
throw new Error('Slug cannot contain null bytes');
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validates frontmatter data
|
|
26
|
+
* @param frontmatter - The frontmatter to validate
|
|
27
|
+
* @returns Validated frontmatter
|
|
28
|
+
*/
|
|
29
|
+
export function validateFrontmatter(frontmatter) {
|
|
30
|
+
if (!frontmatter || typeof frontmatter !== 'object') {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
// Ensure it's a plain object
|
|
34
|
+
if (Array.isArray(frontmatter)) {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
return frontmatter;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validates markdown content
|
|
41
|
+
* @param content - The content to validate
|
|
42
|
+
* @returns True if valid
|
|
43
|
+
* @throws {Error} If content is invalid
|
|
44
|
+
*/
|
|
45
|
+
export function validateContent(content) {
|
|
46
|
+
if (typeof content !== 'string') {
|
|
47
|
+
throw new Error('Content must be a string');
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { MarkdownContent } from './components/MarkdownContent.js';
|
|
2
|
+
export type { MarkdownContentProps, MarkdownComponents } from './components/MarkdownContent.js';
|
|
3
|
+
export { defaultMarkdownComponents } from './components/markdown/defaults.js';
|
|
4
|
+
export { OgImage } from './components/OgImage.js';
|
|
5
|
+
export type { OgImageProps } from './components/OgImage.js';
|
|
6
|
+
export { BlogPostSEO } from './components/BlogPostSEO.js';
|
|
7
|
+
export type { BlogPostSEOProps } from './components/BlogPostSEO.js';
|
|
8
|
+
export { getBlogPost, getAllBlogPosts, getAllBlogPostSlugs } from './core/file-utils.js';
|
|
9
|
+
export { generateBlogPostMetadata, generateBlogListMetadata, generateBlogPostSchema, generateBreadcrumbsSchema, generateSitemap, generateRSSFeed, } from './core/seo.js';
|
|
10
|
+
export { createConfig, loadConfig, getConfig } from './core/config.js';
|
|
11
|
+
export type { BlogPost, BlogPostMetadata, BlogPostFrontmatter, GetBlogPostOptions, Author, Config, } from './core/types.js';
|
|
12
|
+
export { MdxBlogError, BlogPostNotFoundError, FileReadError, DirectoryError, } from './core/errors.js';
|
|
13
|
+
export { POSTS_DIR_NAME, getPostsDirectory } from './core/constants.js';
|
|
14
|
+
export { calculateReadingTime, calculateWordCount, normalizeAuthors } from './core/utils.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,YAAY,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAChG,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGzF,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGvE,YAAY,EACV,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,MAAM,EACN,MAAM,GACP,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,aAAa,EACb,cAAc,GACf,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
export { MarkdownContent } from './components/MarkdownContent.js';
|
|
3
|
+
export { defaultMarkdownComponents } from './components/markdown/defaults.js';
|
|
4
|
+
export { OgImage } from './components/OgImage.js';
|
|
5
|
+
export { BlogPostSEO } from './components/BlogPostSEO.js';
|
|
6
|
+
// Utilities
|
|
7
|
+
export { getBlogPost, getAllBlogPosts, getAllBlogPostSlugs } from './core/file-utils.js';
|
|
8
|
+
// SEO
|
|
9
|
+
export { generateBlogPostMetadata, generateBlogListMetadata, generateBlogPostSchema, generateBreadcrumbsSchema, generateSitemap, generateRSSFeed, } from './core/seo.js';
|
|
10
|
+
// Config
|
|
11
|
+
export { createConfig, loadConfig, getConfig } from './core/config.js';
|
|
12
|
+
// Errors
|
|
13
|
+
export { MdxBlogError, BlogPostNotFoundError, FileReadError, DirectoryError, } from './core/errors.js';
|
|
14
|
+
// Constants
|
|
15
|
+
export { POSTS_DIR_NAME, getPostsDirectory } from './core/constants.js';
|
|
16
|
+
// Utilities
|
|
17
|
+
export { calculateReadingTime, calculateWordCount, normalizeAuthors } from './core/utils.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@next-md-blog/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A React library for parsing and displaying markdown blog posts in Next.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"prepare": "npm run build",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"test:coverage": "vitest run --coverage",
|
|
27
|
+
"prepublishOnly": "npm run build && npm run test"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"react",
|
|
31
|
+
"nextjs",
|
|
32
|
+
"markdown",
|
|
33
|
+
"blog",
|
|
34
|
+
"mdx",
|
|
35
|
+
"content"
|
|
36
|
+
],
|
|
37
|
+
"author": "florianamette",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/florianamette/next-mdx-blog.git",
|
|
42
|
+
"directory": "packages/core"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://github.com/florianamette/next-mdx-blog#readme",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/florianamette/next-mdx-blog/issues"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
53
|
+
"c12": "^2.0.4",
|
|
54
|
+
"gray-matter": "^4.0.3",
|
|
55
|
+
"react-markdown": "^10.1.0",
|
|
56
|
+
"rehype-react": "^7.0.0",
|
|
57
|
+
"remark": "^15.0.1",
|
|
58
|
+
"remark-emoji": "^5.0.2",
|
|
59
|
+
"remark-gfm": "^4.0.0",
|
|
60
|
+
"remark-rehype": "^11.1.1",
|
|
61
|
+
"tailwindcss": "^4.0.0",
|
|
62
|
+
"unist-util-visit": "^5.0.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
66
|
+
"@semantic-release/git": "^10.0.1",
|
|
67
|
+
"@types/node": "^20.0.0",
|
|
68
|
+
"@types/react": "^18.0.0",
|
|
69
|
+
"@types/react-dom": "^18.0.0",
|
|
70
|
+
"@vitest/coverage-v8": "^4.0.8",
|
|
71
|
+
"semantic-release": "^23.0.0",
|
|
72
|
+
"typescript": "^5.0.0",
|
|
73
|
+
"vitest": "^4.0.8"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"next": "^16.0.1",
|
|
77
|
+
"react": "^19.2.0",
|
|
78
|
+
"react-dom": "^19.2.0"
|
|
79
|
+
}
|
|
80
|
+
}
|