@kobalab/liulian 0.9.1 → 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/ChangeLog.md +6 -0
- package/css/liulian.css +7 -0
- package/lib/html/folder.js +1 -1
- package/lib/html/index.js +4 -5
- package/lib/resource/folder.js +12 -3
- package/lib/resource/index.js +7 -0
- package/lib/resource/liulian.js +8 -34
- package/lib/resource/markdown.js +33 -0
- package/lib/resource/text.js +20 -1
- package/lib/text/markdown.js +25 -0
- package/lib/util/html-escape.js +6 -1
- package/package.json +3 -1
package/ChangeLog.md
CHANGED
package/css/liulian.css
CHANGED
package/lib/html/folder.js
CHANGED
|
@@ -97,7 +97,7 @@ module.exports = class Folder extends File {
|
|
|
97
97
|
for (let file of this._r.files.sort(cmp(s))) {
|
|
98
98
|
|
|
99
99
|
if (req.cmd != 'edit'
|
|
100
|
-
&& file.name.match(/^(?:README|HEAD|TAIL)
|
|
100
|
+
&& file.name.match(/^(?:README|HEAD|TAIL)(?:\.md)?$/)) continue;
|
|
101
101
|
|
|
102
102
|
let name = file.name + (file.type ? '' : '/');
|
|
103
103
|
let link = encodeURIComponent(file.name) + (file.type ? '' : '/')
|
package/lib/html/index.js
CHANGED
|
@@ -30,8 +30,8 @@ module.exports = class HTML {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
title(title) {
|
|
33
|
-
if (title) this._.title = title;
|
|
34
|
-
else
|
|
33
|
+
if (title != null) this._.title = title;
|
|
34
|
+
else return this._.title;
|
|
35
35
|
return this;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -68,8 +68,6 @@ module.exports = class HTML {
|
|
|
68
68
|
_head() {
|
|
69
69
|
const req = this._req;
|
|
70
70
|
|
|
71
|
-
if (! this._.stylesheet.length)
|
|
72
|
-
this._.stylesheet.push({url: DEFAULT_STYLE});
|
|
73
71
|
const stylesheet = this._.stylesheet.map(opt=>
|
|
74
72
|
'<link rel="stylesheet" type="text/css" '
|
|
75
73
|
+ `href="${cdata(fixpath(opt.url, req.baseUrl))}"`
|
|
@@ -151,7 +149,8 @@ module.exports = class HTML {
|
|
|
151
149
|
+ `</div>\n`;
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
stringify(content = '') {
|
|
152
|
+
stringify(content = '', needDefaultStyle = ! this._.stylesheet.length) {
|
|
153
|
+
if (needDefaultStyle) this._.stylesheet.push({url: DEFAULT_STYLE});
|
|
155
154
|
return '<!DOCTYPE html>\n'
|
|
156
155
|
+ `<html lang="${cdata(this.lang())}">\n`
|
|
157
156
|
+ this._head()
|
package/lib/resource/folder.js
CHANGED
|
@@ -7,6 +7,7 @@ const fs = require('fs').promises;
|
|
|
7
7
|
const { join } = require('path');
|
|
8
8
|
const HTML = require('../html/folder');
|
|
9
9
|
const parse = require('../text/liulian');
|
|
10
|
+
const md = require('../text/markdown');
|
|
10
11
|
|
|
11
12
|
const File = require('./file');
|
|
12
13
|
|
|
@@ -39,7 +40,7 @@ module.exports = class Folder extends File {
|
|
|
39
40
|
catch(err) {}
|
|
40
41
|
}
|
|
41
42
|
if (this._req.cmd != 'edit') {
|
|
42
|
-
for (let ext of ['', '.html', '.htm']) {
|
|
43
|
+
for (let ext of ['', '.md', '.html', '.htm']) {
|
|
43
44
|
let index = this._files.find(f=>f.name == 'index' + ext);
|
|
44
45
|
if (index) return index.open();
|
|
45
46
|
}
|
|
@@ -99,11 +100,19 @@ module.exports = class Folder extends File {
|
|
|
99
100
|
res.sendText(new HTML(this).edit());
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
|
-
let readme
|
|
103
|
+
let readme;
|
|
104
|
+
for (let file of ['README','README.md']) {
|
|
105
|
+
readme = this._files.find(f=>f.name == file);
|
|
106
|
+
if (readme) break;
|
|
107
|
+
}
|
|
103
108
|
if (readme) {
|
|
104
109
|
await readme.open();
|
|
105
110
|
readme._html = new HTML(this);
|
|
106
|
-
res.sendText(readme._html.folder(
|
|
111
|
+
res.sendText(readme._html.folder(
|
|
112
|
+
readme.type == 'text/x-liulian'
|
|
113
|
+
? await parse(readme)
|
|
114
|
+
: md.render(readme._text)
|
|
115
|
+
));
|
|
107
116
|
}
|
|
108
117
|
else if (this._req.user) {
|
|
109
118
|
res.sendText(new HTML(this).folder());
|
package/lib/resource/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const File = require('./file');
|
|
|
11
11
|
const Folder = require('./folder');
|
|
12
12
|
const Text = require('./text');
|
|
13
13
|
const LiuLian = require('./liulian');
|
|
14
|
+
const Markdown = require('./markdown');
|
|
14
15
|
|
|
15
16
|
async function resource(req, file) {
|
|
16
17
|
let location;
|
|
@@ -35,6 +36,12 @@ async function resource(req, file) {
|
|
|
35
36
|
else if (! basename(path).match(/\./))
|
|
36
37
|
return new LiuLian(req, path, stat,
|
|
37
38
|
location, resource);
|
|
39
|
+
else if (mime.getType(path) == 'text/markdown')
|
|
40
|
+
return new Markdown (req, path, stat,
|
|
41
|
+
location, resource);
|
|
42
|
+
else if (mime.getType(path) == 'application/javascript')
|
|
43
|
+
return new Text (req, path, stat,
|
|
44
|
+
location, resource);
|
|
38
45
|
else if ((mime.getType(path)||'').match(/^text\//))
|
|
39
46
|
return new Text(req, path, stat,
|
|
40
47
|
location, resource);
|
package/lib/resource/liulian.js
CHANGED
|
@@ -18,44 +18,18 @@ module.exports = class LiuLian extends Text {
|
|
|
18
18
|
script(script) { this._html.script(script) }
|
|
19
19
|
meta(attr) { this._html.meta(attr) }
|
|
20
20
|
|
|
21
|
-
async _seekToParent(filename) {
|
|
22
|
-
let pathDir = this._req.pathDir;
|
|
23
|
-
while (pathDir) {
|
|
24
|
-
try {
|
|
25
|
-
const r = await this.openFile(this._req, pathDir + filename);
|
|
26
|
-
await r.open();
|
|
27
|
-
return r.text;
|
|
28
|
-
}
|
|
29
|
-
catch(e) {
|
|
30
|
-
pathDir = pathDir.replace(/[^\/]*\/$/,'');
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return '';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
21
|
async update() {
|
|
37
22
|
await super.update();
|
|
38
23
|
if (this._req.param('text')) this._redirect = [303, this.name];
|
|
39
24
|
}
|
|
40
25
|
|
|
41
|
-
async
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
res.sendText(new HTML(this).diff());
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
this._text = (this.name != 'HEAD'
|
|
53
|
-
? await this._seekToParent('HEAD') + '\n' : '')
|
|
54
|
-
+ this._text + '\n'
|
|
55
|
-
+ (this.name != 'TAIL'
|
|
56
|
-
? await this._seekToParent('TAIL') : '');
|
|
57
|
-
this._html = new HTML(this);
|
|
58
|
-
res.sendText(this._html.stringify(await parse(this)));
|
|
59
|
-
}
|
|
26
|
+
async _send(res) {
|
|
27
|
+
this._text = (this.name != 'HEAD'
|
|
28
|
+
? await this._seekToParent('HEAD') + '\n' : '')
|
|
29
|
+
+ this._text + '\n'
|
|
30
|
+
+ (this.name != 'TAIL'
|
|
31
|
+
? await this._seekToParent('TAIL') : '');
|
|
32
|
+
this._html = new HTML(this);
|
|
33
|
+
res.sendText(this._html.stringify(await parse(this)));
|
|
60
34
|
}
|
|
61
35
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* resource/markdown
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const { strip } = require('../util/html-escape');
|
|
7
|
+
|
|
8
|
+
const HTML = require('../html/text');
|
|
9
|
+
const Text = require('./text');
|
|
10
|
+
const md = require('../text/markdown');
|
|
11
|
+
|
|
12
|
+
module.exports = class Markdown extends Text {
|
|
13
|
+
|
|
14
|
+
async update() {
|
|
15
|
+
await super.update();
|
|
16
|
+
if (this._req.param('text')) this._redirect = [303, this.name];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async _send(res) {
|
|
20
|
+
this._text = (this.name != 'HEAD.md'
|
|
21
|
+
? await this._seekToParent('HEAD.md') + '\n' : '')
|
|
22
|
+
+ this._text + '\n'
|
|
23
|
+
+ (this.name != 'TAIL.md'
|
|
24
|
+
? await this._seekToParent('TAIL.md') : '');
|
|
25
|
+
let html = md.render(this._text);
|
|
26
|
+
let title = strip((html.match(/<title>(.*?)<\/title>/i)||
|
|
27
|
+
html.match(/<h1>(.*?)<\/h1>/i)||[])[1]);
|
|
28
|
+
let style = (html.match(/<link\s?.*?>/ig)||[])
|
|
29
|
+
.filter(tag=>tag.match(/\srel="stylesheet"/i));
|
|
30
|
+
this._html = new HTML(this);
|
|
31
|
+
res.sendText(this._html.title(title).stringify(html, ! style.length));
|
|
32
|
+
}
|
|
33
|
+
}
|
package/lib/resource/text.js
CHANGED
|
@@ -13,6 +13,21 @@ module.exports = class Text extends File {
|
|
|
13
13
|
get text() { return this._text }
|
|
14
14
|
get diff() { return this._diff }
|
|
15
15
|
|
|
16
|
+
async _seekToParent(filename) {
|
|
17
|
+
let pathDir = this._req.pathDir;
|
|
18
|
+
while (pathDir) {
|
|
19
|
+
try {
|
|
20
|
+
const r = await this.openFile(this._req, pathDir + filename);
|
|
21
|
+
await r.open();
|
|
22
|
+
return r.text;
|
|
23
|
+
}
|
|
24
|
+
catch(e) {
|
|
25
|
+
pathDir = pathDir.replace(/[^\/]*\/$/,'');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
|
|
16
31
|
async open() {
|
|
17
32
|
await super.open();
|
|
18
33
|
if (this._backup && this._req.cmd == 'diff') {
|
|
@@ -57,6 +72,10 @@ module.exports = class Text extends File {
|
|
|
57
72
|
if (this._req.cmd == 'edit') res.sendText(new HTML(this).edit());
|
|
58
73
|
else if (this._req.cmd == 'log') res.sendText(new HTML(this).log());
|
|
59
74
|
else if (this._req.cmd == 'diff') res.sendText(new HTML(this).diff());
|
|
60
|
-
else
|
|
75
|
+
else this._send(res);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_send(res) {
|
|
79
|
+
res.sendFile(this._path, this.type);
|
|
61
80
|
}
|
|
62
81
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* text/markdown
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const hljs = require('highlight.js');
|
|
7
|
+
|
|
8
|
+
module.exports = require('markdown-it')({
|
|
9
|
+
html: true,
|
|
10
|
+
linkify: true,
|
|
11
|
+
highlight: function(str, lang) {
|
|
12
|
+
const error = console.error; console.error = ()=>{};
|
|
13
|
+
let html = '';
|
|
14
|
+
if (lang) {
|
|
15
|
+
try {
|
|
16
|
+
html = hljs.highlight(lang, str).value;
|
|
17
|
+
}
|
|
18
|
+
catch(err) {
|
|
19
|
+
html = hljs.highlightAuto(str).value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
console.error = error;
|
|
23
|
+
return html;
|
|
24
|
+
}
|
|
25
|
+
}).use(require('markdown-it-footnote'));
|
package/lib/util/html-escape.js
CHANGED
|
@@ -15,8 +15,13 @@ function cdata(str = '') {
|
|
|
15
15
|
|
|
16
16
|
const cref = replacer(cref_pt, null, cdata);
|
|
17
17
|
|
|
18
|
+
function getAlt(img) {
|
|
19
|
+
return cref((img.match(/\salt="(.*?)"/)||[])[1]);
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
function strip(html = '') {
|
|
19
|
-
return html.replace(
|
|
23
|
+
return html.replace(/<img\s?.*?>/g, getAlt)
|
|
24
|
+
.replace(/<.*?>/g, '')
|
|
20
25
|
.replace(/>/g, '>')
|
|
21
26
|
.replace(/</g, '<')
|
|
22
27
|
.replace(/"/g,'"')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kobalab/liulian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Node.jsで動作するWebサイト作成ツール",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"express": "^4.17.1",
|
|
35
35
|
"express-session": "^1.17.1",
|
|
36
36
|
"highlight.js": "^10.4.1",
|
|
37
|
+
"markdown-it": "^12.3.2",
|
|
38
|
+
"markdown-it-footnote": "^3.0.3",
|
|
37
39
|
"mime": "^2.4.6",
|
|
38
40
|
"multer": "^1.4.2",
|
|
39
41
|
"passport": "^0.4.1",
|