@mryhryki/markdown-preview 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +7 -0
- package/.eslintrc.yaml +34 -0
- package/.github/dependabot.yml +15 -0
- package/.github/workflows/check.yml +32 -0
- package/.github/workflows/update_packages.yml +35 -0
- package/.prettierrc.json +3 -0
- package/CODEOWNERS +1 -0
- package/README.md +16 -11
- package/index.js +2 -2
- package/package.json +10 -5
- package/src/index.js +36 -35
- package/src/lib/directory.js +12 -5
- package/src/lib/file.js +2 -2
- package/src/lib/file_watcher.js +32 -32
- package/src/lib/logger.js +4 -4
- package/src/lib/params.js +27 -29
- package/src/lib/params.test.js +53 -44
- package/src/lib/show.js +3 -2
- package/src/lib/socket_manager.js +2 -4
- package/src/lib/socket_manager.test.js +8 -9
- package/src/markdown.js +9 -9
- package/src/websocket.js +8 -8
- package/template/default-dark.html +3 -3
- package/template/default.html +3 -3
package/.editorconfig
ADDED
package/.eslintrc.yaml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
extends:
|
|
2
|
+
- plugin:@typescript-eslint/recommended
|
|
3
|
+
- plugin:react/recommended
|
|
4
|
+
- plugin:react-hooks/recommended
|
|
5
|
+
- prettier
|
|
6
|
+
plugins:
|
|
7
|
+
- jest
|
|
8
|
+
- "@typescript-eslint"
|
|
9
|
+
- prettier
|
|
10
|
+
- react
|
|
11
|
+
- unused-imports
|
|
12
|
+
env:
|
|
13
|
+
browser: true
|
|
14
|
+
commonjs: true
|
|
15
|
+
es2020: true
|
|
16
|
+
jest/globals: true
|
|
17
|
+
node: true
|
|
18
|
+
globals:
|
|
19
|
+
Atomics: readonly
|
|
20
|
+
SharedArrayBuffer: readonly
|
|
21
|
+
parser: "@typescript-eslint/parser"
|
|
22
|
+
parserOptions:
|
|
23
|
+
ecmaFeatures:
|
|
24
|
+
jsx: true
|
|
25
|
+
ecmaVersion: 11
|
|
26
|
+
sourceType: module
|
|
27
|
+
rules:
|
|
28
|
+
prettier/prettier: error
|
|
29
|
+
react/prop-types: 'off'
|
|
30
|
+
'react-hooks/exhaustive-deps': 'off'
|
|
31
|
+
'@typescript-eslint/no-var-requires': 'off'
|
|
32
|
+
settings:
|
|
33
|
+
react:
|
|
34
|
+
version: detect
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: check
|
|
2
|
+
env:
|
|
3
|
+
TZ: "Asia/Tokyo"
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches:
|
|
8
|
+
- "main"
|
|
9
|
+
pull_request:
|
|
10
|
+
branches:
|
|
11
|
+
- "*"
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
check_branch:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v3
|
|
19
|
+
with:
|
|
20
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
21
|
+
- name: Setup Node
|
|
22
|
+
uses: actions/setup-node@v3
|
|
23
|
+
with:
|
|
24
|
+
node-version: 16
|
|
25
|
+
- name: Update npm
|
|
26
|
+
run: npm install -g npm
|
|
27
|
+
- name: install packages
|
|
28
|
+
run: npm ci
|
|
29
|
+
- name: lint
|
|
30
|
+
run: npm run lint
|
|
31
|
+
- name: test
|
|
32
|
+
run: npm test
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: update_packages
|
|
2
|
+
env:
|
|
3
|
+
TZ: "Asia/Tokyo"
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: "15 11 20 * *" # UTC
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
check_branch:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@v3
|
|
16
|
+
with:
|
|
17
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
18
|
+
- name: Setup Node
|
|
19
|
+
uses: actions/setup-node@v3
|
|
20
|
+
with:
|
|
21
|
+
node-version: 16
|
|
22
|
+
- name: Update packages
|
|
23
|
+
run: |
|
|
24
|
+
npm i -g npm
|
|
25
|
+
npm exec -- npm-check-updates -u
|
|
26
|
+
npm install
|
|
27
|
+
- name: Create Pull Request
|
|
28
|
+
uses: peter-evans/create-pull-request@v4
|
|
29
|
+
with:
|
|
30
|
+
title: "Update package.json"
|
|
31
|
+
commit-message: "Update package.json"
|
|
32
|
+
branch: "update-packages"
|
|
33
|
+
delete-branch: true
|
|
34
|
+
branch-suffix: timestamp
|
|
35
|
+
reviewers: mryhryki
|
package/.prettierrc.json
ADDED
package/CODEOWNERS
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @mryhryki
|
package/README.md
CHANGED
|
@@ -36,28 +36,33 @@ Preview URL : http://localhost:34567
|
|
|
36
36
|
|
|
37
37
|
## Parameter
|
|
38
38
|
|
|
39
|
-
| short | long | environment variable | parameter
|
|
40
|
-
|
|
41
|
-
| -f | --file | MARKDOWN_PREVIEW_FILE | ***relative*** file path
|
|
42
|
-
| -t | --template | MARKDOWN_PREVIEW_TEMPLATE | defined template name (*1) or template file path | no | default |
|
|
43
|
-
| -p | --port | MARKDOWN_PREVIEW_PORT | port number
|
|
44
|
-
| | --log-level | MARKDOWN_PREVIEW_LOG_LEVEL | trace, debug, info<br>warn, error, fatal
|
|
45
|
-
| | --no-opener | MARKDOWN_PREVIEW_NO_OPENER | true (only env var)
|
|
46
|
-
| -v | --version | |
|
|
47
|
-
| -h | --help | |
|
|
39
|
+
| short | long | environment variable | parameter | required | default |
|
|
40
|
+
|-------|-------------|----------------------------|-------------------------------------------------------|----------|-----------|
|
|
41
|
+
| -f | --file | MARKDOWN_PREVIEW_FILE | ***relative*** file path | no | README.md |
|
|
42
|
+
| -t | --template | MARKDOWN_PREVIEW_TEMPLATE | defined template name (*1) or template file path (*2) | no | default |
|
|
43
|
+
| -p | --port | MARKDOWN_PREVIEW_PORT | port number | no | 34567 |
|
|
44
|
+
| | --log-level | MARKDOWN_PREVIEW_LOG_LEVEL | trace, debug, info<br>warn, error, fatal | no | info |
|
|
45
|
+
| | --no-opener | MARKDOWN_PREVIEW_NO_OPENER | true (only env var) | no | |
|
|
46
|
+
| -v | --version | | | no | |
|
|
47
|
+
| -h | --help | | | no | |
|
|
48
48
|
|
|
49
49
|
### *1: Defined Template Names
|
|
50
50
|
|
|
51
51
|
- `default`
|
|
52
52
|
- `default-dark`
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
### *2: How to create a template file
|
|
55
|
+
|
|
56
|
+
Creating a template file is easy.
|
|
57
|
+
At a minimum, all you need to do is load `/markdown-preview-websocket.js` and pass a callback function with the necessary processing to `connectMarkdownPreview`.
|
|
58
|
+
|
|
59
|
+
Sample code is presented below.
|
|
55
60
|
|
|
56
61
|
```html
|
|
57
62
|
<!doctype html>
|
|
58
63
|
<html>
|
|
59
64
|
<head>
|
|
60
|
-
<title>Minimum
|
|
65
|
+
<title>Minimum Template Sample</title>
|
|
61
66
|
</head>
|
|
62
67
|
<body>
|
|
63
68
|
<pre id="raw-markdown"></pre>
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mryhryki/markdown-preview",
|
|
3
3
|
"description": "Markdown realtime preview on browser",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.2",
|
|
5
5
|
"author": "mryhryki",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"publishConfig": {
|
|
@@ -30,18 +30,23 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"express": "^4.18.2",
|
|
32
32
|
"express-ws": "^5.0.2",
|
|
33
|
-
"
|
|
33
|
+
"github-markdown-css": "^5.2.0",
|
|
34
|
+
"log4js": "^6.9.1",
|
|
35
|
+
"marked": "^4.3.0",
|
|
34
36
|
"opener": "^1.5.2",
|
|
35
37
|
"serve-index": "^1.9.1",
|
|
36
|
-
"ws": "^8.
|
|
38
|
+
"ws": "^8.13.0"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
+
"@mryhryki/lint": "^0.0.12",
|
|
42
|
+
"jest": "^29.5.0",
|
|
43
|
+
"nodemon": "^2.0.21"
|
|
41
44
|
},
|
|
42
45
|
"scripts": {
|
|
43
46
|
"start": "node ./index.js",
|
|
44
47
|
"dev": "nodemon --watch ./src/ index.js --no-opener --log-level debug",
|
|
48
|
+
"lint": "mryhryki-lint",
|
|
49
|
+
"lint:fix": "mryhryki-lint --fix",
|
|
45
50
|
"test": "jest",
|
|
46
51
|
"test:watch": "jest --watchAll"
|
|
47
52
|
}
|
package/src/index.js
CHANGED
|
@@ -1,47 +1,48 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const express = require(
|
|
4
|
-
const expressWs = require(
|
|
5
|
-
const serveIndex = require(
|
|
6
|
-
const opener = require(
|
|
7
|
-
const getLogger = require(
|
|
8
|
-
const { showUsage, showVersion } = require(
|
|
9
|
-
const MarkdownHandler = require(
|
|
10
|
-
const WebSocketHandler = require(
|
|
11
|
-
const { rootDir, staticDir } = require(
|
|
12
|
-
const Params = require(
|
|
3
|
+
const express = require("express");
|
|
4
|
+
const expressWs = require("express-ws");
|
|
5
|
+
const serveIndex = require("serve-index");
|
|
6
|
+
const opener = require("opener");
|
|
7
|
+
const getLogger = require("./lib/logger");
|
|
8
|
+
const { showUsage, showVersion } = require("./lib/show");
|
|
9
|
+
const MarkdownHandler = require("./markdown");
|
|
10
|
+
const WebSocketHandler = require("./websocket");
|
|
11
|
+
const { rootDir, staticDir, markedDir, githubMarkdownDir } = require("./lib/directory");
|
|
12
|
+
const Params = require("./lib/params");
|
|
13
13
|
|
|
14
14
|
try {
|
|
15
|
-
const params = new Params(process.env, process.argv.slice(2))
|
|
16
|
-
if (params.help) showUsage()
|
|
17
|
-
if (params.version) showVersion()
|
|
15
|
+
const params = new Params(process.env, process.argv.slice(2));
|
|
16
|
+
if (params.help) showUsage();
|
|
17
|
+
if (params.version) showVersion();
|
|
18
18
|
|
|
19
|
-
const logger = getLogger(params.logLevel)
|
|
20
|
-
const previewUrl = `http://localhost:${params.port}
|
|
19
|
+
const logger = getLogger(params.logLevel);
|
|
20
|
+
const previewUrl = `http://localhost:${params.port}`;
|
|
21
21
|
|
|
22
|
-
console.log(
|
|
23
|
-
console.log(
|
|
24
|
-
console.log(
|
|
25
|
-
console.log(
|
|
26
|
-
console.log(`Preview URL : ${previewUrl}`)
|
|
22
|
+
console.log("Root Directory :", rootDir);
|
|
23
|
+
console.log("Default File :", params.filepath);
|
|
24
|
+
console.log("Extensions :", params.extensions.join(", "));
|
|
25
|
+
console.log("Template File :", params.template);
|
|
26
|
+
console.log(`Preview URL : ${previewUrl}`);
|
|
27
27
|
|
|
28
|
-
const app = express()
|
|
29
|
-
expressWs(app)
|
|
30
|
-
app.get(
|
|
31
|
-
app.ws(
|
|
28
|
+
const app = express();
|
|
29
|
+
expressWs(app);
|
|
30
|
+
app.get("/", (_req, res) => res.redirect(params.filepath));
|
|
31
|
+
app.ws("/ws", WebSocketHandler(logger));
|
|
32
32
|
params.extensions.forEach((ext) => {
|
|
33
|
-
app.get(new RegExp(`^/.+\.${ext}$`), MarkdownHandler(params.template))
|
|
34
|
-
})
|
|
35
|
-
app.use(express.static(rootDir, { index: false }))
|
|
36
|
-
app.use(express.static(staticDir, { index: false }))
|
|
37
|
-
app.use(serveIndex(rootDir, { icons: true, view:
|
|
38
|
-
app.
|
|
33
|
+
app.get(new RegExp(`^/.+\.${ext}$`), MarkdownHandler(params.template));
|
|
34
|
+
});
|
|
35
|
+
app.use(express.static(rootDir, { index: false }));
|
|
36
|
+
app.use(express.static(staticDir, { index: false }));
|
|
37
|
+
app.use(serveIndex(rootDir, { icons: true, view: "details" }));
|
|
38
|
+
app.use("/marked", express.static(markedDir));
|
|
39
|
+
app.use("/gmcss", express.static(githubMarkdownDir));
|
|
40
|
+
app.listen(params.port);
|
|
39
41
|
|
|
40
42
|
if (!params.noOpener) {
|
|
41
|
-
opener(previewUrl)
|
|
43
|
+
opener(previewUrl);
|
|
42
44
|
}
|
|
43
|
-
|
|
44
45
|
} catch (err) {
|
|
45
|
-
console.error(err.message)
|
|
46
|
-
showUsage(true)
|
|
46
|
+
console.error(err.message);
|
|
47
|
+
showUsage(true);
|
|
47
48
|
}
|
package/src/lib/directory.js
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const path = require(
|
|
3
|
+
const path = require("path");
|
|
4
4
|
|
|
5
5
|
const rootDir = process.cwd();
|
|
6
|
-
const projectDir = path.resolve(__dirname,
|
|
7
|
-
const staticDir = path.resolve(projectDir,
|
|
8
|
-
const templateDir = path.resolve(projectDir,
|
|
6
|
+
const projectDir = path.resolve(__dirname, "..", "..");
|
|
7
|
+
const staticDir = path.resolve(projectDir, "static");
|
|
8
|
+
const templateDir = path.resolve(projectDir, "template");
|
|
9
|
+
|
|
10
|
+
const nodeModulesDir = path.join(projectDir, "node_modules");
|
|
11
|
+
|
|
12
|
+
const markedDir = path.join(nodeModulesDir, "marked");
|
|
13
|
+
const githubMarkdownDir = path.join(nodeModulesDir, "github-markdown-css");
|
|
9
14
|
|
|
10
15
|
module.exports = {
|
|
11
16
|
rootDir,
|
|
12
17
|
projectDir,
|
|
13
18
|
staticDir,
|
|
14
19
|
templateDir,
|
|
20
|
+
markedDir,
|
|
21
|
+
githubMarkdownDir,
|
|
15
22
|
};
|
package/src/lib/file.js
CHANGED
package/src/lib/file_watcher.js
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const fs = require(
|
|
4
|
-
const path = require(
|
|
5
|
-
const { rootDir } = require(
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { rootDir } = require("./directory");
|
|
6
6
|
|
|
7
7
|
class FileWatcher {
|
|
8
|
-
constructor
|
|
9
|
-
this.logger = logger
|
|
10
|
-
this._target = {}
|
|
8
|
+
constructor(logger) {
|
|
9
|
+
this.logger = logger;
|
|
10
|
+
this._target = {};
|
|
11
11
|
setInterval(() => {
|
|
12
12
|
Object.keys(this._target).forEach((filepath) => {
|
|
13
13
|
try {
|
|
14
|
-
const fileinfo = this._target[filepath]
|
|
15
|
-
const currentLastModified = this.getFileLastModified(filepath)
|
|
14
|
+
const fileinfo = this._target[filepath];
|
|
15
|
+
const currentLastModified = this.getFileLastModified(filepath);
|
|
16
16
|
if (fileinfo.lastModified !== currentLastModified) {
|
|
17
|
-
this.logger.info(
|
|
18
|
-
fileinfo.lastModified = currentLastModified
|
|
17
|
+
this.logger.info("File update:", path.resolve(rootDir, filepath));
|
|
18
|
+
fileinfo.lastModified = currentLastModified;
|
|
19
19
|
if (this._onFileChanged != null) {
|
|
20
|
-
this._onFileChanged(this.getFileInfo(filepath))
|
|
20
|
+
this._onFileChanged(this.getFileInfo(filepath));
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
} catch (err) {
|
|
24
|
-
console.error(err)
|
|
24
|
+
console.error(err);
|
|
25
25
|
}
|
|
26
|
-
})
|
|
27
|
-
}, 250)
|
|
26
|
+
});
|
|
27
|
+
}, 250 /* check 4 times per second */);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
onFileChanged
|
|
31
|
-
this._onFileChanged = callback
|
|
30
|
+
onFileChanged(callback) {
|
|
31
|
+
this._onFileChanged = callback;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
addTargetFile
|
|
35
|
-
if (this._target[filepath] != null) return
|
|
36
|
-
this.logger.debug(
|
|
34
|
+
addTargetFile(filepath) {
|
|
35
|
+
if (this._target[filepath] != null) return;
|
|
36
|
+
this.logger.debug("Add watch target:", filepath);
|
|
37
37
|
this._target[filepath] = {
|
|
38
38
|
lastModified: this.getFileLastModified(filepath),
|
|
39
|
-
}
|
|
39
|
+
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
removeTargetFile
|
|
43
|
-
if (this._target[filepath] == null) return
|
|
44
|
-
this.logger.debug(
|
|
45
|
-
delete this._target[filepath]
|
|
42
|
+
removeTargetFile(filepath) {
|
|
43
|
+
if (this._target[filepath] == null) return;
|
|
44
|
+
this.logger.debug("Remove watch target:", filepath);
|
|
45
|
+
delete this._target[filepath];
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
getFileLastModified
|
|
49
|
-
return fs.statSync(path.resolve(rootDir, filepath)).mtimeMs
|
|
48
|
+
getFileLastModified(filepath) {
|
|
49
|
+
return fs.statSync(path.resolve(rootDir, filepath)).mtimeMs;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
getFileInfo
|
|
53
|
-
const absolutePath = path.resolve(rootDir, filepath)
|
|
54
|
-
const markdown = fs.readFileSync(absolutePath,
|
|
55
|
-
return { filepath, markdown }
|
|
52
|
+
getFileInfo(filepath) {
|
|
53
|
+
const absolutePath = path.resolve(rootDir, filepath);
|
|
54
|
+
const markdown = fs.readFileSync(absolutePath, "utf-8");
|
|
55
|
+
return { filepath, markdown };
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
module.exports = FileWatcher
|
|
59
|
+
module.exports = FileWatcher;
|
package/src/lib/logger.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
const log4js = require(
|
|
1
|
+
const log4js = require("log4js");
|
|
2
2
|
|
|
3
3
|
const getLogger = (logLevel) => {
|
|
4
4
|
log4js.configure({
|
|
5
5
|
appenders: {
|
|
6
6
|
console: {
|
|
7
|
-
type:
|
|
7
|
+
type: "console",
|
|
8
8
|
layout: {
|
|
9
|
-
type:
|
|
9
|
+
type: "basic",
|
|
10
10
|
},
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
categories: {
|
|
14
14
|
default: {
|
|
15
|
-
appenders: [
|
|
15
|
+
appenders: ["console"],
|
|
16
16
|
level: logLevel,
|
|
17
17
|
},
|
|
18
18
|
},
|
package/src/lib/params.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const path = require(
|
|
4
|
-
const { rootDir, templateDir } = require(
|
|
5
|
-
const { existsFile } = require(
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { rootDir, templateDir } = require("./directory");
|
|
5
|
+
const { existsFile } = require("./file");
|
|
6
6
|
|
|
7
7
|
class Params {
|
|
8
8
|
constructor(env, argv) {
|
|
@@ -21,11 +21,11 @@ class Params {
|
|
|
21
21
|
|
|
22
22
|
getDefaultParams() {
|
|
23
23
|
return {
|
|
24
|
-
filepath:
|
|
25
|
-
extensions:
|
|
26
|
-
template:
|
|
24
|
+
filepath: "README.md",
|
|
25
|
+
extensions: "md, markdown",
|
|
26
|
+
template: "default",
|
|
27
27
|
port: 34567,
|
|
28
|
-
logLevel:
|
|
28
|
+
logLevel: "info",
|
|
29
29
|
noOpener: false,
|
|
30
30
|
version: false,
|
|
31
31
|
help: false,
|
|
@@ -47,7 +47,7 @@ class Params {
|
|
|
47
47
|
params.port = env.MARKDOWN_PREVIEW_PORT;
|
|
48
48
|
}
|
|
49
49
|
if (env.MARKDOWN_PREVIEW_NO_OPENER) {
|
|
50
|
-
params.noOpener = env.MARKDOWN_PREVIEW_NO_OPENER ===
|
|
50
|
+
params.noOpener = env.MARKDOWN_PREVIEW_NO_OPENER === "true";
|
|
51
51
|
}
|
|
52
52
|
if (env.MARKDOWN_PREVIEW_LOG_LEVEL) {
|
|
53
53
|
params.logLevel = env.MARKDOWN_PREVIEW_LOG_LEVEL;
|
|
@@ -59,40 +59,40 @@ class Params {
|
|
|
59
59
|
const params = {};
|
|
60
60
|
for (let i = 0; i < argv.length; i++) {
|
|
61
61
|
switch (argv[i]) {
|
|
62
|
-
case
|
|
63
|
-
case
|
|
62
|
+
case "-f":
|
|
63
|
+
case "--file":
|
|
64
64
|
params.filepath = argv[i + 1];
|
|
65
65
|
i++;
|
|
66
66
|
break;
|
|
67
|
-
case
|
|
68
|
-
case
|
|
67
|
+
case "-e":
|
|
68
|
+
case "--extensions":
|
|
69
69
|
params.extensions = argv[i + 1];
|
|
70
70
|
i++;
|
|
71
71
|
break;
|
|
72
|
-
case
|
|
73
|
-
case
|
|
72
|
+
case "-t":
|
|
73
|
+
case "--template":
|
|
74
74
|
params.template = argv[i + 1];
|
|
75
75
|
i++;
|
|
76
76
|
break;
|
|
77
|
-
case
|
|
78
|
-
case
|
|
77
|
+
case "-p":
|
|
78
|
+
case "--port":
|
|
79
79
|
params.port = argv[i + 1];
|
|
80
80
|
i++;
|
|
81
81
|
break;
|
|
82
|
-
case
|
|
83
|
-
case
|
|
82
|
+
case "-l":
|
|
83
|
+
case "--log-level":
|
|
84
84
|
params.logLevel = argv[i + 1];
|
|
85
85
|
i++;
|
|
86
86
|
break;
|
|
87
|
-
case
|
|
87
|
+
case "--no-opener":
|
|
88
88
|
params.noOpener = true;
|
|
89
89
|
break;
|
|
90
|
-
case
|
|
91
|
-
case
|
|
90
|
+
case "-v":
|
|
91
|
+
case "--version":
|
|
92
92
|
params.version = true;
|
|
93
93
|
break;
|
|
94
|
-
case
|
|
95
|
-
case
|
|
94
|
+
case "-h":
|
|
95
|
+
case "--help":
|
|
96
96
|
params.help = true;
|
|
97
97
|
break;
|
|
98
98
|
default:
|
|
@@ -102,7 +102,6 @@ class Params {
|
|
|
102
102
|
return params;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
|
|
106
105
|
checkFilepath(filepath) {
|
|
107
106
|
if (path.isAbsolute(filepath)) {
|
|
108
107
|
throw new Error(`Absolute path is prohibited: ${filepath}`);
|
|
@@ -117,7 +116,7 @@ class Params {
|
|
|
117
116
|
}
|
|
118
117
|
|
|
119
118
|
checkExtensions(extensions) {
|
|
120
|
-
const extensionList = extensions.split(
|
|
119
|
+
const extensionList = extensions.split(",").map((ext) => ext.trim());
|
|
121
120
|
if (extensionList.length === 0) {
|
|
122
121
|
throw new Error(`Extensions is empty: ${extensions}`);
|
|
123
122
|
}
|
|
@@ -139,11 +138,10 @@ class Params {
|
|
|
139
138
|
return intPort;
|
|
140
139
|
}
|
|
141
140
|
throw new Error(`Invalid port: ${port}`);
|
|
142
|
-
}
|
|
143
|
-
|
|
141
|
+
}
|
|
144
142
|
|
|
145
143
|
checkLogLevel(logLevel) {
|
|
146
|
-
if ([
|
|
144
|
+
if (["trace", "debug", "info", "warn", "error", "fatal"].includes(logLevel)) {
|
|
147
145
|
return logLevel;
|
|
148
146
|
}
|
|
149
147
|
throw new Error(`Invalid log level: ${logLevel}`);
|
package/src/lib/params.test.js
CHANGED
|
@@ -1,39 +1,43 @@
|
|
|
1
|
-
const path = require(
|
|
2
|
-
const { projectDir } = require(
|
|
3
|
-
const Params = require(
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { projectDir } = require("./directory");
|
|
3
|
+
const Params = require("./params");
|
|
4
4
|
|
|
5
5
|
const DEFAULT_VALUES = {
|
|
6
|
-
filepath:
|
|
7
|
-
extensions: [
|
|
8
|
-
template: path.resolve(projectDir,
|
|
6
|
+
filepath: "README.md",
|
|
7
|
+
extensions: ["md", "markdown"],
|
|
8
|
+
template: path.resolve(projectDir, "template/default.html"),
|
|
9
9
|
port: 34567,
|
|
10
|
-
logLevel:
|
|
10
|
+
logLevel: "info",
|
|
11
11
|
noOpener: false,
|
|
12
12
|
version: false,
|
|
13
13
|
help: false,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
describe(
|
|
17
|
-
it(
|
|
16
|
+
describe("Params", () => {
|
|
17
|
+
it("not specify", () => {
|
|
18
18
|
const params = new Params({}, []);
|
|
19
19
|
expect(params._params).toEqual(DEFAULT_VALUES);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
it(
|
|
22
|
+
it("specify all short argument", () => {
|
|
23
23
|
const argv = [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
"-f",
|
|
25
|
+
"test/markdown/markdown1.md",
|
|
26
|
+
"-e",
|
|
27
|
+
"ext1,ext2",
|
|
28
|
+
"-t",
|
|
29
|
+
"test/template/template1.html",
|
|
30
|
+
"-p",
|
|
31
|
+
"100",
|
|
32
|
+
"-v",
|
|
33
|
+
"-h",
|
|
30
34
|
];
|
|
31
35
|
const expectParams = {
|
|
32
|
-
filepath:
|
|
33
|
-
extensions: [
|
|
34
|
-
template: path.resolve(projectDir,
|
|
36
|
+
filepath: "test/markdown/markdown1.md",
|
|
37
|
+
extensions: ["ext1", "ext2"],
|
|
38
|
+
template: path.resolve(projectDir, "test/template/template1.html"),
|
|
35
39
|
port: 100,
|
|
36
|
-
logLevel:
|
|
40
|
+
logLevel: "info",
|
|
37
41
|
noOpener: false,
|
|
38
42
|
version: true,
|
|
39
43
|
help: true,
|
|
@@ -42,23 +46,28 @@ describe('Params', () => {
|
|
|
42
46
|
expect(params._params).toEqual(expectParams);
|
|
43
47
|
});
|
|
44
48
|
|
|
45
|
-
it(
|
|
49
|
+
it("specify all long argument", () => {
|
|
46
50
|
const argv = [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
"--file",
|
|
52
|
+
"test/markdown/markdown1.md",
|
|
53
|
+
"--extensions",
|
|
54
|
+
"ext1,ext2",
|
|
55
|
+
"--template",
|
|
56
|
+
"test/template/template1.html",
|
|
57
|
+
"--port",
|
|
58
|
+
"100",
|
|
59
|
+
"--log-level",
|
|
60
|
+
"trace",
|
|
61
|
+
"--no-opener",
|
|
62
|
+
"--version",
|
|
63
|
+
"--help",
|
|
55
64
|
];
|
|
56
65
|
const expectParams = {
|
|
57
|
-
filepath:
|
|
58
|
-
extensions: [
|
|
59
|
-
template: path.resolve(projectDir,
|
|
66
|
+
filepath: "test/markdown/markdown1.md",
|
|
67
|
+
extensions: ["ext1", "ext2"],
|
|
68
|
+
template: path.resolve(projectDir, "test/template/template1.html"),
|
|
60
69
|
port: 100,
|
|
61
|
-
logLevel:
|
|
70
|
+
logLevel: "trace",
|
|
62
71
|
noOpener: true,
|
|
63
72
|
version: true,
|
|
64
73
|
help: true,
|
|
@@ -67,21 +76,21 @@ describe('Params', () => {
|
|
|
67
76
|
expect(params._params).toEqual(expectParams);
|
|
68
77
|
});
|
|
69
78
|
|
|
70
|
-
it(
|
|
79
|
+
it("specify all environment variable", () => {
|
|
71
80
|
const env = {
|
|
72
|
-
MARKDOWN_PREVIEW_FILE:
|
|
73
|
-
MARKDOWN_PREVIEW_EXTENSIONS:
|
|
74
|
-
MARKDOWN_PREVIEW_TEMPLATE:
|
|
75
|
-
MARKDOWN_PREVIEW_PORT:
|
|
76
|
-
MARKDOWN_PREVIEW_LOG_LEVEL:
|
|
77
|
-
MARKDOWN_PREVIEW_NO_OPENER:
|
|
81
|
+
MARKDOWN_PREVIEW_FILE: "test/markdown/markdown1.md",
|
|
82
|
+
MARKDOWN_PREVIEW_EXTENSIONS: "ext1, ext2",
|
|
83
|
+
MARKDOWN_PREVIEW_TEMPLATE: "test/template/template1.html",
|
|
84
|
+
MARKDOWN_PREVIEW_PORT: "100",
|
|
85
|
+
MARKDOWN_PREVIEW_LOG_LEVEL: "trace",
|
|
86
|
+
MARKDOWN_PREVIEW_NO_OPENER: "true",
|
|
78
87
|
};
|
|
79
88
|
const expectParams = {
|
|
80
|
-
filepath:
|
|
81
|
-
extensions: [
|
|
82
|
-
template: path.resolve(projectDir,
|
|
89
|
+
filepath: "test/markdown/markdown1.md",
|
|
90
|
+
extensions: ["ext1", "ext2"],
|
|
91
|
+
template: path.resolve(projectDir, "test/template/template1.html"),
|
|
83
92
|
port: 100,
|
|
84
|
-
logLevel:
|
|
93
|
+
logLevel: "trace",
|
|
85
94
|
noOpener: true,
|
|
86
95
|
version: false,
|
|
87
96
|
help: false,
|
package/src/lib/show.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
3
|
class SocketManager {
|
|
4
4
|
constructor() {
|
|
@@ -14,9 +14,7 @@ class SocketManager {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
getSockets(filepath) {
|
|
17
|
-
return this._sockets
|
|
18
|
-
.filter(({ filepath: fp }) => fp === filepath)
|
|
19
|
-
.map(s => s.socket);
|
|
17
|
+
return this._sockets.filter(({ filepath: fp }) => fp === filepath).map((s) => s.socket);
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
countSocket(filepath = null) {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
const SocketManager = require(
|
|
1
|
+
const SocketManager = require("./socket_manager");
|
|
2
2
|
|
|
3
|
-
const dummySocket1 = { name:
|
|
4
|
-
const dummySocket2 = { name:
|
|
5
|
-
const dummySocket3 = { name:
|
|
3
|
+
const dummySocket1 = { name: "socket1" };
|
|
4
|
+
const dummySocket2 = { name: "socket2" };
|
|
5
|
+
const dummySocket3 = { name: "socket3" };
|
|
6
6
|
|
|
7
|
-
const dummyFilepath1 =
|
|
8
|
-
const dummyFilepath2 =
|
|
7
|
+
const dummyFilepath1 = "file1";
|
|
8
|
+
const dummyFilepath2 = "file2";
|
|
9
9
|
|
|
10
10
|
const dummyInfo1 = { socket: dummySocket1, filepath: dummyFilepath1 };
|
|
11
11
|
const dummyInfo2 = { socket: dummySocket2, filepath: dummyFilepath2 };
|
|
12
12
|
const dummyInfo3 = { socket: dummySocket3, filepath: dummyFilepath2 };
|
|
13
13
|
|
|
14
|
-
describe(
|
|
15
|
-
it(
|
|
14
|
+
describe("SocketManager", () => {
|
|
15
|
+
it("works normally", () => {
|
|
16
16
|
const socketManager = new SocketManager();
|
|
17
17
|
expect(socketManager._sockets).toEqual([]);
|
|
18
18
|
|
|
@@ -31,7 +31,6 @@ describe('SocketManager', () => {
|
|
|
31
31
|
expect(socketManager.countSocket(dummyFilepath1)).toEqual(1);
|
|
32
32
|
expect(socketManager.countSocket(dummyFilepath2)).toEqual(2);
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
socketManager.removeSocket(dummySocket2);
|
|
36
35
|
expect(socketManager._sockets).toEqual([dummyInfo1, dummyInfo3]);
|
|
37
36
|
|
package/src/markdown.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const path = require(
|
|
4
|
-
const { rootDir } = require(
|
|
5
|
-
const { existsFile } = require(
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { rootDir } = require("./lib/directory");
|
|
5
|
+
const { existsFile } = require("./lib/file");
|
|
6
6
|
|
|
7
7
|
const MarkdownHandler = (template) => (req, res, next) => {
|
|
8
|
-
const filepath = path.resolve(rootDir, decodeURIComponent(req.path.substr(1)))
|
|
8
|
+
const filepath = path.resolve(rootDir, decodeURIComponent(req.path.substr(1)));
|
|
9
9
|
if (existsFile(filepath)) {
|
|
10
|
-
res.sendFile(template)
|
|
10
|
+
res.sendFile(template);
|
|
11
11
|
} else {
|
|
12
|
-
next()
|
|
12
|
+
next();
|
|
13
13
|
}
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
15
|
|
|
16
|
-
module.exports = MarkdownHandler
|
|
16
|
+
module.exports = MarkdownHandler;
|
package/src/websocket.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const path = require(
|
|
4
|
-
const FileWatcher = require(
|
|
5
|
-
const SocketManager = require(
|
|
6
|
-
const { rootDir } = require(
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const FileWatcher = require("./lib/file_watcher");
|
|
5
|
+
const SocketManager = require("./lib/socket_manager");
|
|
6
|
+
const { rootDir } = require("./lib/directory");
|
|
7
7
|
|
|
8
8
|
const WebSocketHandler = (logger) => {
|
|
9
9
|
let socketSeqNo = 1;
|
|
@@ -18,13 +18,13 @@ const WebSocketHandler = (logger) => {
|
|
|
18
18
|
return (ws, req) => {
|
|
19
19
|
const wsSeqNo = socketSeqNo++;
|
|
20
20
|
try {
|
|
21
|
-
logger.debug(
|
|
21
|
+
logger.debug("WebSocket connected:", wsSeqNo);
|
|
22
22
|
const filepath = path.resolve(rootDir, decodeURIComponent(req.query.path.substr(1)));
|
|
23
23
|
fileWatcher.addTargetFile(filepath);
|
|
24
24
|
socketManager.addSocket(ws, filepath);
|
|
25
25
|
|
|
26
|
-
ws.on(
|
|
27
|
-
logger.debug(
|
|
26
|
+
ws.on("close", () => {
|
|
27
|
+
logger.debug("WebSocket close:", wsSeqNo);
|
|
28
28
|
socketManager.removeSocket(ws);
|
|
29
29
|
if (socketManager.countSocket(filepath) === 0) {
|
|
30
30
|
fileWatcher.removeTargetFile(filepath);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Markdown Preview</title>
|
|
7
|
-
<link rel="stylesheet" href="
|
|
7
|
+
<link rel="stylesheet" href="/gmcss/github-markdown-dark.css">
|
|
8
8
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github-dark-dimmed.min.css">
|
|
9
9
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
|
|
10
10
|
</head>
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
<div class="markdown-body">
|
|
13
13
|
<div id="content"></div>
|
|
14
14
|
</div>
|
|
15
|
-
<script src="
|
|
15
|
+
<script src="/marked/marked.min.js"></script>
|
|
16
16
|
<script src="/markdown-preview-websocket.js"></script>
|
|
17
|
-
<script
|
|
17
|
+
<script>
|
|
18
18
|
connectMarkdownPreview(({ markdown }) => {
|
|
19
19
|
document.getElementById('content').innerHTML = marked.parse(markdown);
|
|
20
20
|
document.querySelectorAll('pre code').forEach(block => hljs.highlightBlock(block));
|
package/template/default.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Markdown Preview</title>
|
|
7
|
-
<link rel="stylesheet" href="
|
|
7
|
+
<link rel="stylesheet" href="/gmcss/github-markdown-light.css">
|
|
8
8
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/github.min.css">
|
|
9
9
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
|
|
10
10
|
</head>
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
<div class="markdown-body">
|
|
13
13
|
<div id="content"></div>
|
|
14
14
|
</div>
|
|
15
|
-
<script src="
|
|
15
|
+
<script src="/marked/marked.min.js"></script>
|
|
16
16
|
<script src="/markdown-preview-websocket.js"></script>
|
|
17
|
-
<script
|
|
17
|
+
<script>
|
|
18
18
|
connectMarkdownPreview(({ markdown }) => {
|
|
19
19
|
document.getElementById('content').innerHTML = marked.parse(markdown);
|
|
20
20
|
document.querySelectorAll('pre code').forEach(block => hljs.highlightBlock(block));
|