diff --git a/.eleventy.js b/.eleventy.js deleted file mode 100644 index a3b1838..0000000 --- a/.eleventy.js +++ /dev/null @@ -1,60 +0,0 @@ -const pkg = require("./package.json"); -const Prism = require("prismjs"); -const PrismLoader = require("./src/PrismLoader"); -const hasTemplateFormat = require("./src/hasTemplateFormat"); -const HighlightPairedShortcode = require("./src/HighlightPairedShortcode"); -const LiquidHighlightTag = require("./src/LiquidHighlightTag"); -const markdownPrismJs = require("./src/markdownSyntaxHighlightOptions"); - -module.exports = function(eleventyConfig, options){ - try { - eleventyConfig.versionCheck(pkg["11ty"].compatibility); - } catch(e) { - console.log( `WARN: Eleventy Plugin (${pkg.name}) Compatibility: ${e.message}` ); - } - options = Object.assign({ - init: function({Prism}){}, - lineSeparator: "\n", - errorOnInvalidLanguage: false, - alwaysWrapLineHighlights: false, - preAttributes: {}, - codeAttributes: {}, - languages: [], - }, options); - - for(const language of options.languages){ - PrismLoader(language) - } - - if( hasTemplateFormat(options.templateFormats, "liquid") ) { - eleventyConfig.addLiquidTag("highlight", (liquidEngine) => { - // {% highlight js 0 2 %} - let highlight = new LiquidHighlightTag(liquidEngine); - return highlight.getObject(options); - }); - } - - if( hasTemplateFormat(options.templateFormats, "njk") ) { - eleventyConfig.addPairedNunjucksShortcode("highlight", (content, args) => { - // {% highlight "js 0 2-3" %} - let [language, ...highlightNumbers] = args.split(" "); - return HighlightPairedShortcode(content, language, highlightNumbers.join(" "), options); - }); - } - - if( hasTemplateFormat(options.templateFormats, "md") ) { - // ```js/0,2-3 - eleventyConfig.addMarkdownHighlighter(markdownPrismJs(options)); - } - - // we need to add this as many template languages (Vue, WebC) rely on JavaScript functions (not just 11ty.js) - eleventyConfig.addJavaScriptFunction("highlight", (language, content, highlight1, highlight2) => { - let highlightLines = [highlight1, highlight2].filter(entry => entry).join(" "); - let result = HighlightPairedShortcode(content, language, highlightLines, options); - return result; - }); - - options.init({Prism}) -}; - -module.exports.pairedShortcode = HighlightPairedShortcode; diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 62e8c16..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - env: { - es6: true, - node: true - }, - extends: "eslint:recommended", - parserOptions: { - sourceType: "module", - ecmaVersion: 2017 - }, - rules: { - indent: ["error", 2], - "linebreak-style": ["error", "unix"], - quotes: ["error", "double"], - semi: ["error", "always"] - } -}; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eee523c..28cef5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] - node: ["16", "18", "20", "22", "24"] + node: ["18", "20", "22", "24"] name: Node.js ${{ matrix.node }} on ${{ matrix.os }} steps: - uses: actions/checkout@v3 diff --git a/demo/eleventy-config.js b/demo/eleventy-config.js index c6f37fc..89a6295 100644 --- a/demo/eleventy-config.js +++ b/demo/eleventy-config.js @@ -1,6 +1,6 @@ -const syntaxHighlight = require("../.eleventy.js"); +import syntaxHighlight from "../syntaxHighlight.js"; -module.exports = function(eleventyConfig) { +export default function(eleventyConfig) { eleventyConfig.addPlugin(syntaxHighlight, { // alwaysWrapLineHighlights: true preAttributes: { tabindex: 0 } diff --git a/package.json b/package.json index e1d622c..263bb56 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,9 @@ "publishConfig": { "access": "public" }, - "main": ".eleventy.js", + "main": "syntaxHighlight.js", "scripts": { "test": "npx ava", - "demo": "npx @11ty/eleventy --input=demo --output=demo/_site --config=demo/eleventy-config.js", "start": "npx @11ty/eleventy --input=demo --output=demo/_site --config=demo/eleventy-config.js --serve" }, "repository": { @@ -42,6 +41,7 @@ "markdown-it": "^14.1.0" }, "dependencies": { + "entities": "^7.0.0", "prismjs": "^1.30.0" }, "ava": { @@ -49,7 +49,8 @@ "failFast": false, "files": [ "./test/*.js", - "./test/*.mjs" + "./test/*.cjs" ] - } + }, + "type": "module" } diff --git a/src/HighlightLines.js b/src/HighlightLines.js index 4aa8312..16609d8 100644 --- a/src/HighlightLines.js +++ b/src/HighlightLines.js @@ -1,4 +1,4 @@ -class HighlightLines { +export default class HighlightLines { constructor(rangeStr) { this.highlights = this.convertRangeToHash(rangeStr); } @@ -29,5 +29,3 @@ class HighlightLines { return !!this.highlights[lineNumber]; } } - -module.exports = HighlightLines; diff --git a/src/HighlightLinesGroup.js b/src/HighlightLinesGroup.js index 47c0aaa..431bdb9 100644 --- a/src/HighlightLinesGroup.js +++ b/src/HighlightLinesGroup.js @@ -1,6 +1,6 @@ -const HighlightLines = require("./HighlightLines"); +import HighlightLines from "./HighlightLines.js"; -class HighlightLinesGroup { +export default class HighlightLinesGroup { constructor(str, delimiter) { this.init(str, delimiter); } @@ -64,5 +64,3 @@ class HighlightLinesGroup { return this.splitLineMarkup( line, ``, ``); } } - -module.exports = HighlightLinesGroup; diff --git a/src/HighlightPairedShortcode.js b/src/HighlightPairedShortcode.js index be37d52..f3677eb 100644 --- a/src/HighlightPairedShortcode.js +++ b/src/HighlightPairedShortcode.js @@ -1,9 +1,9 @@ -const Prism = require("prismjs"); -const PrismLoader = require("./PrismLoader"); -const HighlightLinesGroup = require("./HighlightLinesGroup"); -const getAttributes = require("./getAttributes"); +import Prism from "prismjs"; +import PrismLoader from "./PrismLoader.js"; +import HighlightLinesGroup from "./HighlightLinesGroup.js"; +import getAttributes from "./getAttributes.js"; -module.exports = function (content, language, highlightNumbers, options = {}) { +export default function (content, language, highlightNumbers, options = {}) { // default to on if(options.trim === undefined || options.trim === true) { content = content.trim(); @@ -21,19 +21,19 @@ module.exports = function (content, language, highlightNumbers, options = {}) { } } - let group = new HighlightLinesGroup(highlightNumbers); - let lines = highlightedContent.split(/\r?\n/); - lines = lines.map(function(line, j) { - if(options.alwaysWrapLineHighlights || highlightNumbers) { - let lineContent = group.getLineMarkup(j, line); - return lineContent; - } - return line; - }); + let transformedCode = highlightedContent; + if(options.alwaysWrapLineHighlights || highlightNumbers) { + let group = new HighlightLinesGroup(highlightNumbers); + let lines = highlightedContent.split(/\r?\n/); + lines = lines.map(function(line, j) { + return group.getLineMarkup(j, line); + }); + transformedCode = lines.join(options.lineSeparator || "\n"); + } const context = { content: content, language: language, options: options }; const preAttributes = getAttributes(options.preAttributes, context); const codeAttributes = getAttributes(options.codeAttributes, context); - return `
` + lines.join(options.lineSeparator || "
") + "";
+ return `${transformedCode}`;
};
diff --git a/src/LiquidHighlightTag.js b/src/LiquidHighlightTag.js
deleted file mode 100644
index 26eb7ce..0000000
--- a/src/LiquidHighlightTag.js
+++ /dev/null
@@ -1,49 +0,0 @@
-const HighlightPairedShortcode = require("./HighlightPairedShortcode");
-
-class LiquidHighlightTag {
- constructor(liquidEngine) {
- this.liquidEngine = liquidEngine;
- }
-
- getObject(options = {}) {
- let ret = function(highlighter) {
- return {
- parse: function(tagToken, remainTokens) {
- let split = tagToken.args.split(" ");
-
- this.language = split.shift();
- this.highlightLines = split.join(" ");
-
- this.tokens = [];
-
- var stream = highlighter.liquidEngine.parser.parseStream(remainTokens);
-
- stream
- .on("token", token => {
- if (token.name === "endhighlight") {
- stream.stop();
- } else {
- this.tokens.push(token);
- }
- })
- .on("end", x => {
- throw new Error(`tag ${tagToken.getText()} not closed`);
- });
-
- stream.start();
- },
- render: function(scope, hash) {
- let tokens = this.tokens.map(token => {
- return token.raw || token.getText();
- });
- let tokenStr = tokens.join("").trim();
- return Promise.resolve(HighlightPairedShortcode(tokenStr, this.language, this.highlightLines, options));
- }
- };
- };
-
- return ret(this);
- }
-}
-
-module.exports = LiquidHighlightTag;
diff --git a/src/PrismLoader.js b/src/PrismLoader.js
index 5fa6007..ab9e325 100644
--- a/src/PrismLoader.js
+++ b/src/PrismLoader.js
@@ -1,16 +1,17 @@
-const Prism = require("prismjs");
-const PrismLoader = require("prismjs/components/index.js");
+import Prism from "prismjs";
+import PrismLoader from "prismjs/components/index.js";
+
// Avoid "Language does not exist: " console logs
PrismLoader.silent = true;
-require("prismjs/components/prism-diff.js");
+import "prismjs/components/prism-diff.js";
// Load diff-highlight plugin
-require("prismjs/plugins/diff-highlight/prism-diff-highlight");
+import "prismjs/plugins/diff-highlight/prism-diff-highlight.js";
-const PrismAlias = require("./PrismNormalizeAlias");
+import PrismAlias from "./PrismNormalizeAlias.js";
-module.exports = function(language, options = {}) {
+export default function(language, options = {}) {
let diffRemovedRawName = language;
if(language.startsWith("diff-")) {
diffRemovedRawName = language.substr("diff-".length);
diff --git a/src/PrismNormalizeAlias.js b/src/PrismNormalizeAlias.js
index 7738e05..c593c24 100644
--- a/src/PrismNormalizeAlias.js
+++ b/src/PrismNormalizeAlias.js
@@ -3,9 +3,13 @@ const HARDCODED_ALIASES = {
nunjucks: "jinja2",
};
+import { createRequire } from "node:module";
+
+const require = createRequire(import.meta.url);
+
// This was added to make `ts` resolve to `typescript` correctly.
// The Prism loader doesn’t seem to always handle aliasing correctly.
-module.exports = function(language) {
+export default function(language) {
try {
// Careful this is not public API stuff:
// https://github.com/PrismJS/prism/issues/2146
diff --git a/src/getAttributes.js b/src/getAttributes.js
index 603c6a5..cf090a5 100644
--- a/src/getAttributes.js
+++ b/src/getAttributes.js
@@ -1,3 +1,5 @@
+import { escapeAttribute } from "entities/escape";
+
function attributeEntryToString(attribute, context) {
let [key, value] = attribute;
@@ -11,6 +13,9 @@ function attributeEntryToString(attribute, context) {
);
}
+ if(typeof value === "string") {
+ value = escapeAttribute(value);
+ }
return `${key}="${value}"`;
}
@@ -34,7 +39,7 @@ function attributeEntryToString(attribute, context) {
* @param {object} context.options The options passed to the syntax highlighter.
* @returns {string} A string containing the above HTML attributes preceded by a single space.
*/
-function getAttributes(attributes, context = {}) {
+export default function getAttributes(attributes, context = {}) {
let langClass = context.language ? `language-${context.language}` : "";
if (!attributes) {
@@ -58,5 +63,3 @@ function getAttributes(attributes, context = {}) {
throw new Error("Syntax highlighter plugin custom attributes on and must be an object. Received: " + JSON.stringify(attributes));
}
}
-
-module.exports = getAttributes;
diff --git a/src/hasTemplateFormat.js b/src/hasTemplateFormat.js
index ee81e89..677fb34 100644
--- a/src/hasTemplateFormat.js
+++ b/src/hasTemplateFormat.js
@@ -1,10 +1,10 @@
-module.exports = function(templateFormats = ["*"], format = false) {
+export default function(templateFormats = ["*"], format = false) {
if(!Array.isArray(templateFormats)) {
templateFormats = [templateFormats];
}
if( Array.isArray(templateFormats) ) {
- if( templateFormats.indexOf("*") > -1 || templateFormats.indexOf(format) > -1 ) {
+ if(templateFormats.includes("*") || format && templateFormats.includes(format)) {
return true;
}
}
diff --git a/src/markdownSyntaxHighlightOptions.js b/src/markdownSyntaxHighlightOptions.js
deleted file mode 100644
index 098c683..0000000
--- a/src/markdownSyntaxHighlightOptions.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const Prism = require("prismjs");
-const PrismLoader = require("./PrismLoader");
-const HighlightLinesGroup = require("./HighlightLinesGroup");
-const getAttributes = require("./getAttributes");
-
-module.exports = function (options = {}) {
- return function(str, language) {
- if(!language) {
- // empty string means defer to the upstream escaping code built into markdown lib.
- return "";
- }
-
-
- let split = language.split("/");
- if( split.length ) {
- language = split.shift();
- }
-
- let html;
- if(language === "text") {
- html = str;
- } else {
- let loader = PrismLoader(language, options)
- if(!loader) {
- html = str;
- } else {
- html = Prism.highlight(str, loader, language);
- }
- }
-
- let hasHighlightNumbers = split.length > 0;
- let highlights = new HighlightLinesGroup(split.join("/"), "/");
- let lines = html.split("\n");
-
- // Trim last line if it is empty
- if (lines[lines.length - 1] === "") {
- lines = lines.slice(0, -1);
- }
-
- lines = lines.map(function(line, j) {
- if(options.alwaysWrapLineHighlights || hasHighlightNumbers) {
- let lineContent = highlights.getLineMarkup(j, line);
- return lineContent;
- }
- return line;
- });
-
- const context = { content: str, language: language, options: options };
- const preAttributes = getAttributes(options.preAttributes, context);
- const codeAttributes = getAttributes(options.codeAttributes, context);
-
- return `${lines.join(options.lineSeparator || "
")}
`;
- };
-};
diff --git a/syntax-highlight.webc b/syntax-highlight.webc
index d894ea3..54a0bbf 100644
--- a/syntax-highlight.webc
+++ b/syntax-highlight.webc
@@ -1,5 +1,5 @@
-