vowel 0.3.4 → 0.4.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/package.json +1 -1
- package/plugins/markdown/index.js +137 -20
- package/utils.js +30 -0
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@ import { h } from 'hastscript'
|
|
|
19
19
|
import { normalizeHeadings } from 'mdast-normalize-headings'
|
|
20
20
|
import { readFileSync } from "fs"
|
|
21
21
|
import { remove } from "unist-util-remove"
|
|
22
|
-
import { testURL } from "./../../utils.js"
|
|
22
|
+
import { testURL, testHashtags, createHashtagPage, toTitleCase, hashtagRegexSingle } from "./../../utils.js"
|
|
23
23
|
import { toHast } from 'mdast-util-to-hast'
|
|
24
24
|
import { toString as hastToString } from 'hast-util-to-string'
|
|
25
25
|
import { toString as mdastToString } from 'mdast-util-to-string'
|
|
@@ -103,14 +103,6 @@ function makeHead(metadata, url) {
|
|
|
103
103
|
return treeMainHead
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
function toTitleCase(string) {
|
|
107
|
-
if (!string) return
|
|
108
|
-
return string.split(" ").map(word => {
|
|
109
|
-
const letters = word.split("")
|
|
110
|
-
letters[0] = letters[0].toUpperCase()
|
|
111
|
-
return letters.join("")
|
|
112
|
-
}).join(" ")
|
|
113
|
-
}
|
|
114
106
|
|
|
115
107
|
function readURL(data) {
|
|
116
108
|
const hast = fromHtml(data)
|
|
@@ -140,7 +132,7 @@ function readURL(data) {
|
|
|
140
132
|
|
|
141
133
|
|
|
142
134
|
/** @type {Votive.ReadText} */
|
|
143
|
-
function
|
|
135
|
+
function readFile(string, filePath, destinationPath, database, config) {
|
|
144
136
|
const mdast = fromMarkdown(string, {
|
|
145
137
|
// Micromark extensions
|
|
146
138
|
extensions: [
|
|
@@ -198,6 +190,7 @@ function readMarkdown(string, filePath, destinationPath, database, config) {
|
|
|
198
190
|
visit(mdast, (node, index, parent) => {
|
|
199
191
|
if (node.type === "text" && parent.children.length === 1 && parent.type === "paragraph") {
|
|
200
192
|
const validURL = testURL(node.value)
|
|
193
|
+
|
|
201
194
|
if (validURL) {
|
|
202
195
|
|
|
203
196
|
jobs.push({
|
|
@@ -205,6 +198,107 @@ function readMarkdown(string, filePath, destinationPath, database, config) {
|
|
|
205
198
|
runner: "text",
|
|
206
199
|
destination: destinationPath
|
|
207
200
|
})
|
|
201
|
+
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const hashtags = testHashtags(node.value)
|
|
206
|
+
|
|
207
|
+
// TODO: Tags should not appear in menus
|
|
208
|
+
// TODO: Make this work when tags are embedded in text
|
|
209
|
+
|
|
210
|
+
if (hashtags) {
|
|
211
|
+
function convertTagsToLinks(value) {
|
|
212
|
+
const match = value.match(hashtagRegexSingle)
|
|
213
|
+
if (match) {
|
|
214
|
+
const remainder = value.slice(match[0].length)
|
|
215
|
+
const child = {
|
|
216
|
+
type: "link",
|
|
217
|
+
url: `/tags/${match[3]}`,
|
|
218
|
+
children: [
|
|
219
|
+
{
|
|
220
|
+
type: "text",
|
|
221
|
+
value: match[0]
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return [
|
|
227
|
+
{
|
|
228
|
+
type: "text",
|
|
229
|
+
value: match[1]
|
|
230
|
+
},
|
|
231
|
+
child,
|
|
232
|
+
{
|
|
233
|
+
type: "text",
|
|
234
|
+
value: match[4]
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
...convertTagsToLinks(remainder)
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
return [
|
|
241
|
+
{
|
|
242
|
+
type: "text",
|
|
243
|
+
value: value
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
parent.children = convertTagsToLinks(node.value)
|
|
249
|
+
|
|
250
|
+
const markdown = `/tags/**`
|
|
251
|
+
const mdast = fromMarkdown(markdown)
|
|
252
|
+
|
|
253
|
+
const extant = database.target.get("tags.html")
|
|
254
|
+
|
|
255
|
+
// FIXME: Update abstract format
|
|
256
|
+
if (!extant) {
|
|
257
|
+
// Delete if unnecessary
|
|
258
|
+
database.target.create({
|
|
259
|
+
path: `tags.html`,
|
|
260
|
+
abstract: mdast,
|
|
261
|
+
metadata: {
|
|
262
|
+
breadcrumb: "Tags",
|
|
263
|
+
title: "Tags",
|
|
264
|
+
prettyURL: "/tags",
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
database.dependency.track({}, "tags", null, destinationPath, "tags.html")
|
|
270
|
+
database.target.markStale("tags.html")
|
|
271
|
+
|
|
272
|
+
if (hashtags) {
|
|
273
|
+
if (!metadata.tags) {
|
|
274
|
+
metadata.tags = []
|
|
275
|
+
} else if (!Array.isArray(metadata.tags)) {
|
|
276
|
+
metadata.tags = []
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
metadata.tags = []
|
|
280
|
+
|
|
281
|
+
hashtags.forEach(hashtag => {
|
|
282
|
+
const title = toTitleCase(hashtag)
|
|
283
|
+
metadata.tags.push(hashtag)
|
|
284
|
+
|
|
285
|
+
const abstract = createHashtagPage(hashtag)
|
|
286
|
+
|
|
287
|
+
const tagMetadata = {
|
|
288
|
+
breadcrumb: title,
|
|
289
|
+
title: title,
|
|
290
|
+
prettyURL: `/tags/${hashtag}`,
|
|
291
|
+
type: "tag",
|
|
292
|
+
tag: hashtag
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const created = database.target.create({
|
|
296
|
+
path: `tags/${hashtag}.html`,
|
|
297
|
+
abstract,
|
|
298
|
+
metadata: tagMetadata
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
}
|
|
208
302
|
}
|
|
209
303
|
}
|
|
210
304
|
})
|
|
@@ -364,7 +458,7 @@ function getMetadata(tree, filePath) {
|
|
|
364
458
|
}
|
|
365
459
|
|
|
366
460
|
/** @type {Votive.ReadAbstract} */
|
|
367
|
-
function
|
|
461
|
+
function transformFile(abstract, database, config) {
|
|
368
462
|
const jobs = []
|
|
369
463
|
return { abstract, jobs }
|
|
370
464
|
}
|
|
@@ -580,13 +674,31 @@ function readFolder(folder, database, config, isRoot) {
|
|
|
580
674
|
}
|
|
581
675
|
|
|
582
676
|
/** @type {Votive.ProcessorWrite} */
|
|
583
|
-
function
|
|
677
|
+
function writeFile(destination, database, config) {
|
|
584
678
|
const isRoot = destination.path === "index.html"
|
|
585
679
|
|
|
680
|
+
// console.log(destination.metadata)
|
|
681
|
+
|
|
682
|
+
if (destination.metadata.type === "tag") {
|
|
683
|
+
if (!destination.metadata.tag) return false
|
|
684
|
+
|
|
685
|
+
const pages = database.target.getManyWithTrackers({
|
|
686
|
+
recursive: true,
|
|
687
|
+
dependent: destination,
|
|
688
|
+
query: {
|
|
689
|
+
tags: destination.metadata.tag
|
|
690
|
+
}
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
if (!pages.length) return false
|
|
694
|
+
}
|
|
695
|
+
|
|
586
696
|
const settings = database.setting.getByFolder(destination.dir + path.sep)
|
|
587
697
|
|
|
588
698
|
const { abstract, metadata, ...rest } = destination
|
|
589
699
|
|
|
700
|
+
if (metadata.tags) metadata.tags = JSON.parse(metadata.tags)
|
|
701
|
+
|
|
590
702
|
/** @param {string} filePath */
|
|
591
703
|
function listFolders(filePath) {
|
|
592
704
|
if (!filePath) return []
|
|
@@ -907,10 +1019,15 @@ function writeHTML(destination, database, config) {
|
|
|
907
1019
|
const folder = path.relative("/", dir)
|
|
908
1020
|
// const url = new URL(child.value, "thismessage://")
|
|
909
1021
|
const count = url.searchParams.get("count")
|
|
1022
|
+
const tag = url.searchParams.get("tag")
|
|
1023
|
+
const query = tag
|
|
1024
|
+
? { tags: tag }
|
|
1025
|
+
: {}
|
|
1026
|
+
|
|
910
1027
|
const targets = database.target.getManyWithTrackers({
|
|
911
1028
|
folder,
|
|
912
1029
|
recursive,
|
|
913
|
-
query
|
|
1030
|
+
query,
|
|
914
1031
|
dependent: destination.path
|
|
915
1032
|
})
|
|
916
1033
|
|
|
@@ -1152,26 +1269,26 @@ function router(args) {
|
|
|
1152
1269
|
|
|
1153
1270
|
|
|
1154
1271
|
/** @type {Votive.VotiveProcessor} */
|
|
1155
|
-
const
|
|
1272
|
+
const readMarkdown = {
|
|
1156
1273
|
extensions: [".md"],
|
|
1157
1274
|
format: "text",
|
|
1158
|
-
readFile
|
|
1275
|
+
readFile,
|
|
1159
1276
|
readResource: readURL,
|
|
1160
|
-
transformFile
|
|
1161
|
-
readFolder
|
|
1277
|
+
transformFile,
|
|
1278
|
+
readFolder,
|
|
1162
1279
|
}
|
|
1163
1280
|
|
|
1164
|
-
const
|
|
1281
|
+
const writeHTML = {
|
|
1165
1282
|
extensions: [".html"],
|
|
1166
1283
|
format: "text",
|
|
1167
|
-
writeFile
|
|
1284
|
+
writeFile
|
|
1168
1285
|
}
|
|
1169
1286
|
|
|
1170
1287
|
|
|
1171
1288
|
/** @type {Votive.VotivePlugin} */
|
|
1172
1289
|
const vowelMarkdownPlugin = {
|
|
1173
1290
|
name: "vowel",
|
|
1174
|
-
processors: [
|
|
1291
|
+
processors: [readMarkdown, writeHTML],
|
|
1175
1292
|
router
|
|
1176
1293
|
}
|
|
1177
1294
|
|
package/utils.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {fromMarkdown} from 'mdast-util-from-markdown'
|
|
2
|
+
import {toHast} from 'mdast-util-to-hast'
|
|
3
|
+
import {toHtml} from 'hast-util-to-html'
|
|
4
|
+
|
|
5
|
+
|
|
1
6
|
/** @param {string} text */
|
|
2
7
|
export function testURL(text) {
|
|
3
8
|
if (text.match(/^https?:\/\/[\S]+$/)) {
|
|
@@ -8,3 +13,28 @@ export function testURL(text) {
|
|
|
8
13
|
}
|
|
9
14
|
}
|
|
10
15
|
}
|
|
16
|
+
|
|
17
|
+
export const hashtagRegexSingle = /(^|\s)(#([\w\-\/]+))($|\b)/
|
|
18
|
+
export const hashtagRegexGlobal = /(?:^|\s)(#[\w\-\/]+)(?:$|\b)/g
|
|
19
|
+
|
|
20
|
+
export function testHashtags(text) {
|
|
21
|
+
const match = text.match(hashtagRegexGlobal)
|
|
22
|
+
if(match) return match.map(a => a.trim().slice(1))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export function toTitleCase(string) {
|
|
27
|
+
if (!string) return
|
|
28
|
+
return string.split(" ").map(word => {
|
|
29
|
+
const letters = word.split("")
|
|
30
|
+
letters[0] = letters[0].toUpperCase()
|
|
31
|
+
return letters.join("")
|
|
32
|
+
}).join(" ")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function createHashtagPage(tag) {
|
|
36
|
+
const markdown = `# ${toTitleCase(tag)}\n\n/**?tag=${tag}`
|
|
37
|
+
const mdast = fromMarkdown(markdown)
|
|
38
|
+
|
|
39
|
+
return mdast
|
|
40
|
+
}
|