From c77040304c4faf48d5ef7a3b1ef62c71c36388ca Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Mon, 6 Apr 2020 23:25:47 +0100 Subject: [PATCH] Initial commit with basic HTTP endpoint working --- .gitignore | 6 + .idea/.gitignore | 2 + .idea/mermaid-server.iml | 9 + .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .idea/watcherTasks.xml | 8 + .idea/workspace.xml | 144 +++++++++++++ Dockerfile | 34 ++++ README.md | 25 +++ cmd/app/main.go | 98 +++++++++ go.mod | 3 + internal/cache.go | 57 ++++++ internal/diagram.go | 50 +++++ internal/generator.go | 94 +++++++++ internal/http.go | 67 ++++++ mermaidcli/package-lock.json | 381 +++++++++++++++++++++++++++++++++++ mermaidcli/package.json | 14 ++ 18 files changed, 1012 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/mermaid-server.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/watcherTasks.xml create mode 100644 .idea/workspace.xml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 cmd/app/main.go create mode 100644 go.mod create mode 100644 internal/cache.go create mode 100644 internal/diagram.go create mode 100644 internal/generator.go create mode 100644 internal/http.go create mode 100644 mermaidcli/package-lock.json create mode 100644 mermaidcli/package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0bccdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +mermaidcli/node_modules/ +vendor/ +in/ +out/ +.DS_Store +.idea/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/mermaid-server.iml b/.idea/mermaid-server.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/mermaid-server.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f8ee287 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml new file mode 100644 index 0000000..4aabca4 --- /dev/null +++ b/.idea/watcherTasks.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..4c385ce --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + direct + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f38de88 --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..1d207fa --- /dev/null +++ b/README.md @@ -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 +' +``` diff --git a/cmd/app/main.go b/cmd/app/main.go new file mode 100644 index 0000000..88596f5 --- /dev/null +++ b/cmd/app/main.go @@ -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") +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b85d516 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/tomwright/mermaid-server + +go 1.13 diff --git a/internal/cache.go b/internal/cache.go new file mode 100644 index 0000000..9c55000 --- /dev/null +++ b/internal/cache.go @@ -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 +} diff --git a/internal/diagram.go b/internal/diagram.go new file mode 100644 index 0000000..3d73de9 --- /dev/null +++ b/internal/diagram.go @@ -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 +} diff --git a/internal/generator.go b/internal/generator.go new file mode 100644 index 0000000..514ba4f --- /dev/null +++ b/internal/generator.go @@ -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 +} diff --git a/internal/http.go b/internal/http.go new file mode 100644 index 0000000..0176c7d --- /dev/null +++ b/internal/http.go @@ -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) + } +} diff --git a/mermaidcli/package-lock.json b/mermaidcli/package-lock.json new file mode 100644 index 0000000..b8da70a --- /dev/null +++ b/mermaidcli/package-lock.json @@ -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" + } + } + } +} diff --git a/mermaidcli/package.json b/mermaidcli/package.json new file mode 100644 index 0000000..997b451 --- /dev/null +++ b/mermaidcli/package.json @@ -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" + } +}