@vyriy/ssg 0.9.1 → 0.9.2

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.
@@ -0,0 +1,104 @@
1
+ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { dirname, join, relative, sep } from 'node:path';
3
+ import { parsePage } from './parse-page.js';
4
+ import { getContentIndexHref, renderContentIndex, renderPage } from './render-page.js';
5
+ import { getMarkdownHref, writeMarkdownPage } from './markdown-page.js';
6
+ const isNodeError = (error) => {
7
+ return typeof error === 'object' && error !== null && 'code' in error;
8
+ };
9
+ const findReadmePaths = async (directory) => {
10
+ let entries;
11
+ try {
12
+ entries = await readdir(directory, {
13
+ withFileTypes: true,
14
+ });
15
+ }
16
+ catch (error) {
17
+ if (isNodeError(error) && error.code === 'ENOENT') {
18
+ return [];
19
+ }
20
+ throw error;
21
+ }
22
+ const paths = await Promise.all(entries.map(async (entry) => {
23
+ const entryPath = join(directory, entry.name);
24
+ if (entry.isDirectory()) {
25
+ return findReadmePaths(entryPath);
26
+ }
27
+ return entry.name === 'README.md' ? [entryPath] : [];
28
+ }));
29
+ return paths.flat();
30
+ };
31
+ const getSlug = (sectionDirectory, readmePath) => {
32
+ return dirname(relative(sectionDirectory, readmePath))
33
+ .split(sep)
34
+ .filter((segment) => segment && segment !== '.')
35
+ .join('/');
36
+ };
37
+ const writeDocument = async (outputPath, document) => {
38
+ await mkdir(dirname(outputPath), {
39
+ recursive: true,
40
+ });
41
+ await writeFile(outputPath, document);
42
+ };
43
+ const contentIndexPageSize = 10;
44
+ const getContentIndexOutputPath = (outputDirectory, section, page) => {
45
+ return page <= 1
46
+ ? join(outputDirectory, section, 'index.html')
47
+ : join(outputDirectory, section, String(page), 'index.html');
48
+ };
49
+ export const buildContentEntries = async (section, projectRoot) => {
50
+ const sectionDirectory = join(projectRoot, 'site', section);
51
+ const readmePaths = await findReadmePaths(sectionDirectory);
52
+ const entries = (await Promise.all(readmePaths.map(async (readmePath) => {
53
+ const slug = getSlug(sectionDirectory, readmePath);
54
+ const page = parsePage(await readFile(readmePath, 'utf8'));
55
+ if (!slug || !page.published) {
56
+ return undefined;
57
+ }
58
+ const href = `/${section}/${slug}/`;
59
+ return {
60
+ ...page,
61
+ href,
62
+ slug,
63
+ };
64
+ })))
65
+ .filter((entry) => Boolean(entry))
66
+ .sort((left, right) => right.date.localeCompare(left.date) || left.title.localeCompare(right.title));
67
+ return entries;
68
+ };
69
+ export const writeContentEntryDocuments = async (section, entries, outputDirectory, { googleAnalyticsMeasurementId, relatedDocuments = {}, siteUrl, stylesheetContent, stylesheetHref, } = {}) => {
70
+ await Promise.all(entries.map((entry) => Promise.all([
71
+ writeDocument(join(outputDirectory, section, entry.slug, 'index.html'), renderPage(entry, {
72
+ canonicalPath: entry.href,
73
+ googleAnalyticsMeasurementId,
74
+ markdownAlternateHref: getMarkdownHref(entry.href),
75
+ related: relatedDocuments[`${section}:${entry.slug}`] ?? [],
76
+ showTags: true,
77
+ siteUrl,
78
+ stylesheetContent,
79
+ stylesheetHref,
80
+ })),
81
+ writeMarkdownPage(outputDirectory, entry, siteUrl),
82
+ ])));
83
+ };
84
+ export const buildContentSection = async (section, projectRoot, outputDirectory, stylesheetHref, siteUrl, stylesheetContent, googleAnalyticsMeasurementId) => {
85
+ const entries = await buildContentEntries(section, projectRoot);
86
+ const pages = Math.max(1, Math.ceil(entries.length / contentIndexPageSize));
87
+ const indexPaths = Array.from({ length: pages }, (_value, index) => getContentIndexHref(section, index + 1));
88
+ await Promise.all(indexPaths.map((_path, index) => {
89
+ const page = index + 1;
90
+ const pageEntries = entries.slice(index * contentIndexPageSize, page * contentIndexPageSize);
91
+ return writeDocument(getContentIndexOutputPath(outputDirectory, section, page), renderContentIndex(section, pageEntries, {
92
+ googleAnalyticsMeasurementId,
93
+ page,
94
+ pages,
95
+ siteUrl,
96
+ stylesheetHref,
97
+ stylesheetContent,
98
+ }));
99
+ }));
100
+ return {
101
+ entries,
102
+ indexPaths,
103
+ };
104
+ };
package/index.d.ts CHANGED
@@ -1,8 +1,12 @@
1
- export * from './cli.js';
2
- export * from './content.js';
3
- export * from './markdown.js';
4
- export * from './parse-page.js';
5
- export * from './robots.js';
6
- export * from './sitemap.js';
7
- export * from './ssg.js';
8
- export type * from './types.js';
1
+ export { contentMiniSearchOptions, contentSearchOptions, getHomePageFeaturedContent, getMiniSearchIndexJson, getPlainTextFromMarkdown, getRelatedDocumentsMap, getSearchDocuments, getSiteSearchDocuments, writeContentData, } from './content-data.js';
2
+ export { buildStaticSite } from './build-static-site.js';
3
+ export { getWebPageJsonLd, renderJsonLdScript } from './json-ld.js';
4
+ export { renderLlmTxt, writeLlmTxt } from './llm.js';
5
+ export { getMarkdownHref, getMarkdownOutputPath, renderMarkdownPage, writeMarkdownPage } from './markdown-page.js';
6
+ export { getContentIndexHref, renderContentIndex, renderNotFoundPage, renderPage, renderSearchPage, } from './render-page.js';
7
+ export { renderRobotsTxt, writeRobotsTxt } from './robots.js';
8
+ export { renderSitemap, writeSitemap } from './sitemap.js';
9
+ export type { ContentDataSection, HomePageFeaturedContentItem, RelatedDocument, RelatedDocumentsMap, SearchDocument, } from './content-data.js';
10
+ export type { JsonLdValue, WebPageJsonLdOptions } from './json-ld.js';
11
+ export type { LlmTxtOptions, LlmTxtPage } from './llm.js';
12
+ export type { BuildStaticSiteOptions, PageData, SitemapUrl } from './types.js';
package/index.js CHANGED
@@ -1,7 +1,8 @@
1
- export * from './cli.js';
2
- export * from './content.js';
3
- export * from './markdown.js';
4
- export * from './parse-page.js';
5
- export * from './robots.js';
6
- export * from './sitemap.js';
7
- export * from './ssg.js';
1
+ export { contentMiniSearchOptions, contentSearchOptions, getHomePageFeaturedContent, getMiniSearchIndexJson, getPlainTextFromMarkdown, getRelatedDocumentsMap, getSearchDocuments, getSiteSearchDocuments, writeContentData, } from './content-data.js';
2
+ export { buildStaticSite } from './build-static-site.js';
3
+ export { getWebPageJsonLd, renderJsonLdScript } from './json-ld.js';
4
+ export { renderLlmTxt, writeLlmTxt } from './llm.js';
5
+ export { getMarkdownHref, getMarkdownOutputPath, renderMarkdownPage, writeMarkdownPage } from './markdown-page.js';
6
+ export { getContentIndexHref, renderContentIndex, renderNotFoundPage, renderPage, renderSearchPage, } from './render-page.js';
7
+ export { renderRobotsTxt, writeRobotsTxt } from './robots.js';
8
+ export { renderSitemap, writeSitemap } from './sitemap.js';
package/json-ld.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export type JsonLdValue = boolean | number | string | null | readonly JsonLdValue[] | {
2
+ readonly [key: string]: JsonLdValue | undefined;
3
+ };
4
+ export type WebPageJsonLdOptions = {
5
+ readonly canonicalPath?: string;
6
+ readonly description: string;
7
+ readonly siteUrl?: string;
8
+ readonly title: string;
9
+ };
10
+ export declare const renderJsonLdScript: (value: JsonLdValue) => string;
11
+ export declare const getWebPageJsonLd: ({ canonicalPath, description, siteUrl, title }: WebPageJsonLdOptions) => JsonLdValue;
package/json-ld.js ADDED
@@ -0,0 +1,36 @@
1
+ import { getAbsoluteUrl } from './sitemap.js';
2
+ const escapedJsonScriptCharacters = {
3
+ '&': String.raw `\u0026`,
4
+ '<': String.raw `\u003c`,
5
+ '>': String.raw `\u003e`,
6
+ [String.fromCodePoint(0x2028)]: String.raw `\u2028`,
7
+ [String.fromCodePoint(0x2029)]: String.raw `\u2029`,
8
+ };
9
+ const escapeJsonScriptContent = (value) => {
10
+ let escaped = '';
11
+ for (const character of value) {
12
+ escaped += escapedJsonScriptCharacters[character] ?? character;
13
+ }
14
+ return escaped;
15
+ };
16
+ export const renderJsonLdScript = (value) => {
17
+ return `<script type="application/ld+json">${escapeJsonScriptContent(JSON.stringify(value))}</script>`;
18
+ };
19
+ export const getWebPageJsonLd = ({ canonicalPath, description, siteUrl, title }) => {
20
+ return {
21
+ '@context': 'https://schema.org',
22
+ '@type': 'WebPage',
23
+ description,
24
+ isPartOf: {
25
+ '@type': 'WebSite',
26
+ name: 'Vyriy.dev',
27
+ url: getAbsoluteUrl('/', siteUrl),
28
+ },
29
+ name: title,
30
+ publisher: {
31
+ '@type': 'Organization',
32
+ name: 'Vyriy',
33
+ },
34
+ url: canonicalPath ? getAbsoluteUrl(canonicalPath, siteUrl) : undefined,
35
+ };
36
+ };
package/llm.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { ContentDataSection } from './content-data.js';
2
+ export type LlmTxtPage = {
3
+ readonly description: string;
4
+ readonly path: string;
5
+ readonly title: string;
6
+ };
7
+ export type LlmTxtOptions = {
8
+ readonly pages: readonly LlmTxtPage[];
9
+ readonly sections: readonly ContentDataSection[];
10
+ };
11
+ export declare const renderLlmTxt: (options: LlmTxtOptions, siteUrl?: string) => string;
12
+ export declare const writeLlmTxt: (outputDirectory: string, options: LlmTxtOptions, siteUrl?: string) => Promise<void>;
package/llm.js ADDED
@@ -0,0 +1,59 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { getAbsoluteUrl } from './sitemap.js';
4
+ const siteTitle = 'Vyriy.dev';
5
+ const siteDescription = 'A small static React website about the Vyriy component and package library, calm engineering systems, and reusable project contracts.';
6
+ const sectionTitles = {
7
+ blog: 'Blog',
8
+ docs: 'Documentation',
9
+ examples: 'Examples',
10
+ };
11
+ const markdownLinkTextPattern = /[[\]\\]/gu;
12
+ const whitespacePattern = /\s+/gu;
13
+ const escapeMarkdownLinkText = (value) => {
14
+ return value.replaceAll(markdownLinkTextPattern, String.raw `\$&`);
15
+ };
16
+ const normalizeDescription = (value) => {
17
+ return value.replaceAll(whitespacePattern, ' ').trim();
18
+ };
19
+ const renderLlmTxtLine = (page, siteUrl) => {
20
+ const description = normalizeDescription(page.description);
21
+ const descriptionSuffix = description ? ` - ${description}` : '';
22
+ return `- [${escapeMarkdownLinkText(page.title)}](${getAbsoluteUrl(page.path, siteUrl)})${descriptionSuffix}`;
23
+ };
24
+ export const renderLlmTxt = (options, siteUrl) => {
25
+ const mainPages = options.pages.map((page) => renderLlmTxtLine(page, siteUrl));
26
+ const sectionGroups = options.sections
27
+ .map((section) => {
28
+ const entries = section.entries.map((entry) => renderLlmTxtLine({
29
+ description: entry.description,
30
+ path: entry.href,
31
+ title: entry.title,
32
+ }, siteUrl));
33
+ return [
34
+ `## ${sectionTitles[section.section]}`,
35
+ '',
36
+ ...entries,
37
+ ].join('\n');
38
+ })
39
+ .join('\n\n');
40
+ return [
41
+ `# ${siteTitle}`,
42
+ '',
43
+ siteDescription,
44
+ '',
45
+ '## Main Pages',
46
+ '',
47
+ ...mainPages,
48
+ '',
49
+ sectionGroups,
50
+ '',
51
+ ].join('\n');
52
+ };
53
+ export const writeLlmTxt = async (outputDirectory, options, siteUrl) => {
54
+ const outputPath = join(outputDirectory, 'llms.txt');
55
+ await mkdir(dirname(outputPath), {
56
+ recursive: true,
57
+ });
58
+ await writeFile(outputPath, renderLlmTxt(options, siteUrl));
59
+ };
@@ -0,0 +1,5 @@
1
+ import type { ContentEntry } from './types.js';
2
+ export declare const getMarkdownOutputPath: (outputDirectory: string, path: string) => string;
3
+ export declare const getMarkdownHref: (path: string) => string;
4
+ export declare const renderMarkdownPage: (entry: ContentEntry, siteUrl?: string) => string;
5
+ export declare const writeMarkdownPage: (outputDirectory: string, entry: ContentEntry, siteUrl?: string) => Promise<void>;
@@ -0,0 +1,55 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { getAbsoluteUrl } from './sitemap.js';
4
+ const whitespacePattern = /\s+/gu;
5
+ const normalizeDescription = (value) => {
6
+ return value.replaceAll(whitespacePattern, ' ').trim();
7
+ };
8
+ const getMarkdownPathSegments = (path) => {
9
+ const segments = path.split('/').filter(Boolean);
10
+ if (!segments.length || segments.some((segment) => segment === '.' || segment === '..')) {
11
+ throw new Error(`Invalid Markdown output path: ${path}`);
12
+ }
13
+ return segments;
14
+ };
15
+ export const getMarkdownOutputPath = (outputDirectory, path) => {
16
+ const segments = getMarkdownPathSegments(path);
17
+ const fileName = `${segments.at(-1)}.md`;
18
+ return join(outputDirectory, ...segments.slice(0, -1), fileName);
19
+ };
20
+ export const getMarkdownHref = (path) => {
21
+ const segments = getMarkdownPathSegments(path);
22
+ const fileName = `${segments.at(-1)}.md`;
23
+ return `/${[
24
+ ...segments.slice(0, -1),
25
+ fileName,
26
+ ].join('/')}`;
27
+ };
28
+ export const renderMarkdownPage = (entry, siteUrl) => {
29
+ const description = normalizeDescription(entry.description);
30
+ const metadata = [
31
+ entry.date ? `Published: ${entry.date}` : '',
32
+ entry.updatedAt ? `Updated: ${entry.updatedAt}` : '',
33
+ entry.tags.length ? `Tags: ${entry.tags.join(', ')}` : '',
34
+ `Source: ${getAbsoluteUrl(entry.href, siteUrl)}`,
35
+ ].filter(Boolean);
36
+ return [
37
+ `# ${entry.title}`,
38
+ '',
39
+ description,
40
+ '',
41
+ ...metadata,
42
+ '',
43
+ '---',
44
+ '',
45
+ entry.content.trim(),
46
+ '',
47
+ ].join('\n');
48
+ };
49
+ export const writeMarkdownPage = async (outputDirectory, entry, siteUrl) => {
50
+ const outputPath = getMarkdownOutputPath(outputDirectory, entry.href);
51
+ await mkdir(dirname(outputPath), {
52
+ recursive: true,
53
+ });
54
+ await writeFile(outputPath, renderMarkdownPage(entry, siteUrl));
55
+ };
@@ -0,0 +1 @@
1
+ export declare const minifyHtml: (document: string) => string;
package/minify-html.js ADDED
@@ -0,0 +1,51 @@
1
+ const whitespaceInsensitiveTags = new Set([
2
+ 'article',
3
+ 'aside',
4
+ 'body',
5
+ 'br',
6
+ 'dd',
7
+ 'div',
8
+ 'dl',
9
+ 'dt',
10
+ 'figcaption',
11
+ 'figure',
12
+ 'footer',
13
+ 'h1',
14
+ 'h2',
15
+ 'h3',
16
+ 'h4',
17
+ 'h5',
18
+ 'h6',
19
+ 'head',
20
+ 'header',
21
+ 'hr',
22
+ 'html',
23
+ 'li',
24
+ 'link',
25
+ 'main',
26
+ 'meta',
27
+ 'nav',
28
+ 'ol',
29
+ 'p',
30
+ 'section',
31
+ 'style',
32
+ 'title',
33
+ 'ul',
34
+ ]);
35
+ const tagBoundaryPattern = /(<\/?([a-z][\w:-]*)\b[^>]*>)\s+(<\/?([a-z][\w:-]*)\b[^>]*>)/gi;
36
+ const doctypeBoundaryPattern = /(<!doctype html>)\s+(<html\b[^>]*>)/i;
37
+ const isWhitespaceInsensitiveBoundary = (leftTagName, rightTagName) => {
38
+ return (whitespaceInsensitiveTags.has(leftTagName.toLowerCase()) ||
39
+ whitespaceInsensitiveTags.has(rightTagName.toLowerCase()));
40
+ };
41
+ export const minifyHtml = (document) => {
42
+ let minified = document.trim().replace(doctypeBoundaryPattern, '$1$2');
43
+ let previousDocument = '';
44
+ while (minified !== previousDocument) {
45
+ previousDocument = minified;
46
+ minified = minified.replaceAll(tagBoundaryPattern, (match, leftTag, leftTagName, rightTag, rightTagName) => {
47
+ return isWhitespaceInsensitiveBoundary(leftTagName, rightTagName) ? `${leftTag}${rightTag}` : match;
48
+ });
49
+ }
50
+ return minified;
51
+ };
package/package.json CHANGED
@@ -1,16 +1,13 @@
1
1
  {
2
2
  "name": "@vyriy/ssg",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Static Markdown site generator for Vyriy projects.",
5
5
  "homepage": "https://vyriy.dev/docs/ssg/",
6
6
  "type": "module",
7
- "bin": {
8
- "ssg": "./bin/index.js",
9
- "vyriy-ssg": "./bin/index.js"
10
- },
11
7
  "dependencies": {
12
8
  "@types/react": "^19.2.17",
13
- "@vyriy/render": "0.9.1",
9
+ "@vyriy/html": "0.9.2",
10
+ "@vyriy/render": "0.9.2",
14
11
  "minisearch": "^7.2.0",
15
12
  "react": "^19.2.7",
16
13
  "react-markdown": "^10.1.0",
@@ -32,35 +29,45 @@
32
29
  "import": "./index.js",
33
30
  "default": "./index.js"
34
31
  },
35
- "./cli": {
36
- "types": "./cli.d.ts",
37
- "import": "./cli.js",
38
- "default": "./cli.js"
39
- },
40
- "./cli.js": {
41
- "types": "./cli.d.ts",
42
- "import": "./cli.js",
43
- "default": "./cli.js"
44
- },
45
- "./content": {
46
- "types": "./content.d.ts",
47
- "import": "./content.js",
48
- "default": "./content.js"
49
- },
50
- "./content.js": {
51
- "types": "./content.d.ts",
52
- "import": "./content.js",
53
- "default": "./content.js"
54
- },
55
- "./html": {
56
- "types": "./html.d.ts",
57
- "import": "./html.js",
58
- "default": "./html.js"
59
- },
60
- "./html.js": {
61
- "types": "./html.d.ts",
62
- "import": "./html.js",
63
- "default": "./html.js"
32
+ "./build-static-site": {
33
+ "types": "./build-static-site.d.ts",
34
+ "import": "./build-static-site.js",
35
+ "default": "./build-static-site.js"
36
+ },
37
+ "./build-static-site.js": {
38
+ "types": "./build-static-site.d.ts",
39
+ "import": "./build-static-site.js",
40
+ "default": "./build-static-site.js"
41
+ },
42
+ "./components": {
43
+ "types": "./components.d.ts",
44
+ "import": "./components.js",
45
+ "default": "./components.js"
46
+ },
47
+ "./components.js": {
48
+ "types": "./components.d.ts",
49
+ "import": "./components.js",
50
+ "default": "./components.js"
51
+ },
52
+ "./content-data": {
53
+ "types": "./content-data.d.ts",
54
+ "import": "./content-data.js",
55
+ "default": "./content-data.js"
56
+ },
57
+ "./content-data.js": {
58
+ "types": "./content-data.d.ts",
59
+ "import": "./content-data.js",
60
+ "default": "./content-data.js"
61
+ },
62
+ "./content-section": {
63
+ "types": "./content-section.d.ts",
64
+ "import": "./content-section.js",
65
+ "default": "./content-section.js"
66
+ },
67
+ "./content-section.js": {
68
+ "types": "./content-section.d.ts",
69
+ "import": "./content-section.js",
70
+ "default": "./content-section.js"
64
71
  },
65
72
  "./index": {
66
73
  "types": "./index.d.ts",
@@ -72,15 +79,55 @@
72
79
  "import": "./index.js",
73
80
  "default": "./index.js"
74
81
  },
75
- "./markdown": {
76
- "types": "./markdown.d.ts",
77
- "import": "./markdown.js",
78
- "default": "./markdown.js"
79
- },
80
- "./markdown.js": {
81
- "types": "./markdown.d.ts",
82
- "import": "./markdown.js",
83
- "default": "./markdown.js"
82
+ "./json-ld": {
83
+ "types": "./json-ld.d.ts",
84
+ "import": "./json-ld.js",
85
+ "default": "./json-ld.js"
86
+ },
87
+ "./json-ld.js": {
88
+ "types": "./json-ld.d.ts",
89
+ "import": "./json-ld.js",
90
+ "default": "./json-ld.js"
91
+ },
92
+ "./llm": {
93
+ "types": "./llm.d.ts",
94
+ "import": "./llm.js",
95
+ "default": "./llm.js"
96
+ },
97
+ "./llm.js": {
98
+ "types": "./llm.d.ts",
99
+ "import": "./llm.js",
100
+ "default": "./llm.js"
101
+ },
102
+ "./markdown-page": {
103
+ "types": "./markdown-page.d.ts",
104
+ "import": "./markdown-page.js",
105
+ "default": "./markdown-page.js"
106
+ },
107
+ "./markdown-page.js": {
108
+ "types": "./markdown-page.d.ts",
109
+ "import": "./markdown-page.js",
110
+ "default": "./markdown-page.js"
111
+ },
112
+ "./markdown-plain-text": {
113
+ "types": "./markdown-plain-text.d.ts",
114
+ "import": "./markdown-plain-text.js",
115
+ "default": "./markdown-plain-text.js"
116
+ },
117
+ "./markdown-plain-text.js": {
118
+ "types": "./markdown-plain-text.d.ts",
119
+ "import": "./markdown-plain-text.js",
120
+ "default": "./markdown-plain-text.js"
121
+ },
122
+ "./minify-html": {
123
+ "types": "./minify-html.d.ts",
124
+ "import": "./minify-html.js",
125
+ "default": "./minify-html.js"
126
+ },
127
+ "./minify-html.js": {
128
+ "types": "./minify-html.d.ts",
129
+ "import": "./minify-html.js",
130
+ "default": "./minify-html.js"
84
131
  },
85
132
  "./parse-page": {
86
133
  "types": "./parse-page.d.ts",
@@ -92,15 +139,25 @@
92
139
  "import": "./parse-page.js",
93
140
  "default": "./parse-page.js"
94
141
  },
95
- "./plain": {
96
- "types": "./plain.d.ts",
97
- "import": "./plain.js",
98
- "default": "./plain.js"
142
+ "./paths": {
143
+ "types": "./paths.d.ts",
144
+ "import": "./paths.js",
145
+ "default": "./paths.js"
146
+ },
147
+ "./paths.js": {
148
+ "types": "./paths.d.ts",
149
+ "import": "./paths.js",
150
+ "default": "./paths.js"
151
+ },
152
+ "./render-page": {
153
+ "types": "./render-page.d.ts",
154
+ "import": "./render-page.js",
155
+ "default": "./render-page.js"
99
156
  },
100
- "./plain.js": {
101
- "types": "./plain.d.ts",
102
- "import": "./plain.js",
103
- "default": "./plain.js"
157
+ "./render-page.js": {
158
+ "types": "./render-page.d.ts",
159
+ "import": "./render-page.js",
160
+ "default": "./render-page.js"
104
161
  },
105
162
  "./robots": {
106
163
  "types": "./robots.d.ts",
@@ -121,16 +178,6 @@
121
178
  "types": "./sitemap.d.ts",
122
179
  "import": "./sitemap.js",
123
180
  "default": "./sitemap.js"
124
- },
125
- "./ssg": {
126
- "types": "./ssg.d.ts",
127
- "import": "./ssg.js",
128
- "default": "./ssg.js"
129
- },
130
- "./ssg.js": {
131
- "types": "./ssg.d.ts",
132
- "import": "./ssg.js",
133
- "default": "./ssg.js"
134
181
  }
135
182
  }
136
183
  }
package/parse-page.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import type { PageData } from './types.js';
2
- export declare const parsePage: (markdown: string, defaultTitle?: string) => PageData;
2
+ export declare const parsePage: (markdown: string) => PageData;
package/parse-page.js CHANGED
@@ -1,6 +1,4 @@
1
- import { replaceInlineCode, replaceMarkdownLinks } from './plain.js';
2
- const markdownSyntaxPattern = /[#>*_~|[\](){}\\-]+/gu;
3
- const whitespacePattern = /\s+/gu;
1
+ import { replaceInlineCode, replaceMarkdownLinks } from './markdown-plain-text.js';
4
2
  const parseMetadata = (metadata) => {
5
3
  const entries = {};
6
4
  let listKey = '';
@@ -40,13 +38,15 @@ const getNumber = (value) => {
40
38
  const number = Number(value);
41
39
  return Number.isFinite(number) ? number : undefined;
42
40
  };
41
+ const markdownSyntaxPattern = /[#>*_~|[\](){}\\-]+/gu;
42
+ const whitespacePattern = /\s+/gu;
43
43
  const getPlainText = (value) => {
44
44
  return replaceInlineCode(replaceMarkdownLinks(value))
45
45
  .replaceAll(markdownSyntaxPattern, ' ')
46
46
  .replaceAll(whitespacePattern, ' ')
47
47
  .trim();
48
48
  };
49
- const getFallbackTitle = (markdown, defaultTitle) => {
49
+ const getFallbackTitle = (markdown) => {
50
50
  for (const line of markdown.split('\n')) {
51
51
  if (!line.startsWith('#')) {
52
52
  continue;
@@ -61,7 +61,7 @@ const getFallbackTitle = (markdown, defaultTitle) => {
61
61
  return title;
62
62
  }
63
63
  }
64
- return defaultTitle;
64
+ return 'Vyriy';
65
65
  };
66
66
  const getFallbackDescription = (markdown) => {
67
67
  let insideCodeBlock = false;
@@ -88,7 +88,7 @@ const getFallbackDescription = (markdown) => {
88
88
  }
89
89
  return '';
90
90
  };
91
- export const parsePage = (markdown, defaultTitle = 'Vyriy') => {
91
+ export const parsePage = (markdown) => {
92
92
  const frontmatter = /^---\n(?<metadata>[\s\S]*?)\n---\n(?<content>[\s\S]*)$/u.exec(markdown);
93
93
  if (!frontmatter?.groups) {
94
94
  return {
@@ -99,7 +99,7 @@ export const parsePage = (markdown, defaultTitle = 'Vyriy') => {
99
99
  homePage: false,
100
100
  published: true,
101
101
  tags: [],
102
- title: getFallbackTitle(markdown, defaultTitle),
102
+ title: getFallbackTitle(markdown),
103
103
  };
104
104
  }
105
105
  const metadata = parseMetadata(frontmatter.groups.metadata);
@@ -107,8 +107,8 @@ export const parsePage = (markdown, defaultTitle = 'Vyriy') => {
107
107
  const featured = metadata.featured;
108
108
  const homePage = metadata.homePage;
109
109
  const homePageOrder = getNumber(metadata.homePageOrder);
110
- const published = metadata.published;
111
110
  const tags = metadata.tags;
111
+ const published = metadata.published;
112
112
  const updatedAt = getString(metadata.updatedAt);
113
113
  return {
114
114
  content,
@@ -119,7 +119,7 @@ export const parsePage = (markdown, defaultTitle = 'Vyriy') => {
119
119
  ...(homePageOrder === undefined ? {} : { homePageOrder }),
120
120
  published: typeof published === 'boolean' ? published : true,
121
121
  tags: Array.isArray(tags) ? tags : [],
122
- title: getString(metadata.title) || getFallbackTitle(content, defaultTitle),
122
+ title: getString(metadata.title) || getFallbackTitle(content),
123
123
  ...(updatedAt ? { updatedAt } : {}),
124
124
  };
125
125
  };