elm-doc-preview
Advanced tools
Comparing version 1.0.7 to 2.0.0
250
cli.js
#!/usr/bin/env node | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const sane = require("sane"); | ||
const spawn = require("cross-spawn"); | ||
const express = require("express"); | ||
const tmp = require("tmp"); | ||
const chalk = require("chalk"); | ||
const program = require("commander"); | ||
const commander = require("commander"); | ||
const latestVersion = require("latest-version"); | ||
const DocServer = require("./lib/elm-doc-server"); | ||
const pkg = require(path.join(__dirname, "package.json")); | ||
const npmPackage = require(path.join(__dirname, "package.json")); | ||
function error(log) { | ||
console.log(chalk.red("Error:"), chalk.red(log)); | ||
} | ||
program | ||
.version(pkg.version) | ||
.arguments("[path_to_package]") | ||
.action(dir => { | ||
if (fs.existsSync(dir)) { | ||
try { | ||
process.chdir(dir); | ||
} catch (err) { | ||
error(`cannot change directory to ${dir} (${err})`); | ||
process.exit(1); | ||
} | ||
} | ||
}) | ||
.option("-p, --port <port>", "the server listening port", Math.floor, 8000) | ||
.parse(process.argv); | ||
function getFile(filepath) { | ||
if (!fs.existsSync(filepath)) { | ||
return ""; | ||
} | ||
const data = fs.readFileSync(filepath, "utf8"); | ||
if (data) { | ||
return data; | ||
} | ||
return ""; | ||
} | ||
/* | ||
* Get temp file for docs.json | ||
* Program options and usage | ||
*/ | ||
tmp.setGracefulCleanup(); | ||
function init() { | ||
let pkgPath = "."; | ||
const program = commander | ||
.version(npmPackage.version) | ||
.arguments("[path_to_package_or_application]") | ||
.action(dir => { | ||
if (dir !== undefined) { | ||
pkgPath = dir; | ||
} | ||
}) | ||
.option("-p, --port <port>", "the server listening port", Math.floor, 8000); | ||
const docs = tmp.fileSync({ | ||
prefix: "elm-docs-", | ||
postfix: ".json" | ||
}); | ||
program.on("--help", () => { | ||
console.log(""); | ||
console.log("Environment variables:"); | ||
console.log(" ELM_HOME Elm home directory (cache)"); | ||
}); | ||
process.on("SIGINT", () => { | ||
docs.removeCallback(); | ||
process.exit(0); | ||
}); | ||
/* | ||
* Check package | ||
*/ | ||
let elmJson = {}; | ||
try { | ||
elmJson = JSON.parse(fs.readFileSync("elm.json", "utf8")); | ||
} catch (e) { | ||
error(`invalid elm.json file (${e})`); | ||
process.exit(1); | ||
program.parse(process.argv); | ||
program.dir = pkgPath; | ||
return program; | ||
} | ||
if (!("type" in elmJson) || elmJson.type !== "package") { | ||
const type = "type" in elmJson ? elmJson.type : "program"; | ||
error( | ||
`unsupported Elm ${type}, only packages documentation can be previewed` | ||
); | ||
process.exit(1); | ||
} | ||
let pkgName = "name" in elmJson ? elmJson.name : "package"; | ||
if ("version" in elmJson) { | ||
pkgName += ` ${elmJson.version}`; | ||
} | ||
/* | ||
* Find and check Elm | ||
* Check if a newer version is available | ||
*/ | ||
let elm = args => spawn.sync("npx", ["--no-install", "elm"].concat(args)); | ||
let exec = elm(["--version"]); | ||
if (exec.error || exec.status !== 0 || exec.stderr.toString().length > 0) { | ||
elm = args => spawn.sync("elm", args); | ||
exec = elm(["--version"]); | ||
function checkUpdate(currentVersion) { | ||
latestVersion("elm-doc-preview").then(lastVersion => { | ||
if (lastVersion !== currentVersion) { | ||
console.log(chalk.yellow(`elm-doc-preview ${lastVersion} is available`)); | ||
} | ||
}); | ||
} | ||
if (exec.error) { | ||
error(`cannot run 'elm --version' (${exec.error})`); | ||
process.exit(1); | ||
} else if (exec.status !== 0) { | ||
error(`cannot run 'elm --version':`); | ||
process.stderr.write(exec.stderr); | ||
process.exit(exec.status); | ||
} | ||
const elmVersion = exec.stdout.toString().trim(); | ||
if (!elmVersion.startsWith("0.19")) { | ||
error(`unsupported Elm version ${elmVersion}`); | ||
process.exit(1); | ||
} | ||
function buildDoc() { | ||
console.log(" |> building documentation"); | ||
const build = elm(["make", `--docs=${docs.name}`, "--report=json"]); | ||
if (build.error) { | ||
error(`cannot build documentation (${build.error})`); | ||
process.exit(1); | ||
} | ||
return build.stderr.toString(); | ||
} | ||
/* | ||
* Starting message | ||
* Run program | ||
*/ | ||
console.log( | ||
chalk`{bold elm-doc-preview ${pkg.version}} using elm ${elmVersion}` | ||
); | ||
console.log(chalk`Previewing {magenta ${pkgName}} from ${process.cwd()}`); | ||
const program = init(); | ||
checkUpdate(npmPackage.version); | ||
/* | ||
* Set web server | ||
*/ | ||
let ws = null; | ||
const docServer = new DocServer(program.dir); | ||
function send(type, data) { | ||
if (ws !== null) { | ||
ws.send(JSON.stringify({ type, data })); | ||
} | ||
} | ||
function sendCompilation(output) { | ||
console.log(" |>", "updating compilation status"); | ||
send("compilation", output); | ||
} | ||
function sendReadme() { | ||
console.log(" |>", "updating README preview"); | ||
send("readme", getFile("README.md")); | ||
} | ||
function sendDocs() { | ||
console.log(" |>", `updating ${docs.name} preview`); | ||
send("docs", getFile(docs.name)); | ||
} | ||
const app = express(); | ||
require("express-ws")(app); | ||
app.use( | ||
"/", | ||
express.static(path.join(__dirname, "public"), { index: "local.html" }) | ||
); | ||
let buildReport = buildDoc(); | ||
app.ws("/", _ws => { | ||
ws = _ws; | ||
sendCompilation(buildReport); | ||
sendReadme(); | ||
sendDocs(); | ||
}); | ||
app.get("*", (req, res) => { | ||
res.sendFile(path.join(__dirname, "public/local.html")); | ||
}); | ||
let timeout = null; | ||
function onChange(filepath) { | ||
/* Try to batch consecutive updates. | ||
* (for example the way vim saves files would lead to 3 rebuilds else) | ||
*/ | ||
if (timeout) { | ||
clearTimeout(timeout); | ||
} | ||
timeout = setTimeout(() => { | ||
timeout = null; | ||
console.log(" |>", "detected", filepath, "modification"); | ||
if (filepath.endsWith("README.md")) { | ||
sendReadme(); | ||
process | ||
.on("SIGINT", () => { | ||
process.exit(0); | ||
}) | ||
.on("uncaughtException", e => { | ||
if (e.errno === "EADDRINUSE") { | ||
console.log( | ||
chalk.red(`port ${program.port} already used, use --port option`) | ||
); | ||
} else { | ||
buildReport = buildDoc(); | ||
sendCompilation(buildReport); | ||
sendDocs(); | ||
console.log(chalk.red(e)); | ||
} | ||
}, 100); | ||
} | ||
process.exit(1); | ||
}); | ||
/* | ||
* Set files watcher | ||
*/ | ||
const watcher = sane(".", { | ||
glob: ["**/elm.json", "src/**/*.elm", "**/README.md"] | ||
}); | ||
console.log(` |> watching elm.json, README.md and *.elm files`); | ||
function ready() { | ||
console.log( | ||
chalk`{blue Browse} {bold {green <http://localhost:${ | ||
program.port | ||
}>}} {blue to see your documentation}` | ||
); | ||
} | ||
watcher.on("ready", () => { | ||
ready(); | ||
}); | ||
watcher.on("change", filepath => { | ||
onChange(filepath); | ||
}); | ||
watcher.on("add", filepath => { | ||
onChange(filepath); | ||
}); | ||
watcher.on("delete", filepath => { | ||
onChange(filepath); | ||
}); | ||
/* | ||
* Run web server | ||
*/ | ||
app.listen(program.port); | ||
docServer.listen(program.port); |
@@ -6,3 +6,3 @@ # License information | ||
Copyright (c) 2014-2018, Evan Czaplicki | ||
Copyright (c) 2018, Rémi Lefèvre | ||
Copyright (c) 2018-2019, Rémi Lefèvre | ||
@@ -9,0 +9,0 @@ All rights reserved. |
@@ -9,5 +9,7 @@ { | ||
"express-ws": "^4.0.0", | ||
"latest-version": "^4.0.0", | ||
"sane": "^4.0.2", | ||
"serve-static": "^1.13.2", | ||
"tmp": "0.0.33" | ||
"tmp": "0.0.33", | ||
"ws": "^6.2.0" | ||
}, | ||
@@ -30,3 +32,3 @@ "devDependencies": { | ||
}, | ||
"license": "SEE LICENSE in LICENSE.md", | ||
"license": "SEE LICENSE IN LICENSE.md", | ||
"description": "Elm packages documentation previewer with hot reloading.", | ||
@@ -37,7 +39,8 @@ "bugs": { | ||
"homepage": "https://github.com/dmy/elm-doc-preview#readme", | ||
"version": "1.0.7", | ||
"version": "2.0.0", | ||
"bin": { | ||
"elm-doc-preview": "./cli.js" | ||
"elm-doc-preview": "./cli.js", | ||
"edp": "./cli.js" | ||
}, | ||
"main": "./cli.js", | ||
"main": "./lib/elm-doc-server.js", | ||
"scripts": { | ||
@@ -44,0 +47,0 @@ "test": "echo \"Error: no test specified\" && exit 1", |
@@ -46,4 +46,7 @@ var app = Elm.Main.init({ | ||
switch (msg.type) { | ||
case "name": | ||
app.ports.nameUpdated.send(msg.data); | ||
break; | ||
case "compilation": | ||
app.ports.compilationCompleted.send(msg.data); | ||
app.ports.compilationUpdated.send(msg.data); | ||
break; | ||
@@ -56,3 +59,6 @@ case "readme": | ||
break; | ||
case "deps": | ||
app.ports.depsUpdated.send(msg.data); | ||
break; | ||
} | ||
}; |
# elm-doc-preview | ||
This is a documentation previewer for Elm packages (>= 0.19). | ||
It allows previewing `README.md` and `docs.json` files (generated with `elm make --docs=docs.json`). | ||
This is an Elm 0.19 documentation previewer for **packages**, **applications** | ||
and their **dependencies**. | ||
It aims at rendering documentation exactly like the [official package website](https://package.elm-lang.org). | ||
## Online version | ||
There is an online version supporting documentation loading from github that can be used for reviews: | ||
It aims at rendering documentation exactly like the | ||
[official package website](https://package.elm-lang.org) to avoid | ||
any surprise when releasing a package. | ||
https://elm-doc-preview.netlify.com | ||
Note that applications documentation is | ||
[not yet supported by Elm](https://github.com/elm/compiler/issues/1835#issuecomment-440080525), | ||
so only the `README` and dependencies are supported for those at the moment. | ||
## Local version | ||
There is also a local version that supports **hot reloading** for convenient packages documentation editing: | ||
<p align="center"> | ||
<img src="https://raw.githubusercontent.com/dmy/elm-doc-preview/master/screenshots/regex.png" width="400" /> | ||
<img src="https://raw.githubusercontent.com/dmy/elm-doc-preview/master/screenshots/elm-doc-preview.png" width="400" /> | ||
<img src="https://raw.githubusercontent.com/dmy/elm-doc-preview/master/screenshots/compilation.png" width="400" /> | ||
<img src="https://raw.githubusercontent.com/dmy/elm-doc-preview/master/screenshots/term.png" width="400" /> | ||
</p> | ||
# Features | ||
- **Packages** full support with **hot reloading** | ||
- **Offline dependencies documentation** for packages and applications | ||
- **Regex filtering** for focused documentation | ||
- **Compilation errors display** (packages only) | ||
- **Online documentations sharing** for reviews (using the | ||
[online version](#online-version)) | ||
# Installation | ||
```sh | ||
$ npm install -g elm-doc-preview | ||
``` | ||
Then, from the directory where your package `elm.json` is: | ||
# Usage | ||
```sh | ||
Usage: edp|elm-doc-preview [options] [path_to_package_or_application] | ||
Options: | ||
-V, --version output the version number | ||
-p, --port <port> the server listening port (default: 8000) | ||
-h, --help output usage information | ||
Environment variables: | ||
ELM_HOME Elm home directory (cache) | ||
``` | ||
For example, from the directory where your package `elm.json` is: | ||
```sh | ||
$ elm-doc-preview | ||
``` | ||
or | ||
``` | ||
$ edp | ||
``` | ||
or from anywhere: | ||
```sh | ||
$ elm-doc-preview path/to/package | ||
$ elm-doc-preview path/to/package_or_application | ||
``` | ||
As a side effect, this also allows to view installed packages documentation offline from the local cache: | ||
# Online version | ||
There is also an online version supporting documentations loading from github | ||
to share them for online reviews: | ||
https://elm-doc-preview.netlify.com | ||
It does not support hot-reloading or dependencies documentation though. | ||
# API | ||
```javascript | ||
const DocServer = require('elm-doc-preview'); | ||
// constructor(path_to_elm_json = ".") | ||
const server = new DocServer(); | ||
// Optionaly exit cleanly on SIGINT to let temporary files be removed | ||
process.on("SIGINT", () => { process.exit(0); }); | ||
// listen(port = 8000) | ||
server.listen(); | ||
``` | ||
$ elm-doc-preview ~/.elm/0.19.0/package/elm/html/1.0.0/ | ||
``` | ||
# Credits | ||
* Documentation rendering from [package.elm-lang.org](https://github.com/elm/package.elm-lang.org) by Evan Czaplicki. | ||
* Markdown rendering from [Marked.js](https://github.com/markedjs/marked) by Christopher Jeffrey. | ||
* Code highlighting from [highlight.js](https://github.com/highlightjs/highlight.js) by Ivan Sagalaev. | ||
* Code highlighting theme from [Solarized](ethanschoonover.com/solarized) by Jeremy Hull. | ||
* CSS spinner from [SpinKit](https://github.com/tobiasahlin/SpinKit) by Tobias Ahlin. | ||
- Documentation rendering from [package.elm-lang.org](https://github.com/elm/package.elm-lang.org) by Evan Czaplicki. | ||
- Markdown rendering from [Marked.js](https://github.com/markedjs/marked) by Christopher Jeffrey. | ||
- Code highlighting from [highlight.js](https://github.com/highlightjs/highlight.js) by Ivan Sagalaev. | ||
- Code highlighting theme from [Solarized](ethanschoonover.com/solarized) by Jeremy Hull. | ||
- CSS spinner from [SpinKit](https://github.com/tobiasahlin/SpinKit) by Tobias Ahlin. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
228511
429
99
10
4
2
+ Addedlatest-version@^4.0.0
+ Addedws@^6.2.0
+ Added@sindresorhus/is@0.7.0(transitive)
+ Addedcacheable-request@2.1.4(transitive)
+ Addedclone-response@1.0.2(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddecompress-response@3.3.0(transitive)
+ Addeddeep-extend@0.6.0(transitive)
+ Addedduplexer3@0.1.5(transitive)
+ Addedfrom2@2.3.0(transitive)
+ Addedget-stream@3.0.0(transitive)
+ Addedgot@8.3.2(transitive)
+ Addedhas-symbol-support-x@1.4.2(transitive)
+ Addedhas-to-string-tag-x@1.4.1(transitive)
+ Addedhttp-cache-semantics@3.8.1(transitive)
+ Addedini@1.3.8(transitive)
+ Addedinto-stream@3.1.0(transitive)
+ Addedis-object@1.0.2(transitive)
+ Addedis-plain-obj@1.1.0(transitive)
+ Addedis-retry-allowed@1.2.0(transitive)
+ Addedisurl@1.0.0(transitive)
+ Addedjson-buffer@3.0.0(transitive)
+ Addedkeyv@3.0.0(transitive)
+ Addedlatest-version@4.0.0(transitive)
+ Addedlowercase-keys@1.0.01.0.1(transitive)
+ Addedmimic-response@1.0.1(transitive)
+ Addednormalize-url@2.0.1(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedp-cancelable@0.4.1(transitive)
+ Addedp-is-promise@1.1.0(transitive)
+ Addedp-timeout@2.0.1(transitive)
+ Addedpackage-json@5.0.0(transitive)
+ Addedpify@3.0.0(transitive)
+ Addedprepend-http@2.0.0(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedquery-string@5.1.1(transitive)
+ Addedrc@1.2.8(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedregistry-auth-token@3.4.0(transitive)
+ Addedregistry-url@3.1.0(transitive)
+ Addedresponselike@1.0.2(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsort-keys@2.0.0(transitive)
+ Addedstrict-uri-encode@1.1.0(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedstrip-json-comments@2.0.1(transitive)
+ Addedtimed-out@4.0.1(transitive)
+ Addedurl-parse-lax@3.0.0(transitive)
+ Addedurl-to-options@1.0.1(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addedws@6.2.3(transitive)