mirror of https://github.com/curbengh/hexo-yam
Compare commits
298 Commits
Author | SHA1 | Date |
---|---|---|
|
4bd000bfee | |
|
5fb3349dec | |
|
80b2325cbf | |
|
812ff614fc | |
|
702eb2fa0c | |
|
a2c810cfb5 | |
|
30c33c0ad3 | |
|
1c9d91b524 | |
|
c18f4c8476 | |
|
e33fd0ed5d | |
|
73db847fd4 | |
|
7639547408 | |
|
f7df26377a | |
|
1b04f7c8f1 | |
|
18a5d8108b | |
|
7f2033e553 | |
|
e9584b2e0b | |
|
e99e110d39 | |
|
a5f19dbe79 | |
|
c3ed0c68c7 | |
|
f92017f688 | |
|
0abd90c78a | |
|
426da85620 | |
|
bfb886abac | |
|
d99caafe90 | |
|
3cc6f5e79e | |
|
56af48f632 | |
|
0bee9ada0e | |
|
1af8c52cdb | |
|
81ceea413d | |
|
8e937ead21 | |
|
7809098034 | |
|
dffeb0cfc7 | |
|
bfcd93edb7 | |
|
2992e8d8e7 | |
|
cf7e8f675c | |
|
3523b0fd98 | |
|
df3b0513e7 | |
|
dbed65ffeb | |
|
c964cfcf80 | |
|
793bcd81c4 | |
|
f65e7e7a22 | |
|
d9e6228960 | |
|
6c6060f28c | |
|
79f4f24f8e | |
|
b0575e6fdc | |
|
a6f434ff8d | |
|
a6e2ea0879 | |
|
9c8a228e09 | |
|
4b4d3cb342 | |
|
8258359f6b | |
|
c6c7d3743a | |
|
777ffabd2b | |
|
5453fc9ee0 | |
|
c3b899556a | |
|
866ba28c3c | |
|
b54324c154 | |
|
077055ed0b | |
|
d54ed360be | |
|
1ae4d77071 | |
|
0f73e6ed98 | |
|
79f15acb79 | |
|
2ae5520a60 | |
|
ef46c3c6d9 | |
|
4648fa32f1 | |
|
197836b82b | |
|
d757c1b5c7 | |
|
0623de5252 | |
|
fbb2c71e87 | |
|
b3d09fec7a | |
|
3edbe68008 | |
|
1833ffa76e | |
|
63eee78e01 | |
|
7e81770894 | |
|
288a4e3232 | |
|
d8e6969352 | |
|
a6018cb7f5 | |
|
4a271929d5 | |
|
282a905305 | |
|
5f9c3d32d9 | |
|
6d633f0593 | |
|
0e66fc81cf | |
|
7178b50186 | |
|
cc53b9054b | |
|
3ce4b69991 | |
|
1f775df118 | |
|
45ed8c2bac | |
|
c0041b0f23 | |
|
88deed06bb | |
|
ed5d09c803 | |
|
e4b349202c | |
|
460bb9c035 | |
|
eca9b2b7c9 | |
|
be96f15ceb | |
|
fde28cdd9a | |
|
7aa2f90e52 | |
|
b169489ce9 | |
|
81fd44e514 | |
|
1f95af32b7 | |
|
6c21cc6a9b | |
|
3819909c84 | |
|
4f033711e2 | |
|
e05f96f971 | |
|
193cc355be | |
|
679858e4e8 | |
|
1c10c9ee5e | |
|
e621a7937a | |
|
ef57b75638 | |
|
5cc13c1ad8 | |
|
140a005dc7 | |
|
ea29aa0ad5 | |
|
bbc464b29e | |
|
cef2d0e377 | |
|
91c4d936e0 | |
|
4a16fca23e | |
|
d8805d9a9a | |
|
19424d8ae8 | |
|
18e1fd3a78 | |
|
bc742f75fb | |
|
11b07ab00f | |
|
0fd2ed31ee | |
|
ba66c4bc89 | |
|
9ac8969a08 | |
|
353ca8ea37 | |
|
fd117bcd58 | |
|
c8cc870b4c | |
|
327b36782b | |
|
57db21d2ad | |
|
51cc9b1d8d | |
|
c57e227efd | |
|
37ba1d9a2b | |
|
ce8c4a145b | |
|
16cdf467d9 | |
|
3de777904f | |
|
d9817f8a44 | |
|
605c5fd57f | |
|
d68c26a2c2 | |
|
7f60c6959e | |
|
c2bcaa7d69 | |
|
8bbecf676f | |
|
9b94a2c2df | |
|
bdb7e94350 | |
|
e5ab822c45 | |
|
c42b9040a6 | |
|
9e67d11e8a | |
|
e1843f7400 | |
|
b8d48c7f8a | |
|
c721fa8c02 | |
|
81ab472fe1 | |
|
b9f4cd6173 | |
|
fdcdbef4a1 | |
|
64ba16cb22 | |
|
317b5e43d3 | |
|
d75b10b64b | |
|
8d0fdaeb80 | |
|
ab69db2f3e | |
|
d1ca7f9c2b | |
|
4a5c66add2 | |
|
fa6f514a05 | |
|
60642c8048 | |
|
1c530b7d44 | |
|
51ff9d953d | |
|
50d80ccc70 | |
|
9d6b72422b | |
|
6111d21a7c | |
|
7201b3f56f | |
|
440b9ccd8c | |
|
e59e3866b9 | |
|
1a5197b9c9 | |
|
866593110e | |
|
f0b37aaf45 | |
|
48868bfa7e | |
|
ab023da82e | |
|
626369e3e0 | |
|
7e1ec95f9a | |
|
932d36182c | |
|
9df4e8283b | |
|
7d163bcb00 | |
|
4e4605e1a4 | |
|
f7c600545b | |
|
631503aa1a | |
|
b046d2a09e | |
|
e6381ebed3 | |
|
e9609de460 | |
|
679dcaf077 | |
|
9263366537 | |
|
4dc883d269 | |
|
0c270a4594 | |
|
7eda55a1aa | |
|
1fdac53793 | |
|
89a6dcea9e | |
|
2548eb20bf | |
|
de425e4b6f | |
|
85bfd3ba35 | |
|
213700a617 | |
|
26b466c1bf | |
|
887eeda3cc | |
|
48bf9951f0 | |
|
461fe1dd41 | |
|
5de4a237b7 | |
|
2c5ad19932 | |
|
680ee73a03 | |
|
c2e6b898a9 | |
|
e473408673 | |
|
60a045e429 | |
|
90bfe2ca36 | |
|
fd474580ce | |
|
7085b15d10 | |
|
b5639aba85 | |
|
36bca1b939 | |
|
9cb977e2d2 | |
|
ff3b07c9e2 | |
|
ddf4415ef0 | |
|
7e85bd6338 | |
|
2930f1da1d | |
|
ede71a0857 | |
|
b054c0a24b | |
|
5b8549077f | |
|
d964918d21 | |
|
79308b2d44 | |
|
32a519928a | |
|
d72bb5b567 | |
|
2725e230e3 | |
|
bbba062411 | |
|
493683644a | |
|
4923f5c39d | |
|
a6f59a9704 | |
|
43a316d149 | |
|
7d06de7e79 | |
|
37dac8c011 | |
|
374b24e9f4 | |
|
41ecf75f71 | |
|
5fac46455c | |
|
a75fc79e3d | |
|
ba77db0094 | |
|
c69b6d3356 | |
|
55908e655a | |
|
98f174cd7a | |
|
feaf654f15 | |
|
7203ea2abe | |
|
0ce066c2fd | |
|
655f65adcd | |
|
654d279378 | |
|
0623ca7e31 | |
|
3929884c8c | |
|
587b460029 | |
|
9c8af3b30f | |
|
9bb184e9cf | |
|
db58c8e686 | |
|
8531b77cfc | |
|
37aa7f9758 | |
|
f05c379687 | |
|
c9b7323768 | |
|
ea2a4afe99 | |
|
0595a4ae31 | |
|
3d08e37c8f | |
|
08e3cc5a46 | |
|
a87dd05ff4 | |
|
cdee4c0768 | |
|
cceae36368 | |
|
ce7a1f607d | |
|
302ea906a1 | |
|
374c16575b | |
|
55b48a76aa | |
|
15465ca16b | |
|
a219775d6c | |
|
528486761d | |
|
02b323868a | |
|
ad5f82712c | |
|
ce973f940f | |
|
94a8f90c2b | |
|
b93e92b1bb | |
|
5a5a6fb504 | |
|
1de8ec2cd9 | |
|
fa2efb9bd3 | |
|
5e19490e44 | |
|
2b5585be73 | |
|
f1171393f8 | |
|
369bad96b7 | |
|
9b52aed8e4 | |
|
42016f50da | |
|
4f5104c408 | |
|
49c9fcb310 | |
|
1ea89ec108 | |
|
3aa5143adf | |
|
cb4dc87a5a | |
|
2a9c5a52b4 | |
|
4c2b9e2d1f | |
|
f55b96d32a | |
|
6f50b501d6 | |
|
e9ced440d7 | |
|
e82d43d0e2 | |
|
734342df00 | |
|
5c0ef6c738 | |
|
fa30a2f22d | |
|
84b2457371 | |
|
3bd69a5b24 | |
|
7d2f7488aa |
|
@ -0,0 +1,10 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
|
@ -0,0 +1,22 @@
|
|||
name: Linter
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
linter:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-npm-cache
|
||||
restore-keys: |
|
||||
${{ runner.os }}-npm-cache
|
||||
- name: Install Dependencies
|
||||
run: bun install
|
||||
- name: Lint
|
||||
run: bun run lint
|
|
@ -0,0 +1,23 @@
|
|||
name: Semgrep
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/semgrep.yml
|
||||
schedule:
|
||||
# Weekly
|
||||
- cron: "0 0 * * 0"
|
||||
jobs:
|
||||
semgrep:
|
||||
name: Scan
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
||||
container:
|
||||
image: returntocorp/semgrep
|
||||
if: (github.actor != 'dependabot[bot]')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: semgrep ci
|
|
@ -0,0 +1,37 @@
|
|||
name: Snyk
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Weekly
|
||||
- cron: "0 0 * * 0"
|
||||
pull_request:
|
||||
branches:
|
||||
- "dependabot/github_actions/github/codeql-action**"
|
||||
|
||||
jobs:
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
- name: Install Dependencies
|
||||
run: bun install
|
||||
- name: Run Snyk to check for vulnerabilities
|
||||
uses: snyk/actions/node@master
|
||||
continue-on-error: true # To make sure that SARIF upload gets called
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
command: test
|
||||
args: --sarif-file-output=snyk.sarif
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
- name: Monitor for vulnerabilities
|
||||
uses: snyk/actions/node@master
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
command: monitor
|
|
@ -0,0 +1,76 @@
|
|||
name: Tester
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
tester:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
node-version: ["18", "20", "22"]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-npm-cache
|
||||
restore-keys: ${{ runner.os }}-npm-cache
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
- name: Determine zstd binary version
|
||||
shell: bash
|
||||
run: |
|
||||
case "$RUNNER_OS" in
|
||||
"Linux")
|
||||
echo "PLATFORM=linux-x64-gnu" >> "$GITHUB_ENV" ;;
|
||||
"Windows")
|
||||
echo "PLATFORM=win32-x64-msvc" >> "$GITHUB_ENV" ;;
|
||||
"macOS")
|
||||
echo "PLATFORM=darwin-arm64" >> "$GITHUB_ENV" ;;
|
||||
esac
|
||||
- name: Install zstd binary
|
||||
shell: bash
|
||||
run: npm install "@mongodb-js/zstd-$PLATFORM"
|
||||
- name: Test
|
||||
run: npm run test
|
||||
env:
|
||||
CI: true
|
||||
coverage:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node-version: ["20.x"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
- name: Cache NPM dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-npm-cache
|
||||
restore-keys: ${{ runner.os }}-npm-cache
|
||||
- name: Install Dependencies
|
||||
run: bun install
|
||||
- name: Coverage
|
||||
run: npm run test
|
||||
env:
|
||||
CI: true
|
||||
- name: Upload coverage report to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
@ -3,3 +3,5 @@ node_modules/
|
|||
package-lock.json
|
||||
tmp/
|
||||
*.log
|
||||
coverage/
|
||||
bun.lockb
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
.DS_Store
|
||||
node_modules/
|
||||
tmp/
|
||||
*.log
|
||||
package-lock.json
|
||||
.travis.yml
|
||||
.snyk
|
13
.snyk
13
.snyk
|
@ -2,15 +2,4 @@
|
|||
version: v1.12.0
|
||||
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
|
||||
ignore:
|
||||
'npm:braces:20180219':
|
||||
- hexo-fs > chokidar > anymatch > micromatch > braces:
|
||||
reason: Patch/update unavailable
|
||||
expires: '2018-12-31T00:00:00.000Z'
|
||||
'npm:chownr:20180731':
|
||||
- hexo-fs > chokidar > fsevents > node-pre-gyp > tar > chownr:
|
||||
reason: Patch/update unavailable
|
||||
expires: '2018-12-31T00:00:00.000Z'
|
||||
- iltorb > prebuild-install > tar-fs > chownr:
|
||||
reason: Patch/update unavailable
|
||||
expires: '2018-12-31T00:00:00.000Z'
|
||||
patch: {}
|
||||
patch:
|
||||
|
|
20
.travis.yml
20
.travis.yml
|
@ -1,20 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "node" # latest stable Node.js release
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- "node_modules" # cache the modules for faster build
|
||||
|
||||
script:
|
||||
- npm install -g snyk
|
||||
- npm install # install node modules
|
||||
- snyk auth $SNYK_TOKEN
|
||||
- snyk test # Check node modules for vulnerability
|
||||
- snyk protect # Patch node modules (if available)
|
||||
- snyk monitor # Update dependencies to snyk
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master # Only build master branch
|
||||
- /^greenkeeper.*$/ # Greenkeeper branches
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2024 curbengh, 2016-2018 rozbo
|
||||
|
||||
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.
|
347
README.md
347
README.md
|
@ -1,106 +1,319 @@
|
|||
# Hexo-yam
|
||||
# hexo-yam
|
||||
|
||||
[](https://www.npmjs.com/package/hexo-yam)
|
||||
[](https://travis-ci.com/weyusi/hexo-yam)
|
||||
[](https://david-dm.org/weyusi/hexo-yam)
|
||||
[](https://snyk.io/test/npm/hexo-yam)
|
||||
[](https://greenkeeper.io/)
|
||||
[](https://www.npmjs.com/package/hexo-yam)
|
||||
[](https://github.com/curbengh/hexo-yam/actions?query=workflow%3ATester)
|
||||
[](https://codecov.io/gh/curbengh/hexo-yam)
|
||||
[](https://libraries.io/npm/hexo-yam)
|
||||
[](https://snyk.io/test/github/curbengh/hexo-yam)
|
||||
|
||||
> This project is based on [hexo-neat](https://github.com/rozbo/hexo-neat)
|
||||
Yet Another Minifier for Hexo. Minify HTML, JS, CSS, SVG, XML and JSON. Compress static [web assets](https://github.com/curbengh/hexo-yam/blob/ba77db0094a7c07ea9f70f010bfc15541d4105ca/index.js#L64) using gzip, brotli and zstd.
|
||||
|
||||
Yet Another Minifier for Hexo. Minify and compress html, js and css. Support gzip and [brotli](https://en.wikipedia.org/wiki/Brotli) [compressions](https://en.wikipedia.org/wiki/HTTP_compression).
|
||||
## Table of contents
|
||||
|
||||
The original package has not been [updated](https://www.npmjs.com/package/hexo-neat) for a while. I update the [dependencies](https://github.com/weyusi/hexo-yam/blob/master/package.json) and add compression support.
|
||||
|
||||
All the options are the same, so you can use this as a drop-in replacement.
|
||||
|
||||
*Note:* See [HTTP Compression](#http-compression) section below for more info on using brotli.
|
||||
- [Installation](#installation)
|
||||
- [Options](#options)
|
||||
- [HTML](#html)
|
||||
- [CSS](#css)
|
||||
- [JS](#js)
|
||||
- [SVG](#svg)
|
||||
- [XML](#xml)
|
||||
- [JSON](#json)
|
||||
- [Gzip](#gzip)
|
||||
- [Brotli](#brotli)
|
||||
- [Zstd](#zstd)
|
||||
- [Globbing](#globbing)
|
||||
|
||||
## Installation
|
||||
``` bash
|
||||
$ npm install hexo-yam --save
|
||||
```
|
||||
|
||||
## Usage
|
||||
To enable this plugin, insert the following to `_config.yml`:
|
||||
``` yaml
|
||||
neat_enable: true
|
||||
```bash
|
||||
$ npm install --save hexo-yam
|
||||
```
|
||||
For further customization, see below.
|
||||
|
||||
## Options
|
||||
``` yaml
|
||||
neat_html:
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
enable: true
|
||||
exclude:
|
||||
previewServer: true
|
||||
html:
|
||||
css:
|
||||
js:
|
||||
svg:
|
||||
gzip:
|
||||
brotli:
|
||||
xml:
|
||||
json:
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **logger** - Verbose output. Defaults to `false`.
|
||||
- **exclude** - Exclude files
|
||||
- **previewServer** - Disable the plugin when running `hexo server`. Defaults to `true`.
|
||||
- **html** - See [HTML](#html) section
|
||||
- **css** - See [CSS](#css) section
|
||||
- **js** - See [JS](#js) section
|
||||
- **svg** - See [SVG](#svg) section
|
||||
- **gzip** - See [Gzip](#gzip) section
|
||||
- **brotli** - See [Brotli](#brotli) section
|
||||
- **xml** - See [XML](#xml) section
|
||||
- **json** - See [JSON](#json) section
|
||||
|
||||
## HTML
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
html:
|
||||
enable: true
|
||||
exclude:
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`. Set lower value to set higher priority and vice versa.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **exclude** - Exclude files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
For more options, see [HTMLMinifier](https://github.com/kangax/html-minifier).
|
||||
|
||||
----------
|
||||
## CSS
|
||||
|
||||
``` yaml
|
||||
neat_css:
|
||||
enable: true
|
||||
exclude:
|
||||
- '*.min.css'
|
||||
```yaml
|
||||
minify:
|
||||
css:
|
||||
enable: true
|
||||
exclude:
|
||||
- "*.min.css"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **logger** - Verbose output. Defaults to `false`.
|
||||
- **exclude** - Exclude files
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **exclude** - Exclude files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- **level** - Optimization level. Defaults to `2`.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
----------
|
||||
For more options, see [clean-css](https://github.com/jakubpawlowicz/clean-css).
|
||||
|
||||
``` yaml
|
||||
neat_js:
|
||||
enable: true
|
||||
exclude:
|
||||
- '*.min.js'
|
||||
## JS
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
js:
|
||||
enable: true
|
||||
exclude:
|
||||
- "*.min.js"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **mangle** - Mangle file names. Defaults to `true`.
|
||||
- **logger** - Verbose output. Defaults to `false`.
|
||||
- **output** - Output options
|
||||
- **compress** - Compress options
|
||||
- **exclude** - Exclude files
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **exclude** - Exclude files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- **compress** - Compress options.
|
||||
- **mangle** - Mangle variable names. Defaults to `true`. Pass an object to specify [mangle options](https://github.com/terser-js/terser#mangle-options).
|
||||
- **output** - Output options.
|
||||
- To retain comments, `output: {comments: true}`.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
For more options, see [UglifyJS](https://github.com/mishoo/UglifyJS2).
|
||||
For more options, see [Terser](https://github.com/terser-js/terser).
|
||||
|
||||
----------
|
||||
## SVG
|
||||
|
||||
``` yaml
|
||||
neat_gzip:
|
||||
enable: true
|
||||
```yaml
|
||||
minify:
|
||||
svg:
|
||||
enable: true
|
||||
include:
|
||||
- "*.svg"
|
||||
- "!*.min.svg"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **logger** - Verbose output. Defaults to `false`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- Exclude `*.min.svg` by default.
|
||||
- **plugins** - Plugin options.
|
||||
- Examples:
|
||||
```yaml
|
||||
plugins:
|
||||
# Retain comments
|
||||
removeComments: false
|
||||
# Do not remove unused ID attributes
|
||||
cleanupIds: false
|
||||
```
|
||||
- For more options, see [svgo](https://github.com/svg/svgo).
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
----------
|
||||
## XML
|
||||
|
||||
``` yaml
|
||||
neat_brotli:
|
||||
enable: true
|
||||
Remove whitespaces in xml.
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
xml:
|
||||
enable: false
|
||||
include:
|
||||
- "*.xml"
|
||||
- "!*.min.xml"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `false`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- Exclude `*.min.xml` by default.
|
||||
- **removeComments** - Remove [comments](https://developer.mozilla.org/en-US/docs/Web/XML/XML_introduction) in xml. Defaults to `true`.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
For more options, see [minify-xml](https://github.com/kristian/minify-xml#options).
|
||||
|
||||
## JSON
|
||||
|
||||
Remove whitespaces in json.
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
json:
|
||||
enable: false
|
||||
include:
|
||||
- "*.json"
|
||||
- "!*.min.json"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `false`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- Exclude `*.min.json` by default.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
|
||||
## Gzip
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
gzip:
|
||||
enable: true
|
||||
include:
|
||||
- "*.html"
|
||||
- "*.css"
|
||||
- "*.js"
|
||||
- "*.txt"
|
||||
- "*.ttf"
|
||||
- "*.atom"
|
||||
- "*.stl"
|
||||
- "*.xml"
|
||||
- "*.svg"
|
||||
- "*.eot"
|
||||
- "*.json"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **logger** - Verbose output. Defaults to `false`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- Support one-liner, `include: ['*.html','*.css','*.js']`.
|
||||
- Must include asterisk and single quotes. `.html` is invalid. `'*.html'` is valid.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
- **level** - Compression level; lower value may results in faster compression but slightly larger (compressed) file. Range `1-9`. Defaults to `9`, or the value of [`zlib.constants.Z_BEST_COMPRESSION`](https://nodejs.org/docs/latest-v12.x/api/zlib.html#zlib_zlib_constants)
|
||||
|
||||
## HTTP Compression
|
||||
While most modern web browsers [support](https://www.caniuse.com/#feat=brotli) Brotli, you also need to consider whether web servers, hosting platforms, reverse proxy or CDN (whichever relevant to you) support it. As of 2018, GitHub & GitLab Pages and Netlify *do not* support brotli. You can still generate `.br` files, but they won't be serving those files.
|
||||
## Brotli
|
||||
|
||||
If you have access to the web server config, you should disable on-the-fly compression for static files (that are already compressed by this plugin), e.g.
|
||||
```yaml
|
||||
minify:
|
||||
brotli:
|
||||
enable: true
|
||||
include:
|
||||
- "*.html"
|
||||
- "*.css"
|
||||
- "*.js"
|
||||
- "*.txt"
|
||||
- "*.ttf"
|
||||
- "*.atom"
|
||||
- "*.stl"
|
||||
- "*.xml"
|
||||
- "*.svg"
|
||||
- "*.eot"
|
||||
- "*.json"
|
||||
```
|
||||
|
||||
- [nginx](https://github.com/google/ngx_brotli): Make sure both filter and static modules are enabled. This way pre-compressed `.br` files will be served while dynamic content can be compressed on-the-fly. Protip: `brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss;` to prevent compressing media files (which are already compressed anyway).
|
||||
- [Apache](https://httpd.apache.org/docs/2.4/en/mod/mod_brotli.html): See 'Serving pre-compressed content' section of [mod_brotli](https://httpd.apache.org/docs/2.4/en/mod/mod_brotli.html).
|
||||
- [Caddy](https://caddyserver.com/features): [0.9.4+](https://caddyserver.com/blog/caddy-0_9_4-released) by default support pre-compressed `.gz` `.br` files and on-the-fly gzip compress dynamic files.
|
||||
- [express](https://github.com/expressjs/express)/[connect](https://github.com/senchalabs/connect): Use [pre-compressed-assets](https://github.com/domadams/pre-compressed-assets). You still can continue to use [compression](https://github.com/expressjs/compression)/[shrink-ray-current](https://github.com/Alorel/shrink-ray) for dynamic files.
|
||||
- **enable** - Enable the plugin. Defaults to `true`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
- **level** - Compression level. Range `1-11`. Defaults to `11`, or the value of [`zlib.constants.BROTLI_MAX_QUALITY`](https://nodejs.org/docs/latest-v12.x/api/zlib.html#zlib_brotli_constants)
|
||||
|
||||
## Zstd
|
||||
|
||||
```yaml
|
||||
minify:
|
||||
zstd:
|
||||
enable: false
|
||||
include:
|
||||
- "*.html"
|
||||
- "*.css"
|
||||
- "*.js"
|
||||
- "*.txt"
|
||||
- "*.ttf"
|
||||
- "*.atom"
|
||||
- "*.stl"
|
||||
- "*.xml"
|
||||
- "*.svg"
|
||||
- "*.eot"
|
||||
- "*.json"
|
||||
```
|
||||
|
||||
- **enable** - Enable the plugin. Defaults to `false`.
|
||||
- **priority** - Plugin's priority. Defaults to `10`.
|
||||
- **verbose** - Verbose output. Defaults to `false`.
|
||||
- **include** - Include files. Support [wildcard](http://www.globtester.com/) pattern(s) in a string or array.
|
||||
- **globOptions** - See [globbing](#globbing) section.
|
||||
- **level** - Compression level. Range `1-22`. Defaults to `3`, or the value of [`DEFAULT_LEVEL`](https://github.com/mongodb-js/zstd/blob/a3a08c61c9045411c8275e248498dbc583457fb5/src/lib.rs#L9)
|
||||
|
||||
### Cannot find module '@mongodb-js/zstd-linux-x64-gnu'
|
||||
|
||||
`npm install --save @mongodb-js/zstd-linux-x64-gnu`
|
||||
|
||||
- @mongodb-js/zstd-darwin-arm64 (Apple Silicon)
|
||||
- @mongodb-js/zstd-darwin-x64 (Intel Mac)
|
||||
- @mongodb-js/zstd-linux-arm64-gnu
|
||||
- @mongodb-js/zstd-linux-arm64-musl (Alpine)
|
||||
- @mongodb-js/zstd-linux-x64-gnu
|
||||
- @mongodb-js/zstd-linux-x64-musl (Alpine)
|
||||
- @mongodb-js/zstd-win32-x64-msvc
|
||||
|
||||
## Globbing
|
||||
|
||||
Use "globOptions" to customise how glob patterns match files. Refer to [micromatch](https://github.com/micromatch/micromatch#options) for available options.
|
||||
|
||||
- basename is enabled by default, unless the pattern has a slash.
|
||||
- basename is disabled depending on each pattern.
|
||||
- This means the following options would work,
|
||||
|
||||
```yml
|
||||
exclude:
|
||||
- "*foo.html" # basename is enabled
|
||||
- "**/bar/*/*.html" # basename is automatically disabled
|
||||
- "*baz.css" # basename is enabled
|
||||
globOptions:
|
||||
basename: true # default
|
||||
```
|
||||
|
||||
- This behaviour doesn't apply to pattern that starts with `!` (negation).
|
||||
- This limitation only applies to `include:` option used in svg, gzip and brotli.
|
||||
- This means the following options would _not_ work,
|
||||
|
||||
```yml
|
||||
include:
|
||||
- "!foo.svg"
|
||||
- "!**/bar/*/*.svg"
|
||||
globOptions:
|
||||
basename: true
|
||||
```
|
||||
|
||||
- basename will stay disabled, if explicitly disabled in "globOptions".
|
||||
|
||||
## Credits
|
||||
|
||||
All credits go to the following work:
|
||||
|
||||
- [hexo-neat](https://github.com/rozbo/hexo-neat) by rozbo
|
||||
- neat html by [HTMLMinifier](https://github.com/kangax/html-minifier)
|
||||
- neat css by [clean-css](https://github.com/jakubpawlowicz/clean-css)
|
||||
- neat js by [UglifyJS](http://lisperator.net/uglifyjs/)
|
||||
- gzip inspired by [hexo-generator-optimize](https://github.com/JackyRen/hexo-generator-optimize)
|
||||
- gzip feature is inspired by [hexo-generator-optimize](https://github.com/JackyRen/hexo-generator-optimize)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[install]
|
||||
optional = false
|
||||
|
||||
[install.lockfile]
|
||||
save = false
|
145
index.js
145
index.js
|
@ -1,53 +1,108 @@
|
|||
/* global hexo */
|
||||
if (hexo.config.neat_enable === true) {
|
||||
// HTML minifier
|
||||
hexo.config.neat_html = Object.assign({
|
||||
enable: true,
|
||||
logger: false,
|
||||
exclude: [],
|
||||
ignoreCustomComments: [/^\s*more/],
|
||||
removeComments: true,
|
||||
removeCommentsFromCDATA: true,
|
||||
collapseWhitespace: true,
|
||||
collapseBooleanAttributes: true,
|
||||
removeEmptyAttributes: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true
|
||||
}, hexo.config.neat_html)
|
||||
'use strict'
|
||||
|
||||
// Css minifier
|
||||
hexo.config.neat_css = Object.assign({
|
||||
enable: true,
|
||||
logger: false,
|
||||
exclude: ['*.min.css']
|
||||
}, hexo.config.neat_css)
|
||||
hexo.config.minify = Object.assign({
|
||||
enable: true,
|
||||
previewServer: true
|
||||
}, hexo.config.minify)
|
||||
|
||||
// Js minifier
|
||||
hexo.config.neat_js = Object.assign({
|
||||
enable: true,
|
||||
mangle: true,
|
||||
logger: false,
|
||||
output: {},
|
||||
compress: {},
|
||||
exclude: ['*.min.js']
|
||||
}, hexo.config.neat_js)
|
||||
hexo.config.minify.html = Object.assign({
|
||||
enable: true,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
exclude: [],
|
||||
collapseBooleanAttributes: true,
|
||||
collapseWhitespace: true,
|
||||
// Ignore '<!-- more -->' https://hexo.io/docs/tag-plugins#Post-Excerpt
|
||||
ignoreCustomComments: [/^\s*more/],
|
||||
removeComments: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeScriptTypeAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.html)
|
||||
|
||||
// html, css, js compression
|
||||
hexo.config.neat_gzip = Object.assign({
|
||||
enable: true,
|
||||
logger: false
|
||||
}, hexo.config.neat_gzip)
|
||||
hexo.config.minify.css = Object.assign({
|
||||
enable: true,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
exclude: ['*.min.css'],
|
||||
level: 2,
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.css)
|
||||
|
||||
// html, css, js compression
|
||||
hexo.config.neat_brotli = Object.assign({
|
||||
enable: true,
|
||||
logger: false
|
||||
}, hexo.config.neat_brotli)
|
||||
hexo.config.minify.js = Object.assign({
|
||||
enable: true,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
exclude: ['*.min.js'],
|
||||
compress: {},
|
||||
mangle: true,
|
||||
output: {},
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.js)
|
||||
|
||||
hexo.config.minify.svg = Object.assign({
|
||||
enable: true,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.svg', '!*.min.svg'],
|
||||
plugins: {},
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.svg)
|
||||
|
||||
hexo.config.minify.gzip = Object.assign({
|
||||
enable: true,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.gzip)
|
||||
|
||||
hexo.config.minify.brotli = Object.assign({
|
||||
enable: true,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.brotli)
|
||||
|
||||
hexo.config.minify.zstd = Object.assign({
|
||||
enable: false,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.zstd)
|
||||
|
||||
hexo.config.minify.xml = Object.assign({
|
||||
enable: false,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.xml', '!*.min.xml'],
|
||||
removeComments: true,
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.xml)
|
||||
|
||||
hexo.config.minify.json = Object.assign({
|
||||
enable: false,
|
||||
priority: 10,
|
||||
verbose: false,
|
||||
include: ['*.json', '!*.min.json'],
|
||||
globOptions: { basename: true }
|
||||
}, hexo.config.minify.json)
|
||||
|
||||
if (hexo.config.minify.enable === true && !(hexo.config.minify.previewServer === true && ['s', 'server'].includes(hexo.env.cmd))) {
|
||||
const filter = require('./lib/filter')
|
||||
hexo.extend.filter.register('after_render:html', filter.logicHtml)
|
||||
hexo.extend.filter.register('after_render:css', filter.logicCss)
|
||||
hexo.extend.filter.register('after_render:js', filter.logicJs)
|
||||
hexo.extend.filter.register('after_generate', filter.logicGzip)
|
||||
hexo.extend.filter.register('after_generate', filter.logicBrotli)
|
||||
hexo.extend.filter.register('after_render:html', filter.minifyHtml, hexo.config.minify.html.priority)
|
||||
hexo.extend.filter.register('after_render:css', filter.minifyCss, hexo.config.minify.css.priority)
|
||||
hexo.extend.filter.register('after_render:js', filter.minifyJs, hexo.config.minify.js.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.minifySvg, hexo.config.minify.svg.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.gzipFn, hexo.config.minify.gzip.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.brotliFn, hexo.config.minify.brotli.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.zstdFn, hexo.config.minify.zstd.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.minifyXml, hexo.config.minify.xml.priority)
|
||||
hexo.extend.filter.register('after_generate', filter.minifyJson, hexo.config.minify.json.priority)
|
||||
}
|
||||
|
|
467
lib/filter.js
467
lib/filter.js
|
@ -1,184 +1,337 @@
|
|||
/* global hexo */
|
||||
'use strict'
|
||||
|
||||
const { minify: htmlMinify } = require('html-minifier-terser')
|
||||
const CleanCSS = require('clean-css')
|
||||
const UglifyJS = require('uglify-js')
|
||||
const Htmlminifier = require('html-minifier').minify
|
||||
const Promise = require('bluebird')
|
||||
const minimatch = require('minimatch')
|
||||
const { minify: terserMinify } = require('terser')
|
||||
const { optimize: svgOptimize } = require('svgo')
|
||||
const zlib = require('zlib')
|
||||
const br = require('iltorb')
|
||||
const { promisify } = require('util')
|
||||
const gzip = promisify(zlib.gzip)
|
||||
const br = promisify(zlib.brotliCompress)
|
||||
const { minify: compressXml } = require('minify-xml')
|
||||
const micromatch = require('micromatch')
|
||||
const { compress: zstd } = require('@mongodb-js/zstd')
|
||||
|
||||
function logicHtml (str, data) {
|
||||
const hexo = this
|
||||
const options = hexo.config.neat_html
|
||||
// Return if disabled.
|
||||
if (options.enable === false) return
|
||||
|
||||
let path = data.path
|
||||
let exclude = options.exclude
|
||||
if (exclude && !Array.isArray(exclude)) exclude = [exclude]
|
||||
|
||||
if (path && exclude && exclude.length) {
|
||||
for (let i = 0, len = exclude.length; i < len; i++) {
|
||||
if (minimatch(path, exclude[i], { matchBase: true })) return str
|
||||
}
|
||||
}
|
||||
|
||||
let result = Htmlminifier(str, options)
|
||||
let saved = ((str.length - result.length) / str.length * 100).toFixed(2)
|
||||
if (options.logger) {
|
||||
let log = hexo.log || console.log
|
||||
log.log('Minify the html: %s [%s saved]', path, saved + '%')
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function logicCss (str, data) {
|
||||
const hexo = this
|
||||
const options = hexo.config.neat_css
|
||||
// Return if disabled.
|
||||
if (options.enable === false) return
|
||||
|
||||
let path = data.path
|
||||
let exclude = options.exclude
|
||||
if (exclude && !Array.isArray(exclude)) exclude = [exclude]
|
||||
|
||||
if (path && exclude && exclude.length) {
|
||||
for (let i = 0, len = exclude.length; i < len; i++) {
|
||||
if (minimatch(path, exclude[i], { matchBase: true })) return str
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
new CleanCSS({ level: 2 }).minify(str, function (err, result) {
|
||||
if (err) return reject(err)
|
||||
let saved = ((str.length - result.styles.length) / str.length * 100).toFixed(2)
|
||||
resolve(result.styles)
|
||||
if (options.logger) {
|
||||
let log = hexo.log || console.log
|
||||
log.log('Minify the css: %s [%s saved]', path, saved + '%')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function logicJs (str, data) {
|
||||
const hexo = this
|
||||
const options = hexo.config.neat_js
|
||||
// Return if disabled.
|
||||
if (options.enable === false) return
|
||||
|
||||
let path = data.path
|
||||
let exclude = options.exclude
|
||||
if (exclude && !Array.isArray(exclude)) exclude = [exclude]
|
||||
|
||||
if (path && exclude && exclude.length) {
|
||||
for (let i = 0, len = exclude.length; i < len; i++) {
|
||||
if (minimatch(path, exclude[i], { matchBase: true })) return str
|
||||
}
|
||||
}
|
||||
|
||||
// uglifyjs doesn't like unsupported options
|
||||
delete options.enable
|
||||
delete options.exclude
|
||||
let jsLogger = options.logger
|
||||
delete options.logger
|
||||
|
||||
let result = UglifyJS.minify(str, options)
|
||||
let saved = ((str.length - result.code.length) / str.length * 100).toFixed(2)
|
||||
if (jsLogger) {
|
||||
let log = hexo.log || console.log
|
||||
log.log('Minify the js: %s [%s saved]', path, saved + '%')
|
||||
}
|
||||
return result.code
|
||||
}
|
||||
|
||||
function logicGzip () {
|
||||
const hexo = this
|
||||
const options = hexo.config.neat_gzip
|
||||
// Return if disabled.
|
||||
if (options.enable === false) return
|
||||
|
||||
let route = hexo.route
|
||||
let routeList = route.list()
|
||||
|
||||
return Promise.all(routeList.filter(path => (path.endsWith('.html') || path.endsWith('.js') || path.endsWith('.css'))).map(path => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Grab all assets using hexo router
|
||||
let assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
// Extract the content
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', () => {
|
||||
if (assetTxt.length) {
|
||||
// gzip compress using highest level
|
||||
zlib.gzip(assetTxt, { level: zlib.Z_BEST_COMPRESSION }, (err, Input) => {
|
||||
if (!err) {
|
||||
// Save the compressed file to .gz
|
||||
route.set(path + '.gz', Input)
|
||||
// Logging
|
||||
let saved = ((assetTxt.length - Input.toString().length) / assetTxt.length * 100).toFixed(2)
|
||||
if (options.logger) {
|
||||
let log = hexo.log || console.log
|
||||
log.log('Gzip-compressed %s [%s saved]', path, saved + '%')
|
||||
}
|
||||
resolve(assetTxt)
|
||||
} else {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
const isMatch = (path = '', patterns = [], options = {}) => {
|
||||
if (path && patterns) {
|
||||
if (path.length && patterns.length) {
|
||||
if (typeof patterns === 'string') patterns = [patterns]
|
||||
for (const pattern of patterns) {
|
||||
// disable basename if a pattern includes a slash
|
||||
let { basename } = options
|
||||
// only disable when basename is enabled
|
||||
basename = basename && !pattern.includes('/')
|
||||
if (micromatch.isMatch(path, pattern, { ...options, basename })) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const match = (paths = [], patterns = [], options = {}) => {
|
||||
let input = paths
|
||||
if (paths && patterns) {
|
||||
if (paths.length && patterns.length) {
|
||||
const output = []
|
||||
if (typeof patterns === 'string') patterns = [patterns]
|
||||
const exclude = patterns.filter((pattern) => pattern.startsWith('!'))
|
||||
const include = patterns.filter((pattern) => !pattern.startsWith('!'))
|
||||
if (exclude.length) input = micromatch(paths, exclude, options)
|
||||
if (include.length) {
|
||||
for (const pattern of include) {
|
||||
let { basename } = options
|
||||
basename = basename && !pattern.includes('/')
|
||||
const tmp = micromatch(input, pattern, { ...options, basename })
|
||||
if (tmp.length) output.push(...tmp)
|
||||
}
|
||||
return [...new Set(output)]
|
||||
}
|
||||
return input
|
||||
}
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
function logFn (original, minified, path, ext) {
|
||||
const saved = ((original.length - minified.length) / original.length * 100).toFixed(2)
|
||||
const log = this.log || console
|
||||
log.log(`${ext}: ${path} [${saved}% saved]`)
|
||||
}
|
||||
|
||||
async function minifyHtml (str, data) {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.html
|
||||
if (options.enable === false || !str) return
|
||||
|
||||
const { path } = data
|
||||
const { exclude, globOptions, verbose } = options
|
||||
|
||||
// Return if a path matches exclusion pattern
|
||||
if (isMatch(path, exclude, globOptions)) return str
|
||||
|
||||
try {
|
||||
const result = await htmlMinify(str, options)
|
||||
if (verbose) logFn.call(this, str, result, path, 'html')
|
||||
|
||||
return result
|
||||
} catch (err) {
|
||||
throw new Error(`Path: ${path}\n${err}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function minifyCss (str, data) {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.css
|
||||
if (options.enable === false || !str) return
|
||||
|
||||
const { path } = data
|
||||
const { exclude, globOptions, verbose } = options
|
||||
|
||||
if (isMatch(path, exclude, globOptions)) return str
|
||||
|
||||
try {
|
||||
const { styles } = await new CleanCSS(options).minify(str)
|
||||
if (verbose) logFn.call(this, str, styles, path, 'css')
|
||||
return styles
|
||||
} catch (err) {
|
||||
throw new Error(`Path: ${path}\n${err}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function minifyJs (str, data) {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.js
|
||||
if (options.enable === false || !str) return
|
||||
|
||||
const { path } = data
|
||||
const { exclude, globOptions, verbose } = options
|
||||
|
||||
if (isMatch(path, exclude, globOptions)) return str
|
||||
|
||||
// Terser doesn't like unsupported options
|
||||
const jsOptions = Object.assign({}, options)
|
||||
delete jsOptions.enable
|
||||
delete jsOptions.priority
|
||||
delete jsOptions.verbose
|
||||
// Old option, retained to avoid crash when upgrading to v4
|
||||
delete jsOptions.logger
|
||||
delete jsOptions.exclude
|
||||
delete jsOptions.globOptions
|
||||
|
||||
try {
|
||||
const { code } = await terserMinify(str, jsOptions)
|
||||
if (verbose) logFn.call(this, str, code, path, 'js')
|
||||
return code
|
||||
} catch (err) {
|
||||
throw new Error(`Path: ${path}\n${err}`)
|
||||
}
|
||||
}
|
||||
|
||||
function minifySvg () {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.svg
|
||||
if (options.enable === false) return
|
||||
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
// const plugins = Array.isArray(options.plugins) ? extendDefaultPlugins(options.plugins) : extendDefaultPlugins([])
|
||||
const pluginCfg = Object.prototype.toString.call(options.plugins) === '[object Object]' ? { ...options.plugins } : {}
|
||||
const plugins = [{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: pluginCfg
|
||||
}
|
||||
}]
|
||||
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', async () => {
|
||||
if (assetTxt.length) {
|
||||
try {
|
||||
const { data } = svgOptimize(assetTxt, { ...options, plugins })
|
||||
if (verbose) logFn.call(this, assetTxt, data, path, 'svg')
|
||||
resolve(route.set(path, data))
|
||||
} catch (err) {
|
||||
reject(new Error(`Path: ${path}\n${err}`))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function logicBrotli () {
|
||||
function gzipFn () {
|
||||
const hexo = this
|
||||
const options = hexo.config.neat_brotli
|
||||
// Return if disabled.
|
||||
const options = hexo.config.minify.gzip
|
||||
if (options.enable === false) return
|
||||
|
||||
let route = hexo.route
|
||||
let routeList = route.list()
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
let { level } = options
|
||||
if (typeof level !== 'number') level = zlib.constants.Z_BEST_COMPRESSION
|
||||
|
||||
return Promise.all(routeList.filter(path => (path.endsWith('.html') || path.endsWith('.js') || path.endsWith('.css'))).map(path => {
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Grab all assets using hexo router
|
||||
let assetPath = route.get(path)
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', async () => {
|
||||
if (assetTxt.length) {
|
||||
try {
|
||||
const result = await gzip(assetTxt, { level })
|
||||
if (verbose) logFn.call(this, assetTxt, result, path, 'gzip')
|
||||
resolve(route.set(path + '.gz', result))
|
||||
} catch (err) {
|
||||
reject(new Error(`Path: ${path}\n${err}`))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function brotliFn () {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.brotli
|
||||
if (options.enable === false) return
|
||||
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
let { level } = options
|
||||
if (typeof level !== 'number') level = zlib.constants.BROTLI_MAX_QUALITY
|
||||
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', async () => {
|
||||
if (assetTxt.length) {
|
||||
try {
|
||||
const result = await br(assetTxt, { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: level } })
|
||||
if (verbose) logFn.call(this, assetTxt, result, path, 'brotli')
|
||||
resolve(route.set(path + '.br', result))
|
||||
} catch (err) {
|
||||
reject(new Error(`Path: ${path}\n${err}`))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function zstdFn () {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.zstd
|
||||
if (options.enable === false) return
|
||||
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
let { level } = options
|
||||
if (typeof level !== 'number') level = undefined
|
||||
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', async () => {
|
||||
if (assetTxt.length) {
|
||||
try {
|
||||
const input = Buffer.from(assetTxt, 'utf-8')
|
||||
const result = await zstd(input, level)
|
||||
if (verbose) logFn.call(this, assetTxt, result, path, 'zstd')
|
||||
resolve(route.set(path + '.zst', result))
|
||||
} catch (err) {
|
||||
reject(new Error(`Path: ${path}\n${err}`))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function minifyXml () {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.xml
|
||||
if (options.enable === false) return
|
||||
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
// Extract the content
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', () => {
|
||||
if (assetTxt.length) {
|
||||
// Input has to be buffer for brotli
|
||||
let input = new Buffer.from(assetTxt, 'utf-8')
|
||||
// brotli compress using highest level
|
||||
br.compress(input, { quality: br.BROTLI_MAX_QUALITY }, (err, output) => {
|
||||
if (!err) {
|
||||
// Save the compressed file to .br
|
||||
route.set(path + '.br', output)
|
||||
// Logging
|
||||
let saved = ((input.length - output.toString().length) / input.length * 100).toFixed(2)
|
||||
if (options.logger) {
|
||||
let log = hexo.log || console.log
|
||||
log.log('Brotli-compressed %s [%s saved]', path, saved + '%')
|
||||
}
|
||||
resolve(assetTxt)
|
||||
} else {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
try {
|
||||
const result = compressXml(assetTxt, { ...options })
|
||||
if (verbose) logFn.call(this, assetTxt, result, path, 'xml')
|
||||
resolve(route.set(path, result))
|
||||
} catch (err) {
|
||||
reject(new Error(`Path: ${path}\n${err}`))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
function minifyJson () {
|
||||
const hexo = this
|
||||
const options = hexo.config.minify.json
|
||||
if (options.enable === false) return
|
||||
|
||||
const { route } = hexo
|
||||
const routeList = route.list()
|
||||
const { globOptions, include, verbose } = options
|
||||
|
||||
return Promise.all((match(routeList, include, globOptions)).map((path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const assetPath = route.get(path)
|
||||
let assetTxt = ''
|
||||
assetPath.on('data', (chunk) => (assetTxt += chunk))
|
||||
assetPath.on('end', () => {
|
||||
if (assetTxt.length) {
|
||||
try {
|
||||
const result = JSON.stringify(JSON.parse(assetTxt))
|
||||
if (verbose) logFn.call(this, assetTxt, result, path, 'json')
|
||||
resolve(route.set(path, result))
|
||||
} catch (err) {
|
||||
reject(new Error(`Path: ${path}\n${err}`))
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
logicHtml: logicHtml,
|
||||
logicCss: logicCss,
|
||||
logicJs: logicJs,
|
||||
logicGzip: logicGzip,
|
||||
logicBrotli: logicBrotli
|
||||
minifyHtml,
|
||||
minifyCss,
|
||||
minifyJs,
|
||||
minifySvg,
|
||||
gzipFn,
|
||||
brotliFn,
|
||||
zstdFn,
|
||||
minifyXml,
|
||||
minifyJson
|
||||
}
|
||||
|
|
52
package.json
52
package.json
|
@ -1,39 +1,57 @@
|
|||
{
|
||||
"name": "hexo-yam",
|
||||
"description": "Yet Another Minifier. Minify and compress html, js and css",
|
||||
"version": "1.0.4",
|
||||
"description": "Yet Another Minifier. Minify and compress html, js, css, svg, xml and json",
|
||||
"version": "9.0.0",
|
||||
"readme": "README.md",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
"lib": "./lib"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
"files": [
|
||||
"lib/",
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"test": "jest"
|
||||
},
|
||||
"author": "weyusi",
|
||||
"engines": {
|
||||
"node": ">= 18.12.0"
|
||||
},
|
||||
"author": "curben",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/weyusi/hexo-yam",
|
||||
"homepage": "https://github.com/curbengh/hexo-yam",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/weyusi/hexo-yam.git"
|
||||
"url": "git+https://github.com/curbengh/hexo-yam.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "^3.5.2",
|
||||
"clean-css": "^4.2.1",
|
||||
"html-minifier": "^3.5.20",
|
||||
"iltorb": "^2.4.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"uglify-js": "^3.4.9"
|
||||
"clean-css": "^5.1.2",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"micromatch": "^4.0.2",
|
||||
"minify-xml": "^3.2.0",
|
||||
"svgo": "^3.0.0",
|
||||
"terser": "^5.3.0",
|
||||
"@mongodb-js/zstd": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"hexo": "^7.1.0",
|
||||
"jest": "^29.1.2",
|
||||
"standard": "^17.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"html",
|
||||
"js",
|
||||
"css",
|
||||
"minify",
|
||||
"compress",
|
||||
"gzip",
|
||||
"brotli",
|
||||
"zstd",
|
||||
"hexo-yam",
|
||||
"hexo"
|
||||
]
|
||||
],
|
||||
"jest": {
|
||||
"clearMocks": true,
|
||||
"collectCoverage": true,
|
||||
"coverageDirectory": "./coverage/",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const zlib = require('zlib')
|
||||
const { promisify } = require('util')
|
||||
const brotli = promisify(zlib.brotliCompress)
|
||||
const unbrotli = promisify(zlib.brotliDecompress)
|
||||
|
||||
describe('brotli', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const b = require('../lib/filter').brotliFn.bind(hexo)
|
||||
const path = 'foo.txt'
|
||||
const input = 'Lorem ipsum dolor sit amet consectetur adipiscing elit fusce'
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
brotli: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await b()
|
||||
|
||||
const output = hexo.route.get(path.concat('.br'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await brotli(input)
|
||||
const resultUnbr = await unbrotli(result)
|
||||
const expectedUnbr = await unbrotli(expected)
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
expect(resultUnbr.toString()).toBe(input)
|
||||
expect(expectedUnbr.toString()).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.brotli.enable = false
|
||||
const result = await b()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
expect(routeList).not.toContain(path.concat('.br'))
|
||||
|
||||
const result = await b()
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const level = 1
|
||||
hexo.config.minify.brotli.level = level
|
||||
await b()
|
||||
|
||||
const output = hexo.route.get(path.concat('.br'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await brotli(input, { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: level } })
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.brotli.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await b()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`brotli: ${path}`)
|
||||
})
|
||||
|
||||
test('option - level is string', async () => {
|
||||
const level = 'foo'
|
||||
hexo.config.minify.brotli.level = level
|
||||
await b()
|
||||
|
||||
const output = hexo.route.get(path.concat('.br'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await brotli(input, { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY } })
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - exclude non-text file by default', async () => {
|
||||
const path = 'foo.jpg'
|
||||
hexo.route.set(path, input)
|
||||
await b()
|
||||
|
||||
const result = hexo.route.get(path.concat('.br'))
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.brotli.include = 'bar.txt'
|
||||
const path = 'foo/bar.txt'
|
||||
hexo.route.set(path, input)
|
||||
await b()
|
||||
|
||||
const result = hexo.route.get(path.concat('.br'))
|
||||
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.brotli.include = '**/lectus/**/*.txt'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.txt'
|
||||
hexo.route.set(path, input)
|
||||
await b()
|
||||
|
||||
const result = hexo.route.get(path.concat('.br'))
|
||||
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
test('include - basename + slash + basename enabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.brotli.include = [
|
||||
'*.html',
|
||||
'**/sociis/**/*.css'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await b()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = [
|
||||
'lorem/ipsum/dolor.html.br',
|
||||
'gravida/sociis/erat/ante.css.br'
|
||||
]
|
||||
const notExpected = [
|
||||
'aptent/elementum.js.br',
|
||||
'felis/blandit/cursus.svg.br'
|
||||
]
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
||||
})
|
||||
|
||||
test('include - basename + slash + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.brotli.include = [
|
||||
'*.html',
|
||||
'**/sociis/**/*.css'
|
||||
]
|
||||
hexo.config.minify.brotli.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await b()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = [
|
||||
'gravida/sociis/erat/ante.css.br'
|
||||
]
|
||||
const notExpected = [
|
||||
'lorem/ipsum/dolor.html.br',
|
||||
'aptent/elementum.js.br',
|
||||
'felis/blandit/cursus.svg.br'
|
||||
]
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.brotli.include = [
|
||||
'!dolor.html'
|
||||
]
|
||||
hexo.config.minify.brotli.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await b()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = paths.map((path) => path.concat('.br'))
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
})
|
||||
|
||||
test('blns', async () => {
|
||||
const blns = require('./fixtures/blns.json')
|
||||
|
||||
for (const nStr of blns) {
|
||||
hexo.route.remove(path)
|
||||
|
||||
hexo.route.set(path, nStr)
|
||||
|
||||
await b()
|
||||
|
||||
const output = hexo.route.get(path.concat('.br'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const resultUnbr = await unbrotli(result)
|
||||
|
||||
expect(resultUnbr.toString()).toBe(nStr)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,107 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const CleanCSS = require('clean-css')
|
||||
|
||||
describe('css', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const c = require('../lib/filter').minifyCss.bind(hexo)
|
||||
const input = 'foo { bar: baz; } foo { aaa: bbb; }'
|
||||
const path = 'foo.css'
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
css: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
exclude: ['*.min.css'],
|
||||
level: 2,
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
const result = await c(input, { path })
|
||||
const { styles } = await new CleanCSS(hexo.config.minify.css).minify(input)
|
||||
|
||||
expect(result).toBe(styles)
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.css.enable = false
|
||||
const result = await c(input, { path })
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
const result = await c('', { path })
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const customOpt = {
|
||||
level: {
|
||||
1: {
|
||||
mergeAdjacentRules: false
|
||||
}
|
||||
}
|
||||
}
|
||||
hexo.config.minify.css = customOpt
|
||||
|
||||
const result = await c(input, { path })
|
||||
const { styles } = await new CleanCSS(customOpt).minify(input)
|
||||
|
||||
expect(result).toBe(styles)
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.css.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await c(input, { path })
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`css: ${path}`)
|
||||
})
|
||||
|
||||
test('option - invalid', async () => {
|
||||
const customOpt = {
|
||||
level: 9000
|
||||
}
|
||||
hexo.config.minify.css = customOpt
|
||||
|
||||
let expected
|
||||
try {
|
||||
await new CleanCSS(customOpt).minify(input)
|
||||
} catch (err) {
|
||||
expected = err
|
||||
}
|
||||
|
||||
expect(expected).toBeDefined()
|
||||
await expect(c(input, { path })).rejects.toThrow(`Path: ${path}\n${expected}`)
|
||||
})
|
||||
|
||||
test('exclude - *.min.css', async () => {
|
||||
const result = await c(input, { path: 'foo/bar.min.css' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - basename', async () => {
|
||||
const exclude = '*baz.css'
|
||||
hexo.config.minify.css.exclude = exclude
|
||||
const result = await c(input, { path: 'foo/barbaz.css' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - slash in pattern', async () => {
|
||||
const exclude = '**/lectus/**/*.css'
|
||||
hexo.config.minify.css.exclude = exclude
|
||||
const result = await c(input, { path: 'eleifend/lectus/nullam/dapibus/netus.css' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,516 @@
|
|||
[
|
||||
"undefined",
|
||||
"undef",
|
||||
"null",
|
||||
"NULL",
|
||||
"(null)",
|
||||
"nil",
|
||||
"NIL",
|
||||
"true",
|
||||
"false",
|
||||
"True",
|
||||
"False",
|
||||
"TRUE",
|
||||
"FALSE",
|
||||
"None",
|
||||
"hasOwnProperty",
|
||||
"then",
|
||||
"\\",
|
||||
"\\\\",
|
||||
"0",
|
||||
"1",
|
||||
"1.00",
|
||||
"$1.00",
|
||||
"1/2",
|
||||
"1E2",
|
||||
"1E02",
|
||||
"1E+02",
|
||||
"-1",
|
||||
"-1.00",
|
||||
"-$1.00",
|
||||
"-1/2",
|
||||
"-1E2",
|
||||
"-1E02",
|
||||
"-1E+02",
|
||||
"1/0",
|
||||
"0/0",
|
||||
"-2147483648/-1",
|
||||
"-9223372036854775808/-1",
|
||||
"-0",
|
||||
"-0.0",
|
||||
"+0",
|
||||
"+0.0",
|
||||
"0.00",
|
||||
"0..0",
|
||||
".",
|
||||
"0.0.0",
|
||||
"0,00",
|
||||
"0,,0",
|
||||
",",
|
||||
"0,0,0",
|
||||
"0.0/0",
|
||||
"1.0/0.0",
|
||||
"0.0/0.0",
|
||||
"1,0/0,0",
|
||||
"0,0/0,0",
|
||||
"--1",
|
||||
"-",
|
||||
"-.",
|
||||
"-,",
|
||||
"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999",
|
||||
"NaN",
|
||||
"Infinity",
|
||||
"-Infinity",
|
||||
"INF",
|
||||
"1#INF",
|
||||
"-1#IND",
|
||||
"1#QNAN",
|
||||
"1#SNAN",
|
||||
"1#IND",
|
||||
"0x0",
|
||||
"0xffffffff",
|
||||
"0xffffffffffffffff",
|
||||
"0xabad1dea",
|
||||
"123456789012345678901234567890123456789",
|
||||
"1,000.00",
|
||||
"1 000.00",
|
||||
"1'000.00",
|
||||
"1,000,000.00",
|
||||
"1 000 000.00",
|
||||
"1'000'000.00",
|
||||
"1.000,00",
|
||||
"1 000,00",
|
||||
"1'000,00",
|
||||
"1.000.000,00",
|
||||
"1 000 000,00",
|
||||
"1'000'000,00",
|
||||
"01000",
|
||||
"08",
|
||||
"09",
|
||||
"2.2250738585072011e-308",
|
||||
",./;'[]\\-=",
|
||||
"<>?:\"{}|_+",
|
||||
"!@#$%^&*()`~",
|
||||
"\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f",
|
||||
"ᅡタᅡチᅡツᅡテᅡトᅡニᅡヌᅡネᅡノᅡハᅡヒᅡフᅡヘᅡホᅡマᅡミᅡムᅡメᅡモᅡヤᅡユᅡヨᅡラᅡリᅡルᅡレᅡロᅡワᅡンᅡ゙ᅡ゚",
|
||||
"\t\u000b\f ᅡナ £レタ¬タツ¬タテ¬タツ¬タテ¬タト¬タナ¬タニ¬タヌ¬タネ¬タノ¬タハ¬タヒ¬タᄄ¬タᄅ¬タᆵ¬チ゚ ̄タタ",
|
||||
"ᅡᆳタチツテトナワᅴンᅵマ£ᅠホ¬タヒ¬タフ¬タヘ¬タホ¬タマ¬タᆰ¬タᆱ¬タᆲ¬タᆳ¬タᆴ¬チᅠ¬チᄀ¬チᄁ¬チᆪ¬チᄂ¬チᆭ¬チᄃ¬チᄄ¬チᄅ¬チᆰ¬チᆱ¬チᆲ¬チᆳ¬チᆴ¬チᆵᄏᄍᄎᄏムツᄑロᄇᅠロᄇᄀロᄇᄁロᄇᆪンナᄈンナᄡンナᄉンナᄊンナᄋンナᄌンナᄍンナᄎᅠタチᅠタᅠᅠタᄀᅠタᄁᅠタᆪᅠタᄂᅠタᆬᅠタᆭᅠタᄃᅠタᄄᅠタᄅᅠタᆰᅠタᆱᅠタᆲᅠタᆳᅠタᆴᅠタᆵᅠタᄚᅠタᄆᅠタᄇᅠタᄈᅠタᄡᅠタᄉᅠタᄊᅠタᄋᅠタᄌᅠタᄍᅠタᄎᅠタᄏᅠタᄐᅠタᄑᅠタᄒᅠタᅠチタᅠチチᅠチツᅠチテᅠチトᅠチナᅠチニᅠチヌᅠチネᅠチノᅠチハᅠチヒᅠチフᅠチヘᅠチホᅠチマᅠチミᅠチムᅠチメᅠチモᅠチヤᅠチユᅠチヨᅠチラᅠチリᅠチルᅠチレᅠチロᅠチワᅠチンᅠヂᅠチ゚ᅠチᅠᅠチᄀᅠチᄁᅠチᆪᅠチᄂᅠチᆬᅠチᆭᅠチᄃᅠチᄄᅠチᄅᅠチᆰᅠチᆱᅠチᆲᅠチᆳᅠチᆴᅠチᆵᅠチᄚᅠチᄆᅠチᄇᅠチᄈᅠチᄡᅠチᄉᅠチᄊᅠチᄋᅠチᄌᅠチᄍᅠチᄎᅠチᄏᅠチᄐᅠチᄑᅠチᄒᅠチ",
|
||||
"ᄏ",
|
||||
"ᄒ",
|
||||
"ᅫᄅ¬ノネᅢᄃ¬ネレ¬ネᆱᅨワᅡᄉ¬ノᄂ¬ノᆬᅢᄋ",
|
||||
"ᅢᆬᅢ゚¬ネツᅥメᅡ례ル¬ネニᅨレᅡᆲ¬タᆭᅢᆭ",
|
||||
"ᅤモ¬ネムᅡᄡᅡᆴ¬タᅠᅡᆬᅡ뗴ニᅢ죄タ¬タワ¬タリ",
|
||||
"ᅡᄀ¬ト깏ᅡᄁ¬ネ゙ᅡ다ᄊ¬タ깕ᅡᄎ¬タモ¬ノᅠ",
|
||||
"ᅡ졔ロᅢヌ¬ラハᅣ몌ワᅢツᅡᆵᅨリᅡ",
|
||||
"ᅢナᅢヘᅢホᅢマᅨンᅢモᅢヤᆪᅢメᅢレᅢニ¬リテ",
|
||||
"ᅤメ¬ダᅡᄡ¬タᄚᅨヌᅢチᅡ뗴ニᅢリ¬ネマ¬タン¬タル",
|
||||
"`¬チト¬ツᆲ¬タᄍ¬タᄎᆲチᆲツ¬タ가ᄚᅡᄋ¬タレ¬タヤᅡᄆ",
|
||||
"¬ナロ¬ナワ¬ナン¬ナ゙",
|
||||
"チツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒタチツテトナニヌネノハヒフヘホマ",
|
||||
"ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅ",
|
||||
"¬チᄚ¬チᄡ¬チᄉ",
|
||||
"¬ツタ¬ツチ¬ツツ",
|
||||
"¬チᄚ¬チᄡ¬チᄉ¬ツタ¬ツチ¬ツツ",
|
||||
"¢ᄌヤ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ ¢ᄌヤ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ ¢ᄌヤ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍノ¢ᄍヌ¢ᄍヌ¢ᄍヌ¢ᄍヌ",
|
||||
"'",
|
||||
"\"",
|
||||
"''",
|
||||
"\"\"",
|
||||
"'\"'",
|
||||
"\"''''\"'\"",
|
||||
"\"'\"'\"''''\"",
|
||||
"<foo val=¬タワbar¬タン />",
|
||||
"<foo val=¬タワbar¬タン />",
|
||||
"<foo val=¬タンbar¬タワ />",
|
||||
"<foo val=`bar' />",
|
||||
"ヤᄚ¦ᄌᆳ ̄チユ ̄ツモ ̄チᆱ ̄チツ ̄チメ ̄チᆭ¦ᄌヒ ̄チユ ̄チト",
|
||||
" ̄テム ̄テᄐ ̄テニ ̄ツᆪ ̄テᄐ ̄チᄌ│ᄀフ ̄チヒ ̄チᆰ ̄チト ̄チヒ",
|
||||
"¥メフ│ᆪᄑ₩ᄐᄁ│ᆰ゙",
|
||||
"←テᄄ│ミᄑ₩ᅠᄐ",
|
||||
"↓ツᆲ■レフ↑ᄈᄐ■ユル↓ロミ ↓ヨᄡ■ユル↓ラᄚ↑ᄉᆲ↓ニフ",
|
||||
"↓ᄚᆭ↓ᄚᄄ→ᆬᄐ ■テタ↑ᄈᅠ ↓リᄄ ■ホᄇ↓ヒワ→ᄃᄄ↑ᄈᄐ ↓ムロ→ヒᄂ→ᆭᆲ →リᅠ→ᄚᄅ↑ᄚチ■ユリ",
|
||||
"ᄂᄒ₩ワテᄃム¥ᆳᄌ←ルᄁ│ᆰ゙¥ᆳᄌᅠヤᄅᄊ₩ノタ",
|
||||
"↓レᄌ→゙タ→ᄚヤ■ニᅠ→ᆬᄡ",
|
||||
"ᅠワホᅠワᄆᅠンᄍᅠᄆモᅠᄆᄌᅠᄇヨᅠᄈマ",
|
||||
"ミミワ ミミヤミミヌミミンミミタミミᄀミミヌミミモ ミミルミミハミミᄀミミンミミモ/ミミンミミヌミミラミミハミミᄂミミヤ ミミメミミヒミミラ ミミメミミフ ミミワ ミミᄀミミタミミヨミミヌミミᄂミミモミミン ミミᄆミムツ ミムト ミミヤミミヌミミンミミタミミᄀミミヌミミモ ミミマミミニミミナミミᄂミミニミミレミミハミミᄀミミンミミニミミモミミニ",
|
||||
"│ᄀᄄ ̄テン ̄チツA←ᄋラᅤメᅢᄅᄐᄁ←タヘᅢワᅢ゚ᅡᆰᅣナᅢᄆ¦ᄌツ ̄ミタᅠタタ",
|
||||
"ᄎ",
|
||||
"ᄒ",
|
||||
" ̄テᄑ¢ᄐᄐ¢ᄎネトᅪワ¢ᄎネ¢ᄐᄑᄒノ  ̄テᄑ¢ᄐᄐ¢ᄎネトᅪワ¢ᄎネ¢ᄐᄑᄒノ",
|
||||
"(ᄑᄀ¬ラユ ¬ネタ ¬ラユᄑᄀ)",
|
||||
"ᄑタᄑᄄ(ᅡᄡ¬ネタᄑタ¬ネᄅ",
|
||||
"__ᄒロ(,_,*)",
|
||||
" ̄テᄏ(ᆪ¬ネタᆪ) ̄テᄏ:*:",
|
||||
"ᄒ゚ᄑᆬ¬ワ ̄テᄒ¬ユᄇ(ᄑᄀ¬ラユ¬タ¬ラユᄑᄀ)¬ユᄆ¬ワᄑᆬᄒ゚",
|
||||
", ̄タツ ̄テᄏ:*: ̄テᄏ ̄ツワ¬タル( ¬リᄏ ᅬノ ¬リᄏ ) ̄タツ ̄テᄏ:*: ̄テᄏ ̄ツワ¬タル",
|
||||
"(¬ユᆵᅡᄚ¬ヨ가ᄚᄐノ¬ユᆵᄌᄉ ¬ヤᄏ¬ヤチ¬ヤᄏ)",
|
||||
"(ᄒノ¢ᄇᆬロハ¢ᄇᆬᄐノᄒノᄏ ¬ヤᄏ¬ヤチ¬ヤᄏ",
|
||||
"¬ヤᆲ¬ヤタ¬ヤᆲ ̄テホ( ᅡᄎ _ ᅡᄎ ̄テホ)",
|
||||
"( ᅪ가ᄚ ᅪワᅧヨ ᅪ가ᄚ)",
|
||||
"ᅡᆵ\\_( ̄テト)_/ᅡᆵ",
|
||||
"゚リヘ",
|
||||
"゚ムᄅ゚マᄑ",
|
||||
"゚ムᄄ¬タペᆭᄚ ゚ムᄄ゚マ¬タペᆭᄚ ゚ムᄄ¬タペᆭᄆ ゚ムᄄ゚マ¬タペᆭᄆ ゚ᆭᄍ゚マ¬タヘ¬ルツᄌマ",
|
||||
"゚ムᄒ ゚ルヌ ゚メチ ゚ルナ ゚ルニ ゚ルヒ ゚ルホ ゚ルヘ",
|
||||
"゚ミᄉ ゚ルネ ゚ルノ ゚ルハ",
|
||||
"¬ンᄂᄌマ ゚メヤ ゚メフ ゚メユ ゚メ゙ ゚メモ ゚メラ ゚メヨ ゚メリ ゚メン ゚メ゚ ゚メワ ゚メロ ゚メレ ゚メル",
|
||||
"¬ワピマ ゚メᆰ゚マ ゚ムミ゚マ ゚ルプマ ゚ムマ゚マ ゚ルマ゚マ",
|
||||
"゚ムᄄ¬タペムᄅ¬タペムᆭ ゚ムᄄ¬タペムᄅ¬タペムᄃ¬タペムᆭ ゚ムᄄ¬タペムᄄ¬タペムᆭ ゚ムᄅ¬タペムᄅ¬タペムᄃ ゚ムᄄ¬タペムᆭ ゚ムᄄ¬タペムᄃ¬タペムᆭ ゚ムᄅ¬タペムᆭ ゚ムᄅ¬タペムᄃ¬タペムᆭ",
|
||||
"゚レᄒ ゚ニメ ゚ニモ ゚ニユ ゚ニヨ ゚ニラ ゚ニル ゚マᄃ",
|
||||
"0ᄌマ¬テᆪ 1ᄌマ¬テᆪ 2ᄌマ¬テᆪ 3ᄌマ¬テᆪ 4ᄌマ¬テᆪ 5ᄌマ¬テᆪ 6ᄌマ¬テᆪ 7ᄌマ¬テᆪ 8ᄌマ¬テᆪ 9ᄌマ¬テᆪ ゚ヤ゚",
|
||||
"゚ヌᄎ゚ヌᄌ゚ヌᄋ゚ヌᄎ゚ヌᄌ ゚ヌᆭ゚ヌᆱ゚ヌᆭ゚ヌᄇ゚ヌᄌ",
|
||||
"゚ヌᄎ゚ヌᄌ゚ヌᄋ゚ヌᄎ゚ヌᄌ゚ヌᆭ゚ヌᆱ゚ヌᆭ゚ヌᄇ",
|
||||
"゚ヌᄎ゚ヌᄌ゚ヌᄋ゚ヌᄎ゚ヌᄌ゚ヌᆭ",
|
||||
"ᄐムᄐメᄐモ",
|
||||
"ᄀᄁᆪ",
|
||||
"ᆱナ ニチᄈ ᄈツᄋᆰ ネᄄᄃトᆰᆳᆵハᆵフ, ᆲᄇハᄆᆰハ ᄄᄃᄈᆰᆴᆵᄃナ ᆪニ ᆵニネ. ᆬᄚ ヌニᄃ゚ ᄃトᄈᆰᄃᄆ ネᆰニᄉハᄄ テᄃニ. ᆪヌムト ᄃハᄋᄃトハᄃフ ᄄᄆハᄋᄃニハᄃ-チᄆニᄈᄃ ツᆵ ᆪᆴᄚ. ᄈトハナᄃニフ ᆬᆰチᄃツハᄅ ᄄハニ ナᄃ, ハᄚテᄆ ᄃトᆳᆵネᆵ ᆪハ ᄄᄍᆵ, ナᄍᄃナトᄅ ᄄネトニᆵᄃフ ᄃトᆬᄋトᄃツ ᄍト ᆬハネ.",
|
||||
"ᅲムᅱᄚᅱ튜뛰슈ミᅲ뤼ᄡᅲチᅲルᅲᆰ, ᅲムᅱ쥐튜뛰쥬ミ ᅲミᅱ뮤ワᅱ쮸ヤᅱᄡᅲルᅲン, ᅲミᅱ슑 ᅲヤᅱ유뤼쥐튜チᅲ゙ᅱ유ルᅱᄡᅲン, ᅲユᅱᄚᅲミᅱ슑 ᅲヤᅱ쥬ミᅱ쥬뛰쓙",
|
||||
"ᅲヤᅱ쥬ルᅱᄚᅲᆰᅱ쥬ヤtestᄃトᄉチᆳᄃᆰ ᄃトᆰムᆳネト",
|
||||
"ᄋᄑ",
|
||||
"ᄋᄎ",
|
||||
"ナマニホᄃツホᄡホᄅマ ᄈマᄄマトミ ᄃミᄈメᆰミᆴメᆵホᄃナミ ᄃトトマムᄎホᄅミ チミハ ᄃトニマムᄌマナミ ᄃトメツホᄃᆭミナホᄅミ ネホチミハナ ハホᆴマᄉホム ᄃトᆰホムᄋメᄄミハツホᄃᆰマ ᄃトメᆳᄃᄈマネᄄミハホムᄅマフ ",
|
||||
"£レロ£レト£レモ£レミ£レヒ£レメ£レト£レタ£レム£レト£レツ£レム£レマ£レナ£レワ¬タᆰ¬タᆰ¬タᆰ",
|
||||
"¬タᆰ¬タᆰ£レロ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レタ£レワ¬タᆰ",
|
||||
"¬タᆰ¬タᆰtest¬タᆰ",
|
||||
"¬タᆱtest¬タᆱ",
|
||||
"¬タᄅtest¬タᄅ",
|
||||
"test¬チᅠtest¬タᆱ",
|
||||
"¬チᆭtest¬チᄃ",
|
||||
"£ᄍᄚᅩ초초ユoᅪ゙ ᅩᄋiᅩ볿ᅪヌᅩᆰᅪルnᅩンᅩラᅪユvᅩ゚ᅩワᅩリᅩᆭᅪ゚oᅩ쏘ルᅩᄚᅩᅠkᅢ똬レᅩᆴᅩ촑ᅩ쪼모ᄂ ᅩヨtᅩンᅪユᅩ뽃ᅩ콝ᅪ゙hᅩ톼モᅩ볺ᅩ뽀リᅩᄇeᅪヌᅩᆪᅩᄚᅩᆭᅩᆲᅪホ ᅩ꼬토코모リhᅪレᅪホᅪルᅩワᅩᆪᅩ봐ナiᅩᆭᅩ볷ᅩᄚᅩᄂvᅩ콰ヘeᅩ촔ᅩ뽉ᅩᄚ-mᅩᄁiᅪナnᅩヨᅩ초゙ᅩ봂ᅩᄚdᅩ소토゚ᅪルᅩ로토リᅩᄈ ᅩ゙ᅩᆬᅩ모뽌rᅩロᅩラᅩリeᅪルpᅪᅠrᅩ토゙ᅩ콠ᅩラeᅩ초ᅠᅩᆪᅪ゚sᅩリᅪヌᅩ뽜ヘᅩンᅪノeᅪノᅩᆬᅩᆵᅩ゙ᅩ봐レᅩᆲᅪワᅦ쫇ᅪホᅪホᅩ゚ᅩヨᅪヌᅩᄂtᅪヘᅩᆲᅩ놔モᅩ톬ᅪリᅪナiᅩᆰᅩᄆnᅪᅠgᅩᄡᅪノ ᅪマᅪノᅪナcᅩᆲᅩ゚hᅪᄀaᅩᆱᅩ콢ᅪリoᅩᆱᅩ゚ᅩヨᅪヘᅩルᅩンᅪノsᅩラᅩᆭᅩᄇ.ᅩ또쫘ネᅩᆪ",
|
||||
"ᅩ과モᅩ゙ᅪナIᅩラᅩリᅩᆭᅪンnᅪヌᅪヌᅪルvᅩᆴᅩᆱokᅩ볾ᅩルᅪネiᅩヨᅪルᅩᆳᅩ쪼ᅠᅩ゙nᅩ고콡ᅩᆪᅩᄎgᅩ봐ネᅪルᅩᆳᅪルᅩᆲᅪホ ᅩᄚtᅪヤᅩᆭhᅩ゙ᅩᄇeᅩ꼬ᄂ ᅪヘᅩᆲᅩ봐ヨfᅩᄡᅩリᅪユᅩᆪᅢ똬ヨ£ᄎ쫁ᅩᄅlᅪヨᅪヤᅪレiᅪモᅪレᅩᆭᅪᅠnᅪヨᅪヘᅩラᅪモᅩ뽍gᅪヘ ᅩᄄoᅪレᅩᆰᅪᄀfᅩリᅩᆪᅩᆲ ᅩヨᅩリᅪヨᅩ゚ᅪルᅩᆴcᅭノᅪヤᅩᆱᅪヨᅪモᅪヌᅪヨᅪナhᅩ소녻ᅪレᅪヤᅢ고ラᅩ톼ユᅪナoᅩ톣ᅩᆬsᅩ뫄ネᅩ초ヨᅩᆭᅩ콰ᄁ.ᅩロᅩヨᅩ゙ᅩᅠᅩᆱᅩᄚ",
|
||||
"ᅩラᅩ촤ヨᅩ쫊ᅪモ£ᄍᆴᅩ놔ヘᅩᆬᅪヌᅪネhᅩ보チeᅪマᅪモᅩ토ラᅩルᅩ톣ᅪヤ ᅪヌᅩワᅩ모ᅠᅪモᅪヘᅪナNᅪユᅪᅠeᅩラᅩᄆzᅩリᅩンᅩワᅩ촤ルpᅩ노초쫘ヘᅩᆵᅪレeᅩᅠᅩ코ᅠᅪワrᅩ또놔ヘᅩ초ヨᅪヤᅩヨᅩヨdᅩᅠᅩ゚ᅩᆳᅩᆲᅩンᅪ゚iᅩᆭᅪヨᅩ롸モᅪヤᅩᄂaᅩᅠᅩラᅩᆲᅪノᅩルnᅪレᅪワ ᅩ코゙ᅩᄚᅪレᅪナhᅩ솨ノiᅩ뽀゙vᅩ꽈ヌ£ᄌルᅪホᅪ゚-ᅭノᅩᆳᅩ로톼ヤmᅩ놄ᅩᆱiᅪユᅪヌᅩンᅩᆭnᅩラᅪル£ᄌヘᅩ゚ ᅩᆵᅩ봐ユᅪ゙ᅦᆱᅩ゚ᅩᆵᅩᄚᅩ봐ルᅩ코ンf ᅩᆰᅩᄚᅩᄚᅩラᅩヨᅩᆳᅩリᅪリcᅩᆭᅪヘᅩ보゙ᅪヘᅩ로ル£ᄌᆬᅪレaᅩᆴᅪホᅩ゚ᅩルᅪワᅥ고로쫘ホsᅩᄂ.ᅩンᅩン ᅭノZᅩ고ヨᅩワᅪヨᅩᄚᅩᆪᅪノᅩワaᅪヨᅩᄚᅪルᅩᆲᅪᄀlᅩ볾ᅩ뽜ヘᅩᄅgᅩ고゚ᅩ토뫄レᅩ゙ᅩᆲᅪナoᅩラᅪワ.ᅩ゚",
|
||||
"ᅩᆭHᅩᆲᅩ노ラᅩ놔ンeᅪワ ᅩワᅩᆬᅩンᅩ콰ヘᅩ゚ᅩチwᅩユhᅩヨᅩᆵᅪモoᅩンᅪルᅩヨᅪホᅩ몵 ᅭノᅩ초ルᅩ゙ᅩ゚ᅪネWᅩ오톬aᅩ촑ᅪヘᅣᆵᅪネᅪユᅩᆳᅪルᅩᆵᅩワtᅩ쏘톭sᅩリᅪルᅪヨᅩユ ᅩᅠᅩᆱᅩᅠBᅩ콰ヘᅪルᅪノᅩ뽜ナeᅩᄉhᅩ솗ᅪヌᅩᆱᅪルiᅩ쫘モᅩ뽀뽍ᅪホᅩᆱᅩユnᅪ゚dᅩᄡᅩᆰᅩワᅩヨ ᅩᄚᅪノᅩ롸ヌᅪルᅩ봐゙ᅪナTᅪヨᅩ톼モᅩᆰᅪᄁhᅪマᅪモᅩᆴᅩᄏeᅩᆲᅩンᅩ゚ᅪナ ᅩ노쪼ンWᅪルᅩ゙ᅩンᅪヤᅪヌᅪンᅪナaᅪマᅪモᅪヤᅩ쪼톣lᅩᄡᅪヤᅩᄚᅩ노゚ᅪヤ£ᄌ폶.ᅪユ",
|
||||
"Zᅩᆴᅩ゙ᅩᅠᅪルᅪヤᅪナ£ᄌタᅩラᅩ゙ᅪネᅩ코ラ£ᄌ쏴ルᅪホᅩᆵᅩ쪼゙ᅪモGᅩᄏOᅩᆳᅩラᅩᆴ",
|
||||
"ᅨルミnb£ᄡノlミ ミuᅥテミᆵ ᅦンᄍolop ᅧヌᅦン ᅦンᄍoqミl ᅧヌn ᅧヌunp£ᄡノp£ᄡノヤu£ᄡノ ᄍodᆵᅦンᅧヌ poᆵsn£ᄡノᅦン op pᅦンs 'ᅧヌ£ᄡノlᅦン ᅥテu£ᄡノヤs£ᄡノd£ᄡノpミ ᄍnᅧヌᅦンᅧヌヤᅦンsuoヤ 'ᅧヌᅦンᆵミ ᅧヌ£ᄡノs ᄍolop ᆵnsd£ᄡノ ᆵᅦンᄍoᅨᆬ",
|
||||
"00ᅨルᅥヨ$-",
|
||||
"ᄐᄡᄑネᄑナ ᄑムᄑユᄑノᄑテᄑヒ ᄑツᄑメᄑマᄑラᄑホ ᄑニᄑマᄑリ ᄑハᄑユᄑヘᄑミᄑモ ᄑマᄑヨᄑナᄑメ ᄑヤᄑネᄑナ ᄑフᄑチᄑレᄑル ᄑトᄑマᄑヌ",
|
||||
"ンミモンミᄀンミ゙ ンミᆰンミᆴンミᄁンミワンミᄂ ンミロンミᆱンミᄄンミᄚンミᄃ ンミ゚ンミᄄンミᄆ ンミᆪンミᆴンミᆭンミᄅンミᆲ ンミᄄンミᆵンミ゙ンミᆱ ンミᆳンミᄀンミ゙ ンミᆬンミレンミᄈンミᄇ ンミンンミᄄンミᅠ",
|
||||
"ンユンヨヘンヨハ ンヨヨンヨレンヨホンヨネンヨミ ンヨヌンヨランヨヤンヨワンヨモ ンヨヒンヨヤンヨン ンヨマンヨレンヨメンヨユンヨリ ンヨヤンヨロンヨハンヨラ ンヨルンヨヘンヨハ ンヨムンヨニンヨ゚ンヨ゙ ンヨノンヨヤンヨフ",
|
||||
"ンムᄏンメノンメニ ンメメンメヨンメハンメトンメフ ンメテンメモンメミンメリンメマ ンメヌンメミンメル ンメヒンメヨンメホンメムンメヤ ンメミンメランメニンメモ ンメユンメノンメニ ンメヘンメツンメロンメレ ンメナンメミンメネ",
|
||||
"ンモᆪンモᄆンモᆴ ンモᄎンモᄒンモᄇンモᆲンモᄡ ンモᆱンモᄏンモᄌンヤタンモᄋ ンモᆵンモᄌンヤチ ンモᄈンモᄒンモᄊンモᄍンモᄐ ンモᄌンモンモᆴンモᄏ ンモᄑンモᄆンモᆴ ンモᄉンモᆰンヤテンヤツ ンモᆳンモᄌンモᄚ",
|
||||
"ンユヒンユルンユヨ ンユᄁンユᆭンユレンユヤンユワ ンユモンユᆪンユᅠンユᄄンユ゚ ンユランユᅠンユᄅ ンユロンユᆭンユ゙ンユᄀンユᄂ ンユᅠンユᄃンユヨンユᆪ ンユᆬンユルンユヨ ンユンンユメンユᆱンユᆰ ンユユンユᅠンユリ",
|
||||
"ンレテンレムンレホ ンレレンレ゙ンレメンレフンレヤ ンレヒンレロンレリンレᅠンレラ ンレマンレリンレᄀ ンレモンレ゙ンレヨンレルンレワ ンレリンレ゚ンレホンレロ ンレンンレムンレホ ンレユンレハンレᆪンレᄁ ンレヘンレリンレミ",
|
||||
"¬メᆵ¬メᆪ¬メᅠ ¬メᆲ¬メᄚ¬メᄂ¬メ゙¬メᆭ ¬メン¬メᆳ¬メᆰ¬メᄇ¬メᄅ ¬メᄀ¬メᆰ¬メᄈ ¬メᆬ¬メᄚ¬メᄄ¬メᆱ¬メᆴ ¬メᆰ¬メᄆ¬メᅠ¬メᆳ ¬メᆵ¬メᆪ¬メᅠ ¬メᄃ¬メワ¬メᄉ¬メᄡ ¬メ゚¬メᆰ¬メᄁ",
|
||||
"<script>alert(123)</script>",
|
||||
"<script>alert('123');</script>",
|
||||
"<img src=x onerror=alert(123) />",
|
||||
"<svg><script>123<1>alert(123)</script>",
|
||||
"\"><script>alert(123)</script>",
|
||||
"'><script>alert(123)</script>",
|
||||
"><script>alert(123)</script>",
|
||||
"</script><script>alert(123)</script>",
|
||||
"< / script >< script >alert(123)< / script >",
|
||||
" onfocus=JaVaSCript:alert(123) autofocus",
|
||||
"\" onfocus=JaVaSCript:alert(123) autofocus",
|
||||
"' onfocus=JaVaSCript:alert(123) autofocus",
|
||||
"ᄐワscriptᄐ゙alert(123)ᄐワ/scriptᄐ゙",
|
||||
"<sc<script>ript>alert(123)</sc</script>ript>",
|
||||
"--><script>alert(123)</script>",
|
||||
"\";alert(123);t=\"",
|
||||
"';alert(123);t='",
|
||||
"JavaSCript:alert(123)",
|
||||
";alert(123);",
|
||||
"src=JaVaSCript:prompt(132)",
|
||||
"\"><script>alert(123);</script x=\"",
|
||||
"'><script>alert(123);</script x='",
|
||||
"><script>alert(123);</script x=",
|
||||
"\" autofocus onkeyup=\"javascript:alert(123)",
|
||||
"' autofocus onkeyup='javascript:alert(123)",
|
||||
"<script\\x20type=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"<script\\x3Etype=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"<script\\x0Dtype=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"<script\\x09type=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"<script\\x0Ctype=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"<script\\x2Ftype=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"<script\\x0Atype=\"text/javascript\">javascript:alert(1);</script>",
|
||||
"'`\"><\\x3Cscript>javascript:alert(1)</script>",
|
||||
"'`\"><\\x00script>javascript:alert(1)</script>",
|
||||
"ABC<div style=\"x\\x3Aexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:expression\\x5C(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:expression\\x00(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:exp\\x00ression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:exp\\x5Cression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x0Aexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x09expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE3\\x80\\x80expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x84expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xC2\\xA0expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x80expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x8Aexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x0Dexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x0Cexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x87expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xEF\\xBB\\xBFexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x20expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x88expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x00expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x8Bexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x86expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x85expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x82expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\x0Bexpression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x81expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x83expression(javascript:alert(1)\">DEF",
|
||||
"ABC<div style=\"x:\\xE2\\x80\\x89expression(javascript:alert(1)\">DEF",
|
||||
"<a href=\"\\x0Bjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x0Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xC2\\xA0javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x05javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE1\\xA0\\x8Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x18javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x11javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x88javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x89javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x17javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x03javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x0Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x1Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x00javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x10javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x82javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x20javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x13javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x09javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x8Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x14javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x19javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\xAFjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x1Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x81javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x1Djavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x87javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x07javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE1\\x9A\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x83javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x04javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x01javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x08javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x84javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x86javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE3\\x80\\x80javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x12javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x0Djavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x0Ajavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x0Cjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x15javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\xA8javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x16javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x02javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x1Bjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x06javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\xA9javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x80\\x85javascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x1Ejavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\xE2\\x81\\x9Fjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"\\x1Cjavascript:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"javascript\\x00:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"javascript\\x3A:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"javascript\\x09:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"javascript\\x0D:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"<a href=\"javascript\\x0A:javascript:alert(1)\" id=\"fuzzelement1\">test</a>",
|
||||
"`\"'><img src=xxx:x \\x0Aonerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x22onerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x0Bonerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x0Donerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x2Fonerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x09onerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x0Conerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x00onerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x27onerror=javascript:alert(1)>",
|
||||
"`\"'><img src=xxx:x \\x20onerror=javascript:alert(1)>",
|
||||
"\"`'><script>\\x3Bjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\x0Djavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xEF\\xBB\\xBFjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x81javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x84javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE3\\x80\\x80javascript:alert(1)</script>",
|
||||
"\"`'><script>\\x09javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x89javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x85javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x88javascript:alert(1)</script>",
|
||||
"\"`'><script>\\x00javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\xA8javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x8Ajavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE1\\x9A\\x80javascript:alert(1)</script>",
|
||||
"\"`'><script>\\x0Cjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\x2Bjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xF0\\x90\\x96\\x9Ajavascript:alert(1)</script>",
|
||||
"\"`'><script>-javascript:alert(1)</script>",
|
||||
"\"`'><script>\\x0Ajavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\xAFjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\x7Ejavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x87javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x81\\x9Fjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\xA9javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xC2\\x85javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xEF\\xBF\\xAEjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x83javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x8Bjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xEF\\xBF\\xBEjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x80javascript:alert(1)</script>",
|
||||
"\"`'><script>\\x21javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x82javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE2\\x80\\x86javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xE1\\xA0\\x8Ejavascript:alert(1)</script>",
|
||||
"\"`'><script>\\x0Bjavascript:alert(1)</script>",
|
||||
"\"`'><script>\\x20javascript:alert(1)</script>",
|
||||
"\"`'><script>\\xC2\\xA0javascript:alert(1)</script>",
|
||||
"<img \\x00src=x onerror=\"alert(1)\">",
|
||||
"<img \\x47src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img \\x11src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img \\x12src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img\\x47src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img\\x10src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img\\x13src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img\\x32src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img\\x47src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img\\x11src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img \\x47src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img \\x34src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img \\x39src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img \\x00src=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x09=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x10=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x13=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x32=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x12=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x11=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x00=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src\\x47=x onerror=\"javascript:alert(1)\">",
|
||||
"<img src=x\\x09onerror=\"javascript:alert(1)\">",
|
||||
"<img src=x\\x10onerror=\"javascript:alert(1)\">",
|
||||
"<img src=x\\x11onerror=\"javascript:alert(1)\">",
|
||||
"<img src=x\\x12onerror=\"javascript:alert(1)\">",
|
||||
"<img src=x\\x13onerror=\"javascript:alert(1)\">",
|
||||
"<img[a][b][c]src[d]=x[e]onerror=[f]\"alert(1)\">",
|
||||
"<img src=x onerror=\\x09\"javascript:alert(1)\">",
|
||||
"<img src=x onerror=\\x10\"javascript:alert(1)\">",
|
||||
"<img src=x onerror=\\x11\"javascript:alert(1)\">",
|
||||
"<img src=x onerror=\\x12\"javascript:alert(1)\">",
|
||||
"<img src=x onerror=\\x32\"javascript:alert(1)\">",
|
||||
"<img src=x onerror=\\x00\"javascript:alert(1)\">",
|
||||
"<a href=javascript:javascript:alert(1)>XXX</a>",
|
||||
"<img src=\"x` `<script>javascript:alert(1)</script>\"` `>",
|
||||
"<img src onerror /\" '\"= alt=javascript:alert(1)//\">",
|
||||
"<title onpropertychange=javascript:alert(1)></title><title title=>",
|
||||
"<a href=http://foo.bar/#x=`y></a><img alt=\"`><img src=x:x onerror=javascript:alert(1)></a>\">",
|
||||
"<!--[if]><script>javascript:alert(1)</script -->",
|
||||
"<!--[if<img src=x onerror=javascript:alert(1)//]> -->",
|
||||
"<script src=\"/\\%(jscript)s\"></script>",
|
||||
"<script src=\"\\\\%(jscript)s\"></script>",
|
||||
"<IMG \"\"\"><SCRIPT>alert(\"XSS\")</SCRIPT>\">",
|
||||
"<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>",
|
||||
"<IMG SRC=# onmouseover=\"alert('xxs')\">",
|
||||
"<IMG SRC= onmouseover=\"alert('xxs')\">",
|
||||
"<IMG onmouseover=\"alert('xxs')\">",
|
||||
"<IMG SRC=javascript:alert('XSS')>",
|
||||
"<IMG SRC=javascript:alert('XSS')>",
|
||||
"<IMG SRC=javascript:alert('XSS')>",
|
||||
"<IMG SRC=\"jav ascript:alert('XSS');\">",
|
||||
"<IMG SRC=\"jav	ascript:alert('XSS');\">",
|
||||
"<IMG SRC=\"jav
ascript:alert('XSS');\">",
|
||||
"<IMG SRC=\"jav
ascript:alert('XSS');\">",
|
||||
"perl -e 'print \"<IMG SRC=java\\0script:alert(\\\"XSS\\\")>\";' > out",
|
||||
"<IMG SRC=\"  javascript:alert('XSS');\">",
|
||||
"<SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>",
|
||||
"<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>",
|
||||
"<SCRIPT/SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT>",
|
||||
"<<SCRIPT>alert(\"XSS\");//<</SCRIPT>",
|
||||
"<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >",
|
||||
"<SCRIPT SRC=//ha.ckers.org/.j>",
|
||||
"<IMG SRC=\"javascript:alert('XSS')\"",
|
||||
"<iframe src=http://ha.ckers.org/scriptlet.html <",
|
||||
"\\\";alert('XSS');//",
|
||||
"<u oncopy=alert()> Copy me</u>",
|
||||
"<i onwheel=alert(1)> Scroll over me </i>",
|
||||
"<plaintext>",
|
||||
"http://a/%%30%30",
|
||||
"</textarea><script>alert(123)</script>",
|
||||
"1;DROP TABLE users",
|
||||
"1'; DROP TABLE users-- 1",
|
||||
"' OR 1=1 -- 1",
|
||||
"' OR '1'='1",
|
||||
"'; EXEC sp_MSForEachTable 'DROP TABLE ?'; --",
|
||||
" ",
|
||||
"%",
|
||||
"_",
|
||||
"-",
|
||||
"--",
|
||||
"--version",
|
||||
"--help",
|
||||
"$USER",
|
||||
"/dev/null; touch /tmp/blns.fail ; echo",
|
||||
"`touch /tmp/blns.fail`",
|
||||
"$(touch /tmp/blns.fail)",
|
||||
"@{[system \"touch /tmp/blns.fail\"]}",
|
||||
"eval(\"puts 'hello world'\")",
|
||||
"System(\"ls -al /\")",
|
||||
"`ls -al /`",
|
||||
"Kernel.exec(\"ls -al /\")",
|
||||
"Kernel.exit(1)",
|
||||
"%x('ls -al /')",
|
||||
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]><foo>&xxe;</foo>",
|
||||
"$HOME",
|
||||
"$ENV{'HOME'}",
|
||||
"%d",
|
||||
"%s%s%s%s%s",
|
||||
"{0}",
|
||||
"%*.*s",
|
||||
"%@",
|
||||
"%n",
|
||||
"File:///",
|
||||
"../../../../../../../../../../../etc/passwd%00",
|
||||
"../../../../../../../../../../../etc/hosts",
|
||||
"() { 0; }; touch /tmp/blns.shellshock1.fail;",
|
||||
"() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }",
|
||||
"<<< %s(un='%s') = %u",
|
||||
"+++ATH0",
|
||||
"CON",
|
||||
"PRN",
|
||||
"AUX",
|
||||
"CLOCK$",
|
||||
"NUL",
|
||||
"A:",
|
||||
"ZZ:",
|
||||
"COM1",
|
||||
"LPT1",
|
||||
"LPT2",
|
||||
"LPT3",
|
||||
"COM2",
|
||||
"COM3",
|
||||
"COM4",
|
||||
"DCC SEND STARTKEYLOGGER 0 0 0",
|
||||
"Scunthorpe General Hospital",
|
||||
"Penistone Community Church",
|
||||
"Lightwater Country Park",
|
||||
"Jimmy Clitheroe",
|
||||
"Horniman Museum",
|
||||
"shitake mushrooms",
|
||||
"RomansInSussex.co.uk",
|
||||
"http://www.cum.qc.ca/",
|
||||
"Craig Cockburn, Software Specialist",
|
||||
"Linda Callahan",
|
||||
"Dr. Herman I. Libshitz",
|
||||
"magna cum laude",
|
||||
"Super Bowl XXX",
|
||||
"medieval erection of parapets",
|
||||
"evaluate",
|
||||
"mocha",
|
||||
"expression",
|
||||
"Arsenal canal",
|
||||
"classic",
|
||||
"Tyson Gay",
|
||||
"Dick Van Dyke",
|
||||
"basement",
|
||||
"If you're reading this, you've been in a coma for almost 20 years now. We're trying a new technique. We don't know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.",
|
||||
"Roses are \u001b[0;31mred\u001b[0m, violets are \u001b[0;34mblue. Hope you enjoy terminal hue",
|
||||
"But now...\u001b[20Cfor my greatest trick...\u001b[8m",
|
||||
"The quic\b\b\b\b\b\bk brown fo\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007\u0007x... [Beeeep]",
|
||||
"Powerトマトマᄉムᄄマトマトᄉムᄄマᄆᄆヒ ¢ᆬᆪ ¢ᆬᆪh ¢ᆬᆪ ¢ᆬᆪ¥ニラ",
|
||||
"゚マᄈ0゚フネᄌマ",
|
||||
"¢ᄚワ¢ᄆヘ¢ᄚ゙¬タフ¢ᄚᄒ",
|
||||
"ᅳᆵᅳニ흐リ",
|
||||
"{% print 'x' * 64 * 1024**3 %}",
|
||||
"{{ \"\".__class__.__mro__[2].__subclasses__()[40](\"/etc/passwd\").read() }}"
|
||||
]
|
|
@ -0,0 +1,260 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const zlib = require('zlib')
|
||||
const { promisify } = require('util')
|
||||
const gzip = promisify(zlib.gzip)
|
||||
const unzip = promisify(zlib.unzip)
|
||||
|
||||
describe('gzip', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const g = require('../lib/filter').gzipFn.bind(hexo)
|
||||
const path = 'foo.txt'
|
||||
const input = 'Lorem ipsum dolor sit amet consectetur adipiscing elit fusce'
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
gzip: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await g()
|
||||
|
||||
const output = hexo.route.get(path.concat('.gz'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await gzip(input, { level: zlib.constants.Z_BEST_COMPRESSION })
|
||||
const resultUnzip = await unzip(result)
|
||||
const expectedUnzip = await unzip(expected)
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
expect(resultUnzip.toString()).toBe(input)
|
||||
expect(expectedUnzip.toString()).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.gzip.enable = false
|
||||
const result = await g()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
expect(routeList).not.toContain(path.concat('.gz'))
|
||||
|
||||
const result = await g()
|
||||
// empty file resolves to an array of undefined
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const customOpt = {
|
||||
level: 1
|
||||
}
|
||||
hexo.config.minify.gzip.level = customOpt.level
|
||||
await g()
|
||||
|
||||
const output = hexo.route.get(path.concat('.gz'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await gzip(input, customOpt)
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.gzip.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await g()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`gzip: ${path}`)
|
||||
})
|
||||
|
||||
test('option - invalid', async () => {
|
||||
const customOpt = {
|
||||
level: 9000
|
||||
}
|
||||
hexo.config.minify.gzip.level = customOpt.level
|
||||
|
||||
let expected
|
||||
try {
|
||||
await gzip(input, customOpt)
|
||||
} catch (err) {
|
||||
expected = err
|
||||
}
|
||||
expect(expected).toBeDefined()
|
||||
await expect(g()).rejects.toThrow(`Path: ${path}\n${expected}`)
|
||||
})
|
||||
|
||||
test('include - exclude non-text file by default', async () => {
|
||||
const path = 'foo.jpg'
|
||||
hexo.route.set(path, input)
|
||||
await g()
|
||||
|
||||
const result = hexo.route.get(path.concat('.gz'))
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.gzip.include = 'bar.txt'
|
||||
const path = 'foo/bar.txt'
|
||||
hexo.route.set(path, input)
|
||||
await g()
|
||||
|
||||
const result = hexo.route.get(path.concat('.gz'))
|
||||
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.gzip.include = '**/lectus/**/*.txt'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.txt'
|
||||
hexo.route.set(path, input)
|
||||
await g()
|
||||
|
||||
const result = hexo.route.get(path.concat('.gz'))
|
||||
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
test('include - basename + slash + basename enabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.gzip.include = [
|
||||
'*.html',
|
||||
'**/sociis/**/*.css'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await g()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = [
|
||||
'lorem/ipsum/dolor.html.gz',
|
||||
'gravida/sociis/erat/ante.css.gz'
|
||||
]
|
||||
const notExpected = [
|
||||
'aptent/elementum.js.gz',
|
||||
'felis/blandit/cursus.svg.gz'
|
||||
]
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
||||
})
|
||||
|
||||
test('include - basename + slash + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.gzip.include = [
|
||||
'*.html',
|
||||
'**/sociis/**/*.css'
|
||||
]
|
||||
hexo.config.minify.gzip.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await g()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = [
|
||||
'gravida/sociis/erat/ante.css.gz'
|
||||
]
|
||||
const notExpected = [
|
||||
'lorem/ipsum/dolor.html.gz',
|
||||
'aptent/elementum.js.gz',
|
||||
'felis/blandit/cursus.svg.gz'
|
||||
]
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.gzip.include = [
|
||||
'!dolor.html'
|
||||
]
|
||||
hexo.config.minify.gzip.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await g()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = paths.map((path) => path.concat('.gz'))
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
})
|
||||
|
||||
test('blns', async () => {
|
||||
const blns = require('./fixtures/blns.json')
|
||||
|
||||
for (const nStr of blns) {
|
||||
hexo.route.remove(path)
|
||||
|
||||
hexo.route.set(path, nStr)
|
||||
|
||||
await g()
|
||||
|
||||
const output = hexo.route.get(path.concat('.gz'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const resultUnzip = await unzip(result)
|
||||
|
||||
expect(resultUnzip.toString()).toBe(nStr)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
|
@ -0,0 +1,132 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const { minify: htmlMinify } = require('html-minifier-terser')
|
||||
|
||||
describe('html', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const h = require('../lib/filter').minifyHtml.bind(hexo)
|
||||
const input = '<p id="">foo</p>'
|
||||
const path = 'index.html'
|
||||
const defaultCfg = {
|
||||
html: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
exclude: [],
|
||||
collapseBooleanAttributes: true,
|
||||
collapseWhitespace: true,
|
||||
ignoreCustomComments: [/^\s*more/],
|
||||
removeComments: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeScriptTypeAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
let expected = ''
|
||||
|
||||
beforeAll(async () => {
|
||||
expected = await htmlMinify(input, defaultCfg.html)
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = JSON.parse(JSON.stringify(defaultCfg))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
const result = await h(input, { path })
|
||||
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.html.enable = false
|
||||
|
||||
const result = await h(input, { path })
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
const result = await h('', { path })
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const customOpt = { removeEmptyAttributes: false }
|
||||
hexo.config.minify.html = customOpt
|
||||
|
||||
const result = await h(input, { path })
|
||||
const expected = await htmlMinify(input, customOpt)
|
||||
|
||||
expect(result).toBe(input)
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.html.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await h(input, { path })
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`html: ${path}`)
|
||||
})
|
||||
|
||||
test('exclude', async () => {
|
||||
const exclude = '*.min.html'
|
||||
hexo.config.minify.html.exclude = exclude
|
||||
|
||||
const result = await h(input, { path: 'foo/bar.min.html' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - slash in pattern', async () => {
|
||||
const exclude = '**/lectus/**/*.html'
|
||||
hexo.config.minify.html.exclude = exclude
|
||||
|
||||
const result = await h(input, { path: 'eleifend/lectus/nullam/dapibus/netus.html' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - basename is true + slash', async () => {
|
||||
const exclude = ['**/lectus/**/*.html', 'bar.html']
|
||||
const globOptions = { basename: true }
|
||||
hexo.config.minify.html.exclude = exclude
|
||||
hexo.config.minify.html.globOptions = globOptions
|
||||
|
||||
const result = await h(input, { path: 'foo/bar.html' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - basename is false + slash', async () => {
|
||||
const exclude = ['**/lectus/**/*.html', 'bar.html']
|
||||
const globOptions = { basename: false }
|
||||
hexo.config.minify.html.exclude = exclude
|
||||
hexo.config.minify.html.globOptions = globOptions
|
||||
|
||||
const result = await h(input, { path: 'foo/bar.html' })
|
||||
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
|
||||
test('null', async () => {
|
||||
hexo.config.minify.html.exclude = null
|
||||
hexo.config.minify.html.globOptions = null
|
||||
|
||||
const result = await h(input, { path: null })
|
||||
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
|
||||
test('invalid string', async () => {
|
||||
const invalid = '<html><>?:"{}|_+</html>'
|
||||
|
||||
await expect(h(invalid, { path })).rejects.toThrow('Parse Error: <>?:"{}|_+</html>')
|
||||
})
|
||||
})
|
|
@ -0,0 +1,123 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const { minify: terserMinify } = require('terser')
|
||||
|
||||
describe('js', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const j = require('../lib/filter').minifyJs.bind(hexo)
|
||||
const input = 'var o = { "foo": 1, bar: 3 };'
|
||||
const path = 'foo.js'
|
||||
let expected = ''
|
||||
|
||||
beforeAll(async () => {
|
||||
const { code } = await terserMinify(input, { mangle: true })
|
||||
expected = code
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
hexo.config.minify = {
|
||||
js: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
exclude: ['*.min.js'],
|
||||
compress: {},
|
||||
mangle: true,
|
||||
output: {},
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
const result = await j(input, { path })
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(expected).toBeDefined()
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.js.enable = false
|
||||
|
||||
const result = await j(input, { path })
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
const result = await j('', { path })
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const customOpt = {
|
||||
mangle: {
|
||||
properties: true
|
||||
}
|
||||
}
|
||||
hexo.config.minify.js = customOpt
|
||||
|
||||
const result = await j(input, { path })
|
||||
const { code: expected } = await terserMinify(input, customOpt)
|
||||
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.js.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await j(input, { path })
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`js: ${path}`)
|
||||
})
|
||||
|
||||
test('option - invalid', async () => {
|
||||
const customOpt = {
|
||||
mangle: {
|
||||
foo: 'bar'
|
||||
}
|
||||
}
|
||||
hexo.config.minify.js = customOpt
|
||||
|
||||
let expected
|
||||
try {
|
||||
await terserMinify(input, customOpt)
|
||||
} catch (err) {
|
||||
expected = err
|
||||
}
|
||||
|
||||
expect(expected).toBeDefined()
|
||||
await expect(j(input, { path })).rejects.toThrow(`Path: ${path}\n${expected}`)
|
||||
})
|
||||
|
||||
test('exclude - *.min.js', async () => {
|
||||
const result = await j(input, { path: 'foo/bar.min.js' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - basename', async () => {
|
||||
const exclude = '*baz.js'
|
||||
hexo.config.minify.js.exclude = exclude
|
||||
const result = await j(input, { path: 'foo/barbaz.js' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('exclude - slash in pattern', async () => {
|
||||
const exclude = '**/lectus/**/*.js'
|
||||
hexo.config.minify.js.exclude = exclude
|
||||
const result = await j(input, { path: 'eleifend/lectus/nullam/dapibus/netus.js' })
|
||||
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
|
||||
test('invalid string', async () => {
|
||||
const invalid = 'console.log("\\");'
|
||||
|
||||
await expect(j(invalid, { path })).rejects.toThrow(`Path: ${path}\nSyntaxError`)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,190 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
|
||||
describe('xml', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const jsonFn = require('../lib/filter').minifyJson.bind(hexo)
|
||||
const path = 'foo.json'
|
||||
const input = '{\n\t"vitae": "hendrerit",\n\t"tristique": [\n\t\t"primis",\n\t\t"quam"\n\t]\n}'
|
||||
const expected = '{"vitae":"hendrerit","tristique":["primis","quam"]}'
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
json: {
|
||||
enable: false,
|
||||
verbose: false,
|
||||
include: ['*.json', '!*.min.json'],
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
// plugin is disabled by default
|
||||
hexo.config.minify.json.enable = true
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.json.enable = false
|
||||
const result = await jsonFn()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.json.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await jsonFn()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`json: ${path}`)
|
||||
})
|
||||
|
||||
test('invalid input', async () => {
|
||||
hexo.route.set(path, 'foo')
|
||||
await expect(jsonFn()).rejects.toThrow(`Path: ${path}\nSyntaxError`)
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
const result = await jsonFn()
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('include - exclude *.min.json by default', async () => {
|
||||
const path = 'foo.min.json'
|
||||
hexo.route.set(path, input)
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.json.include = 'bar.json'
|
||||
const path = 'foo/bar.json'
|
||||
hexo.route.set(path, input)
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.json.include = '**/lectus/**/*.json'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.json'
|
||||
hexo.route.set(path, input)
|
||||
await jsonFn()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename + slash', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.json',
|
||||
'gravida/sociis/erat/ante.json',
|
||||
'aptent/elementum.json',
|
||||
'felis/blandit/cursus.json'
|
||||
]
|
||||
hexo.config.minify.json.include = [
|
||||
'dolor.json',
|
||||
'**/sociis/**/*.json'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await jsonFn()
|
||||
|
||||
const minPaths = paths.slice(0, 2)
|
||||
const unminPaths = paths.slice(2)
|
||||
|
||||
minPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
unminPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.json',
|
||||
'gravida/sociis/erat/ante.json',
|
||||
'aptent/elementum.json',
|
||||
'felis/blandit/cursus.json'
|
||||
]
|
||||
hexo.config.minify.json.include = [
|
||||
'!dolor.json'
|
||||
]
|
||||
hexo.config.minify.json.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await jsonFn()
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - empty route', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const result = await jsonFn()
|
||||
expect(result.length).toBe(0)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,253 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const { optimize: svgOptimize } = require('svgo')
|
||||
|
||||
describe('svg', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const s = require('../lib/filter').minifySvg.bind(hexo)
|
||||
const input = '<svg><rect x="1" y="2" width="3" height="4" id="a"/></svg>'
|
||||
const path = 'foo.svg'
|
||||
// svgo's plugins option
|
||||
let plugins = [{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {}
|
||||
}
|
||||
}]
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
svg: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
include: ['*.svg', '!*.min.svg'],
|
||||
plugins: {},
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
plugins = [{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {}
|
||||
}
|
||||
}]
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.svg.enable = false
|
||||
const result = await s()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
const result = await s()
|
||||
|
||||
// empty file resolves to an array of undefined
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const customOpt = {
|
||||
cleanupIds: false
|
||||
}
|
||||
hexo.config.minify.svg.plugins = customOpt
|
||||
plugins = [{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: customOpt
|
||||
}
|
||||
}]
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
expect(result).toContain('id="a"')
|
||||
})
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.svg.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await s()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`svg: ${path}`)
|
||||
})
|
||||
|
||||
test('option - plugins - invalid', async () => {
|
||||
hexo.config.minify.svg.plugins = 'invalid'
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
})
|
||||
})
|
||||
|
||||
test('invalid svg', async () => {
|
||||
const input = '{}'
|
||||
hexo.route.set(path, input)
|
||||
|
||||
let expected
|
||||
try {
|
||||
svgOptimize(input, { plugins })
|
||||
} catch (err) {
|
||||
expected = err
|
||||
}
|
||||
expect(expected).toBeDefined()
|
||||
await expect(s()).rejects.toThrow(`Path: ${path}\n${expected}`)
|
||||
})
|
||||
|
||||
test('include - exclude *.min.svg by default', async () => {
|
||||
const path = 'foo.min.svg'
|
||||
hexo.route.set(path, input)
|
||||
await s()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.svg.include = 'bar.svg'
|
||||
const path = 'foo/bar.svg'
|
||||
hexo.route.set(path, input)
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.svg.include = '**/lectus/**/*.svg'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.svg'
|
||||
hexo.route.set(path, input)
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename + slash', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.svg',
|
||||
'gravida/sociis/erat/ante.svg',
|
||||
'aptent/elementum.svg',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.svg.include = [
|
||||
'dolor.svg',
|
||||
'**/sociis/**/*.svg'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
const minPaths = paths.slice(0, 2)
|
||||
const unminPaths = paths.slice(2)
|
||||
|
||||
minPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
})
|
||||
})
|
||||
|
||||
unminPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.svg',
|
||||
'gravida/sociis/erat/ante.svg',
|
||||
'aptent/elementum.svg',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.svg.include = [
|
||||
'!dolor.svg'
|
||||
]
|
||||
hexo.config.minify.svg.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await s()
|
||||
const { data } = svgOptimize(input, { plugins })
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(data)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - empty route', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const result = await s()
|
||||
expect(result.length).toBe(0)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,213 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
|
||||
describe('xml', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const x = require('../lib/filter').minifyXml.bind(hexo)
|
||||
const path = 'foo.xml'
|
||||
const input = '<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns="http://www.w3.org/2005/Atom">\n <!-- foo bar -->\n <title>foo</title>\n</feed>'
|
||||
const expected = '<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>foo</title></feed>'
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
xml: {
|
||||
enable: false,
|
||||
verbose: false,
|
||||
include: ['*.xml', '!*.min.xml'],
|
||||
removeComments: true,
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
// plugin is disabled by default
|
||||
hexo.config.minify.xml.enable = true
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await x()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.xml.enable = false
|
||||
const result = await x()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option - removeComments', async () => {
|
||||
hexo.config.minify.xml.removeComments = false
|
||||
|
||||
await x()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toContain('<!-- foo bar -->')
|
||||
})
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.xml.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await x()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`xml: ${path}`)
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
const result = await x()
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('include - exclude *.min.xml by default', async () => {
|
||||
const path = 'foo.min.xml'
|
||||
hexo.route.set(path, input)
|
||||
await x()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.xml.include = 'bar.xml'
|
||||
const path = 'foo/bar.xml'
|
||||
hexo.route.set(path, input)
|
||||
await x()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.xml.include = '**/lectus/**/*.xml'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.xml'
|
||||
hexo.route.set(path, input)
|
||||
await x()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - basename + slash', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.xml',
|
||||
'gravida/sociis/erat/ante.xml',
|
||||
'aptent/elementum.xml',
|
||||
'felis/blandit/cursus.xml'
|
||||
]
|
||||
hexo.config.minify.xml.include = [
|
||||
'dolor.xml',
|
||||
'**/sociis/**/*.xml'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await x()
|
||||
|
||||
const minPaths = paths.slice(0, 2)
|
||||
const unminPaths = paths.slice(2)
|
||||
|
||||
minPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
unminPaths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.xml',
|
||||
'gravida/sociis/erat/ante.xml',
|
||||
'aptent/elementum.xml',
|
||||
'felis/blandit/cursus.xml'
|
||||
]
|
||||
hexo.config.minify.xml.include = [
|
||||
'!dolor.xml'
|
||||
]
|
||||
hexo.config.minify.xml.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await x()
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
const output = hexo.route.get(inpath)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('include - empty route', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const result = await x()
|
||||
expect(result.length).toBe(0)
|
||||
})
|
||||
|
||||
test('avoid processing CDATA', async () => {
|
||||
const input = '<foo><![CDATA[<p>lorem</p>\n<p>ipsum</p>]]></foo>'
|
||||
hexo.route.set(path, input)
|
||||
|
||||
await x()
|
||||
|
||||
const output = hexo.route.get(path)
|
||||
let result = ''
|
||||
output.on('data', (chunk) => (result += chunk))
|
||||
output.on('end', () => {
|
||||
expect(result).toBe(input)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,256 @@
|
|||
/* eslint-env jest */
|
||||
'use strict'
|
||||
|
||||
const Hexo = require('hexo')
|
||||
const { compress: zstd, decompress: unzstd } = require('@mongodb-js/zstd')
|
||||
|
||||
describe('zstd', () => {
|
||||
const hexo = new Hexo(__dirname)
|
||||
const z = require('../lib/filter').zstdFn.bind(hexo)
|
||||
const path = 'foo.txt'
|
||||
const input = 'Lorem ipsum dolor sit amet consectetur adipiscing elit fusce'
|
||||
const inputBuf = Buffer.from(input, 'utf8')
|
||||
|
||||
beforeEach(() => {
|
||||
hexo.config.minify = {
|
||||
zstd: {
|
||||
enable: true,
|
||||
verbose: false,
|
||||
include: ['*.html', '*.css', '*.js', '*.txt', '*.ttf', '*.atom', '*.stl', '*.xml', '*.svg', '*.eot', '*.json'],
|
||||
globOptions: { basename: true }
|
||||
}
|
||||
}
|
||||
hexo.route.set(path, input)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const routeList = hexo.route.list()
|
||||
routeList.forEach((path) => hexo.route.remove(path))
|
||||
})
|
||||
|
||||
test('default', async () => {
|
||||
await z()
|
||||
|
||||
const output = hexo.route.get(path.concat('.zst'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await zstd(inputBuf)
|
||||
const resultUnzst = await unzstd(result)
|
||||
const expectedUnzst = await unzstd(expected)
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
expect(resultUnzst.toString()).toBe(input)
|
||||
expect(expectedUnzst.toString()).toBe(input)
|
||||
})
|
||||
})
|
||||
|
||||
test('disable', async () => {
|
||||
hexo.config.minify.zstd.enable = false
|
||||
const result = await z()
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('empty file', async () => {
|
||||
hexo.route.set(path, '')
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
expect(routeList).not.toContain(path.concat('.zst'))
|
||||
|
||||
const result = await z()
|
||||
expect(result).toBeDefined()
|
||||
expect(result[0]).toBeUndefined()
|
||||
})
|
||||
|
||||
test('option', async () => {
|
||||
const level = 1
|
||||
hexo.config.minify.zstd.level = level
|
||||
await z()
|
||||
|
||||
const output = hexo.route.get(path.concat('.zst'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await zstd(inputBuf, level)
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
test('option - verbose', async () => {
|
||||
hexo.config.minify.zstd.verbose = true
|
||||
hexo.log.log = jest.fn()
|
||||
await z()
|
||||
|
||||
expect(hexo.log.log.mock.calls[0][0]).toContain(`zstd: ${path}`)
|
||||
})
|
||||
|
||||
test('option - level is string', async () => {
|
||||
const level = 'foo'
|
||||
hexo.config.minify.zstd.level = level
|
||||
await z()
|
||||
|
||||
const output = hexo.route.get(path.concat('.zst'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const expected = await zstd(inputBuf, undefined)
|
||||
|
||||
expect(result.equals(expected)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
test('include - exclude non-text file by default', async () => {
|
||||
const path = 'foo.jpg'
|
||||
hexo.route.set(path, input)
|
||||
await z()
|
||||
|
||||
const result = hexo.route.get(path.concat('.zst'))
|
||||
|
||||
expect(result).toBeUndefined()
|
||||
})
|
||||
|
||||
test('include - basename', async () => {
|
||||
hexo.config.minify.zstd.include = 'bar.txt'
|
||||
const path = 'foo/bar.txt'
|
||||
hexo.route.set(path, input)
|
||||
await z()
|
||||
|
||||
const result = hexo.route.get(path.concat('.zst'))
|
||||
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
test('include - slash in pattern', async () => {
|
||||
hexo.config.minify.zstd.include = '**/lectus/**/*.txt'
|
||||
const path = 'eleifend/lectus/nullam/dapibus/netus.txt'
|
||||
hexo.route.set(path, input)
|
||||
await z()
|
||||
|
||||
const result = hexo.route.get(path.concat('.zst'))
|
||||
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
test('include - basename + slash + basename enabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.zstd.include = [
|
||||
'*.html',
|
||||
'**/sociis/**/*.css'
|
||||
]
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await z()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = [
|
||||
'lorem/ipsum/dolor.html.zst',
|
||||
'gravida/sociis/erat/ante.css.zst'
|
||||
]
|
||||
const notExpected = [
|
||||
'aptent/elementum.js.zst',
|
||||
'felis/blandit/cursus.svg.zst'
|
||||
]
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
||||
})
|
||||
|
||||
test('include - basename + slash + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.zstd.include = [
|
||||
'*.html',
|
||||
'**/sociis/**/*.css'
|
||||
]
|
||||
hexo.config.minify.zstd.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await z()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = [
|
||||
'gravida/sociis/erat/ante.css.zst'
|
||||
]
|
||||
const notExpected = [
|
||||
'lorem/ipsum/dolor.html.zst',
|
||||
'aptent/elementum.js.zst',
|
||||
'felis/blandit/cursus.svg.zst'
|
||||
]
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
expect(routeList).toEqual(expect.not.arrayContaining(notExpected))
|
||||
})
|
||||
|
||||
test('include - reverse pattern + basename disabled', async () => {
|
||||
hexo.route.remove(path)
|
||||
|
||||
const paths = [
|
||||
'lorem/ipsum/dolor.html',
|
||||
'gravida/sociis/erat/ante.css',
|
||||
'aptent/elementum.js',
|
||||
'felis/blandit/cursus.svg'
|
||||
]
|
||||
hexo.config.minify.zstd.include = [
|
||||
'!dolor.html'
|
||||
]
|
||||
hexo.config.minify.zstd.globOptions = {
|
||||
basename: false
|
||||
}
|
||||
|
||||
paths.forEach((inpath) => {
|
||||
hexo.route.set(inpath, input)
|
||||
})
|
||||
await z()
|
||||
|
||||
const routeList = hexo.route.list()
|
||||
const expected = paths.map((path) => path.concat('.zst'))
|
||||
|
||||
expect(routeList).toEqual(expect.arrayContaining(expected))
|
||||
})
|
||||
|
||||
test('blns', async () => {
|
||||
const blns = require('./fixtures/blns.json')
|
||||
|
||||
for (const nStr of blns) {
|
||||
hexo.route.remove(path)
|
||||
|
||||
hexo.route.set(path, nStr)
|
||||
|
||||
await z()
|
||||
|
||||
const output = hexo.route.get(path.concat('.zst'))
|
||||
const buf = []
|
||||
output.on('data', (chunk) => (buf.push(chunk)))
|
||||
output.on('end', async () => {
|
||||
const result = Buffer.concat(buf)
|
||||
const resultUnzst = await unzstd(result)
|
||||
|
||||
expect(resultUnzst.toString()).toBe(nStr)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue