1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
// https://gist.github.com/yuntan/bb82cdf336ec76a15c66b910754f5f33
if (!Object.prototype.then) {
Object.prototype.then = function (f) { return f.call(null, this); }
}
process.stdin.resume();
process.stdin.setEncoding('utf8');
let input_string = '';
process.stdin.on('data', chunk => {
input_string += chunk;
});
process.stdin.on('end', () => {
const text = input_string;
console.log(sb2md(text));
});
function sb2md(text) {
// code block
const escapeCodeBlocks = s => s.replace(
/^code:(.+)$((\n^[ \t].*$)+)/mg,
(_, p1, p2) =>
'```' + p1 + p2.replace(/^[ \t]/mg, '').replace(/\r|\n|\r\n/g, '
') + '
```'
);
const unescapeCodeBlocks = s => s.replace(/\+{3}/g, '\n');
const replaceLine = line =>
/^`{3}/.test(line) ? line :
// level 2 heading
line.replace(/^\[\[([^\[\]]+)\]\]$/, '## $1')
.replace(/^\[\*\s+(\S[^\[\]]*)\]$/, '## $1')
// anchor link
.replace(/\[(\S.*)\s+(https?:\/\/\S+)\](https://scrapbox.io/yuwd/%28%5CS.%2A%29%5Cs%2B%28https%3F%3A%5C/%5C/%5CS%2B%29%5C)/g, '[$1]($2)')
.replace(/\[(https?:\/\/\S+)\s+(\S.*)\](https://scrapbox.io/yuwd/%28https%3F%3A%5C/%5C/%5CS%2B%29%5Cs%2B%28%5CS.%2A%29%5C)/g, '[$2]($1)')
// image block
.replace(/^\[(https?:\/\/\S+\.(png|gif|jpe?g))\](https://scrapbox.io/yuwd/%28https%3F%3A%5C/%5C/%5CS%2B%5C.%28png%7Cgif%7Cjpe%3Fg%29%29%5C)$/, '![]($1)')
.replace(/^\[(https:\/\/gyazo.com\/\S+)\](https://scrapbox.io/yuwd/%28https%3A%5C/%5C/gyazo.com%5C/%5CS%2B%29%5C)$/, '![]($1.png)')
// unordered list
.replace(/^\s{6}(\S.*)$/, ' - $1')
.replace(/^\s{5}(\S.*)$/, ' - $1')
.replace(/^\s{4}(\S.*)$/, ' - $1')
.replace(/^\s{3}(\S.*)$/, ' - $1')
.replace(/^\s{2}(\S.*)$/, ' - $1')
.replace(/^\s(\S.*)$/, '- $1')
// bold text
.replace(/\[\[([^\[\]]+)\]\]/g, '**$1**')
.replace(/\[\*\s+([^\[\]]+)\]/g, '**$1**')
// italic text
.replace(/\[\/\s+([^\[\]]+)\]/g, '*$1*');
return text
.then(escapeCodeBlocks)
.split(/\r|\n|\r\n/)
// first line is level 1 heading
.then(lines => [lines[0].replace(/^(.+)$/, '$1')].concat(lines.slice(1)))
.map(replaceLine)
.join('\n')
.then(unescapeCodeBlocks);
}
|