Skip to content

Commit 5d7e97b

Browse files
committed
add scripts
1 parent 08d8e2d commit 5d7e97b

21 files changed

+1024
-1
lines changed

Diff for: build/index.js

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const chalk = require('chalk');
4+
5+
const url = require('./scripts/url');
6+
const meta = require('./scripts/meta');
7+
const getSlug = require('./scripts/slug');
8+
const markdownRender = require('./scripts/markdownRender');
9+
const listRender = require('./scripts/listRender');
10+
const problemRender = require('./scripts/problemRender');
11+
12+
const problemList = [];
13+
const difficultyMap = {};
14+
const tagMap = {};
15+
16+
function buildProblems () {
17+
const pathReg = /^\d{3}-\d{3}$/;
18+
const fileReg = /\.md$/;
19+
fs.readdirSync(path.resolve(__dirname, '../')).forEach(floder => {
20+
if (!pathReg.test(floder)) return;
21+
fs.readdirSync(path.resolve(__dirname, '../', floder)).forEach(file => {
22+
if (!fileReg.test(file)) return;
23+
const markdown = fs.readFileSync(path.resolve(__dirname, '../', floder, file), 'utf-8');
24+
const content = markdownRender(markdown);
25+
const id = meta.getId(markdown);
26+
const name = meta.getName(markdown);
27+
const slug = getSlug(name);
28+
const difficulty = {
29+
name: meta.getDifficulty(markdown),
30+
slug: ''
31+
};
32+
const tags = meta.getRelatedTopics(markdown).map(name => {
33+
return {
34+
name,
35+
slug: getSlug(name)
36+
};
37+
});
38+
const similarQuestions = meta.getSimilarQuestions(markdown).map(name => {
39+
return {
40+
name,
41+
slug: getSlug(name)
42+
};
43+
});
44+
45+
difficulty.slug = getSlug(difficulty.name);
46+
47+
problemList.push({
48+
id,
49+
name,
50+
slug,
51+
difficulty,
52+
tags
53+
});
54+
if (!difficultyMap[difficulty.slug]) difficultyMap[difficulty.slug] = difficulty.name;
55+
tags.forEach(tag => {
56+
if (!tagMap[tag.slug]) tagMap[tag.slug] = tag.name;
57+
});
58+
59+
problemRender({
60+
id,
61+
name,
62+
slug,
63+
difficulty,
64+
tags,
65+
similarQuestions,
66+
content,
67+
url
68+
});
69+
});
70+
});
71+
}
72+
73+
function buildPages () {
74+
listRender(
75+
'',
76+
url,
77+
Object.keys(tagMap).map(t => ({ name: tagMap[t], slug: t })),
78+
Object.keys(difficultyMap).map(d => ({ name: difficultyMap[d], slug: d })),
79+
problemList,
80+
{},
81+
{}
82+
);
83+
}
84+
85+
function buildTags () {
86+
let list = null;
87+
Object.keys(tagMap).forEach(slug => {
88+
list = problemList.filter(item => {
89+
let res = false;
90+
item.tags.forEach(tag => {
91+
if (tag.slug === slug) res = true;
92+
});
93+
return res;
94+
});
95+
listRender(
96+
`./tag/${slug}`,
97+
url,
98+
Object.keys(tagMap).map(t => ({ name: tagMap[t], slug: t })),
99+
Object.keys(difficultyMap).map(d => ({ name: difficultyMap[d], slug: d })),
100+
list,
101+
{
102+
name: tagMap[slug],
103+
slug
104+
},
105+
{}
106+
);
107+
});
108+
}
109+
110+
function buildDifficulties () {
111+
let list = null;
112+
Object.keys(difficultyMap).forEach(slug => {
113+
list = problemList.filter(item => item.difficulty.slug === slug);
114+
listRender(
115+
`./difficulty/${slug}`,
116+
url,
117+
Object.keys(tagMap).map(t => ({ name: tagMap[t], slug: t })),
118+
Object.keys(difficultyMap).map(d => ({ name: difficultyMap[d], slug: d })),
119+
list,
120+
{},
121+
{
122+
name: difficultyMap[slug],
123+
slug
124+
}
125+
);
126+
});
127+
}
128+
129+
buildProblems();
130+
buildPages();
131+
buildTags();
132+
buildDifficulties();
133+
134+
console.log(`\n${chalk.blue('Done!')}\n`);

Diff for: build/scripts/listRender.js

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
const fs = require('fs');
2+
const fse = require('fs-extra');
3+
const path = require('path');
4+
const jsx = require('react-jsx');
5+
6+
const template = fs.readFileSync(path.resolve(__dirname, '../template/list.jsx'), 'utf-8');
7+
const render = jsx.server(template, {
8+
filename: 'list.jsx',
9+
debug: true,
10+
raw: true
11+
});
12+
13+
const PAGE_SIZE = 30;
14+
const ROOT_DIR = path.resolve(__dirname, '../../');
15+
16+
function getPath (type, page) {
17+
if (page === 1) {
18+
return path.resolve(ROOT_DIR, './docs', type, 'index.html');
19+
} else {
20+
return path.resolve(ROOT_DIR, './docs', type, 'page', `${page}.html`);
21+
}
22+
}
23+
24+
function listRender (type, url, tagList, difficultyList, list, tag, difficulty) {
25+
const len = list.length;
26+
let i = 0;
27+
while (i < len) {
28+
fse.outputFileSync(
29+
getPath(type, i + 1),
30+
render({
31+
list: list.slice(i, PAGE_SIZE),
32+
paging: {
33+
pageNow: i + 1,
34+
pageSize: PAGE_SIZE,
35+
pageCount: len
36+
},
37+
tagList,
38+
difficultyList,
39+
tag,
40+
difficulty,
41+
url
42+
}, {
43+
html: true
44+
})
45+
);
46+
i += PAGE_SIZE;
47+
}
48+
}
49+
50+
module.exports = listRender;

Diff for: build/scripts/markdownRender.js

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const fs = require('fs');
2+
const showdown = require('showdown');
3+
const hljs = require('highlight.js');
4+
5+
const renderCode = function (code, lang) {
6+
const str = code.replace(/¨D/g, '$');
7+
let html = '';
8+
let cls = '';
9+
try {
10+
html = hljs.highlight(lang, str).value;
11+
} catch (e) {
12+
html = hljs.highlightAuto(str).value;
13+
}
14+
cls = lang ? ` lang-${lang}` : '';
15+
return `<pre><code class="hljs${cls}">${html}\n</code></pre>`;
16+
};
17+
18+
const renderer = new showdown.Converter({
19+
ghCompatibleHeaderId: true,
20+
headerLevelStart: 2,
21+
parseImgDimensions: true,
22+
strikethrough: true,
23+
tables: true,
24+
tasklists: true,
25+
smartIndentationFix: true,
26+
requireSpaceBeforeHeadingText: true,
27+
extensions: [
28+
() => {
29+
const codes = {}
30+
return [
31+
{
32+
type: 'lang',
33+
regex: /#([\s\S]*?)##/,
34+
replace: ''
35+
},
36+
{
37+
type: 'lang',
38+
regex: /```([a-zA-Z0-9_\-]*)\n([\s\S]*?)\n```/g,
39+
replace: (_, lang, code, offset) => {
40+
codes[offset] = {
41+
lang,
42+
code
43+
};
44+
return `<!--CODEBLOCK_${offset}-->`;
45+
}
46+
},
47+
{
48+
type: 'output',
49+
regex: /<a\s+href="/g,
50+
replace: '<a target="_blank" href="'
51+
},
52+
{
53+
type: 'output',
54+
regex: /<!--CODEBLOCK_(\d+)-->/g,
55+
replace: (_, id) => {
56+
return renderCode(codes[id].code, codes[id].lang);
57+
}
58+
},
59+
{
60+
type: 'output',
61+
regex: /<!--[\s\S]*?-->/g,
62+
replace: ''
63+
}
64+
]
65+
}
66+
]
67+
});
68+
69+
const markdownRender = function (markdown, html) {
70+
return renderer.makeHtml(markdown);
71+
};
72+
73+
module.exports = markdownRender;

Diff for: build/scripts/meta.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
function getId (markdown) {
2+
const reg = /#\s(\d+)\./;
3+
const process = str => Number(str);
4+
const res = reg.exec(markdown);
5+
return res ? process(res[1]) : 0;
6+
}
7+
8+
function getName (markdown) {
9+
const reg = /#\s\d+\.\s(.*)/;
10+
const process = str => str.trim();
11+
const res = reg.exec(markdown);
12+
return res ? process(res[1]) : 0;
13+
}
14+
15+
function getDifficulty (markdown) {
16+
const reg = /-\sDifficulty:\s(.*)/;
17+
const process = str => str.replace(/\.$/, '');
18+
const res = reg.exec(markdown);
19+
return res ? process(res[1]) : '';
20+
}
21+
22+
function getRelatedTopics (markdown) {
23+
const reg = /-\sRelated\sTopics:\s(.*)/;
24+
const process = str => str.replace(/\.$/, '').split(',').map(t => t.trim());
25+
const res = reg.exec(markdown);
26+
return res ? process(res[1]) : [];
27+
}
28+
29+
function getSimilarQuestions (markdown) {
30+
const reg = /-\sSimilar\sQuestions:\s(.*)/;
31+
const process = str => str.replace(/\.$/, '').split(',').map(t => t.trim());
32+
const res = reg.exec(markdown);
33+
return res ? process(res[1]) : [];
34+
}
35+
36+
module.exports.getId = getId;
37+
module.exports.getName = getName;
38+
module.exports.getDifficulty = getDifficulty;
39+
module.exports.getRelatedTopics = getRelatedTopics;
40+
module.exports.getSimilarQuestions = getSimilarQuestions;

Diff for: build/scripts/problemRender.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const fs = require('fs');
2+
const fse = require('fs-extra');
3+
const path = require('path');
4+
const jsx = require('react-jsx');
5+
6+
const template = fs.readFileSync(path.resolve(__dirname, '../template/problem.jsx'), 'utf-8');
7+
const render = jsx.server(template, {
8+
filename: 'problem.jsx',
9+
debug: true,
10+
raw: true
11+
});
12+
13+
const ROOT_DIR = path.resolve(__dirname, '../../');
14+
15+
function getPath (id, slug) {
16+
return path.resolve(ROOT_DIR, './docs/problem', `${id}-${slug}.html`);
17+
}
18+
19+
function problemRender (problem) {
20+
fse.outputFileSync(
21+
getPath(problem.id, problem.slug),
22+
render(problem, {
23+
html: true
24+
})
25+
);
26+
}
27+
28+
module.exports = problemRender;

Diff for: build/scripts/slug.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function getSlug (name) {
2+
return name.toLowerCase()
3+
.replace(/\s+/g, '-')
4+
.replace(/[^a-z0-9\-\._~]/g, '')
5+
.replace(/\-+/g, '-');
6+
};
7+
8+
module.exports = getSlug;

Diff for: build/scripts/url.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const home = 'https://baffinlee.github.io/leetcode-javascript';
2+
3+
function difficulty (slug, num = 1) {
4+
return num === 1 ? `${home}/difficulty/${slug}` : `${home}/difficulty/${slug}/page/${num}.html`;
5+
}
6+
7+
function tag (slug, num = 1) {
8+
return num === 1 ? `${home}/tag/${slug}` : `${home}/tag/${slug}/page/${num}.html`;
9+
}
10+
11+
function problem (slug) {
12+
return `${home}/problem/${slug}`;
13+
}
14+
15+
function page (num = 1) {
16+
return num === 1 ? home : `${home}/page/${num}.html`;
17+
}
18+
19+
module.exports = {
20+
home,
21+
difficulty,
22+
tag,
23+
page,
24+
problem
25+
};

0 commit comments

Comments
 (0)