From 9ec4418afe94341595856ba83830a799f3cfd280 Mon Sep 17 00:00:00 2001 From: MDLeom <43627182+curbengh@users.noreply.github.com> Date: Sun, 26 Jul 2020 13:25:25 +0100 Subject: [PATCH] feat: reimplementation - Support arguments in tag plugins as renderer options - Support front-matter as renderer options - Support _config.yml as renderer options - Requires Node 10.13+, drop Node 8 - chore(deps): update katex from 0.6.0 to 0.12.0 - chore(deps): add mathjax - chore(deps): update hexo-util from 1.0.0 to 2.2.0 - chore(dev-deps): update eslint from 6.1.0 to 7.5.0 - chore(dev-deps): update eslint-config-hexo from 3.0.0 to 4.1.0 - chore(deps): update mocha from 6.1.2 to 8.0.1 - chore(deps): remove html-entities - chore(dev-deps): remove chai-as-promised, cpx, hexo-fs, npm-run-all & rimraf - ci(travis): add Windows - ci: add GitHub Actions --- .eslintignore | 2 + .eslintrc | 3 + .eslintrc.json | 6 - .github/workflows/linter.yml | 27 ++ .github/workflows/tester.yml | 30 ++ .gitignore | 7 +- .mocharc.yml | 7 + .npmrc | 1 + .travis.yml | 15 +- LICENSE | 21 ++ README.md | 327 ++++++++---------- appveyor.yml | 41 --- asset/inject.swig | 17 - dist/style.css | 122 +++++++ index.js | 33 ++ lib/inject/katex.js | 8 + lib/inject/mathjax.js | 8 + lib/katex.js | 19 + lib/mathjax.js | 31 ++ package.json | 69 ++-- src/consts.js | 9 - src/extend.js | 19 - src/filter/inject.js | 34 -- src/filter/post.js | 34 -- src/index.js | 5 - src/main.js | 21 -- src/option.js | 48 --- src/tag/math.js | 42 --- test/.eslintrc | 6 + test/.eslintrc.json | 10 - .../source/_expected/katex/block.md.skip | 1 - .../_expected/katex/hello-world.md.expected | 13 - .../source/_expected/katex/inline.md.skip | 1 - .../_expected/katex/tag-escape.md.expected | 1 - .../_expected/katex/tag-in-list.md.expected | 6 - .../source/_expected/katex/tag.md.expected | 6 - .../_expected/mathjax/block.md.expected | 1 - .../_expected/mathjax/hello-world.md.expected | 13 - .../_expected/mathjax/inline.md.expected | 1 - .../_expected/mathjax/tag-escape.md.expected | 1 - .../_expected/mathjax/tag-in-list.md.expected | 6 - .../source/_expected/mathjax/tag.md.expected | 6 - test/asset/source/_posts/block.md | 8 - test/asset/source/_posts/hello-world.md | 37 -- test/asset/source/_posts/inline.md | 5 - test/asset/source/_posts/tag-escape.md | 7 - test/asset/source/_posts/tag-in-list.md | 9 - test/asset/source/_posts/tag.md | 14 - test/index.js | 194 +++++++++++ test/katex.spec.js | 24 -- test/mathjax.spec.js | 37 -- test/mocha.opts | 3 - test/scaffolds.js | 10 - test/util.js | 49 --- 54 files changed, 711 insertions(+), 764 deletions(-) create mode 100755 .eslintignore create mode 100755 .eslintrc delete mode 100644 .eslintrc.json create mode 100644 .github/workflows/linter.yml create mode 100644 .github/workflows/tester.yml mode change 100644 => 100755 .gitignore create mode 100755 .mocharc.yml create mode 100755 .npmrc create mode 100644 LICENSE delete mode 100644 appveyor.yml delete mode 100644 asset/inject.swig create mode 100644 dist/style.css create mode 100755 index.js create mode 100755 lib/inject/katex.js create mode 100755 lib/inject/mathjax.js create mode 100755 lib/katex.js create mode 100755 lib/mathjax.js delete mode 100644 src/consts.js delete mode 100644 src/extend.js delete mode 100644 src/filter/inject.js delete mode 100644 src/filter/post.js delete mode 100644 src/index.js delete mode 100644 src/main.js delete mode 100644 src/option.js delete mode 100644 src/tag/math.js create mode 100755 test/.eslintrc delete mode 100644 test/.eslintrc.json delete mode 100644 test/asset/source/_expected/katex/block.md.skip delete mode 100644 test/asset/source/_expected/katex/hello-world.md.expected delete mode 100644 test/asset/source/_expected/katex/inline.md.skip delete mode 100644 test/asset/source/_expected/katex/tag-escape.md.expected delete mode 100644 test/asset/source/_expected/katex/tag-in-list.md.expected delete mode 100644 test/asset/source/_expected/katex/tag.md.expected delete mode 100644 test/asset/source/_expected/mathjax/block.md.expected delete mode 100644 test/asset/source/_expected/mathjax/hello-world.md.expected delete mode 100644 test/asset/source/_expected/mathjax/inline.md.expected delete mode 100644 test/asset/source/_expected/mathjax/tag-escape.md.expected delete mode 100644 test/asset/source/_expected/mathjax/tag-in-list.md.expected delete mode 100644 test/asset/source/_expected/mathjax/tag.md.expected delete mode 100644 test/asset/source/_posts/block.md delete mode 100644 test/asset/source/_posts/hello-world.md delete mode 100644 test/asset/source/_posts/inline.md delete mode 100644 test/asset/source/_posts/tag-escape.md delete mode 100644 test/asset/source/_posts/tag-in-list.md delete mode 100644 test/asset/source/_posts/tag.md create mode 100755 test/index.js delete mode 100644 test/katex.spec.js delete mode 100644 test/mathjax.spec.js delete mode 100644 test/mocha.opts delete mode 100644 test/scaffolds.js delete mode 100644 test/util.js diff --git a/.eslintignore b/.eslintignore new file mode 100755 index 0000000..e1c1079 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +coverage/ +tmp/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100755 index 0000000..d6d70b6 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "hexo" +} \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 3741607..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "hexo", - "globals": { - "hexo": true - } -} diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..c1eaaf8 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,27 @@ +name: Linter + +on: [push, pull_request] + +jobs: + linter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 12.x + uses: actions/setup-node@v1 + with: + node-version: '12.x' + - name: Cache NPM dependencies + uses: actions/cache@v1 + with: + path: node_modules + key: ${{ runner.OS }}-npm-cache + restore-keys: | + ${{ runner.OS }}-npm-cache + - name: Install Dependencies + run: npm install + - name: Lint + run: | + npm run eslint + env: + CI: true diff --git a/.github/workflows/tester.yml b/.github/workflows/tester.yml new file mode 100644 index 0000000..b5a5742 --- /dev/null +++ b/.github/workflows/tester.yml @@ -0,0 +1,30 @@ +name: Tester + +on: [push, pull_request] + +jobs: + tester: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + node-version: ['10.x', '12.x', '14.x'] + fail-fast: false + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Cache NPM dependencies + uses: actions/cache@v1 + with: + path: node_modules + key: ${{ runner.os }}-npm-cache + restore-keys: ${{ runner.os }}-npm-cache + - name: Install Dependencies + run: npm install + - name: Test + run: npm run test + env: + CI: true diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 7bfede5..4863e8a --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ + +.DS_Store node_modules/ -lib/ -test/site/ package-lock.json -*.orig +tmp/ +*.log \ No newline at end of file diff --git a/.mocharc.yml b/.mocharc.yml new file mode 100755 index 0000000..2a55f11 --- /dev/null +++ b/.mocharc.yml @@ -0,0 +1,7 @@ +color: true +reporter: spec +ui: bdd +full-trace: true +exit: true +require: + - "chai/register-should" diff --git a/.npmrc b/.npmrc new file mode 100755 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.travis.yml b/.travis.yml index b88fb32..076b079 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,16 @@ +os: + - linux + - windows + language: node_js + node_js: - - "8" - "10" - - "node" \ No newline at end of file + - "12" + - "14" + +script: + - if [[ $TRAVIS_OS_NAME == "linux" ]]; then + npm run eslint; + fi + - npm run test diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c47134b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 Hexo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 96187bb..6f5b1aa 100644 --- a/README.md +++ b/README.md @@ -1,230 +1,207 @@ # hexo-math -[![Build Status](https://travis-ci.org/hexojs/hexo-math.svg?branch=master)](https://travis-ci.org/hexojs/hexo-math) -[![NPM version](https://badge.fury.io/js/hexo-math.svg)](https://www.npmjs.com/package/hexo-math) -[![Build status](https://ci.appveyor.com/api/projects/status/github/hexojs/hexo-math?branch=master&svg=true)](https://ci.appveyor.com/project/hexojs/hexo-math/branch/master) +[![npm version](https://badge.fury.io/js/hexo-math.svg)](https://www.npmjs.com/package/hexo-math) +[![npm license](https://img.shields.io/npm/l/hexo-math)](./LICENSE) +![npm download](https://img.shields.io/npm/dt/hexo-math) -A hexo plugin that uses MathJax/KaTeX to render math equations. Features: +Embed [KaTeX] and [MathJax] in [Hexo] post/page via tag plugins. Equations are rendered in Hexo (server-side), so browser-side javascript library is not needed and should be removed. CSS stylesheets are included by default but can be easily replaced. -* Dynamic MathJax/KaTeX injection on demand -* Provide support to both inline math syntax and math tags -* Server-side rendering with KaTeX (new in 3.0.0) +## Installation -## New in 3.0.0: Server-side rendering with KaTeX - -Since 3.0.0, hexo-math added support to [KaTeX](https://github.com/Khan/KaTeX) . - -It has serval advantages over MathJax: - -* Server-side rendering -* Faster and smaller - -Current limitations are: -* It supports less commands than MathJax. Check out [this list](https://github.com/Khan/KaTeX/wiki/Function-Support-in-KaTeX) for more information. -* hexo-math will only render math tags with KaTeX - -## Install - -> npm install hexo-math --save - -See [Migration Note](#migration-note) if you are upgrading from an older version. - -## Config - -In your site's `_config.yml`: - -```yaml -math: - engine: 'mathjax' # or 'katex' - mathjax: - src: custom_mathjax_source - config: - # MathJax config - katex: - css: custom_css_source - js: custom_js_source # not used - config: - # KaTeX config -``` - -Your config will be merged into default config: -```js -const DEFAULT_OPTS = { - engine: 'mathjax', - mathjax: { - src: "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js", - config: { - tex2jax: { - inlineMath: [ ['$','$'], ["\\(","\\)"] ], - skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'], - processEscapes: true - }, - TeX: { - equationNumbers: { - autoNumber: "AMS" - } - } - } - }, - katex: { - css: "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css", - js: "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js", - config: { - throwOnError: false, - errorColor: "#cc0000" - } - } -} +```bash +$ npm i hexo-math --save ``` -## Usage +- Requires Hexo 5+ -You can use inline math syntax directly. But always remember to escape any special characters by adding a ```\``` before it. -LaTex equations usually contains tones of special characters like ```\```, which makes it painful to escape them one by one. In such cases, you can use hexo-math's tags to make your life easier. +## Usage -**Inline:** +**KaTeX** -```markdown -Simple inline $a = b + c$. ``` - -**Block:** - -```markdown -$$\frac{\partial u}{\partial t} -= h^2 \left( \frac{\partial^2 u}{\partial x^2} + -\frac{\partial^2 u}{\partial y^2} + -\frac{\partial^2 u}{\partial z^2}\right)$$ +{% katex '{options}' %} +content +{% endkatex %} ``` -**Tag:** +### Examples -Single line content will be parsed as inline math (same as `$...$`): -```markdown -This equation {% math %}\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1 {% endmath %} is inline. ``` - -Multiple line content will be parsed as block math (same as `$$...$$`) -```markdown -{% math %} -\begin{aligned} -\dot{x} & = \sigma(y-x) \\ -\dot{y} & = \rho x - y - xz \\ -\dot{z} & = -\beta z + xy -\end{aligned} -{% endmath %} +{% katex %} +c = \pm\sqrt{a^2 + b^2} +{% endkatex %} ``` -> **Deprecated since 2.0.0** +Override [front-matter](#per-article-configuration) and [global options](#global-options) for a particular content. Options must be specified in [JSON](https://en.wikipedia.org/wiki/JSON#Example) format. ->**Tag Block:** - -```markdown -{% math_block %} -\begin{aligned} -\dot{x} & = \sigma(y-x) \\ -\dot{y} & = \rho x - y - xz \\ -\dot{z} & = -\beta z + xy -\end{aligned} -{% endmath_block %} +``` +{% katex '{ "output": "mathml", "felqn": true, "minRuleThickness": 0.05, "throwOnError": true }' %} +c = \pm\sqrt{a^2 + b^2} +{% endkatex %} ``` -## Migration Note - -### Migrating to 3.0.0 - -* `mathjax` should be moved under `math` section in your `_config.yml` - -### Migrating to 2.1.0 +**MathJax** -* `math_block` is removed +``` +{% mathjax '{options}' %} +content +{% endmathjax %} +``` -### Migrating to 2.0.0 +### Examples -* `math_block` is deprecated (but still usable. This won't break your site) -* `math` block is used to handle both inline and block math due to breaking changes made since Hexo 3.x. (This will break your site if you're using `math` block) +``` +{% mathjax %} +\frac{1}{x^2-1} +{% endmathjax %} +``` -Since Hexo 3.x, nunjucks is used as tag engine instead of swig. Syntax like this won't work any more: +Override [front-matter](#per-article-configuration) and [global options](#global-options) for a particular content. Options must be specified in [JSON](https://en.wikipedia.org/wiki/JSON#Example) format. -```markdown -{% math \frac{|ax + by + c|}{\sqrt{a^{2}+b^{2}}} %} ``` - -Instead, you should use open and close tag since this version: -```markdown -{% math %}\frac{|ax + by + c|}{\sqrt{a^{2}+b^{2}}} {% endmath %} +{% mathjax '{ "conversion": { "em": 14 }, "tex": { "tags": "ams" }, "svg": { "exFactor": 0.03 } }' %} +\frac{1}{x^2-1} +{% endmathjax %} ``` -Change all your `math` tags accordingly. +## Per-article configuration -### Migrating to 1.0.6 +Override the global options via the front-matter of an article (post/page) basis. -**!!!IMPORTANT!!!** - -Since 1.0.6, hexo-math uses a different approach to inject MathJax into your site. MathJax will be injected on-the-fly and on-demand. This means: +``` yml +--- +title: On the Electrodynamics of Moving Bodies +categories: Physics +date: 1905-06-30 12:00:00 +katex: false +mathjax: false +--- +``` -* **You are no longer required to run `hexo math install`** -* MathJax will not be loaded on pages without math tags allowing faster loading speed. +### Options -If you have run `hexo math install` before, please **do run:** +Disable math renderer in an article: +``` yml +--- +katex: false +mathjax: false +--- ``` -$ hexo math -``` - -This will clean up previous installation. Or you can re-install your theme if for some reason this does not work. +Override global options: +``` yml +--- +katex: + output: 'mathml' + felqn: true + minRuleThickness: 0.05 + throwOnError: true +mathjax: + conversion: + em: 14 + tex: + tags: 'ams' + svg: + exFactor: 0.03 +--- +``` -### From 1.0.4 to 1.0.5 (Support Hexo 3.0) +## Global Options -Hexo 3.0 introduces multiple breaking changes. Versions before 1.0.5 won't work with it. -The following changes are made since 1.0.5 to adapt the new 3.0 API: +```yaml +# _config.yml +math: + katex: + css: 'https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css' + options: + throwOnError: false + mathjax: + css: 'https://cdn.jsdelivr.net/gh/hexojs/hexo-math/master/dist/style.css' + options: + conversion: + display: false + tex: + svg: +``` -* Block math tag renamed from `math-block` to `math_block` +- **css**: Location of stylesheet. + * Specify a relative path if you're self-hosting the stylesheet. + * Example: `css: '/css/style.css'` refers to `source/css/style.css` or `themes//source/css/style.css`. + * It can be disabled (`css: false`) if the installed theme has already included one. + * KaTeX defaults to the [official stylesheet](https://github.com/KaTeX/KaTeX/blob/master/src/katex.less). + * MathJax defaults to [style.css](dist/style.css) -### From 1.0.3 and before +### KaTeX -Since 1.0.4, MathJax scripts will be injected in `` section instead of `` section. -Before you update `hexo-math` to newer version, you should run: +``` yaml + katex: + options: + throwOnError: false +``` -> $ hexo math uninstall +- **options**: Refer to the [documentation](https://katex.org/docs/options.html) for available options. -After `hexo-math` is updated, run install again: +### MathJax -> $ hexo math install +``` yaml + mathjax: + options: + conversion: + display: false + tex: + svg: +``` +- **options**: Rendering options. + * **conversion**: [Conversion options](https://docs.mathjax.org/en/latest/web/typeset.html#conversion-options). + * **tex**: [TeX input options](https://docs.mathjax.org/en/latest/options/input/tex.html). + * **svg**: [SVG output options](https://docs.mathjax.org/en/latest/options/output/svg.html). -## Development +## Configuration priority -### Test +Unique options are combined, if there is any duplicate options, [argument](#usage) overrides [front-matter](#per-article-configuration), front-matter overrides [global options](#global-options). -To run the test suit, first you should install dependencies for the test site: +**Example**: -```bash -> $ cd .test-site -> $ npm install +``` +{% katex '{ "output": "html", "felqn": true }' %} +content +{% endkatex %} ``` -Then run `npm test` from `hexo-math`'s root dir. - -#### Add post specs - -In `.test-site/source/_post` folder, add a pair of file for each test cases: - -* [test-case-name].md -* [test-case-name].md.expected +``` yml +# front-matter +--- +katex: + output: 'mathml' + minRuleThickness: 0.05 + throwOnError: true +--- +``` -The `.md` file contains the Markdown source of a post and the `.expected` file contains expected HTML rendered from the source. +``` yml +# _config.yml +math: + katex: + options: + minRuleThickness: 0.03 + maxExpand: 900 +``` -If a test case is added to address certain issues, the issue id should be added to the `.md`'s front matter section: +Following options will be parsed as argument for that specific content: -```markdown -title: "Tag Escape" -date: 2015-04-21 02:47:19 -tags: -issues: -- 10 ---- -{% math %} |a|<1 {% endmath %} +``` js +{ + output: 'html', + felqn: true, + minRuleThickness: 0.05, + throwOnError: true, + maxExpand: 900 +} ``` + +[KaTex]: https://katex.org/ +[MathJax]: https://www.mathjax.org/ +[Hexo]: https://hexo.io/ diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index ef729ca..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Fix line endings in Windows. (runs before repo cloning) -init: - - git config --global core.autocrlf input - -image: -- Visual Studio 2019 - -# Test against these versions of Node.js. -environment: - matrix: - - nodejs_version: "8" - - nodejs_version: "10" - - nodejs_version: "12" - -matrix: - fast_finish: true - -# Install scripts. (runs after repo cloning) -install: - - ps: Install-Product node $env:nodejs_version - -before_test: - - npm install - -cache: - - node_modules -> package.json - -# Post-install test scripts. -test_script: - # Output useful info for debugging. - - node --version - - npm --version - # Run tests - - npm test - - npm run lint - -# Don't actually build. -build: off - -# Set build version format here instead of in the admin panel. -version: "{build}" diff --git a/asset/inject.swig b/asset/inject.swig deleted file mode 100644 index a454073..0000000 --- a/asset/inject.swig +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - diff --git a/dist/style.css b/dist/style.css new file mode 100644 index 0000000..6b7036d --- /dev/null +++ b/dist/style.css @@ -0,0 +1,122 @@ +/* ! + * Adapted from hexo-filter-mathjax 0.5.3 + * Licensed MIT (c) 2019-2020 Mimi (https://zhangshuqiao.org) + */ + +mjx-container[jax="SVG"] { + direction: ltr; +} + +mjx-container[jax="SVG"] > svg { + overflow: visible; +} + +mjx-container[jax="SVG"] > svg a { + fill: blue; + stroke: blue; +} + +mjx-container[jax="SVG"][display="true"] { + display: block; + text-align: center; + margin: 1em 0; +} + +mjx-container[jax="SVG"][justify="left"] { + text-align: left; +} + +mjx-container[jax="SVG"][justify="right"] { + text-align: right; +} + +g[data-mml-node="merror"] > g { + fill: red; + stroke: red; +} + +g[data-mml-node="merror"] > rect[data-background] { + fill: yellow; + stroke: none; +} + +g[data-mml-node="mtable"] > line[data-line] { + stroke-width: 70px; + fill: none; +} + +g[data-mml-node="mtable"] > rect[data-frame] { + stroke-width: 70px; + fill: none; +} + +g[data-mml-node="mtable"] > .mjx-dashed { + stroke-dasharray: 140; +} + +g[data-mml-node="mtable"] > .mjx-dotted { + stroke-linecap: round; + stroke-dasharray: 0,140; +} + +g[data-mml-node="mtable"] > svg { + overflow: visible; +} + +[jax="SVG"] mjx-tool { + display: inline-block; + position: relative; + width: 0; + height: 0; +} + +[jax="SVG"] mjx-tool > mjx-tip { + position: absolute; + top: 0; + left: 0; +} + +mjx-tool > mjx-tip { + display: inline-block; + padding: .2em; + border: 1px solid #888; + font-size: 70%; + background-color: #F8F8F8; + color: black; + box-shadow: 2px 2px 5px #AAAAAA; +} + +g[data-mml-node="maction"][data-toggle] { + cursor: pointer; +} + +mjx-status { + display: block; + position: fixed; + left: 1em; + bottom: 1em; + min-width: 25%; + padding: .2em .4em; + border: 1px solid #888; + font-size: 90%; + background-color: #F8F8F8; + color: black; +} + +foreignObject[data-mjx-xml] { + font-family: initial; + line-height: normal; + overflow: visible; +} + +.MathJax path { + stroke-width: 3; +} + +mjx-container[display="true"] { + overflow: auto hidden; +} + +mjx-container[display="true"] + br { + display: none; +} diff --git a/index.js b/index.js new file mode 100755 index 0000000..d7d88c2 --- /dev/null +++ b/index.js @@ -0,0 +1,33 @@ +/* global hexo */ + +'use strict'; + +hexo.config.math = Object.assign({ + katex: { + css: 'https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css', + options: { + throwOnError: false + } + }, + mathjax: { + css: 'https://cdn.jsdelivr.net/gh/hexojs/hexo-math/master/dist/style.css', + options: { + // https://docs.mathjax.org/en/latest/web/typeset.html#conversion-options + conversion: { + display: false + }, + // https://docs.mathjax.org/en/latest/options/input/tex.html + tex: {}, + // https://docs.mathjax.org/en/latest/options/output/svg.html + svg: {} + } + } +}, hexo.config.math); + +const config = hexo.config.math; + +hexo.extend.tag.register('katex', require('./lib/katex')(hexo), true); +hexo.extend.tag.register('mathjax', require('./lib/mathjax')(hexo), { ends: true, async: true }); + +if (config.katex.css) hexo.extend.injector.register('head_end', require('./lib/inject/katex')(hexo)); +if (config.mathjax.css) hexo.extend.injector.register('head_end', require('./lib/inject/mathjax')(hexo)); diff --git a/lib/inject/katex.js b/lib/inject/katex.js new file mode 100755 index 0000000..6b720f8 --- /dev/null +++ b/lib/inject/katex.js @@ -0,0 +1,8 @@ +'use strict'; + +const { url_for } = require('hexo-util'); + +module.exports = (hexo, css) => () => { + const { css: cssPath } = hexo.config.math.katex; + return `\n`; +}; diff --git a/lib/inject/mathjax.js b/lib/inject/mathjax.js new file mode 100755 index 0000000..8c70db0 --- /dev/null +++ b/lib/inject/mathjax.js @@ -0,0 +1,8 @@ +'use strict'; + +const { url_for } = require('hexo-util'); + +module.exports = (hexo, css) => () => { + const { css: cssPath } = hexo.config.math.mathjax; + return `\n`; +}; diff --git a/lib/katex.js b/lib/katex.js new file mode 100755 index 0000000..55b80d0 --- /dev/null +++ b/lib/katex.js @@ -0,0 +1,19 @@ +'use strict'; + +const { renderToString: renderKatex } = require('katex'); + +module.exports = hexo => { + return function katexFn(args, content) { + if (this.katex === false) return content; + + const { options: globalCfg } = hexo.config.math.katex; + const { katex: fmCfg } = this; + const [jsonCfg] = args; + const argsCfg = jsonCfg ? JSON.parse(jsonCfg) : false; + let options = Object.assign({}, globalCfg); + if (fmCfg) options = Object.assign({}, options, fmCfg); + if (argsCfg) options = Object.assign({}, options, argsCfg); + + return renderKatex(content, options); + }; +}; diff --git a/lib/mathjax.js b/lib/mathjax.js new file mode 100755 index 0000000..40649a4 --- /dev/null +++ b/lib/mathjax.js @@ -0,0 +1,31 @@ +'use strict'; + +const { init } = require('mathjax'); + +module.exports = hexo => { + return async function mathjaxFn(args, content) { + if (this.mathjax === false) return content; + + const { options: globalCfg } = hexo.config.math.mathjax; + const { mathjax: fmCfg } = this; + const [jsonCfg] = args; + const argsCfg = jsonCfg ? JSON.parse(jsonCfg) : false; + let options = Object.assign({}, globalCfg); + if (fmCfg) options = Object.assign({}, options, fmCfg); + if (argsCfg) options = Object.assign({}, options, argsCfg); + const { conversion, svg, tex } = options; + + const MathJax = await init({ + loader: { + load: ['input/tex', 'output/svg'] + }, + tex, + svg + }); + + const { startup, tex2svgPromise } = MathJax; + const svgOut = await tex2svgPromise(content, conversion); + + return startup.adaptor.outerHTML(svgOut); + }; +}; diff --git a/package.json b/package.json index 6284867..409190d 100644 --- a/package.json +++ b/package.json @@ -1,59 +1,50 @@ { "name": "hexo-math", "version": "4.0.0", - "description": "Add math support to hexo", - "main": "src/index.js", - "repository": { - "type": "git", - "url": "https://github.com/hexojs/hexo-math.git" - }, - "scripts": { - "clean": "rimraf test/site", - "pretest:clone": "git clone --recursive https://github.com/hexojs/hexo-starter.git ./test/site", - "pretest:asset": "cpx \"test/asset/**/*\" test/site", - "pretest:bootstrap": "npm --prefix=test/site install", - "pretest": "run-s clean pretest:clone pretest:asset pretest:bootstrap", - "test": "mocha", - "lint": "run-p lint:*", - "lint:src": "eslint src/*.js", - "lint:test": "eslint test/*.js" - }, + "description": "Add KaTeX and MathJax support to Hexo", + "main": "index.js", "directories": { - "asset": "./asset", - "src": "./src" + "lib": "./lib", + "dist": "./dist" }, "files": [ - "asset/", - "src/" + "lib/", + "dist/", + "index.js" ], + "engines": { + "node": ">= 10.13.0" + }, + "scripts": { + "eslint": "eslint .", + "test": "mocha test/index.js" + }, + "repository": "hexojs/hexo-filter-nofollow", "keywords": [ - "website", - "blog", - "cms", - "framework", "hexo", + "katex", + "math", "mathjax" ], "author": "AKFish (http://catx.me)", + "contributors": [ + "Hexo Core Team (https://github.com/orgs/hexojs/teams/core)" + ], "license": "MIT", + "bugs": { + "url": "https://github.com/hexojs/hexo-math/issues" + }, + "homepage": "https://github.com/hexojs/hexo-math", "dependencies": { - "html-entities": "^1.1.3", - "katex": "^0.6.0" + "hexo-util": "^2.2.0", + "katex": "^0.12.0", + "mathjax": "^3.0.5" }, "devDependencies": { "chai": "^4.2.0", - "chai-as-promised": "^7.1.1", - "cpx": "^1.5.0", - "eslint": "^6.1.0", - "eslint-config-hexo": "^3.0.0", + "eslint": "^7.5.0", + "eslint-config-hexo": "^4.1.0", "hexo": "hexojs/hexo", - "hexo-fs": "^2.0.0", - "hexo-util": "^1.0.0", - "mocha": "^6.1.2", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.0" - }, - "engines": { - "node": "^8.9 || ^10.13 || >=12" + "mocha": "^8.0.1" } } diff --git a/src/consts.js b/src/consts.js deleted file mode 100644 index 0a77cd7..0000000 --- a/src/consts.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; -module.exports.INLINE_MATH_REGEX = /\$[\s\S]+?\$/; -module.exports.BLOCK_MATH_REGEX = /^\s*\$\$[\s\S]*\$\$\s*$/m; -module.exports.INLINE_MATH_RENDER_REGEX = /\$([^\n]+?)\$/g; -module.exports.BLOCK_MATH_RENDER_REGEX = /\$\$([\s\S]+?)\$\$/g; - -module.exports.MATH_MARKER = ''; -module.exports.KATEX_INLINE_MARKER = ''; -module.exports.KATEX_BLOCK_MARKER = ''; diff --git a/src/extend.js b/src/extend.js deleted file mode 100644 index 1157a81..0000000 --- a/src/extend.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -// https://github.com/hexojs/hexo/pull/3987 - -const extend = (target, ...sources) => { - const length = sources.length; - - if (length < 1 || target == null) return target; - for (let i = 0; i < length; i++) { - const source = sources[i]; - - for (const key in source) { - target[key] = source[key]; - } - } - return target; -}; - -module.exports = extend; diff --git a/src/filter/inject.js b/src/filter/inject.js deleted file mode 100644 index 13251d9..0000000 --- a/src/filter/inject.js +++ /dev/null @@ -1,34 +0,0 @@ -const { MATH_MARKER, INLINE_MATH_REGEX, BLOCK_MATH_REGEX, KATEX_BLOCK_MARKER, KATEX_INLINE_MARKER } = require('../consts'); - -module.exports = class Inject { - constructor(hexo, opts) { - this.hexo = hexo; - this.opts = opts; - } - register() { - const { filter } = this.hexo.extend; - const injectors = { - mathjax: this._injectMathJax.bind(this), - katex: this._injectKaTeX.bind(this) - }; - filter.register('inject_ready', injectors[this.opts.engine]); - } - _injectMathJax(inject) { - const data = this.opts.mathjax; - const opts = { - data, - inline: true, - shouldInject: (src) => src.indexOf(MATH_MARKER) >= 0 || INLINE_MATH_REGEX.test(src) || BLOCK_MATH_REGEX.test(src) - }; - inject.bodyEnd.require('../../asset/inject.swig', opts); - } - _injectKaTeX(inject) { - const { css } = this.opts.katex; - - const opts = { - shouldInject: (src) => src.indexOf(KATEX_INLINE_MARKER) >= 0 || src.indexOf(KATEX_BLOCK_MARKER) >= 0 - }; - - inject.headEnd.link({ rel: 'stylesheet', href: css }, opts); - } -}; diff --git a/src/filter/post.js b/src/filter/post.js deleted file mode 100644 index 4862b8c..0000000 --- a/src/filter/post.js +++ /dev/null @@ -1,34 +0,0 @@ -const { BLOCK_MATH_RENDER_REGEX, INLINE_MATH_RENDER_REGEX } = require('../consts'); -const { AllHtmlEntities } = require('html-entities'); -const katex = require('katex'); -const entities = new AllHtmlEntities(); -const extend = require('../extend') - -module.exports = class Post { - constructor(hexo, opts) { - this.hexo = hexo; - this.opts = opts; - } - register() { - if (this.opts.engine !== 'katex') return; - const { filter } = this.hexo.extend; - filter.register('before_post_render', this._transform.bind(this)); - } - _transform(data) { - data.content = data.content.replace(BLOCK_MATH_RENDER_REGEX, (m, math) => this._render(m, math, true)); - data.content = data.content.replace(INLINE_MATH_RENDER_REGEX, (m, math) => this._render(m, math, false)); - return data; - } - _render(match, math, isBlock) { - const opts = extend({}, this.opts.katex.config, { displayMode: isBlock }); - - try { - return katex.renderToString(entities.decode(math), opts); - - } catch (e) { - this.hexo.log.error(e); - } - - return match; - } -}; \ No newline at end of file diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 058ebf2..0000000 --- a/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; -const MathJax = require('./main'); - -const math = hexo.math = new MathJax(hexo); -math.register(); diff --git a/src/main.js b/src/main.js deleted file mode 100644 index 61071f2..0000000 --- a/src/main.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; -const MathTag = require('./tag/math'); -const Inject = require('./filter/inject'); -const Post = require('./filter/post'); -const { getOptions } = require('./option'); - -module.exports = class MathJax { - constructor(hexo, opts) { - this.hexo = hexo; - this.opts = getOptions(hexo, opts); - this.tag = new MathTag(hexo, this.opts); - this.injector = new Inject(hexo, this.opts); - this.post = new Post(hexo, this.opts); - } - register() { - const { tag, injector /* post */ } = this; - tag.register(); - injector.register(); - // post.register(); - } -}; diff --git a/src/option.js b/src/option.js deleted file mode 100644 index de75a2e..0000000 --- a/src/option.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -const DEFAULT_OPTS = module.exports.DEFAULT_OPTS = { - engine: 'mathjax', - mathjax: { - src: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js', - config: { - tex2jax: { - inlineMath: [['$', '$'], ['\\(', '\\)']], - skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'], - processEscapes: true - }, - TeX: { - equationNumbers: { - autoNumber: 'AMS' - } - } - } - }, - katex: { - css: 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css', - js: 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js', - config: { - throwOnError: false, - errorColor: '#cc0000' - } - } -}; - -const ENGINES = [ - 'mathjax', - 'katex' -]; - -module.exports.getOptions = function({ config, log }, opts) { - if (config.mathjax === Object(config.mathjax)) { - log.warn('[hexo-math] Deprecation Notice: configuration format changed since 3.0.0. Please move `mathjax` to `math.mathjax` in your site\'s `_config.yml` file'); - if (config.math !== Object(config.math)) config.math = { mathjax: config.mathjax }; - } - - opts = Object.assign({}, opts, config.math, DEFAULT_OPTS); - - if (ENGINES.indexOf(opts.engine) < 0) throw new TypeError('hexo-math does not support engine named \'opts.engine\''); - - log.info(`[hexo-math] Using engine '${opts.engine}'`); - - return opts; -}; diff --git a/src/tag/math.js b/src/tag/math.js deleted file mode 100644 index 711fa1c..0000000 --- a/src/tag/math.js +++ /dev/null @@ -1,42 +0,0 @@ -const { AllHtmlEntities } = require('html-entities'); -const { MATH_MARKER } = require('../consts'); -const katex = require('katex'); -const extend = require('../extend'); -const entities = new AllHtmlEntities(); - -module.exports = class MathTag { - constructor(hexo, opts) { - this.hexo = hexo; - this.opts = opts; - } - register() { - const { tag } = this.hexo.extend; - tag.register('math', this._transform.bind(this), { ends: true }); - } - _transform(args, content) { - const multiLine = /\n/.test(content); - - const transformers = { - mathjax: this._mathJax.bind(this), - katex: this._kaTeX.bind(this) - }; - return transformers[this.opts.engine](content, multiLine); - } - _mathJax(content, multiLine) { - content = entities.encode(content.trim()); - return multiLine ? `$$${content}$$${MATH_MARKER}` - : `$${content}$${MATH_MARKER}`; - } - _kaTeX(content, multiLine) { - content = entities.decode(content.trim()); - const opts = extend({}, this.opts.katex.config, { displayMode: multiLine }); - - try { - return katex.renderToString(content, opts); - } catch (e) { - this.hexo.log.error(e); - } - - return content; - } -}; diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100755 index 0000000..63794c0 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,6 @@ +{ + "extends": "hexo/test", + "env": { + "es6": true + } +} \ No newline at end of file diff --git a/test/.eslintrc.json b/test/.eslintrc.json deleted file mode 100644 index 0b74278..0000000 --- a/test/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "hexo/test", - "root": false, - "globals": { - "chai": true, - "Hexo": true, - "fs": true, - "expect": true - } -} \ No newline at end of file diff --git a/test/asset/source/_expected/katex/block.md.skip b/test/asset/source/_expected/katex/block.md.skip deleted file mode 100644 index 0f9abca..0000000 --- a/test/asset/source/_expected/katex/block.md.skip +++ /dev/null @@ -1 +0,0 @@ -

ut=h2(2ux2+2uy2+2uz2)\frac{\partial u}{\partial t}
= h^2 \left( \frac{\partial^2 u}{\partial x^2} +
\frac{\partial^2 u}{\partial y^2} +
\frac{\partial^2 u}{\partial z^2}\right)

diff --git a/test/asset/source/_expected/katex/hello-world.md.expected b/test/asset/source/_expected/katex/hello-world.md.expected deleted file mode 100644 index 8c3cfe7..0000000 --- a/test/asset/source/_expected/katex/hello-world.md.expected +++ /dev/null @@ -1,13 +0,0 @@ -

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

-

Quick Start

Create a new post

1
$ hexo new "My New Post"
- -

More info: Writing

-

Run server

1
$ hexo server
- -

More info: Server

-

Generate static files

1
$ hexo generate
- -

More info: Generating

-

Deploy to remote sites

1
$ hexo deploy
- -

More info: Deployment

diff --git a/test/asset/source/_expected/katex/inline.md.skip b/test/asset/source/_expected/katex/inline.md.skip deleted file mode 100644 index 647f75b..0000000 --- a/test/asset/source/_expected/katex/inline.md.skip +++ /dev/null @@ -1 +0,0 @@ -

cos2θ=cos2θsin2θ=2cos2θ1\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1

diff --git a/test/asset/source/_expected/katex/tag-escape.md.expected b/test/asset/source/_expected/katex/tag-escape.md.expected deleted file mode 100644 index f581ece..0000000 --- a/test/asset/source/_expected/katex/tag-escape.md.expected +++ /dev/null @@ -1 +0,0 @@ -

This test case is to address issue #10: a<1|a|<1

diff --git a/test/asset/source/_expected/katex/tag-in-list.md.expected b/test/asset/source/_expected/katex/tag-in-list.md.expected deleted file mode 100644 index 4adc36a..0000000 --- a/test/asset/source/_expected/katex/tag-in-list.md.expected +++ /dev/null @@ -1,6 +0,0 @@ -

This test case is to address issue #7:

-
    -
  • a<1|a|<1
  • -
  • cos2θ=cos2θsin2θ=2cos2θ1\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1 -
  • -
diff --git a/test/asset/source/_expected/katex/tag.md.expected b/test/asset/source/_expected/katex/tag.md.expected deleted file mode 100644 index f3ade91..0000000 --- a/test/asset/source/_expected/katex/tag.md.expected +++ /dev/null @@ -1,6 +0,0 @@ -

This equation cos2θ=cos2θsin2θ=2cos2θ1\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1 is inline.
This used to cause problem: ax+by+ca2+b2\frac{|ax + by + c|}{\sqrt{a^{2}+b^{2}}}.

-

This should be rendered as block:

-ut=h2(2ux2+2uy2+2uz2)\frac{\partial u}{\partial t} -= h^2 \left( \frac{\partial^2 u}{\partial x^2} + -\frac{\partial^2 u}{\partial y^2} + -\frac{\partial^2 u}{\partial z^2}\right) diff --git a/test/asset/source/_expected/mathjax/block.md.expected b/test/asset/source/_expected/mathjax/block.md.expected deleted file mode 100644 index b48c6de..0000000 --- a/test/asset/source/_expected/mathjax/block.md.expected +++ /dev/null @@ -1 +0,0 @@ -

$$\frac{\partial u}{\partial t}
= h^2 \left( \frac{\partial^2 u}{\partial x^2} +
\frac{\partial^2 u}{\partial y^2} +
\frac{\partial^2 u}{\partial z^2}\right)$$

diff --git a/test/asset/source/_expected/mathjax/hello-world.md.expected b/test/asset/source/_expected/mathjax/hello-world.md.expected deleted file mode 100644 index 8c3cfe7..0000000 --- a/test/asset/source/_expected/mathjax/hello-world.md.expected +++ /dev/null @@ -1,13 +0,0 @@ -

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

-

Quick Start

Create a new post

1
$ hexo new "My New Post"
- -

More info: Writing

-

Run server

1
$ hexo server
- -

More info: Server

-

Generate static files

1
$ hexo generate
- -

More info: Generating

-

Deploy to remote sites

1
$ hexo deploy
- -

More info: Deployment

diff --git a/test/asset/source/_expected/mathjax/inline.md.expected b/test/asset/source/_expected/mathjax/inline.md.expected deleted file mode 100644 index 31fbf99..0000000 --- a/test/asset/source/_expected/mathjax/inline.md.expected +++ /dev/null @@ -1 +0,0 @@ -

$\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$

diff --git a/test/asset/source/_expected/mathjax/tag-escape.md.expected b/test/asset/source/_expected/mathjax/tag-escape.md.expected deleted file mode 100644 index c1c14fa..0000000 --- a/test/asset/source/_expected/mathjax/tag-escape.md.expected +++ /dev/null @@ -1 +0,0 @@ -

This test case is to address issue #10: $|a|<1$

diff --git a/test/asset/source/_expected/mathjax/tag-in-list.md.expected b/test/asset/source/_expected/mathjax/tag-in-list.md.expected deleted file mode 100644 index c363172..0000000 --- a/test/asset/source/_expected/mathjax/tag-in-list.md.expected +++ /dev/null @@ -1,6 +0,0 @@ -

This test case is to address issue #7:

-
    -
  • $|a|<1$
  • -
  • $\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$ -
  • -
diff --git a/test/asset/source/_expected/mathjax/tag.md.expected b/test/asset/source/_expected/mathjax/tag.md.expected deleted file mode 100644 index ea37fa4..0000000 --- a/test/asset/source/_expected/mathjax/tag.md.expected +++ /dev/null @@ -1,6 +0,0 @@ -

This equation $\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$ is inline.
This used to cause problem: $\frac{|ax + by + c|}{\sqrt{a^{2}+b^{2}}}$.

-

This should be rendered as block:

-$$\frac{\partial u}{\partial t} -= h^2 \left( \frac{\partial^2 u}{\partial x^2} + -\frac{\partial^2 u}{\partial y^2} + -\frac{\partial^2 u}{\partial z^2}\right)$$ diff --git a/test/asset/source/_posts/block.md b/test/asset/source/_posts/block.md deleted file mode 100644 index 28addbd..0000000 --- a/test/asset/source/_posts/block.md +++ /dev/null @@ -1,8 +0,0 @@ -title: "Block" -date: 2015-04-21 02:47:19 -tags: ---- -$$\frac{\partial u}{\partial t} -= h^2 \left( \frac{\partial^2 u}{\partial x^2} + -\frac{\partial^2 u}{\partial y^2} + -\frac{\partial^2 u}{\partial z^2}\right)$$ diff --git a/test/asset/source/_posts/hello-world.md b/test/asset/source/_posts/hello-world.md deleted file mode 100644 index d2f9892..0000000 --- a/test/asset/source/_posts/hello-world.md +++ /dev/null @@ -1,37 +0,0 @@ -title: Hello World ---- -Welcome to [Hexo](http://hexo.io/)! This is your very first post. Check [documentation](http://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](http://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues). - -## Quick Start - -### Create a new post - -``` bash -$ hexo new "My New Post" -``` - -More info: [Writing](http://hexo.io/docs/writing.html) - -### Run server - -``` bash -$ hexo server -``` - -More info: [Server](http://hexo.io/docs/server.html) - -### Generate static files - -``` bash -$ hexo generate -``` - -More info: [Generating](http://hexo.io/docs/generating.html) - -### Deploy to remote sites - -``` bash -$ hexo deploy -``` - -More info: [Deployment](http://hexo.io/docs/deployment.html) diff --git a/test/asset/source/_posts/inline.md b/test/asset/source/_posts/inline.md deleted file mode 100644 index 1b6169d..0000000 --- a/test/asset/source/_posts/inline.md +++ /dev/null @@ -1,5 +0,0 @@ -title: "Inline" -date: 2015-04-21 02:47:19 -tags: ---- -$\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$ diff --git a/test/asset/source/_posts/tag-escape.md b/test/asset/source/_posts/tag-escape.md deleted file mode 100644 index d14326b..0000000 --- a/test/asset/source/_posts/tag-escape.md +++ /dev/null @@ -1,7 +0,0 @@ -title: "Tag Escpae" -date: 2015-04-21 02:47:19 -tags: -issues: -- 10 ---- -This test case is to address issue #10: {% math %} |a|<1 {% endmath %} diff --git a/test/asset/source/_posts/tag-in-list.md b/test/asset/source/_posts/tag-in-list.md deleted file mode 100644 index 486706f..0000000 --- a/test/asset/source/_posts/tag-in-list.md +++ /dev/null @@ -1,9 +0,0 @@ -title: "Tag In List" -date: 2015-04-21 02:47:19 -tags: -issues: -- 7 ---- -This test case is to address issue #7: -* {% math %} |a|<1 {% endmath %} -* {% math %} \cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1 {% endmath %} diff --git a/test/asset/source/_posts/tag.md b/test/asset/source/_posts/tag.md deleted file mode 100644 index 9fe5474..0000000 --- a/test/asset/source/_posts/tag.md +++ /dev/null @@ -1,14 +0,0 @@ -title: "Tag" -date: 2015-04-21 02:47:19 -tags: ---- -This equation {% math %}\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1 {% endmath %} is inline. -This used to cause problem: {% math %}\frac{|ax + by + c|}{\sqrt{a^{2}+b^{2}}} {% endmath %}. - -This should be rendered as block: -{% math %} -\frac{\partial u}{\partial t} -= h^2 \left( \frac{\partial^2 u}{\partial x^2} + -\frac{\partial^2 u}{\partial y^2} + -\frac{\partial^2 u}{\partial z^2}\right) -{% endmath %} diff --git a/test/index.js b/test/index.js new file mode 100755 index 0000000..ab278d6 --- /dev/null +++ b/test/index.js @@ -0,0 +1,194 @@ +'use strict'; + +require('chai').should(); + +const { deepMerge, url_for } = require('hexo-util'); +const Hexo = require('hexo'); +const hexo = new Hexo(__dirname); +const { renderToString: renderKatex } = require('katex'); + +describe('hexo-math', () => { + const defaultCfg = deepMerge(hexo.config, { + math: { + katex: { + enable: true, + css: 'https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css', + options: { + throwOnError: false + } + }, + mathjax: { + enable: true, + css: 'https://cdn.jsdelivr.net/gh/hexojs/hexo-math/master/dist/style.css', + options: { + conversion: { + display: false + }, + svg: {}, + tex: {} + } + } + } + }); + let args = []; + + beforeEach(() => { + hexo.config = deepMerge(hexo.config, defaultCfg); + args = []; + }); + + describe('tag', () => { + describe('katex', () => { + const k = require('../lib/katex')(hexo).bind({}); + const content = 'c = \\pm\\sqrt{a^2 + b^2}'; + + it('default', () => { + const output = k(args, content); + const expected = renderKatex(content, hexo.config.math.katex.options); + + output.should.eql(expected); + }); + + it('config', () => { + hexo.config.math.katex.options.output = 'html'; + const output = k(args, content); + const expected = renderKatex(content, hexo.config.math.katex.options); + + output.should.eql(expected); + }); + + it('args', () => { + const options = { output: 'mathml' }; + args.push(JSON.stringify(options)); + const output = k(args, content); + const expected = renderKatex(content, options); + + output.should.eql(expected); + }); + + it('args should override config', () => { + hexo.config.math.katex.options.output = 'html'; + + const options = { output: 'mathml' }; + args.push(JSON.stringify(options)); + const output = k(args, content); + const expected = renderKatex(content, options); + + output.should.eql(expected); + }); + + it('disable in front-matter', () => { + const fm = { katex: false }; + const k = require('../lib/katex')(hexo).bind(fm); + + const output = k(args, content); + output.should.eql(content); + }); + + it('args should override front-matter', () => { + const fm = { katex: { output: 'html' } }; + const k = require('../lib/katex')(hexo).bind(fm); + const options = { output: 'mathml' }; + args.push(JSON.stringify(options)); + const output = k(args, content); + const expected = renderKatex(content, options); + + output.should.eql(expected); + }); + }); + + describe('mathjax', () => { + const m = require('../lib/mathjax')(hexo).bind({}); + const content = '\\frac{1}{x^2-1}'; + const displayFalse = ''; + const displayTrue = ''; + + it('default', async () => { + const output = await m(args, content); + + output.startsWith(displayFalse).should.eql(true); + }); + + it('config', async () => { + hexo.config.math.mathjax.options.conversion.display = true; + const output = await m(args, content); + + output.startsWith(displayTrue).should.eql(true); + }); + + it('args', async () => { + const options = { conversion: { display: true } }; + args.push(JSON.stringify(options)); + const output = await m(args, content); + + output.startsWith(displayTrue).should.eql(true); + }); + + it('args should override config', async () => { + hexo.config.math.mathjax.options.conversion.display = false; + + const options = { conversion: { display: true } }; + args.push(JSON.stringify(options)); + const output = await m(args, content); + + output.startsWith(displayTrue).should.eql(true); + }); + + it('disable in front-matter', async () => { + const fm = { mathjax: false }; + const m = require('../lib/mathjax')(hexo).bind(fm); + + const output = await m(args, content); + output.should.eql(content); + }); + + it('args should override front-matter', async () => { + const fm = { mathjax: { conversion: { display: false } } }; + const m = require('../lib/mathjax')(hexo).bind(fm); + const options = { conversion: { display: true } }; + args.push(JSON.stringify(options)); + const output = await m(args, content); + + output.startsWith(displayTrue).should.eql(true); + }); + }); + }); + + describe('inject', () => { + const css = path => { + return `\n`; + }; + + describe('katex', () => { + const k = require('../lib/inject/katex')(hexo); + + it('default', () => { + const output = k(); + output.should.eql(css(hexo.config.math.katex.css)); + }); + + it('custom path', () => { + const path = '/foo/bar.css'; + hexo.config.math.katex.css = path; + const output = k(); + output.should.eql(css(path)); + }); + }); + + describe('mathjax', () => { + const m = require('../lib/inject/mathjax')(hexo); + + it('default', () => { + const output = m(); + output.should.eql(css(hexo.config.math.mathjax.css)); + }); + + it('custom path', () => { + const path = '/foo/bar.css'; + hexo.config.math.mathjax.css = path; + const output = m(); + output.should.eql(css(path)); + }); + }); + }); +}); diff --git a/test/katex.spec.js b/test/katex.spec.js deleted file mode 100644 index 5d8cf92..0000000 --- a/test/katex.spec.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; -const util = require('./util'); - -describe('KaTeX', () => { - const h = util.initHexo('katex'); - const {hexo} = h; - before(function() { - this.timeout(0); - return h.setup(); - }); - after(function() { - this.timeout(0); - return h.teardown(); - }); - return it('should pass all test posts', () => { - const posts = hexo.locals.toObject().posts.data; - return posts.forEach(post => { - if (post.katex_expected == null) { - return; - } - return expect(post.content, post.title).to.equal(post.katex_expected); - }); - }); -}); diff --git a/test/mathjax.spec.js b/test/mathjax.spec.js deleted file mode 100644 index 74f0359..0000000 --- a/test/mathjax.spec.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; -const util = require('./util'); - -describe('MathJax', () => { - const h = util.initHexo('mathjax'); - const {hexo, mathJax} = h; - before(function() { - this.timeout(0); - return h.setup(); - }); - after(function() { - this.timeout(0); - return h.teardown(); - }); - it('should pass all test posts', () => { - const posts = hexo.locals.toObject().posts.data; - return posts.forEach(post => { - if (post.mathjax_expected == null) { - return; - } - return expect(post.content, post.title).to.equal(post.mathjax_expected); - }); - }); - return describe('\'math\' tag', () => { - const {tag} = mathJax; - const transform = tag._transform.bind(tag, null); - it('should escape HTML entities', () => { - return expect(transform('|a|<1')).to.equal('$|a|<1$'); - }); - it('should return inline math for single line input', () => { - return expect(transform('a+b=1')).to.equal('$a+b=1$'); - }); - return it('should return block math for multiple line input', () => { - return expect(transform('a+b=1\nc+d=2')).to.equal('$$a+b=1\nc+d=2$$'); - }); - }); -}); diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index ad31045..0000000 --- a/test/mocha.opts +++ /dev/null @@ -1,3 +0,0 @@ ---reporter spec ---require test/scaffolds.js -test/**/*.spec.js \ No newline at end of file diff --git a/test/scaffolds.js b/test/scaffolds.js deleted file mode 100644 index b10b8b9..0000000 --- a/test/scaffolds.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; -global.Hexo = require('hexo'); - -global.fs = require('hexo-fs'); - -global.chai = require('chai'); - -global.expect = chai.expect; - -chai.use(require('chai-as-promised')); diff --git a/test/util.js b/test/util.js deleted file mode 100644 index 3bcb885..0000000 --- a/test/util.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; -const path = require('path'); - -const MathJax = require('../src/main'); - -module.exports = { - // Note: somewhere in hexo's packages there's a global leak. - // Disabled mocha's leak checking for now - initHexo: function(engine) { - const site_dir = './test/site'; - if (!fs.existsSync(site_dir)) { - throw new Error('Test site not found. Run `gulp asset:test` first.'); - } - const base_dir = path.join(__dirname, 'site'); - const hexo = new Hexo(base_dir, { - silent: true - }); - const mathJax = new MathJax(hexo); - mathJax.opts.engine = engine; - mathJax.register(); - hexo.extend.filter.register('after_post_render', function(data) { - const expected_file = path.join(base_dir, `/source/${data.source.replace('_posts', `_expected/${engine}`)}.expected`); - if (fs.existsSync(expected_file)) { - data[`${engine}_expected`] = fs.readFileSync(expected_file); - } else { - console.warn('Test file does not exist: ', expected_file); - } - return data; - }); - const setup = function() { - return hexo.init().then(function() { - return hexo.call('generate', {}); - }); - }; - const teardown = function() { - return hexo.call('clean', {}); - }; - return {base_dir, mathJax, hexo, setup, teardown}; - }, - mockHexoWithThemeConfig: function(theme_base, opts) { - const hexo = { - theme: { - base: theme_base, - config: opts - } - }; - return hexo; - } -};