Compare commits

...

81 Commits

Author SHA1 Message Date
Klemek 4671253147 Merge pull request #21 from Klemek/dev
v1.2.7
2019-08-19 14:34:32 +02:00
Klemek add01b28fe Update package.json 2019-08-19 14:25:01 +02:00
Klemek a27a53e238 faDiagram switch to TOML lang 2019-08-19 14:14:52 +02:00
Klemek 6aff9b4d93 Merge remote-tracking branch 'origin/dev' into dev 2019-08-19 14:14:05 +02:00
Klemek c9f57233a4 faDiagram switch to TOML lang 2019-08-19 14:13:54 +02:00
Klemek 7d72e94aa3 Merge pull request #20 from Klemek/dev
updated package-lock
2019-07-19 11:00:33 +02:00
Klemek 3d6a0b4306 Merge branch 'master' into dev 2019-07-19 10:58:52 +02:00
Klemek babc533efc updated package-lock 2019-07-19 10:56:26 +02:00
Klemek 36908134e6 Merge pull request #19 from Klemek/dependabot/npm_and_yarn/lodash-4.17.15
Bump lodash from 4.17.11 to 4.17.15
2019-07-19 10:50:53 +02:00
dependabot[bot] d426b41368 Bump lodash from 4.17.11 to 4.17.15
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-19 08:48:39 +00:00
Klemek 1836a414eb Merge pull request #18 from Klemek/dev
v1.2.6
2019-07-19 10:46:33 +02:00
Klemek ca49a29dd9 [skip CI] updated version 2019-07-19 10:44:58 +02:00
Klemek 02a768a6af [skip CI] updated README.md 2019-07-19 10:44:26 +02:00
Klemek bbc4d7c270 [skip CI] updated README.md 2019-07-19 10:42:25 +02:00
Klemek bfa1521f85 updated sample to show fa-diagrams 2019-07-19 10:41:21 +02:00
Klemek a05d380fcf fixed parts detection 2019-07-19 10:41:01 +02:00
Klemek 4a32995ca1 fa-diagrams support 2019-07-19 10:19:12 +02:00
Klemek 53e1fe7201 mathjax/plantuml rendering only outside of code/scripts 2019-07-19 10:01:01 +02:00
Klemek 2e8ff1be92 fixed mathjax in code 2019-07-18 16:41:25 +02:00
Klemek e14f9fc4af Merge remote-tracking branch 'origin/dev' into dev 2019-07-18 14:07:34 +02:00
Klemek 896f302bcf updated default template 2019-07-18 14:07:24 +02:00
Klemek cc0bd1cf49 Merge pull request #17 from Klemek/dev
updated CI
2019-07-12 14:07:36 +02:00
Klemek 7a1d9cbbd6 Merge branch 'master' into dev 2019-07-12 13:59:54 +02:00
Clément GOUIN 34e8d4cb6f updated CI 2019-07-12 13:57:27 +02:00
Klemek 4a9b70ac68 Update .travis.yml 2019-07-12 13:53:55 +02:00
Klemek 889258c874 Update .travis.yml 2019-07-12 11:53:02 +02:00
Klemek de26feb05c Merge pull request #16 from Klemek/dev
v1.2.5
2019-07-01 23:17:56 +02:00
Klemek 8bb455b576 Fixed draft rendering bug 2019-07-01 23:15:13 +02:00
Klemek 378ed438b6 Merge pull request #15 from Klemek/dev
v1.2.4
2019-07-01 23:03:23 +02:00
Klemek 3b07b6b9c5 Drafted articles 2019-07-01 22:18:40 +02:00
Klemek b6afcd4992 Update README.md 2019-06-26 21:20:45 +02:00
Klemek 35fcdc7320 Merge pull request #14 from Klemek/dev
v1.2.3
2019-06-26 21:03:49 +02:00
Klemek dfb93b6764 [skip CI]Updated nodemon config 2019-06-26 21:03:39 +02:00
Klemek 6af4012522 Hidden files path matching 2019-06-26 20:59:42 +02:00
Klemek 1b91002c03 Updated templates meta tags 2019-06-26 20:09:08 +02:00
Klemek bedd6a2953 Merge pull request #13 from Klemek/dev
v1.2.2
2019-06-26 19:52:25 +02:00
Klemek 52d37d56cd Bug fix 2019-06-26 19:48:51 +02:00
Klemek fc7bc63c46 Nodemon config 2019-06-26 19:44:52 +02:00
Klemek 4397a76d9b Merge pull request #12 from Klemek/dev
v1.2.1
2019-06-26 19:35:29 +02:00
Klemek ddf964eb27 Updated version 2019-06-26 19:28:29 +02:00
Klemek 4b47276484 Updated readme 2019-06-26 19:28:18 +02:00
Klemek a7fedb149f Host from config if specified 2019-06-26 19:28:00 +02:00
Klemek ea95a285c9 Merge pull request #11 from Klemek/dev
v1.2.0
2019-06-26 19:00:30 +02:00
Klemek 0fde428806 Updated coverage 2019-06-26 18:56:01 +02:00
Klemek 8fc7ff1ca7 Updated version 2019-06-26 18:44:31 +02:00
Klemek ae4e2eb8d5 Fixing Firefox RSS handling 2019-06-26 18:43:41 +02:00
Klemek 528e4be1fe Updated templates 2019-06-26 18:34:40 +02:00
Klemek bd42883330 Update template.ejs 2019-06-26 18:21:44 +02:00
Klemek b6ac0a73b4 Update style.css 2019-06-26 18:21:26 +02:00
Klemek aebc3da5bc Update template.ejs 2019-06-26 16:43:03 +02:00
Klemek 7a4a4f9006 Update footer.ejs 2019-06-26 15:07:32 +02:00
Klemek 1341aa5a56 Update config.default.json 2019-06-26 11:46:06 +02:00
Klemek 5e05f250f4 Update style.css 2019-06-26 10:06:12 +02:00
Klemek 6cf7be3afb Update README.md 2019-06-23 15:37:23 +02:00
Klemek 6aceacad18 Update README.md 2019-06-23 15:34:46 +02:00
Klemek a3a23be1c2 Update README.md 2019-06-23 15:34:34 +02:00
Klemek e8e8024021 Merge pull request #10 from Klemek/dev
v1.1.5
2019-06-23 15:15:45 +02:00
Klemek 1806d60ca7 Fixed meta tags being wrong 2019-06-23 15:14:47 +02:00
Klemek 2c5f2e589f Merge pull request #9 from Klemek/dev
v1.1.4
2019-06-23 15:09:27 +02:00
Klemek 847d228c0a Updated templates 2019-06-23 15:06:15 +02:00
Klemek 576948acee ViewPort property 2019-06-23 15:05:06 +02:00
Klemek fa6d91db20 updated README.md 2019-06-23 15:04:15 +02:00
Klemek 989bcdf130 Pages metadata by default 2019-06-23 15:02:33 +02:00
Klemek 000104c99d Merge pull request #8 from Klemek/dev
v1.1.3
2019-06-23 14:46:52 +02:00
Klemek f2bd0ec10e Fixed config merge 2019-06-23 14:44:32 +02:00
Klemek 97dab302d8 Merge pull request #7 from Klemek/dev
v1.1.2
2019-06-23 14:19:24 +02:00
Klemek 55e258e093 Fixed Express.static mime type 2019-06-23 14:14:35 +02:00
Klemek 7b22a4773d Merge pull request #6 from Klemek/dev
v1.1.1
2019-06-23 13:58:34 +02:00
Klemek 14cd1436c3 Better without infinite loop 2019-06-23 13:56:31 +02:00
Klemek c112e1ea62 Merge pull request #5 from Klemek/dev
v1.1
2019-06-23 13:52:24 +02:00
Klemek bd8385ea60 [skip CI] updated version 2019-06-23 13:51:07 +02:00
Klemek 6dbc7f359b PlantUML integration 2019-06-23 13:48:28 +02:00
Klemek e773f53da1 Merge pull request #4 from Klemek/dev
v1.0.3
2019-06-22 14:41:38 +02:00
Klemek 35a7747d6d better warning when no config.json 2019-06-22 14:38:59 +02:00
Klemek 0d173cfcef [skip CI] updated README.md 2019-06-22 14:37:52 +02:00
Klemek 0480536a20 Updated footer for more info 2019-06-22 14:29:54 +02:00
Klemek 333bbf6eb8 updated article index.md 2019-06-22 14:25:41 +02:00
Klemek 6bdcd6872e MathJax small fix 2019-06-22 14:13:20 +02:00
Klemek 9d3c1d0847 MathJax support 2019-06-22 13:48:08 +02:00
Klemek def326676c More tests 2019-06-22 11:00:02 +02:00
Klemek d343179764 Updated code coverage files 2019-06-22 10:17:04 +02:00
25 changed files with 3004 additions and 430 deletions
+3 -1
View File
@@ -3,6 +3,8 @@
/config.json /config.json
/config.example.json /config.example.json
/data /data
/data/*
/test_data /test_data
/access.log /access.log
/error.log /error.log
/coverage
+2
View File
@@ -0,0 +1,2 @@
/node_modules
/src/lib
+2 -6
View File
@@ -6,15 +6,11 @@ cache:
npm: true npm: true
directories: directories:
- node_modules - node_modules
addons:
apt:
packages:
- graphviz
install: install:
- npm install - npm install
- npm install node-plantuml
before_script: before_script:
- npm install -g jshint - npm install -g jshint
script: script:
- jest --silent --coverage --coverageReporters=text-lcov | coveralls - jest --coverage --silent
- jshint ./src - jshint ./src
- cat ./coverage/lcov.info | coveralls
+86 -8
View File
@@ -1,9 +1,8 @@
# GitBlog.md
[![Build Status](https://img.shields.io/travis/Klemek/GitBlog.md.svg?branch=master)](https://travis-ci.org/Klemek/GitBlog.md) [![Build Status](https://img.shields.io/travis/Klemek/GitBlog.md.svg?branch=master)](https://travis-ci.org/Klemek/GitBlog.md)
[![Coverage Status](https://img.shields.io/coveralls/github/Klemek/GitBlog.md.svg?branch=master)](https://coveralls.io/github/Klemek/GitBlog.md?branch=master) [![Coverage Status](https://img.shields.io/coveralls/github/Klemek/GitBlog.md.svg?branch=master)](https://coveralls.io/github/Klemek/GitBlog.md?branch=master)
# GitBlog.md
A static blog using Markdown pulled from your git repository. A static blog using Markdown pulled from your git repository.
> Step 1 : ```$ vi 2019/06/21/index.md``` > Step 1 : ```$ vi 2019/06/21/index.md```
@@ -14,6 +13,7 @@ A static blog using Markdown pulled from your git repository.
* **[How it works](#how-it-works)** * **[How it works](#how-it-works)**
* **[Installation](#installation)** * **[Installation](#installation)**
* **[Writing an article](#writing-an-article)** * **[Writing an article](#writing-an-article)**
* **[Modules](#modules)**
* **[Configuration](#configuration)** * **[Configuration](#configuration)**
## How it works ## How it works
@@ -80,7 +80,7 @@ On the `/rss` endpoint, the servers gives you a RSS feed based on the list of ar
#### 1. Download and install the latest version from the repo #### 1. Download and install the latest version from the repo
```bash ```bash
git clone https://github.com/klemek/gitblog.md.git git clone https://github.com/klemek/gitblog.md.git
npm install npm install --production
``` ```
#### 2. Create your config file #### 2. Create your config file
```bash ```bash
@@ -124,6 +124,34 @@ Resources are located on the `data` folder and can be referenced as the root of
/styles/main.css => data/styles/main.css /styles/main.css => data/styles/main.css
``` ```
In your template, the following data is sent :
<details>
<summary>details (click)</summary>
<p>
* `info` (every pages)
* `title` : the blog's title as in the config
* `description` the blog's description as in the config
* `host` : the specified or guessed host with the protocol
* `version` : the GitBlog.md current running version
* `request` : the Express request object
* `config` : the content of the config
* `article` (article pages only)
* `title` : the full title
* `thumbnail` the URL path of the thumbnail
* `url` : the URL path for this article (with the title)
* `date` : a JS date
* `year`
* `month`
* `day`
* `path` : the URL path for the folder of the article (without the title)
* `realPath` : the system's path for the folder
* `escapedTitle` : the code with alphanumeric and underscore characters only
* `error` (error pages only) : the error code
</p>
</details>
#### 5. Create and init your git source #### 5. Create and init your git source
You need to [create a new repository](https://github.com/new) on your favorite Git service. You need to [create a new repository](https://github.com/new) on your favorite Git service.
@@ -131,7 +159,10 @@ You need to [create a new repository](https://github.com/new) on your favorite G
```bash ```bash
#gitblog.md/ #gitblog.md/
cd data cd data
git init
git remote add origin <url_of_your_repo.git> git remote add origin <url_of_your_repo.git>
git add .
git commit -m "initial commit"
git push -u origin master git push -u origin master
``` ```
@@ -156,7 +187,7 @@ Here are the steps for Github, if you use another platform adapt it your way (he
```json ```json
"webhook": { "webhook": {
"endpoint": "/webhook", "endpoint": "/webhook",
"secret": "sha1=<value>", "secret": "<value>",
"signature_header": "X-Hub-Signature" "signature_header": "X-Hub-Signature"
}, },
``` ```
@@ -164,6 +195,14 @@ Here are the steps for Github, if you use another platform adapt it your way (he
* Update your webhook on github to include the secret * Update your webhook on github to include the secret
* Check if Github successfully reached the endpoint * Check if Github successfully reached the endpoint
#### 8. Keep your server always up and running (optionnal)
This project `package.json` comes with a [nodemon](https://github.com/remy/nodemon) config.
After installing (`npm i -g nodemon`) you can then run the app with juste the `nodemon` command in the working directory.
With this method, you can do a simple `git pull` to update your server.
## Writing an article ## Writing an article
[back to top](#gitblog-md) [back to top](#gitblog-md)
@@ -192,11 +231,31 @@ On that same folder, you can place resources like images and reference them in r
Any URL like `/year/month/day/anything/` will redirect to this article (and link to correct resources) Any URL like `/year/month/day/anything/` will redirect to this article (and link to correct resources)
## Modules
[back to top](#gitblog-md)
* **RSS**
It allows your users to use the feed to be updated as soon as a new article is out
* **Webhook**
It update your blog from your online repo when it's updated
* **Prism**
It highlight code blocks to be more readable (more info [here](https://prismjs.com/), you will need the corresponding CSS file on your templates)
* **MathJax**
It allows you to add math equations to your articles by simply writing LaTeX between `$$` for full size (and between $ for inline) (more info [here](https://www.mathjax.org/))
* **PlantUML**
It allows you to add UML diagrams with PlantUML Syntax between `@startuml` and `@enduml` (more info [here](http://www.plantuml.com))
* **fa-diagrams**
It allows you to define SVG diagrams with Font-Awesome icons in [TOML](https://github.com/toml-lang/toml) between `@startfad` and `@endfad` (more info [here](https://github.com/Klemek/fa-diagrams))
## Configuration ## Configuration
[back to top](#gitblog-md) [back to top](#gitblog-md)
* `node_port` (default: 3000) * `node_port` (default: 3000)
the port the server is listening to the port the server is listening to
* `host` (default: none)
if set (like `https://mywebsite.com`, it will be used as reference for creating links
by default, host is guessed based on first request
* `data_dir` (default: data) * `data_dir` (default: data)
the directory where will be located the git repo with templates and articles the directory where will be located the git repo with templates and articles
* `view_engine` (default: ejs) * `view_engine` (default: ejs)
@@ -212,18 +271,32 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link
activate the webhook endpoint and its features activate the webhook endpoint and its features
* `prism` (default: true) * `prism` (default: true)
activate Prism code highlighting activate Prism code highlighting
* `mathjax` (default: true)
activate MathJax equations formatting
* `plantuml` (default: true)
activate PlantUML diagram rendering
* `fa-diagrams` (default: true)
activate fa-diagrams rendering
* `home` * `home`
* `title` (default: GitBlog.md)
the title of your blog, **strongly advised to be changed**
given to the template to complete page title and metadata
* `description` (default: A static blog using Markdown pulled from your git repository)
the description of your blog, **strongly advised to be changed**
given to the template to complete page title and metadata
* `index` (default: index.ejs) * `index` (default: index.ejs)
the name of the home page template on the data directory the name of the home page template on the data directory
it will receive `articles`, a list of articles for rendering it will receive `articles`, a list of articles for rendering
* `error` (default: error.ejs) * `error` (default: error.ejs)
the name of the error page template on the data directory the name of the error page template on the data directory
it will receive `error`, the error code it will receive `error`, the error code
* `hidden` (default: `[.ejs]`) * `hidden` (default: `[*.ejs,/.git*]`)
file extensions to be returned 404 when reached path matches to be returned 404 when reached
* `article` * `article`
* `index` (default: index.md) * `index` (default: index.md)
the name of the Markdown page of the article on the `/year/month/day/` directory the name of the Markdown page of the article on the `/year/month/day/` directory
* `draft` (default: draft.md)
the name of the Markdown page of an article not shown on the list
* `template` (default: template.ejs) * `template` (default: template.ejs)
the name of the article page template on the data directory the name of the article page template on the data directory
* `thumbnail_tag`: (default: thumbnail) * `thumbnail_tag`: (default: thumbnail)
@@ -248,4 +321,9 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link
* `pull_command`: (default: git pull) * `pull_command`: (default: git pull)
the command used by the server on webhook trigger the command used by the server on webhook trigger
* `showdown` * `showdown`
Options to be applied to Showdown renderer (see [showdown options](https://github.com/showdownjs/showdown#valid-options) for more info) Options to be applied to Showdown renderer (see [showdown options](https://github.com/showdownjs/showdown/wiki/Showdown-Options) for more info)
* `mathjax`
* `output_format`: (default: svg)
specify the output format between svg, html or MathMl (mml)
* `speak_text`: (default: true)
activate the alternate text in equations
+160 -213
View File
@@ -1,6 +1,6 @@
{ {
"name": "gitblog.md", "name": "gitblog.md",
"version": "1.0.0", "version": "1.2.6",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -285,6 +285,11 @@
} }
} }
}, },
"@iarna/toml": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.3.tgz",
"integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg=="
},
"@jest/console": { "@jest/console": {
"version": "24.7.1", "version": "24.7.1",
"resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz", "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.7.1.tgz",
@@ -1257,8 +1262,7 @@
"abab": { "abab": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
"integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
"dev": true
}, },
"accepts": { "accepts": {
"version": "1.3.7", "version": "1.3.7",
@@ -1272,14 +1276,12 @@
"acorn": { "acorn": {
"version": "5.7.3", "version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
"dev": true
}, },
"acorn-globals": { "acorn-globals": {
"version": "4.3.2", "version": "4.3.2",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz",
"integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==",
"dev": true,
"requires": { "requires": {
"acorn": "^6.0.1", "acorn": "^6.0.1",
"acorn-walk": "^6.0.1" "acorn-walk": "^6.0.1"
@@ -1288,22 +1290,19 @@
"acorn": { "acorn": {
"version": "6.1.1", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
"integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA=="
"dev": true
} }
} }
}, },
"acorn-walk": { "acorn-walk": {
"version": "6.1.1", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
"integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw=="
"dev": true
}, },
"ajv": { "ajv": {
"version": "6.10.0", "version": "6.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
"integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
"dev": true,
"requires": { "requires": {
"fast-deep-equal": "^2.0.1", "fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -1373,8 +1372,7 @@
"array-equal": { "array-equal": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
"dev": true
}, },
"array-flatten": { "array-flatten": {
"version": "1.1.1", "version": "1.1.1",
@@ -1392,7 +1390,6 @@
"version": "0.2.4", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dev": true,
"requires": { "requires": {
"safer-buffer": "~2.1.0" "safer-buffer": "~2.1.0"
} }
@@ -1400,8 +1397,7 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
"dev": true
}, },
"assign-symbols": { "assign-symbols": {
"version": "1.0.0", "version": "1.0.0",
@@ -1425,14 +1421,12 @@
"async-limiter": { "async-limiter": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
"dev": true
}, },
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
"dev": true
}, },
"atob": { "atob": {
"version": "2.1.2", "version": "2.1.2",
@@ -1443,14 +1437,12 @@
"aws-sign2": { "aws-sign2": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
"dev": true
}, },
"aws4": { "aws4": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
"dev": true
}, },
"babel-cli": { "babel-cli": {
"version": "6.26.0", "version": "6.26.0",
@@ -2311,7 +2303,6 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"requires": { "requires": {
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
@@ -2353,8 +2344,7 @@
"browser-process-hrtime": { "browser-process-hrtime": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
"integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw=="
"dev": true
}, },
"browser-resolve": { "browser-resolve": {
"version": "1.11.3", "version": "1.11.3",
@@ -2457,8 +2447,7 @@
"caseless": { "caseless": {
"version": "0.12.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
"dev": true
}, },
"chalk": { "chalk": {
"version": "1.1.3", "version": "1.1.3",
@@ -2604,7 +2593,6 @@
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"requires": { "requires": {
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
} }
@@ -2680,8 +2668,7 @@
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
"dev": true
}, },
"coveralls": { "coveralls": {
"version": "3.0.4", "version": "3.0.4",
@@ -2705,16 +2692,6 @@
} }
} }
}, },
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"crypto": { "crypto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
@@ -2723,14 +2700,12 @@
"cssom": { "cssom": {
"version": "0.3.6", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
"integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A=="
"dev": true
}, },
"cssstyle": { "cssstyle": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz",
"integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==", "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==",
"dev": true,
"requires": { "requires": {
"cssom": "0.3.x" "cssom": "0.3.x"
} }
@@ -2739,7 +2714,6 @@
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
@@ -2748,7 +2722,6 @@
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
"integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
"dev": true,
"requires": { "requires": {
"abab": "^2.0.0", "abab": "^2.0.0",
"whatwg-mimetype": "^2.2.0", "whatwg-mimetype": "^2.2.0",
@@ -2759,7 +2732,6 @@
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"dev": true,
"requires": { "requires": {
"lodash.sortby": "^4.7.0", "lodash.sortby": "^4.7.0",
"tr46": "^1.0.1", "tr46": "^1.0.1",
@@ -2790,8 +2762,7 @@
"deep-is": { "deep-is": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
"dev": true
}, },
"define-properties": { "define-properties": {
"version": "1.1.3", "version": "1.1.3",
@@ -2858,8 +2829,7 @@
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
"dev": true
}, },
"delegate": { "delegate": {
"version": "3.2.0", "version": "3.2.0",
@@ -2902,7 +2872,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
"integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
"dev": true,
"requires": { "requires": {
"webidl-conversions": "^4.0.2" "webidl-conversions": "^4.0.2"
} }
@@ -2911,7 +2880,6 @@
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"requires": { "requires": {
"jsbn": "~0.1.0", "jsbn": "~0.1.0",
"safer-buffer": "^2.1.0" "safer-buffer": "^2.1.0"
@@ -2996,7 +2964,6 @@
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
"integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
"dev": true,
"requires": { "requires": {
"esprima": "^3.1.3", "esprima": "^3.1.3",
"estraverse": "^4.2.0", "estraverse": "^4.2.0",
@@ -3009,7 +2976,6 @@
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"optional": true "optional": true
} }
} }
@@ -3017,20 +2983,17 @@
"esprima": { "esprima": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
"dev": true
}, },
"estraverse": { "estraverse": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
"dev": true
}, },
"esutils": { "esutils": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
"dev": true
}, },
"etag": { "etag": {
"version": "1.8.1", "version": "1.8.1",
@@ -3043,20 +3006,6 @@
"integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==",
"dev": true "dev": true
}, },
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
"integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
"requires": {
"cross-spawn": "^5.0.1",
"get-stream": "^3.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"exit": { "exit": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -3184,8 +3133,7 @@
"extend": { "extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
"dev": true
}, },
"extend-shallow": { "extend-shallow": {
"version": "3.0.2", "version": "3.0.2",
@@ -3221,26 +3169,30 @@
"extsprintf": { "extsprintf": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
"dev": true },
"fa-diagrams": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/fa-diagrams/-/fa-diagrams-1.0.3.tgz",
"integrity": "sha512-z9pFYYnc6s1sUs4lq+DY2m5ddLCKN3jdo5O6hv450WwjiQ7otk1RoGQsvpMcwSU1kMEzPJUI6AeTVvzyIElhwQ==",
"requires": {
"xml-js": "^1.6.11"
}
}, },
"fast-deep-equal": { "fast-deep-equal": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
"dev": true
}, },
"fast-json-stable-stringify": { "fast-json-stable-stringify": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
"dev": true
}, },
"fast-levenshtein": { "fast-levenshtein": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
"dev": true
}, },
"fast-safe-stringify": { "fast-safe-stringify": {
"version": "2.0.6", "version": "2.0.6",
@@ -3305,14 +3257,12 @@
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
"dev": true
}, },
"form-data": { "form-data": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
"requires": { "requires": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.6", "combined-stream": "^1.0.6",
@@ -3915,11 +3865,6 @@
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
}, },
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"get-value": { "get-value": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -3930,7 +3875,6 @@
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
@@ -4026,14 +3970,12 @@
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
"dev": true
}, },
"har-validator": { "har-validator": {
"version": "5.1.3", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"dev": true,
"requires": { "requires": {
"ajv": "^6.5.5", "ajv": "^6.5.5",
"har-schema": "^2.0.0" "har-schema": "^2.0.0"
@@ -4157,7 +4099,6 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
"integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
"dev": true,
"requires": { "requires": {
"whatwg-encoding": "^1.0.1" "whatwg-encoding": "^1.0.1"
} }
@@ -4178,7 +4119,6 @@
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"jsprim": "^1.2.2", "jsprim": "^1.2.2",
@@ -4233,11 +4173,6 @@
"loose-envify": "^1.0.0" "loose-envify": "^1.0.0"
} }
}, },
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
},
"ipaddr.js": { "ipaddr.js": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
@@ -4440,8 +4375,7 @@
"is-typedarray": { "is-typedarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
"dev": true
}, },
"is-windows": { "is-windows": {
"version": "1.0.2", "version": "1.0.2",
@@ -4469,8 +4403,7 @@
"isstream": { "isstream": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
"dev": true
}, },
"istanbul-lib-coverage": { "istanbul-lib-coverage": {
"version": "2.0.5", "version": "2.0.5",
@@ -6680,14 +6613,12 @@
"jsbn": { "jsbn": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
"dev": true
}, },
"jsdom": { "jsdom": {
"version": "11.12.0", "version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"dev": true,
"requires": { "requires": {
"abab": "^2.0.0", "abab": "^2.0.0",
"acorn": "^5.5.3", "acorn": "^5.5.3",
@@ -6732,20 +6663,17 @@
"json-schema": { "json-schema": {
"version": "0.2.3", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
"dev": true
}, },
"json-schema-traverse": { "json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
"dev": true
}, },
"json-stringify-safe": { "json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
"dev": true
}, },
"json5": { "json5": {
"version": "0.5.1", "version": "0.5.1",
@@ -6757,7 +6685,6 @@
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"requires": { "requires": {
"assert-plus": "1.0.0", "assert-plus": "1.0.0",
"extsprintf": "1.3.0", "extsprintf": "1.3.0",
@@ -6780,14 +6707,6 @@
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true "dev": true
}, },
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"requires": {
"invert-kv": "^1.0.0"
}
},
"lcov-parse": { "lcov-parse": {
"version": "0.0.10", "version": "0.0.10",
"resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz",
@@ -6797,8 +6716,7 @@
"left-pad": { "left-pad": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
"integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA=="
"dev": true
}, },
"leven": { "leven": {
"version": "2.1.0", "version": "2.1.0",
@@ -6810,7 +6728,6 @@
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"dev": true,
"requires": { "requires": {
"prelude-ls": "~1.1.2", "prelude-ls": "~1.1.2",
"type-check": "~0.3.2" "type-check": "~0.3.2"
@@ -6838,16 +6755,14 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.11", "version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"dev": true
}, },
"lodash.sortby": { "lodash.sortby": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
"dev": true
}, },
"log-driver": { "log-driver": {
"version": "1.2.7", "version": "1.2.7",
@@ -6931,19 +6846,26 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"mathjax": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz",
"integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ=="
},
"mathjax-node": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/mathjax-node/-/mathjax-node-2.1.1.tgz",
"integrity": "sha1-JcgPSU91QEGP/Pqcx1bf0hUCAb0=",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"jsdom": "^11.0.0",
"mathjax": "^2.7.2"
}
},
"media-typer": { "media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
}, },
"mem": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
"requires": {
"mimic-fn": "^1.0.0"
}
},
"merge-descriptors": { "merge-descriptors": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -7017,11 +6939,6 @@
"mime-db": "1.40.0" "mime-db": "1.40.0"
} }
}, },
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -7237,14 +7154,12 @@
"nwsapi": { "nwsapi": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz",
"integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw=="
"dev": true
}, },
"oauth-sign": { "oauth-sign": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
"dev": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@@ -7366,7 +7281,6 @@
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
"dev": true,
"requires": { "requires": {
"deep-is": "~0.1.3", "deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.4", "fast-levenshtein": "~2.0.4",
@@ -7379,8 +7293,7 @@
"wordwrap": { "wordwrap": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
"dev": true
} }
} }
}, },
@@ -7390,16 +7303,6 @@
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true "dev": true
}, },
"os-locale": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
"integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
"requires": {
"execa": "^0.7.0",
"lcid": "^1.0.0",
"mem": "^1.1.0"
}
},
"os-tmpdir": { "os-tmpdir": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -7496,8 +7399,7 @@
"parse5": { "parse5": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
"dev": true
}, },
"parseurl": { "parseurl": {
"version": "1.3.3", "version": "1.3.3",
@@ -7549,8 +7451,7 @@
"performance-now": { "performance-now": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
"dev": true
}, },
"pify": { "pify": {
"version": "3.0.0", "version": "3.0.0",
@@ -7624,8 +7525,7 @@
"pn": { "pn": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
"dev": true
}, },
"posix-character-classes": { "posix-character-classes": {
"version": "0.1.1", "version": "0.1.1",
@@ -7636,8 +7536,7 @@
"prelude-ls": { "prelude-ls": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
"dev": true
}, },
"preserve": { "preserve": {
"version": "0.2.0", "version": "0.2.0",
@@ -7722,8 +7621,7 @@
"psl": { "psl": {
"version": "1.1.32", "version": "1.1.32",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz",
"integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g=="
"dev": true
}, },
"pump": { "pump": {
"version": "3.0.0", "version": "3.0.0",
@@ -7738,8 +7636,7 @@
"punycode": { "punycode": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
"dev": true
}, },
"qs": { "qs": {
"version": "6.7.0", "version": "6.7.0",
@@ -8308,7 +8205,6 @@
"version": "2.88.0", "version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"dev": true,
"requires": { "requires": {
"aws-sign2": "~0.7.0", "aws-sign2": "~0.7.0",
"aws4": "^1.8.0", "aws4": "^1.8.0",
@@ -8335,20 +8231,17 @@
"punycode": { "punycode": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
"dev": true
}, },
"qs": { "qs": {
"version": "6.5.2", "version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
"dev": true
}, },
"tough-cookie": { "tough-cookie": {
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"dev": true,
"requires": { "requires": {
"psl": "^1.1.24", "psl": "^1.1.24",
"punycode": "^1.4.1" "punycode": "^1.4.1"
@@ -8360,7 +8253,6 @@
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
"integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
"dev": true,
"requires": { "requires": {
"lodash": "^4.17.11" "lodash": "^4.17.11"
} }
@@ -8369,7 +8261,6 @@
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz",
"integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==",
"dev": true,
"requires": { "requires": {
"request-promise-core": "1.1.2", "request-promise-core": "1.1.2",
"stealthy-require": "^1.1.1", "stealthy-require": "^1.1.1",
@@ -8829,8 +8720,7 @@
"sax": { "sax": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
"dev": true
}, },
"select": { "select": {
"version": "1.1.2", "version": "1.1.2",
@@ -9152,7 +9042,6 @@
"version": "1.16.1", "version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dev": true,
"requires": { "requires": {
"asn1": "~0.2.3", "asn1": "~0.2.3",
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
@@ -9200,8 +9089,7 @@
"stealthy-require": { "stealthy-require": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
"dev": true
}, },
"string-length": { "string-length": {
"version": "2.0.0", "version": "2.0.0",
@@ -9363,8 +9251,7 @@
"symbol-tree": { "symbol-tree": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
"dev": true
}, },
"test-exclude": { "test-exclude": {
"version": "5.2.3", "version": "5.2.3",
@@ -9461,7 +9348,6 @@
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"dev": true,
"requires": { "requires": {
"psl": "^1.1.28", "psl": "^1.1.28",
"punycode": "^2.1.1" "punycode": "^2.1.1"
@@ -9471,7 +9357,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
"dev": true,
"requires": { "requires": {
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
@@ -9486,7 +9371,6 @@
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": { "requires": {
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
@@ -9494,14 +9378,12 @@
"tweetnacl": { "tweetnacl": {
"version": "0.14.5", "version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
"dev": true
}, },
"type-check": { "type-check": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"dev": true,
"requires": { "requires": {
"prelude-ls": "~1.1.2" "prelude-ls": "~1.1.2"
} }
@@ -9625,7 +9507,6 @@
"version": "4.2.2", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"dev": true,
"requires": { "requires": {
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
@@ -9672,8 +9553,7 @@
"uuid": { "uuid": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
"dev": true
}, },
"v8flags": { "v8flags": {
"version": "2.1.1", "version": "2.1.1",
@@ -9703,7 +9583,6 @@
"version": "1.10.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"core-util-is": "1.0.2", "core-util-is": "1.0.2",
@@ -9714,7 +9593,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
"integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
"dev": true,
"requires": { "requires": {
"browser-process-hrtime": "^0.1.2" "browser-process-hrtime": "^0.1.2"
} }
@@ -9731,14 +9609,12 @@
"webidl-conversions": { "webidl-conversions": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
"dev": true
}, },
"whatwg-encoding": { "whatwg-encoding": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
"integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
"dev": true,
"requires": { "requires": {
"iconv-lite": "0.4.24" "iconv-lite": "0.4.24"
} }
@@ -9746,14 +9622,12 @@
"whatwg-mimetype": { "whatwg-mimetype": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
"dev": true
}, },
"whatwg-url": { "whatwg-url": {
"version": "6.5.0", "version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"dev": true,
"requires": { "requires": {
"lodash.sortby": "^4.7.0", "lodash.sortby": "^4.7.0",
"tr46": "^1.0.1", "tr46": "^1.0.1",
@@ -9842,7 +9716,6 @@
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"dev": true,
"requires": { "requires": {
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }
@@ -9852,11 +9725,18 @@
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
"integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
}, },
"xml-js": {
"version": "1.6.11",
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
"requires": {
"sax": "^1.2.4"
}
},
"xml-name-validator": { "xml-name-validator": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
"dev": true
}, },
"y18n": { "y18n": {
"version": "3.2.1", "version": "3.2.1",
@@ -9885,6 +9765,73 @@
"which-module": "^2.0.0", "which-module": "^2.0.0",
"y18n": "^3.2.1", "y18n": "^3.2.1",
"yargs-parser": "^8.1.0" "yargs-parser": "^8.1.0"
},
"dependencies": {
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
"integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
"requires": {
"cross-spawn": "^5.0.1",
"get-stream": "^3.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
},
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"requires": {
"invert-kv": "^1.0.0"
}
},
"mem": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
"requires": {
"mimic-fn": "^1.0.0"
}
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"os-locale": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
"integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
"requires": {
"execa": "^0.7.0",
"lcid": "^1.0.0",
"mem": "^1.1.0"
}
}
} }
}, },
"yargs-parser": { "yargs-parser": {
+25 -3
View File
@@ -1,14 +1,16 @@
{ {
"nodePort": 5000,
"name": "gitblog.md", "name": "gitblog.md",
"version": "1.0.2", "version": "1.2.7",
"description": "A static blog using Markdown pulled from your git repository.", "description": "A static blog using Markdown pulled from your git repository.",
"main": "src/server.js", "main": "src/server.js",
"dependencies": { "dependencies": {
"@iarna/toml": "^2.2.3",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"crypto": "^1.0.1", "crypto": "^1.0.1",
"ejs": "^2.6.2", "ejs": "^2.6.2",
"express": "^4.17.1", "express": "^4.17.1",
"fa-diagrams": "^1.0.3",
"mathjax-node": "^2.1.1",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"node-prismjs": "^0.1.2", "node-prismjs": "^0.1.2",
"prismjs": "^1.16.0", "prismjs": "^1.16.0",
@@ -37,5 +39,25 @@
"bugs": { "bugs": {
"url": "https://github.com/klemek/gitblog.md/issues" "url": "https://github.com/klemek/gitblog.md/issues"
}, },
"homepage": "https://github.com/klemek/gitblog.md#readme" "homepage": "https://github.com/klemek/gitblog.md#readme",
"jest": {
"collectCoverageFrom": [
"src/**/*.js",
"!/node_modules/",
"!src/server.js",
"!src/postinstall.js",
"!src/lib/*.js"
]
},
"nodemonConfig": {
"verbose": true,
"ignore": [
"test/*",
"sample_data/*",
"data/*",
"uml/*",
"*.log",
"README.md"
]
}
} }
+119
View File
@@ -4,7 +4,26 @@ If you see this page, that means it's working
## Guide to Markdown formatting ## Guide to Markdown formatting
* [Headers](#headers)
* [Emphasis](#emphasis)
* [Lists](#lists)
* [Links](#links)
* [Images](#images)
* [Code and Syntax Highlighting](#codeandsyntaxhighlighting)
* [Tables](#tables)
* [Blockquotes](#blockquotes)
* [Inline HTML](#inlinehtml)
* [Horizontal Rule](#horizontalrule)
* [Line Breaks](#linebreaks)
* [Check Boxes](#checkboxes)
* [Spoilers](#spoilers)
* [Math Equations](#mathequations)
* [UML](#uml)
* [Diagrams](#diagrams)
* [Youtube Videos](#youtubevideos)
### Headers ### Headers
[Back to top](#top)
# H1 # H1
## H2 ## H2
@@ -22,6 +41,7 @@ Alt-H2
------ ------
### Emphasis ### Emphasis
[Back to top](#top)
Emphasis, aka italics, with *asterisks* or _underscores_. Emphasis, aka italics, with *asterisks* or _underscores_.
@@ -32,6 +52,7 @@ Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~ Strikethrough uses two tildes. ~~Scratch this.~~
### Lists ### Lists
[Back to top](#top)
1. First ordered list item 1. First ordered list item
2. Another item 2. Another item
@@ -51,6 +72,7 @@ Strikethrough uses two tildes. ~~Scratch this.~~
+ Or pluses + Or pluses
### Links ### Links
[Back to top](#top)
[I'm an inline-style link](https://www.google.com) [I'm an inline-style link](https://www.google.com)
@@ -75,6 +97,7 @@ Some text to show that the reference links can follow later.
[link text itself]: http://www.reddit.com [link text itself]: http://www.reddit.com
### Images ### Images
[Back to top](#top)
Here's our logo (hover to see the title text): Here's our logo (hover to see the title text):
@@ -88,6 +111,7 @@ Reference-style:
### Code and Syntax Highlighting ### Code and Syntax Highlighting
[Back to top](#top)
Inline `code` has `back-ticks around` it. Inline `code` has `back-ticks around` it.
@@ -108,6 +132,7 @@ But let's throw in a <b>tag</b>.
### Tables ### Tables
[Back to top](#top)
Colons can be used to align columns. Colons can be used to align columns.
@@ -127,6 +152,7 @@ Markdown | Less | Pretty
1 | 2 | 3 1 | 2 | 3
### Blockquotes ### Blockquotes
[Back to top](#top)
> Blockquotes are very handy in email to emulate reply text. > Blockquotes are very handy in email to emulate reply text.
> This line is part of the same quote. > This line is part of the same quote.
@@ -136,6 +162,7 @@ Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote. > This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
### Inline HTML ### Inline HTML
[Back to top](#top)
<dl> <dl>
<dt>Definition list</dt> <dt>Definition list</dt>
@@ -146,6 +173,7 @@ Quote break.
</dl> </dl>
### Horizontal Rule ### Horizontal Rule
[Back to top](#top)
Three or more... Three or more...
@@ -162,6 +190,7 @@ ___
Underscores Underscores
### Line Breaks ### Line Breaks
[Back to top](#top)
Here's a line for us to start with. Here's a line for us to start with.
@@ -169,3 +198,93 @@ This line is separated from the one above by two newlines, so it will be a *sepa
This line is also a separate paragraph, but... This line is also a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*. This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
### Check Boxes
[Back to top](#top)
* [x] Task completed
* [] Task to do
### Spoilers
[Back to top](#top)
<details><summary>Title of the spoiler (click)</summary><p>
Content of the spoiler
On several lines
</p></details>
### Math Equations
[Back to top](#top)
You can use LaTeX equations with MathJax for full equations and inline ones (based on the number of $) :
$$
\large{\beta=\sum_{i}^{\alpha }\frac{x^{i}}{\alpha}}
$$
Where $\alpha$ is cool
### UML
[Back to top](#top)
You can use PlantUML diagrams with `@startuml` and `@enduml` tags :
@startuml
title Article
cloud web
node nodejs {
TCP -right- [express]
[showdown]
}
package data {
package "2019/06/18" {
component index [
index.md
image.png
...
]
}
}
web -down-> TCP : 1. /2019/06/18/title
express -down-> index : 2. fetch
index -up-> showdown : 3. markdown
showdown -left-> express : 4. html
express -up-> web : 5. html
@enduml
### Diagrams
[Back to top](#top)
You can use [fa-diagrams](https://github.com/Klemek/fa-diagrams) with `@startfad` and `@endfad` tags and using [TOML](https://github.com/toml-lang/toml) inside
@startfad
[[nodes]]
name = "node1"
icon = "laptop-code"
color = "#4E342E"
bottom = "my app"
[[nodes]]
name = "node2"
icon = "globe"
color = "#455A64"
bottom = "world"
[[links]]
from = "node1"
to = "node2"
color = "#333333"
bottom = '"hello"'
[links.top]
icon = "envelope"
@endfad
### Youtube Videos
[Back to top](#top)
Just use the "embedded" export on Youtube with dimensions of 535x300 for best results
<iframe width="535" height="300" src="https://www.youtube.com/embed/FTQbiNvZqaY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
+2 -3
View File
@@ -1,9 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <%- include('head'); %>
<title>Error <%= error %></title> <title><%= info.title %> - Error <%= error %></title>
<link rel="stylesheet" type="text/css" href="/style.css">
</head> </head>
<body> <body>
<main> <main>
+3 -2
View File
@@ -1,5 +1,6 @@
<hr> <hr>
<footer> <footer>
<small>@<%= new Date().getFullYear() %> - Made with <a href="https://github.com/klemek/gitblog.md">GitBlog.md</a> <small><a href="/rss">RSS feed</a> - <%= new Date().getFullYear() %> - Made with <a
href="https://github.com/klemek/gitblog.md">GitBlog.md</a> (v<%= info.version %>)
</small> </small>
</footer> </footer>
+30
View File
@@ -0,0 +1,30 @@
<meta charset="UTF-8">
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<META NAME="ROBOTS" CONTENT="INDEX, FOLLOW">
<meta name="twitter:card" content="summary_large_image">
<%- `<meta property="og:description" content="${info.description}">` %>
<%- `<meta property="twitter:description" content="${info.description}">` %>
<% if(locals.article){ %>
<%- `<meta property="org:url" content="${info.host + article.url}">` %>
<%- `<meta property="og:title" content="${info.title} - ${article.title}">` %>
<%- `<meta property="twitter:title" content="${info.title} - ${article.title}">` %>
<% if (article.thumbnail) { %>
<%- `<meta property="og:image" content="${info.host}/${article.thumbnail}">` %>
<%- `<meta property="twitter:image" content="${info.host}/${article.thumbnail}">` %>
<% } %>
<link rel="stylesheet" type="text/css" href="/css/prism.css">
<% } else { %>
<%- `<meta property="org:url" content="${info.host}/">` %>
<%- `<meta property="og:title" content="${info.title} - Home">` %>
<%- `<meta property="twitter:title" content="${info.title} - Home">` %>
<%- `<meta property="description" content="${info.description}">` %>
<% } %>
<link rel="alternate" type="application/rss+xml" title="RSS feed" href="/rss"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<link rel="stylesheet" type="text/css" href="/style.css">
+8 -7
View File
@@ -1,22 +1,23 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <%- include('head'); %>
<title>GitBlog.md - Home</title> <title><%= info.title %> - Home</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head> </head>
<body> <body>
<main> <main>
<h1>GitBlog.md</h1> <h1 class="title"><%= info.title %></h1>
A static blog using Markdown pulled from your git repository <%= info.description %>
<h2>Articles in this blog :</h2> <h2>Articles in this blog :</h2>
<% articles.forEach((article) => { %> <% articles.forEach((article) => { %>
<div class="article"> <div class="article">
<h3><%- `<a href="${article.url}">${article.title}</a>` %></h3> <%- `<a href="${article.url}">` %>
<span class="time"><span>Published on</span> <%= article.year + '-' + article.month + '-' + article.day %></span> <h3><%- `${article.title}` %></h3>
<span class="time"><span>Published on</span>&nbsp;&nbsp;<%= article.year + '-' + ('0' + article.month).slice(-2) + '-' + ('0' + article.day).slice(-2) %></span>
<% if(article.thumbnail){ %> <% if(article.thumbnail){ %>
<%- `<img alt="thumbnail" src=${article.thumbnail}>` %> <%- `<img alt="thumbnail" src=${article.thumbnail}>` %>
<% } %> <% } %>
<%- `</a>` %>
</div> </div>
<% }); %> <% }); %>
<%- include('footer'); %> <%- include('footer'); %>
+39 -8
View File
@@ -8,7 +8,7 @@ body, html {
} }
body { body {
font: 14px/1.45 -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif; font: 15px sans-serif;
color: #111; color: #111;
-webkit-text-size-adjust: none; -webkit-text-size-adjust: none;
background-color: #F5F5F5; background-color: #F5F5F5;
@@ -16,8 +16,8 @@ body {
} }
main { main {
max-width: 75ch; max-width: 45rem;
padding: 2ch; padding: 2rem;
margin: auto; margin: auto;
background-color: #F0F0F0; background-color: #F0F0F0;
min-height: 100vh; min-height: 100vh;
@@ -54,11 +54,18 @@ pre {
padding: 10px 16px; padding: 10px 16px;
} }
:not(pre) > code {
padding: 0.25em 0.5em;
border-radius: 0.25em;
background: #DDD;
font-size: 90%;
}
blockquote { blockquote {
border-left: 0.5em solid #ccc; border-left: 0.5em solid #ccc;
padding-left: 1em; padding-left: 1em;
margin: 0.25em 0; margin: 0.25em 0;
color: #333; color: #555;
} }
blockquote > p { blockquote > p {
@@ -108,10 +115,11 @@ main.article div.header a.link-home {
line-height: 2.4; line-height: 2.4;
} }
main.article div.header h1, main.article div.header h2, div.article h3 { main.article div.header h1, main.article div.header h2, .title {
margin-top: 0.85em; margin-top: 0.85em;
margin-bottom: 0.25em; margin-bottom: 0.25em;
font-size: 2em; font-size: 2em;
font-weight: bold;
} }
main.article div.header h1 a, main.article div.header h2 a, div.article h3 a { main.article div.header h1 a, main.article div.header h2 a, div.article h3 a {
@@ -123,13 +131,36 @@ main.article div.header span.time, div.article span.time {
} }
div.article { div.article {
margin-left: 1em; margin: 0 1em 1em 1em;
} }
div.article h3 { div.article h3 {
font-size: 1.3em; font-size: 1.3em;
margin:0;
color: #3C3CA1;
} }
div.article a {
text-decoration: none;
color: inherit;
}
div.article img{
max-width: 100%;
height: auto;
margin-right:1em;
margin-top:0.25em;
}
div.article:hover {
opacity: 0.9;
}
div.article:active {
opacity: 0.8;
}
#text { #text {
text-align: justify; text-align: justify;
hyphens: auto; hyphens: auto;
@@ -139,7 +170,7 @@ div.article h3 {
text-align: left; text-align: left;
} }
#text img { #text img, #text svg {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
} }
+4 -6
View File
@@ -1,17 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <%- include('head'); %>
<title>GitBlog.md - <%= article.title %></title> <title><%= info.title %> - <%= article.title %></title>
<link rel="stylesheet" type="text/css" href="/prism.css">
<link rel="stylesheet" type="text/css" href="/style.css">
</head> </head>
<body> <body>
<main class="article"> <main class="article">
<div class="header"> <div class="header">
<a class="link-home" href="/">↑</a> <a class="link-home" href="/">↑</a>
<h1><%= article.title %></h1> <h1><%= article.title %></h1>
<span class="time"><span>Published on</span> <%= article.year + '-' + article.month + '-' + article.day %></span> <span class="time"><span><%= article.draft ? 'Drafted on' : 'Published on' %></span>&nbsp;&nbsp;<%= article.year + '-' + ('0' + article.month).slice(-2) + '-' + ('0' + article.day).slice(-2) %></span>
</div> </div>
<div id="text"><%- article.content %></div> <div id="text"><%- article.content %></div>
<br> <br>
@@ -19,4 +17,4 @@
<%- include('footer'); %> <%- include('footer'); %>
</main> </main>
</body> </body>
</html> </html>
+74 -48
View File
@@ -2,6 +2,7 @@ const express = require('express');
const app = express(); const app = express();
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const pjson = require('../package.json');
app.enable('trust proxy'); app.enable('trust proxy');
@@ -25,6 +26,28 @@ const cons = {
}; };
module.exports = (config) => { module.exports = (config) => {
/**
* Fetch articles from the data folder and send success as a response
* @param success
* @param error
*/
let reload;
/**
* Render the page with the view engine and catch errors
* @param req
* @param res
* @param vPath - path of the view
* @param data - data to pass to the view
* @param code - code to send along the page
*/
let render;
/**
* Show an error with the correct page
* @param req
* @param res
* @param code - error code
*/
let showError;
const fw = require('./file_walker')(config); const fw = require('./file_walker')(config);
const renderer = require('./renderer')(config); const renderer = require('./renderer')(config);
@@ -35,13 +58,9 @@ module.exports = (config) => {
const articles = {}; const articles = {};
let lastRSS = ''; let lastRSS = '';
let host = config['host'];
/** reload = (success, error) => {
* Fetch articles from the data folder and send success as a response
* @param success
* @param error
*/
const reload = (success, error) => {
fw.fetchArticles((err, dict) => { fw.fetchArticles((err, dict) => {
if (err) { if (err) {
console.error(cons.error, 'error loading articles : ' + err); console.error(cons.error, 'error loading articles : ' + err);
@@ -50,8 +69,9 @@ module.exports = (config) => {
Object.keys(articles).forEach((key) => delete articles[key]); Object.keys(articles).forEach((key) => delete articles[key]);
Object.keys(dict).forEach((key) => articles[key] = dict[key]); Object.keys(dict).forEach((key) => articles[key] = dict[key]);
const nb = Object.keys(articles).length; const nb = Object.keys(articles).length;
const dnb = Object.values(articles).filter(a => a.draft).length;
if (nb > 0) if (nb > 0)
console.log(cons.ok, `loaded ${nb} article${nb > 1 ? 's' : ''}`); console.log(cons.ok, `loaded ${nb} article${nb > 1 ? 's' : ''} (${dnb} drafted)`);
else else
console.log(cons.warn, `no articles loaded, check your configuration`); console.log(cons.warn, `no articles loaded, check your configuration`);
@@ -63,39 +83,45 @@ module.exports = (config) => {
if (config['test']) if (config['test'])
app.reload = reload; app.reload = reload;
/** render = (req, res, vPath, data, code = 200) => {
* Render the page with the view engine and catch errors data.info = {
* @param res title: config['home']['title'],
* @param vPath - path of the view description: config['home']['description'],
* @param data - data to pass to the view host: host,
* @param code - code to send along the page version: pjson.version,
*/ request: req,
const render = (res, vPath, data, code = 200) => { config: config
};
res.render(vPath, data, (err, html) => { res.render(vPath, data, (err, html) => {
if (err) { if (err && vPath !== path.join(config['data_dir'], config['home']['error'])) {
console.log(cons.error, `failed to render page ${vPath} : ${err}`);
showError(req, res, 500);
} else if (err) {
res.sendStatus(500); res.sendStatus(500);
console.log(cons.error, `failed to render ${vPath} : ${err}`); console.log(cons.error, `failed to render error page : ${err}`);
} else } else
res.status(code).send(html); res.status(code).send(html);
}); });
}; };
/** showError = (req, res, code) => {
* Show an error with the correct page
* @param resPath - the page of the original error
* @param code - error code
* @param res
*/
const showError = (resPath, code, res) => {
const errorPath = path.join(config['data_dir'], config['home']['error']); const errorPath = path.join(config['data_dir'], config['home']['error']);
fs.access(errorPath, fs.constants.R_OK, (err) => { fs.access(errorPath, fs.constants.R_OK, (err) => {
if (err) if (err)
res.sendStatus(code); res.sendStatus(code);
else else
render(res, errorPath, {error: code, path: resPath}, code); render(req, res, errorPath, {error: code}, code);
}); });
}; };
app.use((req, res, next) => {
if (!host) {
host = 'http://' + req.headers.host;
console.log(cons.ok, 'Currently hosted on ' + host);
}
next();
});
//log request at result end //log request at result end
app.use((req, res, next) => { app.use((req, res, next) => {
if (config['access_log']) { if (config['access_log']) {
@@ -117,9 +143,13 @@ module.exports = (config) => {
const homePath = path.join(config['data_dir'], config['home']['index']); const homePath = path.join(config['data_dir'], config['home']['index']);
fs.access(homePath, fs.constants.R_OK, (err) => { fs.access(homePath, fs.constants.R_OK, (err) => {
if (err) if (err)
showError(req.path, 404, res); showError(req, res, 404);
else else
render(res, homePath, {articles: Object.values(articles).sort((a, b) => ('' + b.path).localeCompare(a.path))}); render(req, res, homePath,
{
articles: Object.values(articles)
.filter(d => !d.draft).sort((a, b) => ('' + b.path).localeCompare(a.path))
});
}); });
}); });
@@ -130,23 +160,23 @@ module.exports = (config) => {
const feed = new Rss({ const feed = new Rss({
'title': config['rss']['title'], 'title': config['rss']['title'],
'description': config['rss']['description'], 'description': config['rss']['description'],
'feed_url': 'http://' + req.headers.host + req.url, 'feed_url': host + req.url,
'site_url': 'http://' + req.headers.host 'site_url': host
}); });
Object.values(articles) Object.values(articles)
.slice(0, config['rss']['length']) .slice(0, config['rss']['length'])
.forEach((article) => { .forEach((article) => {
feed.item({ feed.item({
title: article.title, title: article.title,
url: 'http://' + req.headers.host + article.url, url: host + article.url,
date: article.date date: article.date
}); });
}); });
lastRSS = feed.xml(); lastRSS = feed.xml();
} }
res.type('rss').send(lastRSS); res.type(req.headers['user-agent'].match(/Mozilla/) ? 'text/xml' : 'rss').send(lastRSS);
} else { } else {
showError(req.path, 404, res); showError(req, res, 404);
} }
}); });
@@ -154,10 +184,7 @@ module.exports = (config) => {
app.post(config['webhook']['endpoint'], (req, res) => { app.post(config['webhook']['endpoint'], (req, res) => {
if (config['modules']['webhook']) { if (config['modules']['webhook']) {
if (config['webhook']['signature_header'] && config['webhook']['secret']) { if (config['webhook']['signature_header'] && config['webhook']['secret']) {
const payload = JSON.stringify(req.body); const payload = JSON.stringify(req.body) || '';
if (!payload) {
return res.sendStatus(403);
}
const hmac = crypto.createHmac('sha1', config['webhook']['secret']); const hmac = crypto.createHmac('sha1', config['webhook']['secret']);
const digest = 'sha1=' + hmac.update(payload).digest('hex'); const digest = 'sha1=' + hmac.update(payload).digest('hex');
const checksum = req.headers[config['webhook']['signature_header']]; const checksum = req.headers[config['webhook']['signature_header']];
@@ -192,21 +219,21 @@ module.exports = (config) => {
const articlePath = req.path.substr(1, 10); const articlePath = req.path.substr(1, 10);
const article = articles[articlePath]; const article = articles[articlePath];
if (!article) if (!article)
showError(req.path, 404, res); showError(req, res, 404);
else { else {
renderer.render(path.join(article.realPath, config['article']['index']), (err, html) => { renderer.render(article.realPath, (err, html) => {
if (err) { if (err) {
console.log(cons.error, `failed to render article ${req.path} : ${err}`); console.log(cons.error, `failed to render article ${req.path} : ${err}`);
return showError(req.path, 500, res); return showError(req, res, 500);
} }
article.content = html; article.content = html;
const templatePath = path.join(config['data_dir'], config['article']['template']); const templatePath = path.join(config['data_dir'], config['article']['template']);
fs.access(templatePath, fs.constants.R_OK, (err) => { fs.access(templatePath, fs.constants.R_OK, (err) => {
if (err) { if (err) {
console.log(cons.error, `no template found at ${templatePath}`); console.log(cons.error, `no template found at ${templatePath}`);
showError(req.path, 500, res); showError(req, res, 500);
} else } else
render(res, templatePath, {article: article}); render(req, res, templatePath, {article: article});
}); });
}); });
} }
@@ -216,18 +243,17 @@ module.exports = (config) => {
}); });
// catch all hidden file type and return 404 // catch all hidden file type and return 404
app.get('*', (req, res, next) => { config['home']['hidden'].forEach(pathMatcher => {
if (config['home']['hidden'].includes(path.extname(req.path))) app.get(pathMatcher, (req, res) => {
showError(req.path, 404, res); showError(req, res, 404);
else });
next();
}); });
// serve all static files via get // serve all static files via get
app.get('*', express.static(config['data_dir'])); app.get('*', express.static(path.join(__dirname, '..', config['data_dir'])));
// catch express.static errors (mostly not found) by displaying 404 // catch express.static errors (mostly not found) by displaying 404
app.get('*', (req, res) => { app.get('*', (req, res) => {
showError(req.path, 404, res); showError(req, res, 404);
}); });
// catch all other methods and return 400 // catch all other methods and return 400
+19 -4
View File
@@ -1,5 +1,6 @@
{ {
"node_port": 3000, "node_port": 3000,
"host": "",
"data_dir": "data", "data_dir": "data",
"view_engine": "ejs", "view_engine": "ejs",
"access_log": "access.log", "access_log": "access.log",
@@ -7,17 +8,24 @@
"modules": { "modules": {
"rss": true, "rss": true,
"webhook": true, "webhook": true,
"prism": true "prism": true,
"mathjax": true,
"plantuml": true,
"fa-diagrams": true
}, },
"home": { "home": {
"title": "GitBlog.md",
"description": "A static blog using Markdown pulled from your git repository",
"index": "index.ejs", "index": "index.ejs",
"error": "error.ejs", "error": "error.ejs",
"hidden": [ "hidden": [
".ejs" "*.ejs",
"/.git*"
] ]
}, },
"article": { "article": {
"index": "index.md", "index": "index.md",
"draft": "draft.md",
"template": "template.ejs", "template": "template.ejs",
"thumbnail_tag": "thumbnail", "thumbnail_tag": "thumbnail",
"default_title": "Untitled", "default_title": "Untitled",
@@ -33,7 +41,7 @@
"endpoint": "/webhook", "endpoint": "/webhook",
"secret": "", "secret": "",
"signature_header": "", "signature_header": "",
"pull_command": "git pull" "pull_command": "git pull origin master"
}, },
"showdown": { "showdown": {
"parseImgDimensions": true, "parseImgDimensions": true,
@@ -42,5 +50,12 @@
"tasklists": true, "tasklists": true,
"openLinksInNewWindow": true, "openLinksInNewWindow": true,
"emoji": true "emoji": true
},
"mathjax": {
"output_format": "svg",
"speak_text": true
},
"plantuml": {
"output_format": "svg"
} }
} }
+5 -1
View File
@@ -10,6 +10,10 @@ const fs = require('fs');
const merge = (ref, src) => { const merge = (ref, src) => {
if (typeof ref !== typeof src) { if (typeof ref !== typeof src) {
return ref; return ref;
} else if (ref.length && !src.length) {
return ref;
} else if (ref.length && src.length) {
return src;
} else if (typeof ref === 'object') { } else if (typeof ref === 'object') {
const out = {}; const out = {};
Object.keys(ref).forEach((key) => out[key] = merge(ref[key], src[key])); Object.keys(ref).forEach((key) => out[key] = merge(ref[key], src[key]));
@@ -25,7 +29,7 @@ module.exports = () => {
let config = JSON.parse(configData); let config = JSON.parse(configData);
return merge(refConfig, config); return merge(refConfig, config);
} catch (error) { } catch (error) {
console.error('Failed to load config.json : ' + error); console.log('\x1b[33m⚠\x1b[0m %s', 'Failed to load config.json : ' + error);
return refConfig; return refConfig;
} }
}; };
+8 -6
View File
@@ -1,7 +1,7 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const joinUrl = (...paths) => path.join(...paths).replace(/\\/g,'/'); const joinUrl = (...paths) => path.join(...paths).replace(/\\/g, '/');
/** /**
* Get all files path inside a given folder path * Get all files path inside a given folder path
@@ -71,8 +71,8 @@ module.exports = (config) => {
if (err) if (err)
return cb(err); return cb(err);
const paths = fileList const paths = fileList
.map((p) => p.substr(config['data_dir'].length+1).split(path.sep)) .map((p) => p.substr(config['data_dir'].length + 1).split(path.sep))
.filter((p) => p.length === 4 && p[3] === config['article']['index'] && .filter((p) => p.length === 4 && (p[3] === config['article']['index'] || p[3] === config['article']['draft']) &&
/^\d{4}$/.test(p[0]) && /^\d{2}$/.test(p[1]) && /^\d{2}$/.test(p[2])); /^\d{4}$/.test(p[0]) && /^\d{2}$/.test(p[1]) && /^\d{2}$/.test(p[2]));
if (paths.length === 0) if (paths.length === 0)
cb(null, {}); cb(null, {});
@@ -81,7 +81,8 @@ module.exports = (config) => {
paths.forEach((p) => { paths.forEach((p) => {
const article = { const article = {
path: joinUrl(p[0], p[1], p[2]), path: joinUrl(p[0], p[1], p[2]),
realPath: path.join(config['data_dir'], p[0], p[1], p[2]), draft: p[3] === config['article']['draft'],
realPath: path.join(config['data_dir'], p[0], p[1], p[2], p[3]),
year: parseInt(p[0]), year: parseInt(p[0]),
month: parseInt(p[1]), month: parseInt(p[1]),
day: parseInt(p[2]) day: parseInt(p[2])
@@ -89,14 +90,15 @@ module.exports = (config) => {
article.date = new Date(article.year, article.month, article.day); article.date = new Date(article.year, article.month, article.day);
article.date.setUTCHours(0); article.date.setUTCHours(0);
remaining++; remaining++;
readIndexFile(path.join(article.realPath, config['article']['index']), config['article']['thumbnail_tag'], (err, info) => { readIndexFile(article.realPath, config['article']['thumbnail_tag'], (err, info) => {
if (err) if (err)
return cb(err); return cb(err);
article.title = info.title || config['article']['default_title']; article.title = info.title || config['article']['default_title'];
article.thumbnail = info.thumbnail ? joinUrl(article.path, info.thumbnail) : config['article']['default_thumbnail']; article.thumbnail = info.thumbnail ? joinUrl(article.path, info.thumbnail) : config['article']['default_thumbnail'];
article.escapedTitle = article.title.toLowerCase().replace(/[^\w]/gm, ' ').trim().replace(/ /gm, '_'); article.escapedTitle = article.title.toLowerCase().replace(/[^\w]/gm, ' ').trim().replace(/ /gm, '_');
article.url = '/' + joinUrl(article.path, article.escapedTitle) + '/'; article.url = '/' + joinUrl(article.path, article.escapedTitle) + '/';
articles[article.path] = article; if (!articles[article.path] || !article.draft)
articles[article.path] = article;
remaining--; remaining--;
if (remaining === 0) if (remaining === 0)
cb(null, articles); cb(null, articles);
File diff suppressed because it is too large Load Diff
+202 -21
View File
@@ -1,35 +1,216 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path');
const showdown = require('showdown'); const showdown = require('showdown');
const Prism = require('node-prismjs');
module.exports = (config) => { module.exports = (config) => {
const converter = new showdown.Converter(config['showdown']); const converter = new showdown.Converter(config['showdown']);
/**
* get parts outside of codes/scripts
* @param {string} data
* @returns {{index:number, end:number, text:string}[]} parts
*/
const getParts = (data) => {
let parts = [];
let match;
let i = 0;
while ((match = /```/m.exec(data.slice(i)))) {
parts.push({
index: i,
text: data.slice(i, i + match.index),
});
i += match.index + match[0].length;
}
if (i < data.length)
parts.push({
index: i,
text: data.slice(i, data.length),
});
parts = parts.filter((p, i) => i % 2 === 0); //filter out code parts
// detect scripts outside of code
parts.forEach((p, pi) => {
let i = 0;
const subParts = [];
while ((match = /(<script>((?:(?!<\/script>)[\s\S])*)<\/script>)/gm.exec(p.text.slice(i)))) {
subParts.push({
index: p.index + i,
text: p.text.slice(i, i + match.index),
});
i += match.index + match[0].length;
}
if (i < p.text.length)
subParts.push({
index: p.index + i,
text: p.text.slice(i, p.text.length),
});
parts.splice(pi, 1, ...subParts);
});
parts.forEach(part => part.end = part.index + part.text.length);
return parts;
};
const renderShowDown = (data, cb) => {
const html = converter.makeHtml(data);
cb(html);
};
let Prism;
if (config['modules']['prism'])
Prism = require('node-prismjs');
const renderPrism = (data, cb) => {
if (!config['modules']['prism'])
return cb(data);
const codeRegex = /```([\w-]+)\r?\n((?:(?!```)[\s\S])*)\r?\n```/m;
let match;
while ((match = codeRegex.exec(data))) {
const lang = match[1].trim();
const code = match[2].trim();
const block = Prism.highlight(code, Prism.languages[lang] || Prism.languages.autoit, lang);
data = data.slice(0, match.index) + `<pre><code class="${lang} language-${lang}">` + block + '</code></pre>' + data.slice(match.index + match[0].length);
}
cb(data);
};
if (config['modules']['plantuml']) {
require('./script_loader')(path.join(__dirname, 'lib', 'plantuml_synchro.js'));
}
const renderPlantUML = (data, cb) => {
if (!config['modules']['plantuml'])
return cb(data);
const parts = getParts(data);
const umlRegex = /@startuml\r?\n((?:(?!@enduml)[\s\S])*)\r?\n@enduml/m;
let match;
parts.forEach(part => {
while ((match = umlRegex.exec(part.text))) {
const code = match[1].trim();
const s = unescape(encodeURIComponent(code)); // jshint ignore:line
const compressed = global['zip_deflate'](s);
const url = `http://www.plantuml.com/plantuml/${config['plantuml']['output_format']}/${encode64(compressed)}`;// jshint ignore:line
part.text = part.text.slice(0, match.index) + `<img alt="generated PlantUML diagram" src="${url}">` + part.text.slice(match.index + match[0].length);
}
data = data.slice(0, part.index) + part.text + data.slice(part.end);
});
cb(data);
};
let mjAPI;
if (config['modules']['mathjax']) {
mjAPI = require('mathjax-node');
mjAPI.config({
MathJax: {
tex2jax: {
inlineMath: [['$', '$']],
displayMath: [['$$', '$$']]
}
}
});
}
const renderMathJax = (data, cb) => {
if (!config['modules']['mathjax'])
return cb(data);
const parts = getParts(data);
const doMJ = (match, format, i) => {
const eq = match[1].trim();
const output = config['mathjax']['output_format'];
const mjConf = {
math: eq,
format: format,
speakText: config['mathjax']['speak_text']
};
mjConf[output] = true;
mjAPI.typeset(mjConf, (res) => {
data = data.slice(0, parts[i].index + match.index) + res[output] + data.slice(parts[i].index + match.index + match[0].length);
renderMathJax(data, (data2) => {
cb(data2);
});
});
};
const eqRegex = /\$\$((?:(?!\$\$)[\s\S])*)\$\$/m;
const inlineEqRegex = /\$([^$\n]*)\$/;
for (let i = 0; i < parts.length; i++) {
let match;
if ((match = eqRegex.exec(parts[i].text))) {
return doMJ(match, 'TeX', i);
} else if ((match = inlineEqRegex.exec(parts[i].text))) {
return doMJ(match, 'inline-TeX', i);
}
}
cb(data);
};
let faDiagrams;
let toml;
if (config['modules']['fa-diagrams']) {
faDiagrams = require('fa-diagrams');
toml = require('@iarna/toml');
}
const renderFaDiagrams = (data, cb) => {
if (!config['modules']['fa-diagrams'])
return cb(data);
const parts = getParts(data);
const diagramsRegex = /@startfad\r?\n((?:(?!@endfad)[\s\S])*)\r?\n@endfad/m;
let match;
parts.forEach(part => {
while ((match = diagramsRegex.exec(part.text))) {
const code = match[1].trim();
let output;
try {
const diagData = toml.parse(code);
const findLineBreaks = (data) => {
Object.keys(data).forEach(key => {
if (typeof data[key] === 'object')
findLineBreaks(data[key]);
else if (typeof data[key] === 'string')
data[key] = data[key].replace(/\\n/gm, '\n');
});
};
findLineBreaks(diagData);
output = faDiagrams.compute(diagData);
} catch (err) {
output = `<b style="color:red">${err.toString()}</b>`;
}
part.text = part.text.slice(0, match.index) + output + part.text.slice(match.index + match[0].length);
}
data = data.slice(0, part.index) + part.text + data.slice(part.end);
});
cb(data);
};
return { return {
getParts: config['test'] ? getParts : undefined,
renderShowDown: config['test'] ? renderShowDown : undefined,
renderPrism: config['test'] ? renderPrism : undefined,
renderPlantUML: config['test'] ? renderPlantUML : undefined,
renderMathJax: config['test'] ? renderMathJax : undefined,
renderFaDiagrams: config['test'] ? renderFaDiagrams : undefined,
render: (file, cb) => { render: (file, cb) => {
fs.readFile(file, {encoding: 'UTF-8'}, (err, data) => { fs.readFile(file, {encoding: 'UTF-8'}, (err, data) => {
if (err) if (err)
return cb(err); return cb(err);
if (config['modules']['prism']) { renderPlantUML(data, (data) => {
const codeRegex = /```([\w-]+)\r?\n((?:(?!```)[\s\S])*)\r?\n```/m; renderFaDiagrams(data, (data) => {
let match; renderMathJax(data, (data) => {
while ((match = codeRegex.exec(data))) { renderPrism(data, (data) => {
const lang = match[1].trim(); renderShowDown(data, (html) => {
const code = match[2].trim(); cb(null, html);
try { });
const block = Prism.highlight(code, Prism.languages[lang] || Prism.languages.autoit, lang); });
data = data.slice(0, match.index) + `<pre><code class="${lang} language-${lang}">` + block + '</code></pre>' + data.slice(match.index + match[0].length); });
} catch (err) { });
console.error(err); });
}
}
}
const html = converter.makeHtml(data);
cb(null, html);
}); });
} }
}; };
+10
View File
@@ -0,0 +1,10 @@
const fs = require('fs');
/**
* Import client-side script into the "global" var
* @param scriptPath
*/
module.exports = (scriptPath) => {
eval.call(global, fs.readFileSync(scriptPath, {encoding: 'UTF-8'}));
};
+119 -44
View File
@@ -13,19 +13,23 @@ const config = require('../src/config')();
config['test'] = true; config['test'] = true;
config['data_dir'] = dataDir; config['data_dir'] = dataDir;
config['home']['index'] = testIndex; config['webhook']['endpoint'] = '/webhooktest';
config['home']['error'] = testError;
config['article']['template'] = testTemplate;
config['home']['hidden'].push('.test');
config['rss']['endpoint'] = '/rsstest'; config['rss']['endpoint'] = '/rsstest';
config['rss']['length'] = 2; config['rss']['length'] = 2;
config['webhook']['endpoint'] = '/webhooktest'; config['home']['error'] = testError;
config['access_log'] = path.join(dataDir, 'access.log'); config['article']['template'] = testTemplate;
config['error_log'] = path.join(dataDir, 'error.log');
const app = require('../src/app')(config); const app = require('../src/app')(config);
beforeEach((done, fail) => { beforeEach((done, fail) => {
config['home']['index'] = testIndex;
config['data_dir'] = dataDir;
config['article']['index'] = 'index.md';
config['access_log'] = '';
config['error_log'] = '';
config['modules']['rss'] = true;
config['modules']['webhook'] = true;
utils.deleteFolderSync(dataDir); utils.deleteFolderSync(dataDir);
fs.mkdirSync(dataDir); fs.mkdirSync(dataDir);
app.reload(done, fail); app.reload(done, fail);
@@ -37,17 +41,22 @@ afterAll(() => {
} }
}); });
describe('Test reload', () => {
test('reload fail', (done, fail) => {
config['data_dir'] = '';
app.reload(fail, done);
});
});
describe('Test request logging', () => { describe('Test request logging', () => {
test('test no log', (done) => { test('test no log', (done) => {
const tmp = config['access_log'];
config['access_log'] = '';
request(app).get('/rsstest').then(() => { request(app).get('/rsstest').then(() => {
config['access_log'] = tmp;
expect(fs.existsSync(path.join(dataDir, 'access.log'))).toBe(false); expect(fs.existsSync(path.join(dataDir, 'access.log'))).toBe(false);
done(); done();
}); });
}); });
test('test get 200', (done) => { test('test get 200', (done) => {
config['access_log'] = path.join(dataDir, 'access.log');
request(app).get('/rsstest').then(() => { request(app).get('/rsstest').then(() => {
fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => { fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => {
expect(err).toBeNull(); expect(err).toBeNull();
@@ -57,6 +66,7 @@ describe('Test request logging', () => {
}); });
}); });
test('test post 400', (done) => { test('test post 400', (done) => {
config['access_log'] = path.join(dataDir, 'access.log');
request(app).post('/rsstest').then(() => { request(app).post('/rsstest').then(() => {
fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => { fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => {
expect(err).toBeNull(); expect(err).toBeNull();
@@ -66,6 +76,7 @@ describe('Test request logging', () => {
}); });
}); });
test('test 2 requests', (done) => { test('test 2 requests', (done) => {
config['access_log'] = path.join(dataDir, 'access.log');
request(app).get('/rss').then(() => { request(app).get('/rss').then(() => {
request(app).post('/rsstest').then(() => { request(app).post('/rsstest').then(() => {
fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => { fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => {
@@ -81,26 +92,20 @@ describe('Test request logging', () => {
describe('Test error logging', () => { describe('Test error logging', () => {
test('test no log', (done) => { test('test no log', (done) => {
const tmp = config['home']['hidden']; config['home']['index'] = null;
config['home']['hidden'] = null; request(app).get('/').then(() => {
const tmp2 = config['errpr_log'];
config['error_log'] = '';
request(app).get('/somefile.txt').then(() => {
config['home']['hidden'] = tmp;
config['error_log'] = tmp2;
expect(fs.existsSync(path.join(dataDir, 'error.log'))).toBe(false); expect(fs.existsSync(path.join(dataDir, 'error.log'))).toBe(false);
done(); done();
}); });
}); });
test('test null error ', (done) => { test('test null error ', (done) => {
const tmp = config['home']['hidden']; config['home']['index'] = null;
config['home']['hidden'] = null; config['error_log'] = path.join(dataDir, 'error.log');
request(app).get('/somefile.txt').then(() => { request(app).get('/').then(() => {
config['home']['hidden'] = tmp;
fs.readFile(path.join(dataDir, 'error.log'), {encoding: 'UTF-8'}, (err, data) => { fs.readFile(path.join(dataDir, 'error.log'), {encoding: 'UTF-8'}, (err, data) => {
expect(err).toBeNull(); expect(err).toBeNull();
const start = data.split('\n').slice(0, 2).join('\n'); const start = data.split('\n').slice(0, 2).join('\n');
const expected = '500 GET /somefile.txt ' + new Date().toUTCString() + ' ::ffff:127.0.0.1\nTypeError: Cannot read property \'includes\' of null'; const expected = '500 GET / ' + new Date().toUTCString() + ' ::ffff:127.0.0.1\nTypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object';
expect(start).toBe(expected); expect(start).toBe(expected);
done(); done();
}); });
@@ -116,10 +121,34 @@ describe('Test root path', () => {
}); });
}); });
test('404 no index but error page', (done) => { test('404 no index but error page', (done) => {
fs.writeFileSync(path.join(dataDir, testError), 'error <%= error %> at <%= path %>'); fs.writeFileSync(path.join(dataDir, testError), 'error <%= error %>');
request(app).get('/').then((response) => { request(app).get('/').then((response) => {
expect(response.statusCode).toBe(404); expect(response.statusCode).toBe(404);
expect(response.text).toBe('error 404 at /'); expect(response.text).toBe('error 404');
done();
});
});
test('500 render error', (done) => {
fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= null.length %>');
request(app).get('/').then((response) => {
expect(response.statusCode).toBe(500);
done();
});
});
test('500 render error with page', (done) => {
fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= null.length %>');
fs.writeFileSync(path.join(dataDir, testError), 'error <%= error %>');
request(app).get('/').then((response) => {
expect(response.statusCode).toBe(500);
expect(response.text).toBe('error 500');
done();
});
});
test('500 render error with failing page', (done) => {
fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= null.length %>');
fs.writeFileSync(path.join(dataDir, testError), 'error <%= null.error %>');
request(app).get('/').then((response) => {
expect(response.statusCode).toBe(500);
done(); done();
}); });
}); });
@@ -131,14 +160,17 @@ describe('Test root path', () => {
done(); done();
}); });
}); });
test('200 2 articles', (done, fail) => { test('200 2 articles 1 drafted', (done, fail) => {
utils.createEmptyDirs([ utils.createEmptyDirs([
path.join(dataDir, '2019', '05', '05'), path.join(dataDir, '2019', '05', '05'),
path.join(dataDir, '2018', '05', '05') path.join(dataDir, '2018', '05', '05'),
path.join(dataDir, '2017', '05', '05')
]); ]);
utils.createEmptyFiles([ utils.createEmptyFiles([
path.join(dataDir, '2019', '05', '05', 'index.md'), path.join(dataDir, '2019', '05', '05', 'draft.md'),
path.join(dataDir, '2018', '05', '05', 'index.md') path.join(dataDir, '2018', '05', '05', 'index.md'),
path.join(dataDir, '2018', '05', '05', 'draft.md'),
path.join(dataDir, '2017', '05', '05', 'index.md'),
]); ]);
fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= articles.length %>'); fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= articles.length %>');
app.reload(() => { app.reload(() => {
@@ -156,18 +188,35 @@ describe('Test RSS feed', () => {
config['modules']['rss'] = false; config['modules']['rss'] = false;
request(app).get('/rsstest').then((response) => { request(app).get('/rsstest').then((response) => {
expect(response.statusCode).toBe(404); expect(response.statusCode).toBe(404);
config['modules']['rss'] = true;
done(); done();
}); });
}); });
test('200 empty rss', (done) => { test('200 empty rss', (done) => {
request(app).get('/rsstest').then((response) => { request(app).get('/rsstest').then((response) => {
expect(response.statusCode).toBe(200); expect(response.statusCode).toBe(200);
expect(response.type).toBe('application/rss+xml');
expect(response.text.length).toBeGreaterThan(0); expect(response.text.length).toBeGreaterThan(0);
expect(response.text.split('<item>').length).toBe(1); expect(response.text.split('<item>').length).toBe(1);
done(); done();
}); });
}); });
test('200 Mozilla fix', (done) => {
request(app).get('/rsstest').set('user-agent', 'Mozilla Firefox 64.0').then((response) => {
expect(response.statusCode).toBe(200);
expect(response.type).toBe('text/xml');
done();
});
});
test('200 rss cache', (done) => {
request(app).get('/rsstest').then(() => {
request(app).get('/rsstest').then((response) => {
expect(response.statusCode).toBe(200);
expect(response.text.length).toBeGreaterThan(0);
expect(response.text.split('<item>').length).toBe(1);
done();
});
});
});
test('200 2 rss items', (done, fail) => { test('200 2 rss items', (done, fail) => {
utils.createEmptyDirs([ utils.createEmptyDirs([
path.join(dataDir, '2019', '05', '05'), path.join(dataDir, '2019', '05', '05'),
@@ -213,7 +262,6 @@ describe('Test webhook', () => {
config['modules']['webhook'] = false; config['modules']['webhook'] = false;
request(app).post('/webhooktest').then((response) => { request(app).post('/webhooktest').then((response) => {
expect(response.statusCode).toBe(400); expect(response.statusCode).toBe(400);
config['modules']['webhook'] = true;
done(); done();
}); });
}); });
@@ -244,14 +292,6 @@ describe('Test webhook', () => {
done(); done();
}); });
}); });
test('403 no payload', (done) => {
config['webhook']['signature_header'] = 'testheader';
config['webhook']['secret'] = 'testvalue';
request(app).post('/webhooktest').then((response) => {
expect(response.statusCode).toBe(403);
done();
});
});
test('403 wrong secret', (done) => { test('403 wrong secret', (done) => {
config['webhook']['signature_header'] = 'testheader'; config['webhook']['signature_header'] = 'testheader';
config['webhook']['secret'] = 'testvalue'; config['webhook']['secret'] = 'testvalue';
@@ -282,6 +322,18 @@ describe('Test articles rendering', () => {
}); });
}); });
test('500 fail to render', (done, fail) => {
utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]);
fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello');
fs.writeFileSync(path.join(dataDir, testTemplate), '<%- articl.content %><%- `<a href="${article.url}">reload</a>` %>');
app.reload(() => {
request(app).get('/2019/05/05/hello/').then((response) => {
expect(response.statusCode).toBe(500);
done();
});
}, fail);
});
test('500 no template', (done, fail) => { test('500 no template', (done, fail) => {
utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]);
fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello'); fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello');
@@ -306,6 +358,19 @@ describe('Test articles rendering', () => {
}, fail); }, fail);
}); });
test('200 rendered draft', (done, fail) => {
utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]);
fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'draft.md'), '# Hello');
fs.writeFileSync(path.join(dataDir, testTemplate), '<%- article.content %><%- `<a href="${article.url}">reload</a>` %>');
app.reload(() => {
request(app).get('/2019/05/05/hello/').then((response) => {
expect(response.statusCode).toBe(200);
expect(response.text).toBe('<h1 id="hello">Hello</h1><a href="/2019/05/05/hello/">reload</a>');
done();
});
}, fail);
});
test('200 other url', (done, fail) => { test('200 other url', (done, fail) => {
utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]);
utils.createEmptyFiles([ utils.createEmptyFiles([
@@ -344,24 +409,34 @@ describe('Test static files', () => {
}); });
}); });
test('404 invalid file but error page', (done) => { test('404 invalid file but error page', (done) => {
fs.writeFileSync(path.join(dataDir, testError), 'error <%= error %> at <%= path %>'); fs.writeFileSync(path.join(dataDir, testError), 'error <%= error %>');
request(app).get('/somefile.txt').then((response) => { request(app).get('/somefile.txt').then((response) => {
expect(response.statusCode).toBe(404); expect(response.statusCode).toBe(404);
expect(response.text).toBe('error 404 at /somefile.txt'); expect(response.text).toBe('error 404');
done(); done();
}); });
}); });
test('404 hidden file', (done) => { test('404 hidden file', (done) => {
fs.writeFileSync(path.join(dataDir, 'somefile.test'), ''); utils.createEmptyDirs([path.join(dataDir, 'tmp')]);
request(app).get('/somefile.test').then((response) => { fs.writeFileSync(path.join(dataDir, 'tmp', 'somefile.ejs'), '');
request(app).get('/tmp/somefile.ejs').then((response) => {
expect(response.statusCode).toBe(404);
done();
});
});
test('404 hidden folder', (done) => {
utils.createEmptyDirs([path.join(dataDir, '.git')]);
fs.writeFileSync(path.join(dataDir, '.git', 'file.txt'), '');
request(app).get('/.git/file.txt').then((response) => {
expect(response.statusCode).toBe(404); expect(response.statusCode).toBe(404);
done(); done();
}); });
}); });
test('200 valid file', (done) => { test('200 valid file', (done) => {
fs.writeFileSync(path.join(dataDir, 'somefile.txt'), 'filecontent'); fs.writeFileSync(path.join(dataDir, 'somefile.css'), 'filecontent');
request(app).get('/somefile.txt').then((response) => { request(app).get('/somefile.css').then((response) => {
expect(response.statusCode).toBe(200); expect(response.statusCode).toBe(200);
expect(response.type).toBe('text/css');
expect(response.text).toBe('filecontent'); expect(response.text).toBe('filecontent');
done(); done();
}); });
+14
View File
@@ -64,4 +64,18 @@ test('wrong config fixed', () => {
expect(config).toBeDefined(); expect(config).toBeDefined();
expect(config['node_port']).toBe(3000); expect(config['node_port']).toBe(3000);
expect(config['data_dir']).toBe('data2'); expect(config['data_dir']).toBe('data2');
});
test('array parsing', () => {
fs.writeFileSync(configFile, '{"home":{"hidden":["item1","item2"]}}');
const config = require('../src/config')();
expect(config).toBeDefined();
expect(config['home']['hidden']).toEqual(['item1', 'item2']);
});
test('array fix', () => {
fs.writeFileSync(configFile, '{"home":{"hidden":{}}}');
const config = require('../src/config')();
expect(config).toBeDefined();
expect(config['home']['hidden']).toEqual(['*.ejs', '/.git*']);
}); });
+66 -4
View File
@@ -6,13 +6,14 @@ const utils = require('./test_utils');
const dataDir = 'test_data'; const dataDir = 'test_data';
const testIndex = 'testindex.md'; const testIndex = 'testindex.md';
const joinUrl = (...paths) => path.join(...paths).replace(/\\/g,'/'); const joinUrl = (...paths) => path.join(...paths).replace(/\\/g, '/');
const config = { const config = {
'test': true, 'test': true,
'data_dir': dataDir, 'data_dir': dataDir,
'article': { 'article': {
'index': testIndex, 'index': testIndex,
'draft': 'draft.md',
'default_title': 'Untitled', 'default_title': 'Untitled',
'default_thumbnail': 'default.png', 'default_thumbnail': 'default.png',
'thumbnail_tag': 'thumbnail' 'thumbnail_tag': 'thumbnail'
@@ -22,6 +23,7 @@ const config = {
const fw = require('../src/file_walker')(config); const fw = require('../src/file_walker')(config);
beforeEach(() => { beforeEach(() => {
config['data_dir'] = dataDir;
utils.deleteFolderSync(dataDir); utils.deleteFolderSync(dataDir);
fs.mkdirSync(dataDir); fs.mkdirSync(dataDir);
}); });
@@ -193,7 +195,6 @@ describe('Test article fetching', () => {
fw.fetchArticles((err, list) => { fw.fetchArticles((err, list) => {
expect(err).not.toBeNull(); expect(err).not.toBeNull();
expect(list).not.toBeDefined(); expect(list).not.toBeDefined();
config['data_dir'] = dataDir;
done(); done();
}); });
}); });
@@ -235,9 +236,10 @@ describe('Test article fetching', () => {
expect(Object.keys(dict).length).toBe(1); expect(Object.keys(dict).length).toBe(1);
expect(dict[joinUrl('2019', '05', '05')]).toEqual({ expect(dict[joinUrl('2019', '05', '05')]).toEqual({
path: joinUrl('2019', '05', '05'), path: joinUrl('2019', '05', '05'),
realPath: dir, realPath: file,
year: 2019, year: 2019,
month: 5, month: 5,
draft: false,
day: 5, day: 5,
date: date, date: date,
title: 'Untitled', title: 'Untitled',
@@ -265,10 +267,11 @@ describe('Test article fetching', () => {
expect(Object.keys(dict).length).toBe(1); expect(Object.keys(dict).length).toBe(1);
expect(dict[joinUrl('2019', '05', '05')]).toEqual({ expect(dict[joinUrl('2019', '05', '05')]).toEqual({
path: joinUrl('2019', '05', '05'), path: joinUrl('2019', '05', '05'),
realPath: dir, realPath: file,
year: 2019, year: 2019,
month: 5, month: 5,
day: 5, day: 5,
draft: false,
date: date, date: date,
title: 'Title with : info !', title: 'Title with : info !',
thumbnail: joinUrl('2019', '05', '05', './thumbnail.jpg'), thumbnail: joinUrl('2019', '05', '05', './thumbnail.jpg'),
@@ -278,5 +281,64 @@ describe('Test article fetching', () => {
done(); done();
}); });
}); });
test('correct draft file', (done) => {
const dir = path.join(dataDir, '2019', '05', '05');
const file = path.join(dir, 'draft.md');
utils.createEmptyDirs([dir]);
fs.writeFileSync(file, `
# Title with : info !
![thumbnail](./thumbnail.jpg)
this is some text
`);
const date = new Date(2019, 5, 5);
date.setUTCHours(0);
fw.fetchArticles((err, dict) => {
expect(err).toBeNull();
expect(dict).toBeDefined();
expect(Object.keys(dict).length).toBe(1);
expect(dict[joinUrl('2019', '05', '05')]).toEqual({
path: joinUrl('2019', '05', '05'),
realPath: file,
year: 2019,
month: 5,
day: 5,
draft: true,
date: date,
title: 'Title with : info !',
thumbnail: joinUrl('2019', '05', '05', './thumbnail.jpg'),
escapedTitle: 'title_with___info',
url: '/' + joinUrl('2019', '05', '05', 'title_with___info') + '/',
});
done();
});
});
test('index file override draft', (done) => {
const dir = path.join(dataDir, '2019', '05', '05');
const file = path.join(dir, testIndex);
const file2 = path.join(dir, 'draft.md');
utils.createEmptyDirs([dir]);
utils.createEmptyFiles([file, file2]);
const date = new Date(2019, 5, 5);
date.setUTCHours(0);
fw.fetchArticles((err, dict) => {
expect(err).toBeNull();
expect(dict).toBeDefined();
expect(Object.keys(dict).length).toBe(1);
expect(dict[joinUrl('2019', '05', '05')]).toEqual({
path: joinUrl('2019', '05', '05'),
realPath: file,
year: 2019,
month: 5,
draft: false,
day: 5,
date: date,
title: 'Untitled',
thumbnail: 'default.png',
escapedTitle: 'untitled',
url: '/' + joinUrl('2019', '05', '05', 'untitled') + '/',
});
done();
});
});
}); });
+238 -45
View File
@@ -7,18 +7,33 @@ const dataDir = 'test_data';
const file = path.join(dataDir, 'test.md'); const file = path.join(dataDir, 'test.md');
const config = { const config = {
'test': true,
'modules': { 'modules': {
'prism': true, 'prism': true,
'mathjax': true,
'plantuml': true,
'fa-diagrams': true,
}, },
'showdown': { 'showdown': {
'simplifiedAutoLink': true, 'simplifiedAutoLink': true,
'smartIndentationFix': true 'smartIndentationFix': true
},
'mathjax': {
'output_format': 'html',
'speak_text': false
},
'plantuml': {
'output_format': 'svg'
} }
}; };
const renderer = require('../src/renderer')(config); const renderer = require('../src/renderer')(config);
beforeEach(() => { beforeEach(() => {
config['modules']['prism'] = true;
config['modules']['mathjax'] = true;
config['modules']['plantuml'] = true;
config['modules']['fa-diagrams'] = true;
utils.deleteFolderSync(dataDir); utils.deleteFolderSync(dataDir);
fs.mkdirSync(dataDir); fs.mkdirSync(dataDir);
}); });
@@ -29,68 +44,246 @@ afterAll(() => {
} }
}); });
test('invalid file', (done) => { describe('get parts', () => {
renderer.render('invalid file', (err, html) => { test('normal', () => {
expect(err).not.toBeNull(); const data = 'Hello\nthere\ngeneral\nkenobi';
expect(html).not.toBeDefined(); const parts = renderer.getParts(data);
done(); expect(parts.map(p => p.text)).toEqual([
'Hello\nthere\ngeneral\nkenobi'
]);
});
test('lot of stuff', () => {
const data = 'Hello\nthere\n```code```\ngeneral<script>script</script>\n<script>script2</script>\n```<script>script3</script>```kenobi';
const parts = renderer.getParts(data);
expect(parts).toEqual([
{
index: 0,
end: 12,
text: 'Hello\nthere\n'
},
{
index: 22,
end: 30,
text: '\ngeneral'
},
{
index: 53,
end: 54,
text: '\n'
},
{
index: 78,
end: 79,
text: '\n'
},
{
index: 109,
end: 115,
text: 'kenobi'
},
]);
}); });
}); });
test('normal file', (done) => { describe('Test Showdown', () => {
fs.writeFileSync(file, `# Hello`); test('normal', (done) => {
renderer.render(file, (err, html) => { renderer.renderShowDown('# Hello', (html) => {
expect(err).toBeNull(); expect(html).toBe('<h1 id="hello">Hello</h1>');
expect(html).toBe('<h1 id="hello">Hello</h1>'); done();
done(); });
});
test('custom rules', (done) => {
renderer.renderShowDown('www.google.com', (html) => {
expect(html).toBe('<p><a href="http://www.google.com">www.google.com</a></p>');
done();
});
});
test('code format', (done) => {
renderer.renderShowDown('```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```', (html) => {
expect(html).toBe('<pre><code class="python language-python">print("hello")\n</code></pre>\n<pre><code class="python language-python">print("hello")\n</code></pre>');
done();
});
}); });
}); });
test('custom rules', (done) => { describe('Test Prism', () => {
fs.writeFileSync(file, `www.google.com`); test('no prism', (done) => {
renderer.render(file, (err, html) => { config['modules']['prism'] = false;
expect(err).toBeNull(); renderer.renderPrism('```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```', (data) => {
expect(html).toBe('<p><a href="http://www.google.com">www.google.com</a></p>'); expect(data).toBe('```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```');
done(); done();
});
});
test('prism correct', (done) => {
renderer.renderPrism('```python\nprint("hello")\n```', (data) => {
expect(data).not.toBe('<pre><code class="python language-python">print("hello")\n</code></pre>');
expect(data.indexOf('<pre><code class="python language-python">')).toBe(0);
done();
});
});
test('prism invalid lang', (done) => {
renderer.renderPrism('```pythdon\nprint("hello")\n```', (data) => {
expect(data).not.toBe('<pre><code class="pythdon language-pythdon">print("hello")\n</code></pre>');
expect(data.indexOf('<pre><code class="pythdon language-pythdon">')).toBe(0);
done();
});
});
test('prism mutliple code blocks', (done) => {
renderer.renderPrism('```python\n\n```\n```python\n\n```', (data) => {
expect(data).toBe('<pre><code class="python language-python"></code></pre>\n<pre><code class="python language-python"></code></pre>');
done();
});
}); });
}); });
test('no prism', (done) => { describe('Test PlantUML', () => {
config['modules']['prism'] = false; test('no plantuml', (done) => {
fs.writeFileSync(file, '```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```'); config['modules']['plantuml'] = false;
renderer.render(file, (err, html) => { renderer.renderPlantUML('@startuml\nBob -> Alice : hello\n@enduml', (data) => {
expect(err).toBeNull(); expect(data).toBe('@startuml\nBob -> Alice : hello\n@enduml');
expect(html).toBe('<pre><code class="python language-python">print("hello")\n</code></pre>\n<pre><code class="python language-python">print("hello")\n</code></pre>'); done();
config['modules']['prism'] = true; });
done(); });
test('plantuml correct', (done) => {
renderer.renderPlantUML('@startuml\nBob -> Alice : hello\n@enduml', (data) => {
expect(data).toBe('<img alt="generated PlantUML diagram" src="http://www.plantuml.com/plantuml/svg/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000">');
done();
});
});
test('plantuml ignored in code', (done) => {
renderer.renderPlantUML('code:\n```@startuml\nBob -> Alice : hello\n@enduml```\n ```@startuml``` @enduml', (data) => {
expect(data).toBe('code:\n```@startuml\nBob -> Alice : hello\n@enduml```\n ```@startuml``` @enduml');
done();
});
});
test('plantuml multiple uml', (done) => {
renderer.renderPlantUML('@startuml\nBob -> Alice : hello\n@enduml\n@startuml\nBob -> Alice : hello\n@enduml', (data) => {
expect(data).toBe('<img alt="generated PlantUML diagram" src="http://www.plantuml.com/plantuml/svg/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000">\n<img alt="generated PlantUML diagram" src="http://www.plantuml.com/plantuml/svg/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000">');
done();
});
}); });
}); });
test('prism correct', (done) => {
fs.writeFileSync(file, '```python\nprint("hello")\n```'); describe('Test MathJax', () => {
renderer.render(file, (err, html) => { test('no mathjax', (done) => {
expect(err).toBeNull(); config['modules']['mathjax'] = false;
expect(html).not.toBe('<pre><code class="python language-python">print("hello")\n</code></pre>'); renderer.renderMathJax('$$\nhello\n$$\ntest$test$', (data) => {
expect(html.indexOf('<pre><code class="python language-python">')).toBe(0); expect(data).toBe('$$\nhello\n$$\ntest$test$');
done(); done();
});
});
test('full eq', (done) => {
renderer.renderMathJax('$$\n\nA\n\n$$', (data) => {
expect(data).toBe('<span class=\"mjx-chtml MJXc-display\" style=\"text-align: center;\">' +
'<span class=\"mjx-math\"><span class=\"mjx-mrow\"><span class=\"mjx-mi\">' +
'<span class=\"mjx-char MJXc-TeX-math-I\" style=\"padding-top: 0.519em; padding-bottom: 0.298em;\">' +
'A' +
'</span></span></span></span></span>');
done();
});
});
test('inline eq', (done) => {
renderer.renderMathJax('start $a$ end', (data) => {
expect(data).toBe('start ' +
'<span class=\"mjx-chtml\">' +
'<span class=\"mjx-math\"><span class=\"mjx-mrow\"><span class=\"mjx-mi\">' +
'<span class=\"mjx-char MJXc-TeX-math-I\" style=\"padding-top: 0.225em; padding-bottom: 0.298em;\">' +
'a' +
'</span></span></span></span></span>' +
' end');
done();
});
});
test('fake inline eq', (done) => {
renderer.renderMathJax('i have $6\nyou have $5', (data) => {
expect(data).toBe('i have $6\nyou have $5');
done();
});
});
test('no eq in code / script', (done) => {
renderer.renderMathJax('this code is ```start $a$ end $$hello$$``` beautiful <script>$A$</script>\n```$no eq$```', (data) => {
expect(data).toBe('this code is ```start $a$ end $$hello$$``` beautiful <script>$A$</script>\n```$no eq$```');
done();
});
});
test('multiple eq', (done) => {
renderer.renderMathJax('$$\n\nA\n\n$$\nstart $a$ end\n$$\n\nA\n\n$$', (data) => {
expect(data).toBe('' +
'<span class=\"mjx-chtml MJXc-display\" style=\"text-align: center;\">' +
'<span class=\"mjx-math\"><span class=\"mjx-mrow\"><span class=\"mjx-mi\">' +
'<span class=\"mjx-char MJXc-TeX-math-I\" style=\"padding-top: 0.519em; padding-bottom: 0.298em;\">' +
'A' +
'</span></span></span></span></span>\n' +
'start ' +
'<span class=\"mjx-chtml\">' +
'<span class=\"mjx-math\"><span class=\"mjx-mrow\"><span class=\"mjx-mi\">' +
'<span class=\"mjx-char MJXc-TeX-math-I\" style=\"padding-top: 0.225em; padding-bottom: 0.298em;\">' +
'a' +
'</span></span></span></span></span>' +
' end\n' +
'<span class=\"mjx-chtml MJXc-display\" style=\"text-align: center;\">' +
'<span class=\"mjx-math\"><span class=\"mjx-mrow\"><span class=\"mjx-mi\">' +
'<span class=\"mjx-char MJXc-TeX-math-I\" style=\"padding-top: 0.519em; padding-bottom: 0.298em;\">' +
'A' +
'</span></span></span></span></span>');
done();
});
}); });
}); });
test('prism invalid lang', (done) => { describe('Test fa-diagrams', () => {
fs.writeFileSync(file, '```pythdon\nprint("hello")\n```'); test('no fa-diagrams', (done) => {
renderer.render(file, (err, html) => { config['modules']['fa-diagrams'] = false;
expect(err).toBeNull(); renderer.renderFaDiagrams('@startfad\noptions.rendering.color=\'red\'\n@endfad', (data) => {
expect(html).not.toBe('<pre><code class="pythdon language-pythdon">print("hello")\n</code></pre>'); expect(data).toBe('@startfad\noptions.rendering.color=\'red\'\n@endfad');
expect(html.indexOf('<pre><code class="pythdon language-pythdon">')).toBe(0); done();
done(); });
});
test('no fa-diagrams in code', (done) => {
renderer.renderFaDiagrams('code:\n```\n@startfad\noptions.rendering.color=\'red\'\n@endfad\n```', (data) => {
expect(data).toBe('code:\n```\n@startfad\noptions.rendering.color=\'red\'\n@endfad\n```');
done();
});
});
test('valid fa-diagrams', (done) => {
renderer.renderFaDiagrams('before\n@startfad\noptions.rendering.color=\'red\'\n@endfad\nafter', (data) => {
expect(data).toBe('before\n<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 0 0" width="0" height="0" font-family="Arial" font-size="15" fill="red" stroke-width="0"></svg>\nafter');
done();
});
});
test('invalid toml', (done) => {
renderer.renderFaDiagrams('before\n@startfad\noptions.rendering.color=red\n@endfad\nafter', (data) => {
expect(data).toBe('before\n<b style="color:red">TomlError: Unexpected character, expecting string, number, datetime, boolean, inline array or inline table at row 1, col 26, pos 25:\n' +
'1> options.rendering.color=red\n' +
' ^\n' +
'\n</b>\nafter');
done();
});
}); });
}); });
test('prism mutliple code blocks', (done) => { describe('Test render', () => {
fs.writeFileSync(file, '```python\n\n```\n\n```python\n\n```'); test('invalid file', (done) => {
renderer.render(file, (err, html) => { renderer.render('invalid file', (err, html) => {
expect(err).toBeNull(); expect(err).not.toBeNull();
expect(html).toBe('<pre><code class="python language-python"></code></pre>\n<pre><code class="python language-python"></code></pre>'); expect(html).not.toBeDefined();
done(); done();
});
});
test('normal file', (done) => {
fs.writeFileSync(file, `# Hello`);
renderer.render(file, (err, html) => {
expect(err).toBeNull();
expect(html).toBe('<h1 id="hello">Hello</h1>');
done();
});
}); });
}); });
+51
View File
@@ -0,0 +1,51 @@
/* jshint -W117 */
const fs = require('fs');
const path = require('path');
const utils = require('./test_utils');
const dataDir = 'test_data';
beforeEach(() => {
utils.deleteFolderSync(dataDir);
fs.mkdirSync(dataDir);
});
afterAll(() => {
if (fs.existsSync(dataDir)) {
utils.deleteFolderSync(dataDir);
}
});
test('load 1 script', () => {
const file = path.join(dataDir, 'test.js');
fs.writeFileSync(file, `
var a = 5;
function b(){
return a;
}`);
require('../src/script_loader')(file);
expect(global['b']).toBeDefined();
expect(global['b']()).toBe(5);
});
test('load 2 script', () => {
const file1 = path.join(dataDir, 'test.js');
fs.writeFileSync(file1, `
var a = 5;
function b(){
return a;
}`);
const file2 = path.join(dataDir, 'test2.js');
fs.writeFileSync(file2, `
var a = 9;
function b(){
return a;
}`);
require('../src/script_loader')(file1);
expect(global['b']).toBeDefined();
expect(global['b']()).toBe(5);
require('../src/script_loader.js')(file2);
expect(global['b']).toBeDefined();
expect(global['b']()).toBe(9);
});