Comparing version 1.20.1 to 1.21.0
@@ -790,25 +790,45 @@ /** | ||
this.processor.register("contents resolving", async (site) => { | ||
const all = site["posts"].concat(site["pages"]); | ||
for (const p of all) { | ||
const node = parseNode(p["content"]); | ||
resolveHeadingIDs(node); | ||
p["toc"] = genTOC(node); | ||
resolveAnchors( | ||
node, | ||
site["siteConfig"]["baseURL"], | ||
site["siteConfig"]["rootDir"], | ||
p["docPath"] | ||
); | ||
resolveImages(node, site["siteConfig"]["rootDir"], p["docPath"]); | ||
await resolveCodeBlocks(node, site["siteConfig"]["highlight"]); | ||
p["content"] = serializeNode(node); | ||
if (p["content"].indexOf("<!--more-->") !== -1) { | ||
const split = p["content"].split("<!--more-->"); | ||
p["excerpt"] = split[0]; | ||
p["more"] = split[1]; | ||
p["content"] = split.join("<a id=\"more\"></a>"); | ||
// Do contents resolving by default. | ||
if (this.site["siteConfig"]["contentsResolving"]["enable"]) { | ||
this.processor.register("contents resolving", async (site) => { | ||
const crOpts = site["siteConfig"]["contentsResolving"]; | ||
const all = site["posts"].concat(site["pages"]); | ||
for (const p of all) { | ||
const node = parseNode(p["content"]); | ||
if (crOpts["headingIDs"]["enable"]) { | ||
resolveHeadingIDs(node, crOpts["headingIDs"]); | ||
} | ||
if (crOpts["toc"]["enable"]) { | ||
p["toc"] = genTOC(node, crOpts["toc"]); | ||
} | ||
if (crOpts["anchors"]["enable"]) { | ||
resolveAnchors( | ||
node, | ||
site["siteConfig"]["baseURL"], | ||
site["siteConfig"]["rootDir"], | ||
p["docPath"], | ||
crOpts["anchors"] | ||
); | ||
} | ||
if (crOpts["images"]["enable"]) { | ||
resolveImages( | ||
node, | ||
site["siteConfig"]["rootDir"], | ||
p["docPath"], | ||
crOpts["images"] | ||
); | ||
} | ||
if (crOpts["codeBlocks"]["enable"]) { | ||
resolveCodeBlocks(node, crOpts["codeBlocks"]); | ||
} | ||
p["content"] = serializeNode(node); | ||
if (p["content"].indexOf("<!--more-->") !== -1) { | ||
const split = p["content"].split("<!--more-->"); | ||
p["excerpt"] = split[0]; | ||
p["more"] = split[1]; | ||
p["content"] = split.join("<a id=\"more\"></a>"); | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -815,0 +835,0 @@ |
@@ -1060,4 +1060,6 @@ /** | ||
* @param {Object} node parse5 Node. | ||
* @param {Object} [opts] | ||
* @param {String} [opts.safeChar="-"] Char used to replace unsupported chars. | ||
*/ | ||
const resolveHeadingIDs = (node) => { | ||
const resolveHeadingIDs = (node, opts = {}) => { | ||
const headingNames = ["h1", "h2", "h3", "h4", "h5", "h6"]; | ||
@@ -1071,13 +1073,12 @@ const headingIDs = {}; | ||
if (text != null) { | ||
// Remove some chars in escaped ID because | ||
// bootstrap scrollspy cannot support it. | ||
const encoded = encodeURI( | ||
text.trim().replace(/[\s()[\]{}<>.,!@#$%^&*=|`'/?~]+/g, "") | ||
); | ||
// Replace some chars in escaped ID because scrollspy cannot support it. | ||
const encoded = encodeURI(text.trim().replace( | ||
/[\s()[\]{}<>.,!@#$%^&*=|`'/?~]+/g, | ||
opts["safeChar"] || "-" | ||
)); | ||
const id = headingIDs[encoded] == null | ||
? encoded | ||
: `${encoded}-${headingIDs[encoded]++}`; | ||
// If we have `abc`, `abc` and `abc-1`, | ||
// we must save the `abc-1` generated by the second `abc`, | ||
// to prevent 2 `abc-1` for the last `abc-1`. | ||
// If we have `abc`, `abc` and `abc-1`, we must save the `abc-1` generated | ||
// by the second `abc`, to prevent 2 `abc-1` for the last `abc-1`. | ||
headingIDs[id] = 1; | ||
@@ -1101,4 +1102,5 @@ setNodeAttr(node, "id", id); | ||
* @param {Object} node parse5 Node. | ||
* @param {Object} [opts] | ||
*/ | ||
const genTOC = (node) => { | ||
const genTOC = (node, opts = {}) => { | ||
const headingNames = ["h1", "h2", "h3", "h4", "h5", "h6"]; | ||
@@ -1151,4 +1153,5 @@ const toc = []; | ||
* @param {String} docPath | ||
* @param {Object} [opts] | ||
*/ | ||
const resolveAnchors = (node, baseURL, rootDir, docPath) => { | ||
const resolveAnchors = (node, baseURL, rootDir, docPath, opts = {}) => { | ||
const isCurrentHost = isCurrentHostFn(baseURL, rootDir); | ||
@@ -1185,6 +1188,7 @@ const getPath = getPathFn(rootDir); | ||
* @param {Object} node parse5 Node. | ||
* @param {String} [rootDir] Site rootDir. | ||
* @param {String} [docPath] | ||
* @param {String} rootDir Site rootDir. | ||
* @param {String} docPath | ||
* @param {Object} [opts] | ||
*/ | ||
const resolveImages = (node, rootDir, docPath) => { | ||
const resolveImages = (node, rootDir, docPath, opts = {}) => { | ||
const getPath = getPathFn(rootDir); | ||
@@ -1209,59 +1213,8 @@ // Replace relative path to absolute path. | ||
/** | ||
* @private | ||
* @description Require hljs still takes a long time so only require it | ||
* when needed. | ||
*/ | ||
let hljs = null; | ||
/** | ||
* @private | ||
* @description Cache table for hljs's aliases. | ||
*/ | ||
let hljsAliases = null; | ||
/** | ||
* @private | ||
* @return {Map} Key is alias, value is hljs language name. | ||
*/ | ||
const hljsLoadAliases = () => { | ||
const hljsAliases = new Map(); | ||
const languages = hljs.listLanguages(); | ||
for (const lang of languages) { | ||
// First add language itself. | ||
hljsAliases.set(lang, lang); | ||
// Then add its aliases. | ||
const aliases = hljs.getLanguage(lang)["aliases"]; | ||
if (aliases != null) { | ||
for (const alias of aliases) { | ||
hljsAliases.set(alias, lang); | ||
} | ||
} | ||
} | ||
return hljsAliases; | ||
}; | ||
/** | ||
* @description Format and highlight code block. | ||
* @description Update code blocks. | ||
* @param {Object} node parse5 Node. | ||
* @param {Object} [hlOpts] Highlight options. | ||
* @return {Promise<null>} Importing hljs requires await. | ||
* @param {Object} [opts] | ||
* @param {Boolean} [opts.lineNumbers=false] Generate line numbers. | ||
*/ | ||
const resolveCodeBlocks = async (node, hlOpts = {}) => { | ||
// Enable hljs prefix and gutter by default. | ||
hlOpts = Object.assign({"hljs": true, "gutter": true}, hlOpts); | ||
// Only load hljs if enabled. | ||
if (hlOpts["enable"]) { | ||
if (hlOpts["hljs"]) { | ||
hlOpts["classPrefix"] = "hljs-"; | ||
} | ||
if (hljs == null) { | ||
// import is a keyword, not a function. | ||
const module = await import("highlight.js"); | ||
hljs = module["default"]; | ||
} | ||
hljs.configure(hlOpts); | ||
if (hljsAliases == null) { | ||
hljsAliases = hljsLoadAliases(); | ||
} | ||
} | ||
const resolveCodeBlocks = (node, opts = {}) => { | ||
const codeBlockNodes = nodesFilter(node, (node) => { | ||
@@ -1291,37 +1244,12 @@ return node["tagName"] === "pre" && | ||
} | ||
results.push(" class=\"code-block"); | ||
if (hlOpts["enable"]) { | ||
// Because we want to use hljs' css, | ||
// so `hljs` is added here to set background. | ||
results.push(" highlight hljs"); | ||
} | ||
results.push("\">"); | ||
results.push(" class=\"code-block\">"); | ||
// Highlight first for making gutter. | ||
// Some info means skipping highlight. | ||
let data; | ||
if (!hlOpts["enable"] || | ||
lang === "none" || | ||
lang === "plain" || | ||
lang === "plaintext" || | ||
lang === "nohighlight") { | ||
data = {"value": escapedCode}; | ||
} else if (hljsAliases.has(lang)) { | ||
// If user gives a reasonable language hint (but maybe incorrect), | ||
// we use it, because auto detect all code is too slow. | ||
data = hljs.highlight(code, {"language": hljsAliases.get(lang)}); | ||
} else { | ||
// No language hint, or just not resonable. | ||
data = hljs.highlightAuto(code); | ||
} | ||
if (hlOpts["gutter"]) { | ||
results.push("<pre class=\"gutter\">"); | ||
// Highlight should not change lines. | ||
// But may replace `\n` with `<br>`, so use original code here. | ||
const codeLines = code.split(/\r?\n/g); | ||
// It seems marked.js starts to keep the last `\n`, | ||
// which will leave an empty line after splitting, | ||
// and we should not add gutter for the last empty line. | ||
// Don't do trim here! We only skip empty line. | ||
if (opts["lineNumbers"]) { | ||
results.push("<pre class=\"line-numbers gutter\">"); | ||
// Highlight should not change lines, but may replace `\n` with `<br>`, | ||
// so use original code here. | ||
const codeLines = escapedCode.split(/\r?\n/g); | ||
// It seems marked.js starts to keep the last `\n`, which will leave an | ||
// empty line after splitting, and we should not add line number for the | ||
// last empty line. Don't do trim here, we only ignore! | ||
if (codeLines[codeLines.length - 1].length === 0) { | ||
@@ -1340,8 +1268,3 @@ codeLines.pop(); | ||
results.push("<pre class=\"code\">"); | ||
// If highlight is disabled or skipped, data["language"] will be null. | ||
// Then we set class to original info, | ||
// so user can do highlight in browser. | ||
if (hlOpts["enable"] && data["language"] != null) { | ||
results.push(`<code class="language-${data["language"]}">`); | ||
} else if (info != null) { | ||
if (info != null) { | ||
results.push(`<code class="${info}">`); | ||
@@ -1351,3 +1274,3 @@ } else { | ||
} | ||
results.push(data["value"]); | ||
results.push(escapedCode); | ||
results.push("</code></pre>"); | ||
@@ -1354,0 +1277,0 @@ |
{ | ||
"name": "hikarujs", | ||
"version": "1.20.1", | ||
"version": "1.21.0", | ||
"description": "A static site generator that generates routes based on directories naturally.", | ||
@@ -35,3 +35,2 @@ "type": "module", | ||
"fs-extra": "^11.2.0", | ||
"highlight.js": "^11.9.0", | ||
"marked": "^12.0.0", | ||
@@ -38,0 +37,0 @@ "nunjucks": "^3.2.4", |
Sorry, the diff of this file is not supported yet
9
141904
4156
- Removedhighlight.js@^11.9.0
- Removedhighlight.js@11.11.1(transitive)