vowel 0.1.46 → 0.2.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.
- package/README.md +82 -20
- package/bin.js +2 -78
- package/docs-source/$features/cards.md +7 -0
- package/docs-source/$features/editing.md +7 -0
- package/docs-source/$features/emoji.md +7 -0
- package/docs-source/$features/frontmatter.md +7 -0
- package/docs-source/$features/lists.md +7 -0
- package/docs-source/$features/navigation.md +7 -0
- package/docs-source/$features/rich-previews.md +7 -0
- package/docs-source/$features/robots.md +7 -0
- package/docs-source/$features/rss.md +7 -0
- package/docs-source/$features/sitemap.md +7 -0
- package/docs-source/$features/speed.md +7 -0
- package/docs-source/$features/static.md +7 -0
- package/docs-source/$features/taxonomies.md +7 -0
- package/docs-source/.cache.json +9 -0
- package/docs-source/.obsidian/app.json +3 -0
- package/docs-source/.obsidian/appearance.json +3 -0
- package/docs-source/.obsidian/core-plugins-migration.json +30 -0
- package/docs-source/.obsidian/core-plugins.json +20 -0
- package/docs-source/.obsidian/workspace.json +168 -0
- package/docs-source/.stackblitzrc +3 -0
- package/docs-source/.vercel/README.txt +11 -0
- package/docs-source/.vercel/project.json +1 -0
- package/docs-source/about.md +3 -0
- package/docs-source/assets/styles.css +51 -0
- package/docs-source/blog/home.md +5 -0
- package/docs-source/blog/url-ui.md +21 -0
- package/docs-source/docs/.votive.db +0 -0
- package/docs-source/docs/deploy.md +67 -0
- package/docs-source/docs/file-structure.md +31 -0
- package/docs-source/docs/folder-settings.md +23 -0
- package/docs-source/docs/home.md +55 -0
- package/docs-source/docs/images.md +10 -0
- package/docs-source/docs/items.md +13 -0
- package/docs-source/docs/pages.md +141 -0
- package/docs-source/docs/settings.md +4 -0
- package/docs-source/docs/styling.md +34 -0
- package/docs-source/docs/taxonomies.md +37 -0
- package/docs-source/home.md +42 -0
- package/docs-source/roadmap.md +98 -0
- package/docs-source/settings.md +12 -0
- package/extractDate.js +83 -0
- package/getMetadata.js +41 -0
- package/index.js +669 -0
- package/jsconfig.json +9 -17
- package/package.json +61 -63
- package/regex.js +36 -0
- package/{src/lib/components → stylesheets}/DefaultStyles.css +5 -5
- package/utils.js +10 -0
- package/.cache.json +0 -1
- package/.prettierrc +0 -8
- package/.vscode/settings.json +0 -3
- package/CHANGELOG.md +0 -79
- package/server.js +0 -87
- package/src/app.d.ts +0 -12
- package/src/app.html +0 -13
- package/src/lib/components/Breadcrumbs.svelte +0 -19
- package/src/lib/components/ConditionalWrapper.svelte +0 -10
- package/src/lib/components/DefaultStyles.svelte +0 -11
- package/src/lib/components/FrontMatterTaxonomy.svelte +0 -48
- package/src/lib/components/Frontmatter.svelte +0 -56
- package/src/lib/components/FrontmatterProperty.svelte +0 -78
- package/src/lib/components/Markdown/Image.svelte +0 -50
- package/src/lib/components/Markdown/Link.svelte +0 -19
- package/src/lib/components/Markdown/LinkPreview.svelte +0 -45
- package/src/lib/components/Markdown/Text.svelte +0 -6
- package/src/lib/components/Markdown/index.svelte +0 -147
- package/src/lib/components/Markdown/validators.js +0 -29
- package/src/lib/components/Nav.svelte +0 -40
- package/src/lib/components/NoStyles.svelte +0 -5
- package/src/lib/components/Page.svelte +0 -90
- package/src/lib/components/ResetStyles.svelte +0 -7
- package/src/lib/components/Sitemap.svelte +0 -38
- package/src/lib/components/TypographyStyles.svelte +0 -10
- package/src/lib/components/index.js +0 -12
- package/src/lib/index.js +0 -1
- package/src/lib/utilities/buildURL.js +0 -18
- package/src/lib/utilities/checkFileExists.js +0 -16
- package/src/lib/utilities/createFolderClass.js +0 -4
- package/src/lib/utilities/createPageClass.js +0 -6
- package/src/lib/utilities/getFileLabel.js +0 -35
- package/src/lib/utilities/getFolder.js +0 -16
- package/src/lib/utilities/getFolderLabel.js +0 -12
- package/src/lib/utilities/getMetadata.js +0 -46
- package/src/lib/utilities/getPage.js +0 -25
- package/src/lib/utilities/getPagesByFolder.js +0 -95
- package/src/lib/utilities/index.js +0 -22
- package/src/lib/utilities/isActiveLink.js +0 -12
- package/src/lib/utilities/isObject.js +0 -8
- package/src/lib/utilities/loadCache.js +0 -28
- package/src/lib/utilities/mutateMarkdownAST.js +0 -68
- package/src/lib/utilities/mutateMarkdownFrontmatter.js +0 -113
- package/src/lib/utilities/parseDate.js +0 -43
- package/src/lib/utilities/processMarkdownFiles.js +0 -243
- package/src/lib/utilities/readMarkdownFile.js +0 -188
- package/src/lib/utilities/regexPatterns.js +0 -12
- package/src/lib/utilities/resolveHomeDirPath.js +0 -5
- package/src/lib/utilities/sendWebmention.js +0 -34
- package/src/lib/utilities/writeCache.js +0 -14
- package/src/routes/$vowel/published.json/+server.js +0 -54
- package/src/routes/+error.svelte +0 -110
- package/src/routes/[...path]/+layout.server.js +0 -78
- package/src/routes/[...path]/+page.server.js +0 -42
- package/src/routes/[...path]/+page.svelte +0 -186
- package/src/routes/feed.xml/+server.js +0 -120
- package/src/routes/robots.txt/+server.js +0 -54
- package/src/routes/sitemap.xml/+server.js +0 -68
- package/static/favicon.png +0 -0
- package/static/styles.css +0 -0
- package/svelte.config.js +0 -30
- package/vercel.json +0 -5
- package/vite.config.js +0 -84
- /package/{src/lib/components → stylesheets}/ResetStyles.css +0 -0
- /package/{src/lib/components → stylesheets}/TypographyStyles.css +0 -0
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
// @ts-ignore
|
|
4
|
-
import { buildURL, checkFileExists, readMarkdownFile } from '.';
|
|
5
|
-
|
|
6
|
-
function DefaultFile(url) {
|
|
7
|
-
return {
|
|
8
|
-
ast: [
|
|
9
|
-
{
|
|
10
|
-
type: 'paragraph',
|
|
11
|
-
children: [
|
|
12
|
-
{
|
|
13
|
-
type: 'h1',
|
|
14
|
-
value: 'hey there',
|
|
15
|
-
// value: url + '?count=10',
|
|
16
|
-
position: {
|
|
17
|
-
start: {
|
|
18
|
-
line: 5,
|
|
19
|
-
column: 1,
|
|
20
|
-
offset: 25
|
|
21
|
-
},
|
|
22
|
-
end: {
|
|
23
|
-
line: 5,
|
|
24
|
-
column: 8,
|
|
25
|
-
offset: 32
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
],
|
|
30
|
-
position: {
|
|
31
|
-
start: {
|
|
32
|
-
line: 5,
|
|
33
|
-
column: 1,
|
|
34
|
-
offset: 25
|
|
35
|
-
},
|
|
36
|
-
end: {
|
|
37
|
-
line: 5,
|
|
38
|
-
column: 8,
|
|
39
|
-
offset: 32
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
url
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function DefaultDirectory(path) {
|
|
49
|
-
return {
|
|
50
|
-
$: DefaultFile(path),
|
|
51
|
-
_: DefaultFile(path)
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** @typedef {Object} AdditionalFileProperties
|
|
56
|
-
* @property {string} [url] - URL to the page for the file.
|
|
57
|
-
* @property {number} [date] - Document date.
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
/** @typedef {import("./readMarkdownFile").ParsedMarkdown & AdditionalFileProperties} MarkdownFile */
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @typedef {Object} Subdirectory
|
|
64
|
-
* @description A subdirectory of markdown files
|
|
65
|
-
* @property {MarkdownFile} $ A home file
|
|
66
|
-
* @property {MarkdownFile} _ A settingsfile
|
|
67
|
-
* @property {Object.<string, Object>} [additionalProps] Files or child directories.
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @typedef {Object.<string, MarkdownFile | Subdirectory>} Directory
|
|
72
|
-
* @description A directory of markdown files
|
|
73
|
-
* @property {MarkdownFile} $ A home file.
|
|
74
|
-
* @property {MarkdownFile} _ A settings file.
|
|
75
|
-
* @property {Object.<string, MarkdownFile | Subdirectory>} [additionalProps] Files or child directories.
|
|
76
|
-
*/
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Recursively read a directory of markdown files and return an object of the files.
|
|
80
|
-
* @param {string} directoryPath - The directory to read.
|
|
81
|
-
* @param {string} parents - A string representing the parent directories.
|
|
82
|
-
* @param {import('./loadCache').Cache} cache
|
|
83
|
-
* @returns {Promise<Directory>}
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Recursively read a directory of markdown files and return an object of the files.
|
|
88
|
-
* @param {string} folderPath - The directory to read.
|
|
89
|
-
* @param {string} parents - A string representing the parent directories.
|
|
90
|
-
* @param {import('./loadCache').Cache} cache
|
|
91
|
-
* @returns {Promise<Directory>}
|
|
92
|
-
*/
|
|
93
|
-
async function readFolder(folderPath, parents, cache, hidden, publishedData, domain) {
|
|
94
|
-
function filterFiles(file) {
|
|
95
|
-
if (file.name.startsWith('.')) return false;
|
|
96
|
-
if (file.name.startsWith('README')) return false;
|
|
97
|
-
if (file.isFile() && !file.name.endsWith('.md')) return false;
|
|
98
|
-
if (file.name === 'node_modules') return false;
|
|
99
|
-
if (file.name === 'assets') return false;
|
|
100
|
-
if (file.name === 'templates') return false;
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let files = (await fs.readdir(folderPath, { withFileTypes: true })).filter(filterFiles);
|
|
105
|
-
|
|
106
|
-
console.log(`filesfound:${files.length}`);
|
|
107
|
-
|
|
108
|
-
const promises = files.map(
|
|
109
|
-
async (file) => await readFile(file, parents, cache, folderPath, hidden, publishedData, domain)
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const folder = (await Promise.all(promises)).reduce((acc, obj) => ({ ...acc, ...obj }), {});
|
|
113
|
-
|
|
114
|
-
if (typeof folder === 'object' && !folder?.$) {
|
|
115
|
-
folder.$ = DefaultFile(parents || '/');
|
|
116
|
-
folder.$.imputedProperties = {
|
|
117
|
-
fileName: parents.split('/').at(-1) || 'Home'
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (typeof folder === 'object' && !folder?._) {
|
|
122
|
-
folder._ = DefaultFile(parents);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return folder;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function buildHREF(url, domain) {
|
|
129
|
-
try {
|
|
130
|
-
const urlObj = new URL(domain)
|
|
131
|
-
urlObj.pathname = url
|
|
132
|
-
return urlObj.href
|
|
133
|
-
} catch (e) {
|
|
134
|
-
return undefined
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async function readFile(file, parents, cache, folderPath, hidden, publishedData, domain) {
|
|
140
|
-
const route = path.parse(file.name).name;
|
|
141
|
-
const url = buildURL(parents, route);
|
|
142
|
-
const filePath = path.join(folderPath, file.name);
|
|
143
|
-
|
|
144
|
-
const extension = path.extname(file.name);
|
|
145
|
-
|
|
146
|
-
const hide = (file.name.startsWith('$') && file.name.length > 1) || hidden;
|
|
147
|
-
|
|
148
|
-
if (file.isFile() && extension === '.md') {
|
|
149
|
-
const href = buildHREF(url, domain)
|
|
150
|
-
const startLoad = performance.now();
|
|
151
|
-
const shortPath = parents + '/' + file.name;
|
|
152
|
-
|
|
153
|
-
let filePublishedData = publishedData?.find(item => item.path === url)
|
|
154
|
-
if(publishedData && !filePublishedData) {
|
|
155
|
-
publishedData.push({
|
|
156
|
-
path: url,
|
|
157
|
-
webmentions: []
|
|
158
|
-
})
|
|
159
|
-
filePublishedData = publishedData.at(-1)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const { ast, frontmatter, imputedProperties } = await readMarkdownFile(filePath, cache, filePublishedData, href);
|
|
163
|
-
|
|
164
|
-
const loadTime = (performance.now() - startLoad).toFixed(2);
|
|
165
|
-
// console.log(`📄 ${shortPath} (${loadTime}ms)`);
|
|
166
|
-
console.log('fileread');
|
|
167
|
-
if (frontmatter.published == false) return;
|
|
168
|
-
if (file.name === 'home.md' || file.name === 'settings.md') {
|
|
169
|
-
const key = file.name === 'home.md' ? '$' : '_';
|
|
170
|
-
return {
|
|
171
|
-
[key]: {
|
|
172
|
-
...frontmatter,
|
|
173
|
-
imputedProperties,
|
|
174
|
-
ast,
|
|
175
|
-
url
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
[route]: {
|
|
182
|
-
$: {
|
|
183
|
-
...frontmatter,
|
|
184
|
-
imputedProperties,
|
|
185
|
-
ast,
|
|
186
|
-
// url,
|
|
187
|
-
url: hide ? false : url
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/** @type Directory */
|
|
194
|
-
if (file.isDirectory()) {
|
|
195
|
-
const settingsPath = path.join(folderPath, file.name, 'settings.md');
|
|
196
|
-
const settingsFileExists = await checkFileExists(settingsPath);
|
|
197
|
-
|
|
198
|
-
/** @type {MarkdownFile} */
|
|
199
|
-
const _ = settingsFileExists ? await readMarkdownFile(settingsPath, cache) : DefaultFile(url);
|
|
200
|
-
|
|
201
|
-
const shortPath = parents + '/' + file.name;
|
|
202
|
-
|
|
203
|
-
const startLoad = performance.now();
|
|
204
|
-
const folder = await readFolder(path.join(folderPath, file.name), url, cache, hide, publishedData, domain);
|
|
205
|
-
|
|
206
|
-
const loadTime = (performance.now() - startLoad).toFixed(2);
|
|
207
|
-
// console.log(`📁 ${shortPath} (${loadTime}ms)`);
|
|
208
|
-
|
|
209
|
-
if (!folder.hasOwnProperty('$')) {
|
|
210
|
-
const $ = DefaultFile(url);
|
|
211
|
-
Object.assign(folder, { $ });
|
|
212
|
-
}
|
|
213
|
-
if (!folder.hasOwnProperty('_')) {
|
|
214
|
-
const _ = DefaultFile(url);
|
|
215
|
-
Object.assign(folder, { _ });
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
[file.name]: folder
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* @typedef {Object} ProcessedFiles
|
|
226
|
-
* @description The return value of the processing function.
|
|
227
|
-
* @property {Directory} folder - The root directory.
|
|
228
|
-
* @property {Cache} finalCache - The application cache.
|
|
229
|
-
*/
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Recursively reads the markdown files in a directory and returns a representative object.
|
|
233
|
-
* @param {import('./loadCache').Cache} cache
|
|
234
|
-
* @returns {Promise<ProcessedFiles>}
|
|
235
|
-
*/
|
|
236
|
-
export default async function processMarkdownFiles(cache, publishedData, domain) {
|
|
237
|
-
/** @type {Array<string>} */
|
|
238
|
-
// @ts-ignore
|
|
239
|
-
const [homeDir] = $home;
|
|
240
|
-
const folder = await readFolder(homeDir, '', cache, null, publishedData, domain);
|
|
241
|
-
|
|
242
|
-
return { folder, finalCache: cache };
|
|
243
|
-
}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import { remark } from 'remark';
|
|
3
|
-
import remarkFrontmatter from 'remark-frontmatter';
|
|
4
|
-
import remarkDirective from 'remark-directive';
|
|
5
|
-
import remarkHTML from 'remark-html';
|
|
6
|
-
import remarkGFM from 'remark-gfm';
|
|
7
|
-
import yaml from 'js-yaml';
|
|
8
|
-
import { toString } from 'mdast-util-to-string';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
|
|
11
|
-
import { mutateMarkdownAST, mutateMarkdownFrontmatter } from '.';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {Object} FrontmatterNode
|
|
15
|
-
* @property {"yaml"} type - The type is yaml.
|
|
16
|
-
* @property {string} value - The value of the node.
|
|
17
|
-
* @property {Object} [position] - The position of the node.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Parse a frontmatter node to a JS object.
|
|
22
|
-
* @param {FrontmatterNode | undefined} frontmatterNode - A markdown node of type "yaml".
|
|
23
|
-
* @returns {Object} A JS object containing the frontmatter
|
|
24
|
-
*/
|
|
25
|
-
function parseFrontmatter(frontmatterNode) {
|
|
26
|
-
if (!frontmatterNode) return {};
|
|
27
|
-
const frontmatter = yaml.load(frontmatterNode.value);
|
|
28
|
-
if (frontmatter && typeof frontmatter === 'object') {
|
|
29
|
-
return frontmatter;
|
|
30
|
-
}
|
|
31
|
-
return {};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function deduceDescriptionFromAST(ast) {
|
|
35
|
-
for (let i = 0; i < ast?.length; i++) {
|
|
36
|
-
if (ast?.[i]?.type === 'paragraph') {
|
|
37
|
-
const firstParagraph = toString(ast[i]);
|
|
38
|
-
if (firstParagraph.length > 150) {
|
|
39
|
-
return firstParagraph.slice(0, 150);
|
|
40
|
-
} else if (firstParagraph.length > 1) {
|
|
41
|
-
return firstParagraph;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function deduceImageFromAST(ast) {
|
|
49
|
-
for (let i = 0; i < ast?.length; i++) {
|
|
50
|
-
const node = ast?.[i]
|
|
51
|
-
if (node.type === 'figure') {
|
|
52
|
-
for(let i = 0; i < node.children.length; i++) {
|
|
53
|
-
const child = node.children[i]
|
|
54
|
-
if(child.type === "image") {
|
|
55
|
-
return child.url
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function demoteHeadings(ast, start) {
|
|
64
|
-
for (let i = start; i < ast.length; i++) {
|
|
65
|
-
const node = ast[i];
|
|
66
|
-
if (node.type === 'heading') {
|
|
67
|
-
node.depth = node.depth + 1;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function checkHeadings(ast, start = 1) {
|
|
73
|
-
for (let i = start; i < ast.length; i++) {
|
|
74
|
-
if (ast[i]?.depth === 1) {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function extractTitleFromHeading(node) {
|
|
82
|
-
return node?.children?.[0].value;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function imputeTitleFromAST(ast) {
|
|
86
|
-
if (ast?.[0]?.depth === 1) {
|
|
87
|
-
return extractTitleFromHeading(ast[0]);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* @typedef {Object} ParsedMarkdown
|
|
95
|
-
* @property {Object.<string, *>} [frontmatter] - Metadata for the document.
|
|
96
|
-
* @property {Array<Object>} ast - The content of the document.
|
|
97
|
-
* @property {Object} imputedProperties - Metadata imputed from content.
|
|
98
|
-
* @property {string} [url] - URL for the page.
|
|
99
|
-
* @description An object containing the parsed frontmatter and filtered AST.
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Reads a Markdown file and parses its content into frontmatter and abstract syntax tree (AST).
|
|
104
|
-
* It also filters out YAML frontmatter nodes from the AST.
|
|
105
|
-
*
|
|
106
|
-
* @async
|
|
107
|
-
* @function
|
|
108
|
-
* @param {string} filePath - The path to the Markdown file.
|
|
109
|
-
* @param {Object} cache - An optional cache object that can be passed to mutate the AST.
|
|
110
|
-
* @returns {Promise<ParsedMarkdown>}
|
|
111
|
-
* @throws {Error} Will throw an error if the file cannot be read or parsed.
|
|
112
|
-
*/
|
|
113
|
-
export default async function readMarkdownFile(filePath, cache, publishedData, url) {
|
|
114
|
-
const fileName = path.basename(filePath.slice(0, -3));
|
|
115
|
-
|
|
116
|
-
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
117
|
-
const markdownParser = remark().use(remarkFrontmatter, ['yaml']).use(remarkHTML);
|
|
118
|
-
|
|
119
|
-
const parsedMarkdown = markdownParser.parse(fileContent);
|
|
120
|
-
const frontmatterNode = parsedMarkdown.children.find((node) => node.type === 'yaml');
|
|
121
|
-
const frontmatter = frontmatterNode?.type === 'yaml' ? parseFrontmatter(frontmatterNode) : {};
|
|
122
|
-
const ast = remark()
|
|
123
|
-
.use(remarkDirective)
|
|
124
|
-
.use(remarkFrontmatter)
|
|
125
|
-
.use(remarkGFM)
|
|
126
|
-
.parse(fileContent);
|
|
127
|
-
|
|
128
|
-
const footnotes = [];
|
|
129
|
-
|
|
130
|
-
for (let i = 0; i < ast.children.length; i++) {
|
|
131
|
-
if (ast.children[i].type === 'footnoteDefinition') {
|
|
132
|
-
footnotes.push(ast.children[i]);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (footnotes.length) {
|
|
137
|
-
ast.children.push({
|
|
138
|
-
type: 'footnotes',
|
|
139
|
-
children: footnotes
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// ast.children.sort((a, b) => {
|
|
144
|
-
// if (a.type !== 'footnoteDefinition' && b.type === 'footnoteDefinition') return -1;
|
|
145
|
-
// return 0;
|
|
146
|
-
// });
|
|
147
|
-
|
|
148
|
-
const filteredAST = ast.children.filter((child) => child.type !== 'yaml');
|
|
149
|
-
|
|
150
|
-
const imputedTitle = imputeTitleFromAST(filteredAST);
|
|
151
|
-
|
|
152
|
-
if (imputedTitle) {
|
|
153
|
-
filteredAST.shift();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (imputedTitle && checkHeadings(filteredAST, 1)) {
|
|
157
|
-
demoteHeadings(filteredAST, 1);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!frontmatter.title && imputedTitle) frontmatter.title = imputedTitle;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const imputedProperties = {
|
|
165
|
-
description: deduceDescriptionFromAST(filteredAST),
|
|
166
|
-
title: imputedTitle,
|
|
167
|
-
fileName
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const webmentions = publishedData?.webmentions
|
|
172
|
-
|
|
173
|
-
const promises = [mutateMarkdownAST(ast.children, cache, webmentions, url)];
|
|
174
|
-
|
|
175
|
-
// Don't mutate frontmatter on the settings pages
|
|
176
|
-
if (!filePath.endsWith('settings.md'))
|
|
177
|
-
promises.push(mutateMarkdownFrontmatter(frontmatter, cache, webmentions));
|
|
178
|
-
|
|
179
|
-
await Promise.all(promises);
|
|
180
|
-
|
|
181
|
-
const imputedImage = deduceImageFromAST(filteredAST)
|
|
182
|
-
|
|
183
|
-
if(imputedImage) {
|
|
184
|
-
imputedProperties.image = imputedImage
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return { frontmatter, ast: filteredAST, imputedProperties };
|
|
188
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const img = /^https?:\/\/\S+(avif|gif|heif|jpeg|jpg|png|tiff|webp)(\?\S+)?/;
|
|
2
|
-
const pdf = /^https?:\/\/\S+(pdf)(\?\S+)?/;
|
|
3
|
-
const url = /^https?:\/\/\S+$/;
|
|
4
|
-
const path = /^\/[\/\S]+$/;
|
|
5
|
-
// const humanDate = /^((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|January|February|March|April|May|June|July|August|September|October|November|December)[\d\040,\/(nd|rd|st|th)]{8,12}|[\d\040,\/(nd|rd|st|th)]{1,5}(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|January|February|March|April|May|June|July|August|September|October|November|December),?\040\d{2,4})$/;
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
url,
|
|
9
|
-
img,
|
|
10
|
-
path,
|
|
11
|
-
pdf
|
|
12
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export default async function sendWebmention({ endpoint, source, target }) {
|
|
2
|
-
try {
|
|
3
|
-
if (endpoint) {
|
|
4
|
-
const params = new URLSearchParams()
|
|
5
|
-
params.append('source', source)
|
|
6
|
-
params.append('target', target)
|
|
7
|
-
|
|
8
|
-
const response = await fetch(endpoint, {
|
|
9
|
-
method: "POST",
|
|
10
|
-
body: params,
|
|
11
|
-
headers: {
|
|
12
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
|
13
|
-
}
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
console.log({
|
|
17
|
-
source, target,
|
|
18
|
-
webmentionResponse: await response.json()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
if(response.status === 429) {
|
|
22
|
-
return "429"
|
|
23
|
-
} else if (response.status >= 200 && response.status < 300) {
|
|
24
|
-
return "success"
|
|
25
|
-
} else {
|
|
26
|
-
console.log({ failure: await response.json() })
|
|
27
|
-
return "failure"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
} catch (error) {
|
|
31
|
-
console.log({ error })
|
|
32
|
-
return "error"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import { resolveHomeDirPath } from '.';
|
|
3
|
-
|
|
4
|
-
export default async function writeCache(data, homeDir) {
|
|
5
|
-
const cachePath = resolveHomeDirPath('.cache.json', homeDir);
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const jsonData = JSON.stringify(data, null, 2);
|
|
9
|
-
await fs.writeFile(cachePath, jsonData, 'utf8');
|
|
10
|
-
console.log('Cache updated');
|
|
11
|
-
} catch (error) {
|
|
12
|
-
console.error('Error updating cache data:', error);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
processMarkdownFiles,
|
|
3
|
-
loadCache,
|
|
4
|
-
checkFileExists,
|
|
5
|
-
readMarkdownFile
|
|
6
|
-
} from '$lib/utilities';
|
|
7
|
-
import { join } from 'path';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export const prerender = true;
|
|
11
|
-
|
|
12
|
-
async function getPublishedData(domain) {
|
|
13
|
-
try {
|
|
14
|
-
const publishedURL = new URL("/$vowel/published.json", domain)
|
|
15
|
-
const publishedDataResponse = await fetch(publishedURL.href)
|
|
16
|
-
const publushedDataJSON = await publishedDataResponse.json()
|
|
17
|
-
return publushedDataJSON
|
|
18
|
-
} catch (e) {
|
|
19
|
-
console.log(e)
|
|
20
|
-
return undefined
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export async function GET() {
|
|
25
|
-
// everything.request.url
|
|
26
|
-
|
|
27
|
-
let settings
|
|
28
|
-
|
|
29
|
-
const settingsPath = join($home[0], "/settings.md")
|
|
30
|
-
const settingsExists = await checkFileExists(settingsPath);
|
|
31
|
-
if (settingsExists) {
|
|
32
|
-
settings = await readMarkdownFile(settingsPath)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Get published articles from live site
|
|
36
|
-
const publishedData = await getPublishedData(settings.frontmatter.domain)
|
|
37
|
-
|
|
38
|
-
if($publish[0]) {
|
|
39
|
-
const initialCache = await loadCache($home[0]);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const { folder: website } = await processMarkdownFiles(initialCache, publishedData, settings.frontmatter.domain);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const headers = {
|
|
46
|
-
'Cache-Control': 'max-age=0, s-maxage=1',
|
|
47
|
-
'Content-Type': 'text/plain'
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const response = new Response(JSON.stringify(publishedData), {
|
|
51
|
-
headers
|
|
52
|
-
});
|
|
53
|
-
return response;
|
|
54
|
-
}
|
package/src/routes/+error.svelte
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { page } from '$app/stores';
|
|
3
|
-
import {
|
|
4
|
-
Nav,
|
|
5
|
-
Page,
|
|
6
|
-
Breadcrumbs,
|
|
7
|
-
Sitemap,
|
|
8
|
-
ResetStyles,
|
|
9
|
-
DefaultStyles,
|
|
10
|
-
TypographyStyles,
|
|
11
|
-
NoStyles
|
|
12
|
-
} from '$lib/components/index.js';
|
|
13
|
-
import { invalidateAll } from '$app/navigation';
|
|
14
|
-
|
|
15
|
-
const themes = {
|
|
16
|
-
none: NoStyles,
|
|
17
|
-
reset: ResetStyles,
|
|
18
|
-
typography: TypographyStyles,
|
|
19
|
-
default: DefaultStyles
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
let { error: data } = $page;
|
|
23
|
-
|
|
24
|
-
const { website } = $derived(data);
|
|
25
|
-
|
|
26
|
-
const { slogan, theme } = $derived(website?._);
|
|
27
|
-
|
|
28
|
-
// Import CSS for HMR in dev mode
|
|
29
|
-
if (data.dev && data.files.css.exists) {
|
|
30
|
-
import(/* @vite-ignore */ data.files.css.path);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const siteTitle = website._.title;
|
|
34
|
-
|
|
35
|
-
function makePageMetaTitle() {
|
|
36
|
-
if (siteTitle) return `Page not found = ${siteTitle}`;
|
|
37
|
-
return `Page not found`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function getFavicon() {
|
|
41
|
-
if (website._?.icon)
|
|
42
|
-
return `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 20 90 60%22><text y=%22.9em%22 font-size=%2290%22>${website._.icon}</text></svg>`;
|
|
43
|
-
if (data.files.favicon.exists) return '/favicon.png';
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const favicon = getFavicon();
|
|
48
|
-
|
|
49
|
-
$effect(() => {
|
|
50
|
-
// Update website on file change
|
|
51
|
-
if (import.meta.hot) {
|
|
52
|
-
import.meta.hot.on('vowel:update', ({ path, file }) => {
|
|
53
|
-
invalidateAll().then(() => {
|
|
54
|
-
window.location.reload();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
import.meta.hot.on('vowel:refresh', () => {
|
|
58
|
-
console.log('Refresh');
|
|
59
|
-
invalidateAll().then(() => {
|
|
60
|
-
window.location.reload();
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
</script>
|
|
66
|
-
|
|
67
|
-
<svelte:component this={themes[theme || 'default']} />
|
|
68
|
-
|
|
69
|
-
<svelte:head>
|
|
70
|
-
<title>{makePageMetaTitle()}</title>
|
|
71
|
-
<meta property="og:site_name" content={website._.title} />
|
|
72
|
-
{#if favicon}
|
|
73
|
-
<link rel="icon" href={favicon} />
|
|
74
|
-
{/if}
|
|
75
|
-
{#if !data.dev && data.files.css.exists}
|
|
76
|
-
<link rel="stylesheet" href="/styles.css" />
|
|
77
|
-
{/if}
|
|
78
|
-
</svelte:head>
|
|
79
|
-
|
|
80
|
-
<div data-sveltekit-preload-data="hover" class="page 404">
|
|
81
|
-
<header>
|
|
82
|
-
{#if website._.logo}
|
|
83
|
-
<a href="/" class="site-logo">
|
|
84
|
-
{#if website._.logo.endsWith('.svg')}
|
|
85
|
-
<object type="image/svg+xml" data={website._.logo} title={website._.title || undefined}
|
|
86
|
-
></object>
|
|
87
|
-
{:else}
|
|
88
|
-
<img alt="website logo" src={website._.logo} />
|
|
89
|
-
{/if}
|
|
90
|
-
</a>
|
|
91
|
-
{/if}
|
|
92
|
-
{#if siteTitle}
|
|
93
|
-
<a href="/" class="site-title">{siteTitle}</a>
|
|
94
|
-
{/if}
|
|
95
|
-
{#if website._.slogan}
|
|
96
|
-
<p class="slogan">{website._.slogan}</p>
|
|
97
|
-
{/if}
|
|
98
|
-
<Nav folder={website} segments={['']} />
|
|
99
|
-
</header>
|
|
100
|
-
<main>
|
|
101
|
-
<h1>Page Not Found</h1>
|
|
102
|
-
</main>
|
|
103
|
-
<nav class="sidebar">
|
|
104
|
-
<Sitemap section={website} segments={['']} root />
|
|
105
|
-
</nav>
|
|
106
|
-
<footer>
|
|
107
|
-
© {website._.author ? website._.author + ' ' : ''}
|
|
108
|
-
{new Date().getFullYear()}
|
|
109
|
-
</footer>
|
|
110
|
-
</div>
|