From b27cf0380ab8dae945c89e7f536a7b1f4debfd15 Mon Sep 17 00:00:00 2001 From: Andrew Lisowski Date: Sun, 14 Feb 2021 09:49:37 -0800 Subject: [PATCH] upgrade deps, convert to TypeScript, and add "langs" option --- .gitignore | 1 + README.md | 21 ++++-- index.js | 120 ------------------------------- package-lock.json | 179 ++++++++++++++++++++-------------------------- package.json | 9 +-- src/index.ts | 111 ++++++++++++++++++++++++++++ tsconfig.json | 12 ++++ 7 files changed, 225 insertions(+), 228 deletions(-) delete mode 100644 index.js create mode 100644 src/index.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index ad46b30..9c8e13a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ logs npm-debug.log* yarn-debug.log* yarn-error.log* +dist # Runtime data pids diff --git a/README.md b/README.md index 0638973..4f0c652 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ var shiki = require('rehype-shiki') rehype() .data('settings', {fragment: true}) .use(shiki) - .process(vfile.readSync('example.html'), function(err, file) { + .process(vfile.readSync('example.html'), function (err, file) { console.error(report(err || file)) console.log(String(file)) }) @@ -46,10 +46,11 @@ Now, running `node example` yields: example.html: no issues found

Hello World!

-
var name = "World";
+
var name = "World";
 console.warn("Hello, " + name + "!")
 
- ``` ## API @@ -58,7 +59,7 @@ example.html: no issues found Apply syntax highlighting to `pre > code` using [**shiki**][shiki]; which tokenises the code block and new [**hast**][hast] nodes are subsequently created from (using this plugin). -Configure the language by using the `language-foo` class on the `code` element. For example; +Configure the language by using the `language-foo` class on the `code` element. For example; ```html
console.log("Hello world!")
@@ -78,6 +79,18 @@ This is in respect to the [mdast-util-to-hast code handler](https://github.com/s `boolean`, default: `true` - Whether to apply the background theme colour to the `pre` element. +##### `options.langs` + +`ILanguageRegistration[]`, default: `[]` - Languages other than the default languages to load into shiki + +```json +{ + "id": "rockstar", + "scopeName": "source.rockstar", + "path": "./rockstar.tmLanguage.json" // or `plist` +} +``` + ## License [MIT][license] © [@rsclarke][rsclarke] diff --git a/index.js b/index.js deleted file mode 100644 index 4662ca1..0000000 --- a/index.js +++ /dev/null @@ -1,120 +0,0 @@ -const shiki = require('shiki') -const visit = require('unist-util-visit') -const { - commonLangIds, - commonLangAliases, - otherLangIds -} = require('shiki-languages') -const hastToString = require('hast-util-to-string') -const u = require('unist-builder') - -const languages = [...commonLangIds, ...commonLangAliases, ...otherLangIds] - -module.exports = attacher - -function attacher(options) { - var settings = options || {} - var theme = settings.theme || 'nord' - var useBackground = - typeof settings.useBackground === 'undefined' - ? true - : Boolean(settings.useBackground) - var shikiTheme - var highlighter - - try { - shikiTheme = shiki.getTheme(theme) - } catch (_) { - try { - shikiTheme = shiki.loadTheme(theme) - } catch (_) { - throw new Error('Unable to load theme: ' + theme) - } - } - - return transformer - - async function transformer(tree) { - highlighter = await shiki.getHighlighter({ - theme: shikiTheme, - langs: languages - }) - visit(tree, 'element', visitor) - } - - function visitor(node, index, parent) { - if (!parent || parent.tagName !== 'pre' || node.tagName !== 'code') { - return - } - - if (useBackground) { - addStyle(parent, 'background: ' + shikiTheme.bg) - } - - const lang = codeLanguage(node) - - if (!lang) { - // Unknown language, fall back to a foreground colour - addStyle(node, 'color: ' + shikiTheme.settings.foreground) - return - } - - const tokens = highlighter.codeToThemedTokens(hastToString(node), lang) - const tree = tokensToHast(tokens) - - node.children = tree - } -} - -function tokensToHast(lines) { - let tree = [] - - for (const line of lines) { - if (line.length === 0) { - tree.push(u('text', '\n')) - } else { - for (const token of line) { - tree.push( - u( - 'element', - { - tagName: 'span', - properties: {style: 'color: ' + token.color} - }, - [u('text', token.content)] - ) - ) - } - - tree.push(u('text', '\n')) - } - } - - // Remove the last \n - tree.pop() - - return tree -} - -function addStyle(node, style) { - var props = node.properties || {} - var styles = props.style || [] - styles.push(style) - props.style = styles - node.properties = props -} - -function codeLanguage(node) { - const className = node.properties.className || [] - var value - - for (const element of className) { - value = element - - if (value.slice(0, 9) === 'language-') { - return value.slice(9) - } - } - - return null -} diff --git a/package-lock.json b/package-lock.json index ad9b05a..4e18de7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, "requires": { "@babel/highlight": "^7.8.3" } @@ -62,6 +63,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -400,6 +402,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -408,6 +411,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -571,7 +575,8 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -735,6 +740,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -892,11 +898,6 @@ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -993,6 +994,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -1076,6 +1078,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -1083,12 +1086,8 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "commondir": { "version": "1.0.1", @@ -1105,7 +1104,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "configstore": { "version": "5.0.1", @@ -1396,11 +1396,6 @@ "minimalistic-assert": "^1.0.0" } }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -1597,7 +1592,8 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "eslint": { "version": "7.5.0", @@ -2235,7 +2231,8 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, "espurify": { "version": "2.0.1", @@ -2278,7 +2275,8 @@ "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, "events": { "version": "3.2.0", @@ -2620,7 +2618,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "function-bind": { "version": "1.1.1", @@ -2665,6 +2664,7 @@ "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2953,6 +2953,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -2961,7 +2962,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.5", @@ -3311,7 +3313,8 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "js-types": { "version": "1.0.0", @@ -3323,6 +3326,7 @@ "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3362,6 +3366,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, "requires": { "minimist": "^1.2.5" }, @@ -3369,7 +3374,8 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true } } }, @@ -3739,6 +3745,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3746,7 +3753,8 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "minimist-options": { "version": "4.1.0", @@ -3792,6 +3800,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -3999,17 +4008,17 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } }, "onigasm": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.4.tgz", - "integrity": "sha512-BJKxCTsK0mrLh+A6AuNzknxaULZRKM5uywA2goluMLLCjfMm/PTUa0M7oSH1Ltb6CT1oKXn2atHR75Y3JQ0SSg==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", + "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", "requires": { - "lru-cache": "^5.1.1", - "tslint": "^5.20.1" + "lru-cache": "^5.1.1" } }, "open": { @@ -4176,7 +4185,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "3.1.1", @@ -4187,7 +4197,8 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true }, "path-type": { "version": "4.0.0", @@ -4603,6 +4614,7 @@ "version": "1.15.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, "requires": { "path-parse": "^1.0.6" } @@ -4755,31 +4767,27 @@ "dev": true }, "shiki": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.1.7.tgz", - "integrity": "sha512-9J0PhAdXv6tt3FZf82oKZkcV8c8NRZYJEOH0eIrrxfcyNzMuB79tJFGFSI3OhhiYFL5namob/Ii0Ri4iDoF15A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.2.tgz", + "integrity": "sha512-BjUCxVbxMnvjs8jC4b+BQ808vwjJ9Q8NtLqPwXShZ307HdXiDFYP968ORSVfaTNNSWYDBYdMnVKJ0fYNsoZUBA==", "requires": { - "onigasm": "^2.2.1", - "shiki-languages": "^0.1.6", - "shiki-themes": "^0.1.7", - "vscode-textmate": "git+https://github.com/octref/vscode-textmate.git" + "onigasm": "^2.2.5", + "vscode-textmate": "^5.2.0" + }, + "dependencies": { + "vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==" + } } }, "shiki-languages": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/shiki-languages/-/shiki-languages-0.1.6.tgz", - "integrity": "sha512-rMu+z97UCPKMtPBkzLBItReawXnlOgXZmELFwI/s3ATxd9VzJgSQTtQW/hmW5EYCrzF2kAUjoOnn+50/MPWjgQ==", - "requires": { - "vscode-textmate": "git+https://github.com/octref/vscode-textmate.git" - } - }, - "shiki-themes": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/shiki-themes/-/shiki-themes-0.1.7.tgz", - "integrity": "sha512-mpF/VynGun/uNdjOIPnyPv4boN/QYDh+zE94SavgvmatMHkXXjZhls19Xv9rcRwuxUrWfXjaPkEZj7VAk94GGg==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/shiki-languages/-/shiki-languages-0.2.7.tgz", + "integrity": "sha512-REmakh7pn2jCn9GDMRSK36oDgqhh+rSvJPo77sdWTOmk44C5b0XlYPwJZcFOMJWUZJE0c7FCbKclw4FLwUKLRw==", "requires": { - "json5": "^2.1.0", - "vscode-textmate": "git+https://github.com/octref/vscode-textmate.git" + "vscode-textmate": "^5.2.0" } }, "signal-exit": { @@ -4996,7 +5004,8 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true }, "static-extend": { "version": "0.1.2", @@ -5133,6 +5142,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { "has-flag": "^3.0.0" }, @@ -5140,7 +5150,8 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true } } }, @@ -5317,42 +5328,8 @@ "tslib": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", - "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==" - }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "requires": { - "tslib": "^1.8.1" - } - } - } + "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==", + "dev": true }, "tsutils": { "version": "3.17.1", @@ -5432,9 +5409,9 @@ "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" }, "unist-util-is": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz", - "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.4.tgz", + "integrity": "sha512-3dF39j/u423v4BBQrk1AQ2Ve1FxY5W3JKwXxVFzBODQ6WEvccguhgp802qQLKSnxPODE6WuRZtV+ohlUg4meBA==" }, "unist-util-visit": { "version": "2.0.3", @@ -5447,9 +5424,9 @@ } }, "unist-util-visit-parents": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.0.tgz", - "integrity": "sha512-0g4wbluTF93npyPrp/ymd3tCDTMnP0yo2akFD2FIBAYXq/Sga3lwaU1D8OYKbtpioaI6CkDcQ6fsMnmtzt7htw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", "requires": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" @@ -5662,8 +5639,9 @@ "dev": true }, "vscode-textmate": { - "version": "git+https://github.com/octref/vscode-textmate.git#e65aabe2227febda7beaad31dd0fca1228c5ddf3", - "from": "git+https://github.com/octref/vscode-textmate.git" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==" }, "which": { "version": "2.0.2", @@ -5717,7 +5695,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write": { "version": "1.0.3", diff --git a/package.json b/package.json index 45392e1..80f9c8e 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,12 @@ "description": "rehype plugin to highlight code blocks with shiki", "main": "index.js", "files": [ - "index.js" + "dist" ], "scripts": { "format": "prettier --write '**/*.js' && xo --fix", - "test": "xo" + "test": "xo", + "build": "tsc" }, "repository": { "type": "git", @@ -30,8 +31,8 @@ "homepage": "https://github.com/rsclarke/rehype-shiki#readme", "dependencies": { "hast-util-to-string": "^1.0.4", - "shiki": "^0.1.7", - "shiki-languages": "^0.1.6", + "shiki": "^0.9.2", + "shiki-languages": "^0.2.7", "unist-builder": "^2.0.3", "unist-util-visit": "^2.0.3" }, diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..4b649df --- /dev/null +++ b/src/index.ts @@ -0,0 +1,111 @@ +import * as shiki from 'shiki' +import {BUNDLED_LANGUAGES} from 'shiki-languages' +import {Node} from 'unist' +import visit from 'unist-util-visit' +import hastToString from 'hast-util-to-string' +import u from 'unist-builder' + +interface NodeWithChildren extends Node { + children?: Node[] + value?: string +} + +function tokensToHast(lines: shiki.IThemedToken[][]) { + let tree = [] + + for (const line of lines) { + if (line.length === 0) { + tree.push(u('text', '\n')) + } else { + for (const token of line) { + tree.push( + u( + 'element', + { + tagName: 'span', + properties: {style: `color: ${token.color!}`} + }, + [u('text', token.content)] + ) + ) + } + + tree.push(u('text', '\n')) + } + } + + // Remove the last \n + tree.pop() + + return tree +} + +function addStyle(node: Node, style: string) { + const props = (node.properties || {}) as Record + + props.style = props.style ? props.style + ';' + style : style + node.properties = props +} + +function codeLanguage(node: Node) { + const props = (node.properties || {}) as Record + const className = props.className || [] + + let value: string + + for (const element of className) { + value = element + + if (value.startsWith('language-')) { + return value.slice(9) + } + } + + return null +} + +interface PluginOptions { + theme?: string + useBackground?: boolean + langs?: shiki.ILanguageRegistration[] +} + +function attacher(options: PluginOptions = {}) { + const {theme = 'github-light', useBackground = true, langs = []} = options + + let highlighter: shiki.Highlighter + + return transformer + + async function transformer(tree: NodeWithChildren) { + highlighter = await shiki.getHighlighter({ + theme, + langs: [...BUNDLED_LANGUAGES, ...langs] + }) + + visit(tree, 'element', (node, _, parent) => { + if (!parent || parent.tagName !== 'pre' || node.tagName !== 'code') { + return + } + + if (useBackground) { + addStyle(node, 'background: ' + highlighter.getBackgroundColor()) + } + + const lang = codeLanguage(node) + + if (!lang) { + // Unknown language, fall back to a foreground colour + addStyle(node, 'color: ' + highlighter.getForegroundColor()) + return + } + + const tokens = highlighter.codeToThemedTokens(hastToString(node), lang) + const tree = tokensToHast(tokens) + + node.children = tree + }) + } +} + +export = attacher diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f149629 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,12 @@ +{ + "include": ["src/**/*", "typings/**/*"], + + "compilerOptions": { + "outDir": "dist", + "jsx": "react", + "declaration": true, + "esModuleInterop": true, + "lib": ["DOM", "es2019"], + "strict": true + } +}