Initial commit with basic HTTP endpoint working

This commit is contained in:
Tom Wright 2020-04-06 23:25:47 +01:00
commit c77040304c
18 changed files with 1012 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
mermaidcli/node_modules/
vendor/
in/
out/
.DS_Store
.idea/

2
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml

9
.idea/mermaid-server.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mermaid-server.iml" filepath="$PROJECT_DIR$/.idea/mermaid-server.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

8
.idea/watcherTasks.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<enabled-global>
<option value="go fmt" />
</enabled-global>
</component>
</project>

144
.idea/workspace.xml Normal file
View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="ecb0f36f-87fb-46cd-8377-658fb925fcb6" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/.gitignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/mermaid-server.iml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/watcherTasks.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Dockerfile" afterDir="false" />
<change afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change afterPath="$PROJECT_DIR$/cmd/app/main.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/cache.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/diagram.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/generator.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/http.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/mermaidcli/package-lock.json" afterDir="false" />
<change afterPath="$PROJECT_DIR$/mermaidcli/package.json" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Go File" />
</list>
</option>
</component>
<component name="GOROOT" path="/usr/local/Cellar/go/1.13.4/libexec" />
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="GoLibraries">
<option name="indexEntireGoPath" value="false" />
</component>
<component name="IgnoredFileRootStore">
<option name="generatedRoots">
<set>
<option value="$PROJECT_DIR$/.idea" />
</set>
</option>
</component>
<component name="ProjectId" id="1aAyop8moitN1kIl9HmAAe8m135" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showExcludedFiles" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="DefaultGoTemplateProperty" value="Go File" />
<property name="NewWatcherDialog.advanced.open" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="configurable.Global.GOPATH.is.expanded" value="true" />
<property name="configurable.Project.GOPATH.is.expanded" value="true" />
<property name="go.import.settings.migrated" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="node.js.detected.package.eslint" value="true" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.path.for.package.eslint" value="project" />
<property name="node.js.path.for.package.tslint" value="project" />
<property name="node.js.selected.package.eslint" value="(autodetect)" />
<property name="node.js.selected.package.tslint" value="(autodetect)" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
<property name="settings.editor.selected.configurable" value="go.vgo" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
<recent name="$PROJECT_DIR$/mermaidcli" />
</key>
</component>
<component name="RunManager">
<configuration name="app" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="mermaid-server" />
<working_directory value="$PROJECT_DIR$/" />
<go_parameters value="-i" />
<parameters value="--mermaid=./mermaidcli/node_modules/.bin/mmdc --in=./in --out=./out" />
<EXTENSION ID="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" />
</ENTRIES>
</EXTENSION>
<kind value="PACKAGE" />
<filePath value="$PROJECT_DIR$/" />
<package value="mermaid-server/cmd/app" />
<directory value="$PROJECT_DIR$/" />
<method v="2" />
</configuration>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="VgoProject">
<integration-enabled>true</integration-enabled>
<vendoring-mode>true</vendoring-mode>
<proxy>direct</proxy>
</component>
<component name="WindowStateProjectService">
<state x="184" y="112" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1586211567682">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state x="184" y="112" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.1440.900@0.0.1440.900" timestamp="1586211567682" />
<state x="474" y="208" key="EnvironmentVariablesDialog" timestamp="1586194300455">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state x="474" y="208" key="EnvironmentVariablesDialog/0.0.1440.900@0.0.1440.900" timestamp="1586194300455" />
<state width="1398" height="226" key="GridCell.Tab.0.bottom" timestamp="1586211724295">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state width="1398" height="226" key="GridCell.Tab.0.bottom/0.0.1440.900@0.0.1440.900" timestamp="1586211724295" />
<state width="1398" height="226" key="GridCell.Tab.0.center" timestamp="1586211724293">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state width="1398" height="226" key="GridCell.Tab.0.center/0.0.1440.900@0.0.1440.900" timestamp="1586211724293" />
<state width="1398" height="226" key="GridCell.Tab.0.left" timestamp="1586211724292">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state width="1398" height="226" key="GridCell.Tab.0.left/0.0.1440.900@0.0.1440.900" timestamp="1586211724292" />
<state width="1398" height="226" key="GridCell.Tab.0.right" timestamp="1586211724294">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state width="1398" height="226" key="GridCell.Tab.0.right/0.0.1440.900@0.0.1440.900" timestamp="1586211724294" />
<state x="229" y="89" key="SettingsEditor" timestamp="1586192882553">
<screen x="0" y="0" width="1440" height="900" />
</state>
<state x="229" y="89" key="SettingsEditor/0.0.1440.900@0.0.1440.900" timestamp="1586192882553" />
</component>
</project>

34
Dockerfile Normal file
View File

@ -0,0 +1,34 @@
# This stage builds the mermaidcli executable.
FROM node:12.12.0-buster as node
WORKDIR /root
# copy the mermaidcli node package into the container and install
COPY ./mermaidcli/* .
RUN npm install
# This stage builds the go executable.
FROM golang:1.13-buster as go
WORKDIR /root
COPY . .
RUN go build -o bin/app cmd/app/main.go
# Final stage that will be pushed.
FROM debian:buster-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update 2>/dev/null && \
apt install -y --no-install-recommends \
ca-certificates \
2>/dev/null
COPY --from=node /root/node_modules/.bin/mmdc ./mermaidcli
COPY --from=go /root/bin/app ./app
# We should now have all the required dependencies to build the proto files.
CMD ["./app", "--mermaid=./mermaidcli"]

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# mermaid-server
Use mermaid-js to generate diagrams in a HTTP endpoint.
While this currently serves the diagrams via HTTP, it could easily be manipulated to server diagrams via other means.
## Basic usage
Start the HTTP server:
```
go run cmd/app/main.go --mermaid=./mermaidcli/node_modules/.bin/mmdc --in=./in --out=./out
```
Send CURL request to generate a diagram:
```
curl --location --request POST 'http://localhost:80/generate' \
--header 'Content-Type: text/plain' \
--data-raw 'graph LR
A-->B
B-->C
C-->D
C-->F
'
```

98
cmd/app/main.go Normal file
View File

@ -0,0 +1,98 @@
package main
import (
"flag"
"fmt"
"mermaid-server/internal"
"net/http"
"os"
)
var testInput = []byte(`
graph TB
subgraph "Jira"
createTicket["Create ticket"]
updateTicket["Update ticket"]
fireWebhook["Fire webhook"]
createTicket-->fireWebhook
updateTicket-->fireWebhook
end
subgraph "Jira Webhook"
receiveWebhook["Receive webhook"]
storeEvent["Store event in immutable list"]
publishNewStoredEventEvent["Publish message to notify system of new event"]
createEvent["Create internal event that will be stored"]
setCreatedAt["Set created at date to now"]
setSourceJira["Set source to Jira webhook"]
receiveWebhook-->createEvent-->setCreatedAt-->setSourceJira-->storeEvent
storeEvent-->publishNewStoredEventEvent
end
fireWebhook-->receiveWebhook
subgraph "Play Event"
publishEventUpdated["Publish message to notify system of new status"]
verifyEventSource["Verify event source"]
parsePayload["Parse event payload using source to determine structure"]
findEventHandler["Find the handler for the specific event type + version"]
getLatestPersistedState["Get latest persisted state"]
changeInMemoryStateUsingEventData["Change in-memory state using event data"]
persistUpdatedState["Persist updated state"]
verifyEventSource-->parsePayload
parsePayload-->findEventHandler
findEventHandler-->getLatestPersistedState-->changeInMemoryStateUsingEventData-->persistUpdatedState
persistUpdatedState-->publishEventUpdated
end
publishNewStoredEventEvent-->verifyEventSource
`)
func main() {
mermaid := flag.String("mermaid", "", "The full path to the mermaidcli executable.")
in := flag.String("in", "", "Directory to store input files.")
out := flag.String("out", "", "Directory to store output files.")
flag.Parse()
if *mermaid == "" {
_, _ = fmt.Fprintf(os.Stderr, "Missing required argument `mermaid`")
os.Exit(1)
}
if *in == "" {
_, _ = fmt.Fprintf(os.Stderr, "Missing required argument `in`")
os.Exit(1)
}
if *out == "" {
_, _ = fmt.Fprintf(os.Stderr, "Missing required argument `out`")
os.Exit(1)
}
cache := internal.NewDiagramCache()
generator := internal.NewGenerator(cache, *mermaid, *in, *out)
httpHandler := internal.GenerateHTTPHandler(generator)
r := http.NewServeMux()
r.Handle("/generate", http.HandlerFunc(httpHandler))
httpServer := &http.Server{
Addr: ":80",
Handler: r,
}
_, _ = fmt.Fprintf(os.Stdout, "Listening on address %s", httpServer.Addr)
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
_, _ = fmt.Fprintf(os.Stderr, "Could not listen for http connections: %s", err)
os.Exit(1)
}
_, _ = fmt.Fprintf(os.Stdout, "Shutdown")
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/tomwright/mermaid-server
go 1.13

57
internal/cache.go Normal file
View File

@ -0,0 +1,57 @@
package internal
// DiagramCache provides the ability to cache diagram results.
type DiagramCache interface {
// Store stores a diagram in the cache.
Store(diagram *Diagram) error
// Has returns true if we have a cache stored for the given diagram description.
Has(diagram *Diagram) (bool, error)
// Get returns a cached version of the given diagram description.
Get(diagram *Diagram) (*Diagram, error)
}
// NewDiagramCache returns an implementation of DiagramCache.
func NewDiagramCache() DiagramCache {
return &inMemoryDiagramCache{
idToDiagram: map[string]*Diagram{},
}
}
// inMemoryDiagramCache is an in-memory implementation of DiagramCache.
type inMemoryDiagramCache struct {
idToDiagram map[string]*Diagram
}
// Store stores a diagram in the cache.
func (c *inMemoryDiagramCache) Store(diagram *Diagram) error {
id, err := diagram.ID()
if err != nil {
return err
}
c.idToDiagram[id] = diagram
return nil
}
// Has returns true if we have a cache stored for the given diagram description.
func (c *inMemoryDiagramCache) Has(diagram *Diagram) (bool, error) {
id, err := diagram.ID()
if err != nil {
return false, err
}
if d, ok := c.idToDiagram[id]; ok && d != nil {
return true, nil
}
return false, nil
}
// Get returns a cached version of the given diagram description.
func (c *inMemoryDiagramCache) Get(diagram *Diagram) (*Diagram, error) {
id, err := diagram.ID()
if err != nil {
return nil, err
}
if d, ok := c.idToDiagram[id]; ok && d != nil {
return d, nil
}
return nil, nil
}

50
internal/diagram.go Normal file
View File

@ -0,0 +1,50 @@
package internal
import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"strings"
)
// NewDiagram returns a new diagram.
func NewDiagram(description []byte) *Diagram {
return &Diagram{
description: []byte(strings.TrimSpace(string(description))),
}
}
type Diagram struct {
// iD is the ID of the Diagram
id string
// description is the description of the diagram.
description []byte
// Output is the filepath to the output file.
Output string
}
// ID returns an ID for the diagram.
// The ID is set from the diagram description.
func (d *Diagram) ID() (string, error) {
if d.id != "" {
return d.id, nil
}
encoded := base64.StdEncoding.EncodeToString(d.description)
hash := md5.Sum([]byte(encoded))
d.id = hex.EncodeToString(hash[:])
return d.id, nil
}
// Description returns the diagram description.
func (d *Diagram) Description() []byte {
return d.description
}
// Description returns the diagram description.
func (d *Diagram) WithDescription(description []byte) *Diagram {
d.description = description
d.id = ""
return d
}

94
internal/generator.go Normal file
View File

@ -0,0 +1,94 @@
package internal
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os/exec"
)
// Generator provides the ability to generate a diagram.
type Generator interface {
// Generate generates the given diagram.
Generate(diagram *Diagram) error
}
func NewGenerator(cache DiagramCache, mermaidCLIPath string, inPath string, outPath string) Generator {
return &cachingGenerator{
cache: cache,
mermaidCLIPath: mermaidCLIPath,
inPath: inPath,
outPath: outPath,
}
}
// cachingGenerator is an implementation of Generator.
type cachingGenerator struct {
cache DiagramCache
mermaidCLIPath string
inPath string
outPath string
}
// Generate generates the given diagram.
func (c cachingGenerator) Generate(diagram *Diagram) error {
has, err := c.cache.Has(diagram)
if err != nil {
return err
}
if has {
cached, err := c.cache.Get(diagram)
if err != nil {
return err
}
*diagram = *cached
return nil
}
if err := c.generate(diagram); err != nil {
return err
}
if err := c.cache.Store(diagram); err != nil {
return err
}
return nil
}
// generate does the actual file generation.
func (c cachingGenerator) generate(diagram *Diagram) error {
id, err := diagram.ID()
if err != nil {
return err
}
has, err := c.cache.Has(diagram)
if err != nil {
return err
}
if has {
cached, err := c.cache.Get(diagram)
if err != nil {
return err
}
*diagram = *cached
return nil
}
inPath := fmt.Sprintf("%s/%s.mmd", c.inPath, id)
outPath := fmt.Sprintf("%s/%s.svg", c.outPath, id)
if err := ioutil.WriteFile(inPath, diagram.description, 0644); err != nil {
return err
}
cmd := exec.Command(c.mermaidCLIPath, "-i", inPath, "-o", outPath)
var stdOut bytes.Buffer
cmd.Stdout = bufio.NewWriter(&stdOut)
if err := cmd.Run(); err != nil {
return fmt.Errorf("%w: %s", err, string(stdOut.Bytes()))
}
diagram.Output = outPath
return nil
}

67
internal/http.go Normal file
View File

@ -0,0 +1,67 @@
package internal
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func writeJSON(rw http.ResponseWriter, value interface{}, status int) {
bytes, err := json.Marshal(value)
if err != nil {
panic("could not marshal value: " + err.Error())
}
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(status)
if _, err := rw.Write(bytes); err != nil {
panic("could not write bytes to response: " + err.Error())
}
}
func writeSVG(rw http.ResponseWriter, data []byte, status int) {
rw.Header().Set("Content-Type", "image/svg+xml")
rw.WriteHeader(status)
if _, err := rw.Write(data); err != nil {
panic("could not write bytes to response: " + err.Error())
}
}
func writeErr(rw http.ResponseWriter, err error, status int) {
writeJSON(rw, map[string]interface{}{
"error": err,
}, status)
}
func GenerateHTTPHandler(generator Generator) func(rw http.ResponseWriter, r *http.Request) {
return func(rw http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeErr(rw, fmt.Errorf("expected HTTP method POST"), http.StatusBadRequest)
return
}
// Get description from request body
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
writeErr(rw, fmt.Errorf("could not read body: %s", err), http.StatusInternalServerError)
return
}
// Create a diagram from the description
d := NewDiagram(bytes)
// Generate the diagram
if err := generator.Generate(d); err != nil {
writeErr(rw, fmt.Errorf("could not generate diagram: %s", err), http.StatusInternalServerError)
return
}
// Output the diagram as an SVG.
// We assume generate always generates an SVG at this point in time.
diagramBytes, err := ioutil.ReadFile(d.Output)
if err != nil {
writeErr(rw, fmt.Errorf("could not read diagram bytes: %s", err), http.StatusInternalServerError)
return
}
writeSVG(rw, diagramBytes, http.StatusOK)
}
}

381
mermaidcli/package-lock.json generated Normal file
View File

@ -0,0 +1,381 @@
{
"name": "mermaid-server-cli",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@mermaid-js/mermaid-cli": {
"version": "8.4.8",
"resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-8.4.8.tgz",
"integrity": "sha512-25Ichye2lpNso9Dylrm5a+SJWZ5rpuPxVw1OVdcl9ZoTDGxdE3AyTfcCjoT5oKVfDUd+Uu2ONUsfJBtw42I8uw==",
"requires": {
"chalk": "^3.0.0",
"commander": "^4.0.1",
"puppeteer": "^2.0.0"
}
},
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"@types/mime-types": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz",
"integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM="
},
"agent-base": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
"integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g=="
},
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI="
},
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"chalk": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"extract-zip": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
"integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
"requires": {
"concat-stream": "^1.6.2",
"debug": "^2.6.9",
"mkdirp": "^0.5.4",
"yauzl": "^2.10.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"requires": {
"pend": "~1.2.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"https-proxy-agent": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
"integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
"requires": {
"agent-base": "5",
"debug": "4"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"mime": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
"integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
},
"mime-db": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
},
"mime-types": {
"version": "2.1.26",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
"requires": {
"mime-db": "1.43.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "^1.2.5"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"puppeteer": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.1.1.tgz",
"integrity": "sha512-LWzaDVQkk1EPiuYeTOj+CZRIjda4k2s5w4MK4xoH2+kgWV/SDlkYHmxatDdtYrciHUKSXTsGgPgPP8ILVdBsxg==",
"requires": {
"@types/mime-types": "^2.1.0",
"debug": "^4.1.0",
"extract-zip": "^1.6.6",
"https-proxy-agent": "^4.0.0",
"mime": "^2.0.3",
"mime-types": "^2.1.25",
"progress": "^2.0.1",
"proxy-from-env": "^1.0.0",
"rimraf": "^2.6.1",
"ws": "^6.1.0"
}
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"supports-color": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
"requires": {
"has-flag": "^4.0.0"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"yauzl": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"requires": {
"buffer-crc32": "~0.2.3",
"fd-slicer": "~1.1.0"
}
}
}
}

14
mermaidcli/package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "mermaid-server-cli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@mermaid-js/mermaid-cli": "^8.4.8"
}
}