markdown-cache 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/.editorconfig +4 -0
- package/.prettierignore +6 -0
- package/.prettierrc +23 -0
- package/.vscode/extensions.json +3 -0
- package/.vscode/settings.json +11 -0
- package/README.md +1 -0
- package/index.js +5 -0
- package/md-cache.js +145 -0
- package/package.json +25 -0
package/.editorconfig
ADDED
package/.prettierignore
ADDED
package/.prettierrc
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tabWidth": 2,
|
|
3
|
+
"useTabs": false,
|
|
4
|
+
"printWidth": 80,
|
|
5
|
+
"semi": true,
|
|
6
|
+
"endOfLine": "lf",
|
|
7
|
+
"singleQuote": false,
|
|
8
|
+
"arrowParens": "always",
|
|
9
|
+
"overrides": [
|
|
10
|
+
{
|
|
11
|
+
"files": "src/index.html",
|
|
12
|
+
"options": {
|
|
13
|
+
"printWidth": 10000
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"files": "api_src/anitxt/*.json",
|
|
18
|
+
"options": {
|
|
19
|
+
"printWidth": 1
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"explorer.fileNesting.enabled": true,
|
|
3
|
+
"explorer.fileNesting.patterns": {
|
|
4
|
+
"package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .prettier*, prettier*, .editorconfig"
|
|
5
|
+
},
|
|
6
|
+
"editor.codeActionsOnSave": {
|
|
7
|
+
"source.fixAll": "explicit"
|
|
8
|
+
},
|
|
9
|
+
"editor.formatOnSave": true,
|
|
10
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
11
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# md-cache
|
package/index.js
ADDED
package/md-cache.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
import fm from "front-matter";
|
|
6
|
+
|
|
7
|
+
export default class MarkdownCache {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
if (!options.md) {
|
|
10
|
+
throw new Error("No markdown-it provide!");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.md = options.md;
|
|
14
|
+
this.fmParser = fm;
|
|
15
|
+
|
|
16
|
+
this.root = options.root || process.cwd();
|
|
17
|
+
this.mdRoot = options.mdRoot || "markdown";
|
|
18
|
+
|
|
19
|
+
this.markdownDir = path.join(this.root, this.mdRoot);
|
|
20
|
+
|
|
21
|
+
this.cacheDir = path.join(this.root, ".cache");
|
|
22
|
+
this.htmlCacheDir = path.join(this.cacheDir, "md_html");
|
|
23
|
+
this.fmCacheDir = path.join(this.cacheDir, "md_fm");
|
|
24
|
+
|
|
25
|
+
this.metadataPath = path.join(this.cacheDir, "md_cache.json");
|
|
26
|
+
|
|
27
|
+
this._initPromise = null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async _init() {
|
|
31
|
+
await fs.mkdir(this.htmlCacheDir, { recursive: true });
|
|
32
|
+
await fs.mkdir(this.fmCacheDir, { recursive: true });
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
await fs.access(this.metadataPath);
|
|
36
|
+
} catch {
|
|
37
|
+
await fs.writeFile(this.metadataPath, "{}", "utf-8");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async _ensureInit() {
|
|
42
|
+
if (!this._initPromise) {
|
|
43
|
+
this._initPromise = () => this._init();
|
|
44
|
+
}
|
|
45
|
+
await this._initPromise();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_getHash(content) {
|
|
49
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_getCacheKey(requestPath) {
|
|
53
|
+
return this._getHash(requestPath);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async _readMetadata() {
|
|
57
|
+
const data = await fs.readFile(this.metadataPath, "utf-8");
|
|
58
|
+
return JSON.parse(data || "{}");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async _writeMetadata(metadata) {
|
|
62
|
+
await fs.writeFile(this.metadataPath, JSON.stringify(metadata), "utf-8");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async _readMarkdown(requestPath) {
|
|
66
|
+
const fullPath = path.join(this.markdownDir, requestPath);
|
|
67
|
+
return fs.readFile(fullPath, "utf-8");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_getFrontmatter(attributes) {
|
|
71
|
+
return Object.assign(
|
|
72
|
+
{ author: "xyxjs", license: "CC BY-NC-SA 4.0" },
|
|
73
|
+
attributes,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async _build(requestPath) {
|
|
78
|
+
await this._ensureInit();
|
|
79
|
+
|
|
80
|
+
let rawContent;
|
|
81
|
+
try {
|
|
82
|
+
rawContent = await this._readMarkdown(requestPath);
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const parsed = this.fmParser(rawContent);
|
|
88
|
+
|
|
89
|
+
const fmJson = this._getFrontmatter(parsed.attributes);
|
|
90
|
+
const mdBody = parsed.body + "\n[TOC]\n";
|
|
91
|
+
|
|
92
|
+
const contentHash = this._getHash(rawContent);
|
|
93
|
+
const cacheKey = this._getCacheKey(requestPath);
|
|
94
|
+
|
|
95
|
+
const metadata = await this._readMetadata();
|
|
96
|
+
const record = metadata[requestPath];
|
|
97
|
+
|
|
98
|
+
const htmlPath = path.join(this.htmlCacheDir, `${cacheKey}.html`);
|
|
99
|
+
const jsonPath = path.join(this.fmCacheDir, `${cacheKey}.json`);
|
|
100
|
+
|
|
101
|
+
if (record && record.hash === contentHash) {
|
|
102
|
+
try {
|
|
103
|
+
const [html, json] = await Promise.all([
|
|
104
|
+
fs.readFile(htmlPath, "utf-8"),
|
|
105
|
+
fs.readFile(jsonPath, "utf-8"),
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
html,
|
|
110
|
+
fm: JSON.parse(json),
|
|
111
|
+
};
|
|
112
|
+
} catch {}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const html = this.md.render(mdBody);
|
|
116
|
+
|
|
117
|
+
await Promise.all([
|
|
118
|
+
fs.writeFile(htmlPath, html, "utf-8"),
|
|
119
|
+
fs.writeFile(jsonPath, JSON.stringify(fmJson), "utf-8"),
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
metadata[requestPath] = {
|
|
123
|
+
hash: contentHash,
|
|
124
|
+
cacheFileName: cacheKey,
|
|
125
|
+
updatedAt: Date.now(),
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
await this._writeMetadata(metadata);
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
html,
|
|
132
|
+
fm: fmJson,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async html(requestPath) {
|
|
137
|
+
const result = await this._build(requestPath);
|
|
138
|
+
return result ? result.html : "Markdown file not found.";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async fm(requestPath) {
|
|
142
|
+
const result = await this._build(requestPath);
|
|
143
|
+
return result ? result.fm : {};
|
|
144
|
+
}
|
|
145
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "markdown-cache",
|
|
3
|
+
"author": "xyxjs",
|
|
4
|
+
"description": "Provide markdown with markdown-it & cache",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"markdown",
|
|
7
|
+
"markdown-it",
|
|
8
|
+
"cache",
|
|
9
|
+
"express"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"version": "1.0.0",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git://github.com/xyxjs/md-cache.git"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/xyxjs/md-cache/issues"
|
|
19
|
+
},
|
|
20
|
+
"main": "index.js",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"front-matter": "^4.0.2"
|
|
24
|
+
}
|
|
25
|
+
}
|