├── site ├── .npmrc ├── static │ ├── robots.txt │ ├── cover.png │ ├── favicon.ico │ └── fonts │ │ ├── Menlo-Regular.ttf │ │ └── RedHatDisplay-Bold.ttf ├── .gitignore ├── .prettierignore ├── src │ ├── lib │ │ ├── CodeEditor │ │ │ ├── lang │ │ │ │ ├── syntax.grammar.d.ts │ │ │ │ ├── syntax.grammar │ │ │ │ └── index.ts │ │ │ └── CodeEditor.svelte │ │ └── utils.ts │ ├── global.d.ts │ ├── routes │ │ ├── index.svelte │ │ ├── $layout.svelte │ │ └── playground │ │ │ ├── _diagwiz.svelte │ │ │ ├── index.svelte │ │ │ └── _playground.svelte │ ├── app.html │ ├── app.css │ └── assets │ │ └── logo.svg ├── .prettierrc ├── diagwiz │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── Cargo.lock ├── README.md ├── .eslintrc.cjs ├── svelte.config.cjs ├── tsconfig.json ├── package.json └── package-lock.json ├── .gitignore ├── src ├── ascii_canvas │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── diagrams │ ├── base │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── seq │ │ ├── Cargo.toml │ │ ├── src │ │ ├── lib.rs │ │ ├── syntax.pest │ │ ├── renderer.rs │ │ ├── parser.rs │ │ └── layout.rs │ │ └── tests │ │ └── snapshot.rs └── cli │ ├── Cargo.toml │ └── src │ └── main.rs ├── Cargo.toml ├── .github └── workflows │ ├── diagwiz-audit.yml │ ├── site-ci.yml │ ├── diagwiz-ci.yml │ └── diagwiz-release.yml ├── LICENSE ├── README.md └── Cargo.lock /site/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /site/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /.svelte 4 | /build 5 | /functions 6 | -------------------------------------------------------------------------------- /site/.prettierignore: -------------------------------------------------------------------------------- 1 | .svelte/** 2 | static/** 3 | build/** 4 | node_modules/** 5 | diagwiz/** 6 | -------------------------------------------------------------------------------- /site/static/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjagiello/diagwiz/HEAD/site/static/cover.png -------------------------------------------------------------------------------- /site/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjagiello/diagwiz/HEAD/site/static/favicon.ico -------------------------------------------------------------------------------- /site/static/fonts/Menlo-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjagiello/diagwiz/HEAD/site/static/fonts/Menlo-Regular.ttf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | target/ 3 | 4 | # Site 5 | site/.svelte 6 | site/build 7 | site/node_modules/ 8 | site/public/build/ 9 | -------------------------------------------------------------------------------- /site/src/lib/CodeEditor/lang/syntax.grammar.d.ts: -------------------------------------------------------------------------------- 1 | import { Parser } from "lezer"; 2 | 3 | export declare const parser: Parser; 4 | -------------------------------------------------------------------------------- /site/static/fonts/RedHatDisplay-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kjagiello/diagwiz/HEAD/site/static/fonts/RedHatDisplay-Bold.ttf -------------------------------------------------------------------------------- /site/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "singleQuote": false, 4 | "trailingComma": "es5", 5 | "printWidth": 100 6 | } 7 | -------------------------------------------------------------------------------- /site/src/global.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /src/ascii_canvas/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ascii_canvas" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /src/ascii_canvas/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ascii_canvas" 3 | version = "0.1.0" 4 | authors = ["Krzysztof Jagiello "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | default-members = ["src/cli"] 3 | members = ["src/cli"] 4 | exclude = ["site/diagwiz"] 5 | 6 | [profile.dev] 7 | panic = "abort" 8 | split-debuginfo = "unpacked" 9 | 10 | [profile.release] 11 | panic = "abort" 12 | lto = true 13 | -------------------------------------------------------------------------------- /site/diagwiz/src/lib.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen] 4 | pub fn render(input: String) -> Result { 5 | let input = format!("{}\n", input); 6 | diagram_seq::transform(input.as_str()).map_err(|e| e.to_string().into()) 7 | } 8 | -------------------------------------------------------------------------------- /site/README.md: -------------------------------------------------------------------------------- 1 | # diagwiz site 2 | 3 | ## Developing 4 | 5 | ```bash 6 | # Install the dependencies 7 | npm ci 8 | 9 | # Start the development server 10 | npm run dev 11 | 12 | # or start the server and open the app in a new browser tab 13 | npm run dev -- --open 14 | ``` 15 | -------------------------------------------------------------------------------- /src/diagrams/base/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diagram_base" 3 | version = "0.1.0" 4 | authors = ["Krzysztof Jagiello "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | -------------------------------------------------------------------------------- /site/src/routes/index.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | Diagwiz 15 | 16 | -------------------------------------------------------------------------------- /src/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diagwiz" 3 | version = "0.1.0" 4 | authors = ["Krzysztof Jagiello "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | diagram_base = { path = "../diagrams/base", version = "0.1.0" } 9 | diagram_seq = { path = "../diagrams/seq", version = "0.1.0" } 10 | clap = { version = "2.33.3" } 11 | -------------------------------------------------------------------------------- /src/diagrams/base/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | #[derive(Debug)] 4 | pub enum TransformError { 5 | ParseError(String), 6 | } 7 | 8 | impl fmt::Display for TransformError { 9 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 10 | match self { 11 | TransformError::ParseError(msg) => write!(f, "Invalid syntax:\n{}", msg), 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/diagwiz-audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit (diagwiz) 2 | 3 | on: 4 | schedule: 5 | - cron: '5 0 * * *' 6 | push: 7 | paths: 8 | - '**/Cargo.toml' 9 | - '**/Cargo.lock' 10 | pull_request: 11 | 12 | jobs: 13 | audit: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: actions-rs/audit-check@v1 18 | with: 19 | token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /site/diagwiz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diagwiz" 3 | version = "0.1.0" 4 | authors = ["Krzysztof Jagiello "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [profile.release] 11 | lto = true 12 | opt-level = "s" 13 | 14 | [dependencies] 15 | diagram_base = { path = "../../src/diagrams/base", version = "0.1.0" } 16 | diagram_seq = { path = "../../src/diagrams/seq", version = "0.1.0" } 17 | wasm-bindgen = "0.2" 18 | -------------------------------------------------------------------------------- /src/diagrams/seq/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diagram_seq" 3 | version = "0.1.0" 4 | authors = ["Krzysztof Jagiello "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | ascii_canvas = { path = "../../ascii_canvas", version = "0.1.0" } 9 | diagram_base = { path = "../base", version = "0.1.0" } 10 | cassowary = "~0.3.0" 11 | pest = "~2.1" 12 | pest_derive = "~2.1" 13 | unicode-segmentation = "~1.7.1" 14 | 15 | [dev-dependencies] 16 | pretty_assertions = "~0.7" 17 | -------------------------------------------------------------------------------- /site/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %svelte.head% 10 | 11 | 12 |
%svelte.body%
13 | 14 | 15 | -------------------------------------------------------------------------------- /site/src/lib/CodeEditor/lang/syntax.grammar: -------------------------------------------------------------------------------- 1 | @top Program { (stmt "\n"*) * } 2 | @skip { space | LineComment } 3 | 4 | stmt { 5 | Alias | 6 | Message 7 | } 8 | 9 | Alias { kw<"alias"> Identifier "=" String } 10 | Message { Identifier MessageOperator Identifier ":" String } 11 | 12 | kw { @specialize[@name={term}] } 13 | 14 | @tokens { 15 | Identifier { $[a-zA-Z_0-9]+ } 16 | String { '"' (!["\\] | "\\" _)* '"' } 17 | LineComment { ("#" | "//") ![\n]* } 18 | MessageOperator { "->" } 19 | // space { std.whitespace+ } 20 | space { $[ \t]+ } 21 | } 22 | 23 | @detectDelim 24 | -------------------------------------------------------------------------------- /site/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], 5 | plugins: ["svelte3", "@typescript-eslint"], 6 | ignorePatterns: ["*.cjs"], 7 | overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }], 8 | settings: { 9 | "svelte3/typescript": require("typescript"), 10 | }, 11 | parserOptions: { 12 | sourceType: "module", 13 | ecmaVersion: 2019, 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true, 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /site/src/lib/CodeEditor/lang/index.ts: -------------------------------------------------------------------------------- 1 | import { parser } from "./syntax.grammar"; 2 | import { LezerLanguage, LanguageSupport } from "@codemirror/language"; 3 | import { styleTags, tags as t } from "@codemirror/highlight"; 4 | 5 | export const DiagwizLanguage = LezerLanguage.define({ 6 | parser: parser.configure({ 7 | props: [ 8 | styleTags({ 9 | LineComment: t.lineComment, 10 | "Alias/alias": t.definitionKeyword, 11 | "Alias/Identifier": t.variableName, 12 | "Alias/String": t.string, 13 | "Message/Identifier": t.variableName, 14 | "Message/String": t.string, 15 | }), 16 | ], 17 | }), 18 | }); 19 | 20 | export function diagwiz(): LanguageSupport { 21 | return new LanguageSupport(DiagwizLanguage); 22 | } 23 | -------------------------------------------------------------------------------- /src/diagrams/seq/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate pest; 2 | #[macro_use] 3 | extern crate pest_derive; 4 | 5 | use diagram_base::TransformError; 6 | 7 | mod layout; 8 | mod parser; 9 | mod renderer; 10 | 11 | impl From for TransformError { 12 | fn from(err: parser::ParserError) -> TransformError { 13 | match err { 14 | parser::ParserError::SyntaxError(details) => TransformError::ParseError(details), 15 | } 16 | } 17 | } 18 | 19 | pub fn transform(input: &str) -> Result { 20 | let diagram = parser::diagram(input)?; 21 | let output = renderer::render(diagram); 22 | Ok(output) 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | #[test] 28 | fn test_smoke() { 29 | let data = r#" 30 | alias a="Foo" 31 | alias b="Bar" 32 | a->b:"hey" 33 | "#; 34 | let result = super::transform(data).unwrap(); 35 | assert_eq!(result.contains("Foo"), true); 36 | assert_eq!(result.contains("Bar"), true); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /site/src/lib/CodeEditor/CodeEditor.svelte: -------------------------------------------------------------------------------- 1 | 33 | 34 |
35 | -------------------------------------------------------------------------------- /site/svelte.config.cjs: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require("svelte-preprocess"); 2 | const static = require("@sveltejs/adapter-static"); 3 | const pkg = require("./package.json"); 4 | const ViteRsw = require("vite-plugin-rsw").default; 5 | const lezer = require("lezer-generator/rollup").lezer; 6 | 7 | /** @type {import('@sveltejs/kit').Config} */ 8 | module.exports = { 9 | // Consult https://github.com/sveltejs/svelte-preprocess 10 | // for more information about preprocessors 11 | preprocess: sveltePreprocess(), 12 | kit: { 13 | // Build a static version 14 | adapter: static(), 15 | 16 | // hydrate the
element in src/app.html 17 | target: "#svelte", 18 | 19 | vite: { 20 | ssr: { 21 | noExternal: Object.keys(pkg.dependencies || {}), 22 | }, 23 | plugins: [ 24 | // Rust support 25 | ViteRsw({ 26 | mode: "release", 27 | crates: ["diagwiz"], 28 | }), 29 | 30 | // Lezer grammar support 31 | lezer(), 32 | ], 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/diagrams/seq/src/syntax.pest: -------------------------------------------------------------------------------- 1 | WHITESPACE = _{ " " } 2 | COMMENT = _{ ("#" | "//") ~ (!"\n" ~ ANY)* } 3 | 4 | // Make sure that that no keyword in this rule is a prefix of a any 5 | // succeeding keyword. For example { "alias" | "aliasson" } will never match 6 | // "aliassion" 7 | _keyword = @{ "alias" } 8 | keyword = @{ _keyword } 9 | 10 | // Allow any identifier that is not a keyword. Also, identifiers are not begin 11 | // with a digit. 12 | identifier = @{ 13 | !(keyword ~ !ASCII_ALPHA) 14 | ~ (ASCII_ALPHA | "_") 15 | ~ (ASCII_ALPHANUMERIC | "_")* 16 | } 17 | 18 | string = _{ "\"" ~ string_inner ~ "\"" } 19 | string_inner = @{ string_char* } 20 | string_char = { 21 | !("\"" | "\\") ~ ANY 22 | | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") 23 | | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) 24 | } 25 | 26 | edge = { "-->" | "->" | "<--" | "<-" } 27 | alias = { ^"alias " ~ identifier ~ "=" ~ string } 28 | pair = { identifier ~ edge ~ identifier ~ (":" ~ string)? } 29 | 30 | expr = _{ alias | pair } 31 | main = { SOI ~ ((expr? ~ NEWLINE)* ~ EOI) | (expr? ~ EOI) } 32 | -------------------------------------------------------------------------------- /site/src/app.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "RedHatDisplay"; 3 | font-weight: bold; 4 | src: local("Red Hat Display Bold"), url("/fonts/RedHatDisplay-Bold.ttf") format("truetype"); 5 | } 6 | 7 | @font-face { 8 | font-family: "Menlo"; 9 | font-weight: normal; 10 | src: local("Menlo Regular"), url("/fonts/Menlo-Regular.ttf") format("truetype"); 11 | } 12 | 13 | :root { 14 | --secondary-bg-color: #000; 15 | --link-color: #000; 16 | 17 | /* Toast style */ 18 | --toastContainerTop: auto; 19 | --toastContainerRight: auto; 20 | --toastContainerBottom: 2rem; 21 | --toastContainerLeft: calc(50vw - 8rem); 22 | } 23 | 24 | html, 25 | body, 26 | #svelte { 27 | width: 100%; 28 | height: 100%; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | padding: 0; 34 | box-sizing: border-box; 35 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, 36 | "Helvetica Neue", sans-serif; 37 | } 38 | 39 | pre { 40 | font-family: Menlo, monospace; 41 | font-weight: normal; 42 | } 43 | 44 | svg { 45 | vertical-align: top; 46 | } 47 | 48 | a { 49 | color: var(--link-color); 50 | } 51 | -------------------------------------------------------------------------------- /site/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "es2020", 5 | "lib": ["es2020"], 6 | "target": "es2019", 7 | /** 8 | svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript 9 | to enforce using \`import type\` instead of \`import\` for Types. 10 | */ 11 | "importsNotUsedAsValues": "error", 12 | "isolatedModules": true, 13 | "resolveJsonModule": true, 14 | /** 15 | To have warnings/errors of the Svelte compiler at the correct position, 16 | enable source maps by default. 17 | */ 18 | "sourceMap": true, 19 | "esModuleInterop": true, 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "baseUrl": ".", 23 | "allowJs": true, 24 | "checkJs": true, 25 | "paths": { 26 | "$app/*": [".svelte/dev/runtime/app/*", ".svelte/build/runtime/app/*"], 27 | "$service-worker": [".svelte/build/runtime/service-worker"], 28 | "$lib/*": ["src/lib/*"] 29 | } 30 | }, 31 | "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"] 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Krzysztof Jagiello 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /site/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { toast } from "@zerodevx/svelte-toast"; 2 | 3 | export const debounce = (f, timeout = 250) => { 4 | let timer; 5 | return (...v) => { 6 | clearTimeout(timer); 7 | timer = setTimeout(() => f(...v), timeout); 8 | }; 9 | }; 10 | 11 | export const toastSuccess = (msg: string) => 12 | toast.push(msg, { 13 | theme: { 14 | "--toastBackground": "#48BB78", 15 | "--toastProgressBackground": "#2F855A", 16 | }, 17 | }); 18 | 19 | export const toastError = (msg: string) => 20 | toast.push(msg, { 21 | theme: { 22 | "--toastBackground": "#F56565", 23 | "--toastProgressBackground": "#C53030", 24 | }, 25 | }); 26 | 27 | export const measureTime = (f) => { 28 | const t0 = performance.now(); 29 | f(); 30 | const t1 = performance.now(); 31 | return t1 - t0; 32 | }; 33 | 34 | export const copyTextToClipboard = (text: string) => 35 | navigator.clipboard 36 | .writeText(text) 37 | .then(() => toastSuccess("Copied to clipboard")) 38 | .catch((e) => { 39 | console.error("clipboard.writeText failed", e); 40 | toastError("Could not access the clipboard"); 41 | }); 42 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "site", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "svelte-kit dev", 6 | "build": "svelte-kit build && mkdir -p build/assets && mv build/_app/assets/*.wasm build/assets", 7 | "start": "svelte-kit start", 8 | "lint": "prettier --check . && eslint --ignore-path .gitignore .", 9 | "format": "prettier --write ." 10 | }, 11 | "devDependencies": { 12 | "@codemirror/basic-setup": "^0.18.0", 13 | "@sveltejs/adapter-static": "next", 14 | "@sveltejs/kit": "next", 15 | "@types/lz-string": "^1.3.34", 16 | "@typescript-eslint/eslint-plugin": "^4.19.0", 17 | "@typescript-eslint/parser": "^4.19.0", 18 | "@zerodevx/svelte-toast": "^0.2.1", 19 | "eslint": "^7.22.0", 20 | "eslint-config-prettier": "^8.1.0", 21 | "eslint-plugin-svelte3": "^3.1.2", 22 | "lezer-generator": "^0.13.3", 23 | "lz-string": "^1.4.4", 24 | "prettier": "~2.2.1", 25 | "prettier-plugin-svelte": "^2.2.0", 26 | "svelte": "^3.29.0", 27 | "svelte-preprocess": "^4.0.0", 28 | "tslib": "^2.0.0", 29 | "typescript": "^4.0.0", 30 | "vite": "^2.1.0", 31 | "vite-plugin-rsw": "^1.3.1" 32 | }, 33 | "type": "module", 34 | "dependencies": {} 35 | } 36 | -------------------------------------------------------------------------------- /site/src/routes/$layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |
8 |

diagwiz logo DIAGWIZ

9 |

playgroundbeta

10 |
11 |
12 | 13 |
14 |
15 | 16 | 66 | -------------------------------------------------------------------------------- /site/src/routes/playground/_diagwiz.svelte: -------------------------------------------------------------------------------- 1 | 43 | 44 | {#await diagwiz} 45 | 46 | {:then _} 47 | 48 | {:catch error} 49 | null} /> 50 | {/await} 51 | -------------------------------------------------------------------------------- /site/src/routes/playground/index.svelte: -------------------------------------------------------------------------------- 1 | 34 | 35 | 36 | Playground • Diagwiz 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | 3 | use clap::{App, Arg}; 4 | use diagram_base::TransformError; 5 | use std::fs::File; 6 | use std::io::{self, Read}; 7 | use std::path::Path; 8 | use std::process; 9 | 10 | const PKG_NAME: &str = env!("CARGO_PKG_NAME"); 11 | const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); 12 | const PKG_AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); 13 | 14 | fn read_from_stdin() -> io::Result { 15 | let stdin = io::stdin(); 16 | let mut handle = stdin.lock(); 17 | let mut buffer = String::new(); 18 | handle.read_to_string(&mut buffer)?; 19 | Ok(buffer) 20 | } 21 | 22 | fn read_from_path(path: &str) -> io::Result { 23 | let path = Path::new(path); 24 | let mut handle = File::open(&path)?; 25 | let mut buffer = String::new(); 26 | handle.read_to_string(&mut buffer)?; 27 | Ok(buffer) 28 | } 29 | 30 | fn render(input: &str) -> Result { 31 | let output = diagram_seq::transform(input)?; 32 | Ok(output) 33 | } 34 | 35 | fn main() -> io::Result<()> { 36 | let matches = App::new(PKG_NAME) 37 | .version(PKG_VERSION) 38 | .about("Diagrams as code") 39 | .author(PKG_AUTHORS) 40 | .arg( 41 | Arg::with_name("PATH") 42 | .help("Path to the .diag file to generate diagram for (- for STDIN).") 43 | .required(false) 44 | .index(1), 45 | ) 46 | .get_matches(); 47 | 48 | let input = { 49 | let path = matches.value_of("PATH").unwrap_or("-"); 50 | let (verbose_path, result) = match path { 51 | "-" => ("STDIN", read_from_stdin()), 52 | path => (path, read_from_path(path)), 53 | }; 54 | result.unwrap_or_else(|e| { 55 | eprintln!("{}: {}", verbose_path, e); 56 | process::exit(1); 57 | }) 58 | }; 59 | 60 | let output = render(input.as_str()); 61 | match output { 62 | Ok(repr) if !repr.is_empty() => println!("{}", repr), 63 | Ok(_) => eprintln!("Warning: No diagram was generated"), 64 | Err(err) => { 65 | eprintln!("{}", err); 66 | process::exit(1); 67 | } 68 | } 69 | Ok(()) 70 | } 71 | -------------------------------------------------------------------------------- /.github/workflows/site-ci.yml: -------------------------------------------------------------------------------- 1 | name: CI (site) 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | lint: 12 | name: Lint 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout sources 16 | uses: actions/checkout@v2 17 | 18 | - name: Setup Node 19 | uses: actions/setup-node@v2 20 | with: 21 | node-version: '14' 22 | 23 | - name: Install dependencies 24 | run: npm ci 25 | working-directory: site/ 26 | 27 | - name: Run the linters 28 | run: npm run lint 29 | working-directory: site/ 30 | 31 | deploy: 32 | name: Deploy 33 | needs: lint 34 | if: ${{ github.event == 'push' }} 35 | runs-on: ubuntu-latest 36 | steps: 37 | - name: Checkout sources 38 | uses: actions/checkout@v2 39 | 40 | - name: Install Rust toolchain 41 | uses: actions-rs/toolchain@v1 42 | with: 43 | profile: minimal 44 | toolchain: nightly 45 | override: true 46 | 47 | - name: Setup cache for Rust 48 | uses: Swatinem/rust-cache@v1 49 | 50 | - name: Install wasm-pack 51 | uses: actions-rs/cargo@v1 52 | with: 53 | command: install 54 | args: wasm-pack 55 | 56 | - name: Build diagwiz for wasm 57 | run: wasm-pack build --release --target web 58 | working-directory: site/diagwiz/ 59 | 60 | - name: Setup Node 61 | uses: actions/setup-node@v2 62 | with: 63 | node-version: '14' 64 | 65 | - name: Install Node dependencies 66 | run: npm ci 67 | working-directory: site/ 68 | 69 | - name: Link diagwiz for wasm 70 | run: npm link ./diagwiz/pkg 71 | working-directory: site/ 72 | 73 | - name: Build the site 74 | run: npm run build 75 | working-directory: site/ 76 | 77 | - name: Add the .nojekyll marker 78 | run: touch build/.nojekyll 79 | working-directory: site/ 80 | 81 | - name: Deploy 82 | uses: JamesIves/github-pages-deploy-action@4.1.0 83 | with: 84 | branch: gh-pages 85 | folder: site/build/ 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # diagwiz -- diagrams as code 2 | 3 | [![CI](https://github.com/kjagiello/diagwiz/actions/workflows/diagwiz-ci.yml/badge.svg?event=push)](https://github.com/kjagiello/diagwiz/actions/workflows/diagwiz-ci.yml) [![Security audit](https://github.com/kjagiello/diagwiz/actions/workflows/diagwiz-audit.yml/badge.svg)](https://github.com/kjagiello/diagwiz/actions/workflows/diagwiz-audit.yml) 4 | 5 | **Warning**: This project is in early experimental stage. Functionality is 6 | subject to change and YMMV. Feel free to open an issue if you have any 7 | suggestions, Rust tips & tricks (my first Rust project) or stumbled upon any 8 | bugs. 9 | 10 | ## Supported diagrams 11 | 12 | - [Sequence diagrams](https://en.wikipedia.org/wiki/Sequence_diagram) 13 | 14 | ## Online playground 15 | 16 | You can experiment building diagrams with diagwiz using the 17 | [online playground](https://diagwiz.io/playground). 18 | 19 | # Installation 20 | 21 | As the package is currently in experimental stage, you can install it by 22 | building it from the source or by downloading the pre-compiled binary from the 23 | latest nightly release. 24 | 25 | ## Download a nightly binary 26 | 27 | Visit the [nightly release page](https://github.com/kjagiello/diagwiz/releases/tag/nightly) 28 | and download a binary compatible with your system. 29 | 30 | ## Install from source 31 | 32 | ```bash 33 | cargo install --git https://github.com/kjagiello/diagwiz 34 | ``` 35 | 36 | # Usage example 37 | 38 | ```bash 39 | $ cat < example.diag 40 | alias ali = "Alice" 41 | 42 | ali->Bob: "Hello!" 43 | Bob->Bob: "(Bob thinks)" 44 | Bob-->ali: "Hello back!" 45 | EOF 46 | 47 | $ diagwiz < example.diag 48 | ┌───────┐ ┌─────┐ 49 | │ Alice │ │ Bob │ 50 | └───────┘ └─────┘ 51 | │ Hello! │ 52 | │──────────────▶│ 53 | │ │ 54 | │ │─┐ 55 | │ │ │ (Bob thinks) 56 | │ │◀┘ 57 | │ │ 58 | │ Hello back! │ 59 | │◀--------------│ 60 | │ │ 61 | ┌───────┐ ┌─────┐ 62 | │ Alice │ │ Bob │ 63 | └───────┘ └─────┘ 64 | ``` 65 | 66 | 67 | # Known issues 68 | 69 | - Characters with a column width other than 1 cause artifacts in the ASCII 70 | representation of a diagram 71 | - For some inputs, the generated layout might change on every run. This is due 72 | to the [Cassowary algorithm implementation](https://github.com/dylanede/cassowary-rs) 73 | not being deterministic and finding multiple optimal solutions for the given 74 | constraints. 75 | -------------------------------------------------------------------------------- /.github/workflows/diagwiz-ci.yml: -------------------------------------------------------------------------------- 1 | name: CI (diagwiz) 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | 10 | jobs: 11 | check: 12 | name: Check 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout sources 16 | uses: actions/checkout@v2 17 | 18 | - name: Install toolchain 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | profile: minimal 22 | toolchain: nightly 23 | override: true 24 | 25 | - name: Run cargo check 26 | uses: actions-rs/cargo@v1 27 | with: 28 | command: check 29 | 30 | test: 31 | name: Test 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | build: [linux, linux-arm, macos, win-msvc, win-gnu, win32-msvc] 36 | include: 37 | - build: linux 38 | os: ubuntu-18.04 39 | rust: nightly 40 | target: x86_64-unknown-linux-musl 41 | - build: linux-arm 42 | os: ubuntu-18.04 43 | rust: nightly 44 | target: arm-unknown-linux-gnueabihf 45 | - build: macos 46 | os: macos-latest 47 | rust: nightly 48 | target: x86_64-apple-darwin 49 | - build: win-msvc 50 | os: windows-2019 51 | rust: nightly 52 | target: x86_64-pc-windows-msvc 53 | - build: win-gnu 54 | os: windows-2019 55 | rust: nightly-x86_64-gnu 56 | target: x86_64-pc-windows-gnu 57 | - build: win32-msvc 58 | os: windows-2019 59 | rust: nightly 60 | target: i686-pc-windows-msvc 61 | steps: 62 | - name: Checkout sources 63 | uses: actions/checkout@v2 64 | - name: Install toolchain 65 | uses: actions-rs/toolchain@v1 66 | with: 67 | toolchain: ${{ matrix.rust }} 68 | target: ${{ matrix.target }} 69 | profile: minimal 70 | override: true 71 | 72 | - name: Run cargo test 73 | uses: actions-rs/cargo@v1 74 | with: 75 | use-cross: true 76 | command: test 77 | args: --target ${{ matrix.target }} --all 78 | 79 | lint: 80 | name: Lint 81 | runs-on: ubuntu-latest 82 | steps: 83 | - name: Checkout sources 84 | uses: actions/checkout@v2 85 | 86 | - name: Install toolchain 87 | uses: actions-rs/toolchain@v1 88 | with: 89 | profile: minimal 90 | toolchain: nightly 91 | override: true 92 | components: rustfmt, clippy 93 | 94 | - name: Run cargo fmt 95 | uses: actions-rs/cargo@v1 96 | with: 97 | command: fmt 98 | args: --all -- --check 99 | 100 | # Clippy does not produce any warnings without a cargo clean 101 | # https://github.com/rust-lang/rust-clippy/issues/1495 102 | - name: Clean the build files for clippy 103 | uses: actions-rs/cargo@v1 104 | with: 105 | command: clean 106 | 107 | - name: Run cargo clippy 108 | uses: actions-rs/cargo@v1 109 | with: 110 | command: clippy 111 | -------------------------------------------------------------------------------- /site/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/diagrams/seq/src/renderer.rs: -------------------------------------------------------------------------------- 1 | use crate::layout; 2 | use crate::parser; 3 | use std::collections::HashMap; 4 | use std::collections::HashSet; 5 | use std::iter::FromIterator; 6 | use std::sync::Arc; 7 | 8 | pub fn render(diag: parser::SequenceDiagram) -> String { 9 | // Gather all the unique participants in the following order: 10 | // 1. Nodes with explicit aliases (this enables easy reordering by moving around aliases) 11 | // 2. The rest of the participants in the order they appear 12 | let ordered_participants = { 13 | let mut participants = Vec::new(); 14 | diag.aliases 15 | .iter() 16 | .for_each(|a| participants.push(&a.id[..])); 17 | diag.messages.iter().for_each(|m| { 18 | participants.push(&m.source[..]); 19 | participants.push(&m.target[..]); 20 | }); 21 | 22 | // Deduplicate the participants 23 | let mut unique_participants: HashSet<&str> = HashSet::from_iter(participants.clone()); 24 | let participants: Vec<&str> = participants 25 | .clone() 26 | .iter() 27 | .cloned() 28 | .filter(|p| unique_participants.remove(p)) 29 | .collect(); 30 | participants 31 | }; 32 | 33 | // Gather all the aliases. For the nodes without an explicit alias, set it to the alias to the 34 | // node ID 35 | let aliases = { 36 | let mut aliases = HashMap::new(); 37 | diag.aliases.iter().for_each(|a| { 38 | aliases.insert(&a.id[..], &a.label[..]); 39 | }); 40 | diag.messages.iter().for_each(|m| { 41 | aliases.entry(&m.source).or_insert(&m.source); 42 | aliases.entry(&m.target).or_insert(&m.target); 43 | }); 44 | aliases 45 | }; 46 | 47 | // Construct the layout participants 48 | let participants = { 49 | let mut participants = HashMap::new(); 50 | ordered_participants.iter().for_each(|p| { 51 | participants.insert( 52 | p.to_string(), 53 | Arc::from(layout::Participant { 54 | id: p.to_string(), 55 | name: aliases.get(p).unwrap().to_string(), 56 | }), 57 | ); 58 | }); 59 | participants 60 | }; 61 | 62 | // Construct the layout 63 | let mut layout = layout::Layout::new(); 64 | for participant in ordered_participants { 65 | layout.add_participant(participants.get(participant).unwrap().clone()); 66 | } 67 | for message in diag.messages { 68 | layout.add_message(layout::Message { 69 | source: participants.get(&message.source).unwrap().clone(), 70 | target: participants.get(&message.target).unwrap().clone(), 71 | payload: message.payload, 72 | edge_style: match message.edge_style { 73 | parser::EdgeStyle::Continuous => layout::EdgeStyle::Continuous, 74 | parser::EdgeStyle::Dashed => layout::EdgeStyle::Dashed, 75 | }, 76 | }) 77 | } 78 | 79 | layout.render() 80 | } 81 | 82 | #[cfg(test)] 83 | mod test { 84 | use crate::parser; 85 | 86 | #[test] 87 | fn smoke() { 88 | let mut diag = parser::SequenceDiagram::default(); 89 | diag.aliases.push(parser::Alias { 90 | id: "test1".to_string(), 91 | label: "label".to_string(), 92 | }); 93 | diag.aliases.push(parser::Alias { 94 | id: "test2".to_string(), 95 | label: "label".to_string(), 96 | }); 97 | super::render(diag); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /.github/workflows/diagwiz-release.yml: -------------------------------------------------------------------------------- 1 | name: Release (diagwiz) 2 | 3 | on: 4 | schedule: 5 | - cron: '5 0 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | build: [linux, linux-arm, macos, win-msvc, win-gnu, win32-msvc] 16 | include: 17 | - build: linux 18 | os: ubuntu-18.04 19 | rust: nightly 20 | target: x86_64-unknown-linux-musl 21 | - build: linux-arm 22 | os: ubuntu-18.04 23 | rust: nightly 24 | target: arm-unknown-linux-gnueabihf 25 | - build: macos 26 | os: macos-latest 27 | rust: nightly 28 | target: x86_64-apple-darwin 29 | - build: win-msvc 30 | os: windows-2019 31 | rust: nightly 32 | target: x86_64-pc-windows-msvc 33 | win: true 34 | - build: win-gnu 35 | os: windows-2019 36 | rust: nightly-x86_64-gnu 37 | target: x86_64-pc-windows-gnu 38 | win: true 39 | - build: win32-msvc 40 | os: windows-2019 41 | rust: nightly 42 | target: i686-pc-windows-msvc 43 | win: true 44 | steps: 45 | - name: Checkout sources 46 | uses: actions/checkout@v2 47 | 48 | - name: Install toolchain 49 | uses: actions-rs/toolchain@v1 50 | with: 51 | toolchain: ${{ matrix.rust }} 52 | target: ${{ matrix.target }} 53 | profile: minimal 54 | override: true 55 | 56 | - name: Run cargo build 57 | uses: actions-rs/cargo@v1 58 | with: 59 | use-cross: true 60 | command: build 61 | args: --release --target ${{ matrix.target }} 62 | 63 | - name: Upload artifact 64 | uses: actions/upload-artifact@v2 65 | with: 66 | name: diagwiz-${{ matrix.target }} 67 | path: | 68 | target/${{ matrix.target }}/release/diagwiz 69 | target/${{ matrix.target }}/release/diagwiz.exe 70 | retention-days: 1 71 | if-no-files-found: error 72 | 73 | release-nightly: 74 | name: Release (nightly) 75 | needs: build 76 | runs-on: ubuntu-latest 77 | steps: 78 | - name: Declare variables 79 | id: vars 80 | shell: bash 81 | run: echo "::set-output name=sha_short::${GITHUB_SHA::8}" 82 | 83 | - name: Download artifacts 84 | uses: actions/download-artifact@v2 85 | 86 | - name: Delete previous nightly release 87 | uses: dev-drprasad/delete-tag-and-release@v0.1.2 88 | env: 89 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 90 | with: 91 | delete_release: true 92 | tag_name: nightly 93 | 94 | - name: Create release 95 | uses: meeDamian/github-release@2.0 96 | with: 97 | token: ${{ secrets.GITHUB_TOKEN }} 98 | tag: nightly 99 | name: diagwiz-nightly 100 | prerelease: true 101 | commitish: ${{ github.sha }} 102 | gzip: false 103 | allow_override: true 104 | files: | 105 | diagwiz-x86_64-unknown-linux-musl:./diagwiz-x86_64-unknown-linux-musl/diagwiz 106 | diagwiz-arm-unknown-linux-gnueabihf:./diagwiz-arm-unknown-linux-gnueabihf/diagwiz 107 | diagwiz-x86_64-apple-darwin:./diagwiz-x86_64-apple-darwin/diagwiz 108 | diagwiz-x86_64-pc-windows-msvc:./diagwiz-x86_64-pc-windows-msvc/diagwiz.exe 109 | diagwiz-x86_64-pc-windows-gnu:./diagwiz-x86_64-pc-windows-gnu/diagwiz.exe 110 | diagwiz-i686-pc-windows-msvc:./diagwiz-i686-pc-windows-msvc/diagwiz.exe 111 | body: diagwiz nightly build 112 | 113 | cleanup: 114 | name: Cleanup 115 | if: always() 116 | needs: release-nightly 117 | runs-on: ubuntu-latest 118 | steps: 119 | - uses: geekyeggo/delete-artifact@v1 120 | with: 121 | name: | 122 | diagwiz-x86_64-unknown-linux-musl 123 | diagwiz-arm-unknown-linux-gnueabihf 124 | diagwiz-x86_64-apple-darwin 125 | diagwiz-x86_64-pc-windows-msvc 126 | diagwiz-x86_64-pc-windows-gnu 127 | diagwiz-i686-pc-windows-msvc 128 | -------------------------------------------------------------------------------- /src/diagrams/seq/tests/snapshot.rs: -------------------------------------------------------------------------------- 1 | use pretty_assertions::assert_eq; 2 | use std::fmt; 3 | 4 | #[derive(PartialEq, Eq)] 5 | pub struct PrettyString<'a>(pub &'a str); 6 | 7 | /// Make diff to display string as multi-line string 8 | impl<'a> fmt::Debug for PrettyString<'a> { 9 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 10 | f.write_str(self.0) 11 | } 12 | } 13 | 14 | macro_rules! assert_renders { 15 | ($input:expr, $output:expr$(,)*) => {{ 16 | assert_eq!( 17 | PrettyString($input.unwrap().as_str()), 18 | PrettyString($output), 19 | ); 20 | }}; 21 | } 22 | 23 | #[test] 24 | fn test_loop() { 25 | assert_renders!( 26 | diagram_seq::transform("a->a"), 27 | concat!( 28 | "┌────┐ \n", 29 | "│ a │ \n", 30 | "└────┘ \n", 31 | " │─┐ \n", 32 | " │ │ \n", 33 | " │◀┘ \n", 34 | " │ \n", 35 | "┌────┐ \n", 36 | "│ a │ \n", 37 | "└────┘ ", 38 | ), 39 | ); 40 | } 41 | 42 | #[test] 43 | fn test_two_participants_with_continuous_line() { 44 | assert_renders!( 45 | diagram_seq::transform("a->b"), 46 | concat!( 47 | "┌────┐ ┌────┐ \n", 48 | "│ a │ │ b │ \n", 49 | "└────┘ └────┘ \n", 50 | " │ │ \n", 51 | " │─────▶│ \n", 52 | " │ │ \n", 53 | "┌────┐ ┌────┐ \n", 54 | "│ a │ │ b │ \n", 55 | "└────┘ └────┘ ", 56 | ), 57 | ); 58 | } 59 | 60 | #[test] 61 | fn test_two_participants_with_dashed_line() { 62 | assert_renders!( 63 | diagram_seq::transform("a-->b"), 64 | concat!( 65 | "┌────┐ ┌────┐ \n", 66 | "│ a │ │ b │ \n", 67 | "└────┘ └────┘ \n", 68 | " │ │ \n", 69 | " │-----▶│ \n", 70 | " │ │ \n", 71 | "┌────┐ ┌────┐ \n", 72 | "│ a │ │ b │ \n", 73 | "└────┘ └────┘ ", 74 | ), 75 | ); 76 | } 77 | 78 | #[test] 79 | fn test_two_participants_with_message() { 80 | assert_renders!( 81 | diagram_seq::transform( 82 | r#" 83 | a->b: "hello world" 84 | "# 85 | .into() 86 | ), 87 | concat!( 88 | "┌────┐ ┌────┐ \n", 89 | "│ a │ │ b │ \n", 90 | "└────┘ └────┘ \n", 91 | " │ hello world │ \n", 92 | " │───────────────▶│ \n", 93 | " │ │ \n", 94 | "┌────┐ ┌────┐ \n", 95 | "│ a │ │ b │ \n", 96 | "└────┘ └────┘ ", 97 | ), 98 | ); 99 | } 100 | 101 | #[test] 102 | fn test_complex() { 103 | assert_renders!( 104 | diagram_seq::transform( 105 | r#" 106 | alias a = "Alice" 107 | alias b = "Bob" 108 | alias c = "Charlie" 109 | 110 | a->c: "hello world" 111 | b->a: "hello there" 112 | c-->a: "hello back" 113 | c->b: "hello back too" 114 | b->b: "hello?" 115 | "# 116 | .into() 117 | ), 118 | concat!( 119 | "┌────────┐ ┌──────┐ ┌──────────┐ \n", 120 | "│ Alice │ │ Bob │ │ Charlie │ \n", 121 | "└────────┘ └──────┘ └──────────┘ \n", 122 | " │ hello world │ \n", 123 | " │──────────────────────────────────▶│ \n", 124 | " │ │ │ \n", 125 | " │ hello there │ │ \n", 126 | " │◀───────────────│ │ \n", 127 | " │ │ │ \n", 128 | " │ hello back │ \n", 129 | " │◀----------------------------------│ \n", 130 | " │ │ │ \n", 131 | " │ │ hello back too │ \n", 132 | " │ │◀─────────────────│ \n", 133 | " │ │ │ \n", 134 | " │ │─┐ │ \n", 135 | " │ │ │ hello? │ \n", 136 | " │ │◀┘ │ \n", 137 | " │ │ │ \n", 138 | "┌────────┐ ┌──────┐ ┌──────────┐ \n", 139 | "│ Alice │ │ Bob │ │ Charlie │ \n", 140 | "└────────┘ └──────┘ └──────────┘ ", 141 | ), 142 | ); 143 | } 144 | -------------------------------------------------------------------------------- /site/src/routes/playground/_playground.svelte: -------------------------------------------------------------------------------- 1 | 50 | 51 |
52 | 53 |
54 |
55 |
56 |

Output

57 |
    58 |
  • Copy
  • 59 |
  • Share
  • 60 |
  • Execution time: {executionTime} ms
  • 61 |
62 |
63 |
{stdout}
64 |
65 |
66 |

67 |

Errors ({errorCount})

68 | 71 | 72 |
{stderr}
73 |
74 |
75 | {#if browser} 76 | 77 | {/if} 78 |
79 | 80 | 198 | -------------------------------------------------------------------------------- /src/ascii_canvas/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::iter::FromIterator; 2 | 3 | type CanvasBuffer = Vec>; 4 | 5 | #[derive(Debug)] 6 | pub struct Rect { 7 | pub left: usize, 8 | pub top: usize, 9 | pub width: usize, 10 | pub height: usize, 11 | } 12 | 13 | impl Rect { 14 | fn right(&self) -> usize { 15 | self.left + self.width 16 | } 17 | 18 | fn bottom(&self) -> usize { 19 | self.top + self.height 20 | } 21 | 22 | fn contains(&self, rect: &Rect) -> bool { 23 | let horizontal = self.left..(self.right() + 1); 24 | let vertical = self.top..(self.bottom() + 1); 25 | horizontal.contains(&rect.left) 26 | && horizontal.contains(&rect.right()) 27 | && vertical.contains(&rect.top) 28 | && vertical.contains(&rect.bottom()) 29 | } 30 | } 31 | 32 | pub struct TextCanvas { 33 | bounds: Rect, 34 | buffer: CanvasBuffer, 35 | } 36 | 37 | pub struct TextCanvasRegion<'a> { 38 | bounds: Rect, 39 | buffer: &'a mut CanvasBuffer, 40 | } 41 | 42 | #[derive(Debug, PartialEq)] 43 | pub enum DrawError { 44 | HorizontalOverflow, 45 | VerticalOverflow, 46 | } 47 | 48 | pub type DrawResult = Result<(), DrawError>; 49 | 50 | pub trait Draw { 51 | fn bounds(&self) -> &Rect; 52 | fn buffer_mut(&mut self) -> &mut CanvasBuffer; 53 | 54 | fn draw(&mut self, left: usize, top: usize, rows: &[&str]) -> DrawResult { 55 | // TODO: ensure that the draw cannot happen outside of the region 56 | let bounds = self.bounds(); 57 | let max_length = rows.iter().map(|s| s.chars().count()).max().unwrap(); 58 | if max_length > bounds.width - left { 59 | Err(DrawError::HorizontalOverflow) 60 | } else if rows.len() > bounds.height - top { 61 | Err(DrawError::VerticalOverflow) 62 | } else { 63 | let left = left + bounds.left; 64 | let top = top + bounds.top; 65 | let buffer = self.buffer_mut(); 66 | let pairs = buffer[top..top + rows.len()].iter_mut().zip(rows); 67 | for (brow, drow) in pairs { 68 | brow.splice(left..left + drow.chars().count(), drow.chars()); 69 | } 70 | Ok(()) 71 | } 72 | } 73 | } 74 | 75 | impl Draw for TextCanvas { 76 | fn bounds(&self) -> &Rect { 77 | &self.bounds 78 | } 79 | 80 | fn buffer_mut(&mut self) -> &mut CanvasBuffer { 81 | &mut self.buffer 82 | } 83 | } 84 | 85 | impl<'a> Draw for TextCanvasRegion<'a> { 86 | fn bounds(&self) -> &Rect { 87 | &self.bounds 88 | } 89 | 90 | fn buffer_mut(&mut self) -> &mut CanvasBuffer { 91 | &mut self.buffer 92 | } 93 | } 94 | 95 | impl TextCanvas { 96 | pub fn new(width: usize, height: usize) -> TextCanvas { 97 | TextCanvas { 98 | bounds: Rect { 99 | left: 0, 100 | top: 0, 101 | width, 102 | height, 103 | }, 104 | buffer: (0..height).map(|_| vec![' '; width]).collect(), 105 | } 106 | } 107 | 108 | pub fn region( 109 | &mut self, 110 | left: usize, 111 | top: usize, 112 | width: usize, 113 | height: usize, 114 | ) -> TextCanvasRegion { 115 | let bounds = Rect { 116 | left, 117 | top, 118 | width, 119 | height, 120 | }; 121 | if !self.bounds.contains(&bounds) { 122 | panic!( 123 | "Creating invalid region. Canvas bounds: {:?}, region bounds: {:?}", 124 | self.bounds, bounds 125 | ); 126 | } 127 | TextCanvasRegion { 128 | bounds, 129 | buffer: &mut self.buffer, 130 | } 131 | } 132 | 133 | pub fn content(&self) -> String { 134 | self.buffer 135 | .iter() 136 | .map(String::from_iter) 137 | .collect::>() 138 | .join("\n") 139 | } 140 | } 141 | 142 | #[cfg(test)] 143 | mod tests { 144 | use super::*; 145 | 146 | #[test] 147 | fn overlapping_text() { 148 | let mut canvas = TextCanvas::new(5, 5); 149 | let data = ["123", "456", "789"]; 150 | canvas.draw(0, 0, &data).expect("Draw failed"); 151 | canvas.draw(2, 2, &data).expect("Draw failed"); 152 | #[rustfmt::skip] 153 | let expected = vec![ 154 | "123 ", 155 | "456 ", 156 | "78123", 157 | " 456", 158 | " 789", 159 | ]; 160 | assert_eq!(canvas.content(), expected.join("\n")); 161 | } 162 | 163 | #[test] 164 | fn horizontal_overflow() { 165 | let data = ["123", "456", "789"]; 166 | let mut canvas = TextCanvas::new(2, 3); 167 | assert_eq!(canvas.draw(0, 0, &data), Err(DrawError::HorizontalOverflow)); 168 | } 169 | 170 | #[test] 171 | fn vertical_overflow() { 172 | let data = ["123", "456", "789"]; 173 | let mut canvas = TextCanvas::new(3, 2); 174 | assert_eq!(canvas.draw(0, 0, &data), Err(DrawError::VerticalOverflow)); 175 | } 176 | 177 | #[test] 178 | fn unicode_boundaries() { 179 | // Draw a 4 byte character on the canvas, then try to replace it with a 1 byte character 180 | // and ensure that the replacement process respects the character boundaries. 181 | let mut canvas = TextCanvas::new(1, 1); 182 | 183 | let data = ["𩸽"]; 184 | canvas.draw(0, 0, &data).expect("Draw failed"); 185 | assert_eq!(canvas.content(), data.join("\n")); 186 | 187 | let data = ["a"]; 188 | canvas.draw(0, 0, &data).expect("Draw failed"); 189 | assert_eq!(canvas.content(), data.join("\n")); 190 | } 191 | 192 | #[test] 193 | fn region_draw() { 194 | let mut canvas = TextCanvas::new(3, 1); 195 | 196 | // Paint in a one pixel region 197 | let mut region1 = canvas.region(0, 0, 1, 1); 198 | let data = ["a"]; 199 | region1.draw(0, 0, &data).expect("Draw failed"); 200 | 201 | // Paint in a different one pixel region twice 202 | let mut region2 = canvas.region(2, 0, 1, 1); 203 | let data = ["z"]; 204 | region2.draw(0, 0, &data).expect("Draw failed"); 205 | let data = ["b"]; 206 | region2.draw(0, 0, &data).expect("Draw failed"); 207 | 208 | // Inspect the canvas content 209 | let expected = ["a b"]; 210 | assert_eq!(canvas.content(), expected.join("\n")); 211 | } 212 | 213 | #[test] 214 | fn region_horizontal_overflow() { 215 | let mut canvas = TextCanvas::new(3, 3); 216 | let mut region = canvas.region(0, 0, 1, 1); 217 | let data = ["a"]; 218 | assert_eq!(region.draw(1, 0, &data), Err(DrawError::HorizontalOverflow)); 219 | } 220 | 221 | #[test] 222 | fn region_vertical_overflow() { 223 | let mut canvas = TextCanvas::new(3, 3); 224 | let mut region = canvas.region(0, 0, 1, 1); 225 | let data = ["a"]; 226 | assert_eq!(region.draw(0, 1, &data), Err(DrawError::VerticalOverflow)); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /src/diagrams/seq/src/parser.rs: -------------------------------------------------------------------------------- 1 | use pest::Parser; 2 | 3 | #[derive(Parser)] 4 | #[grammar = "syntax.pest"] 5 | pub struct SequenceDiagramParser; 6 | 7 | #[derive(Debug, Clone, PartialEq)] 8 | pub enum EdgeStyle { 9 | Continuous, 10 | Dashed, 11 | } 12 | 13 | #[derive(Debug, Clone, PartialEq)] 14 | enum EdgeDirection { 15 | Left, 16 | Right, 17 | } 18 | 19 | fn parse_edge(edge: &str) -> Result<(EdgeStyle, EdgeDirection), ParserError> { 20 | match edge { 21 | "->" => Ok((EdgeStyle::Continuous, EdgeDirection::Right)), 22 | "-->" => Ok((EdgeStyle::Dashed, EdgeDirection::Right)), 23 | "<-" => Ok((EdgeStyle::Continuous, EdgeDirection::Left)), 24 | "<--" => Ok((EdgeStyle::Dashed, EdgeDirection::Left)), 25 | _ => Err(ParserError::SyntaxError("Invalid edge".to_string())), 26 | } 27 | } 28 | 29 | #[derive(Debug, Clone, PartialEq)] 30 | pub struct Alias { 31 | /// The ID of the node 32 | pub id: String, 33 | /// The label of the node 34 | pub label: String, 35 | } 36 | 37 | #[derive(Debug, Clone, PartialEq)] 38 | pub struct Message { 39 | /// The sender of the message 40 | pub source: String, 41 | /// The style of the message arrow 42 | pub edge_style: EdgeStyle, 43 | /// The recipient of the message 44 | pub target: String, 45 | /// The edge label 46 | pub payload: String, 47 | } 48 | 49 | #[derive(Debug, Clone, Default)] 50 | pub struct SequenceDiagram { 51 | /// List of aliases 52 | pub aliases: Vec, 53 | /// List of messages 54 | pub messages: Vec, 55 | } 56 | 57 | #[derive(Debug, PartialEq)] 58 | pub enum ParserError { 59 | SyntaxError(String), 60 | } 61 | 62 | pub fn diagram(input: &str) -> Result { 63 | let ast = SequenceDiagramParser::parse(Rule::main, input); 64 | match ast { 65 | // TODO: rename 66 | Ok(mut ast) => { 67 | let mut diag = SequenceDiagram::default(); 68 | for stmt in ast.next().unwrap().into_inner() { 69 | match stmt.as_rule() { 70 | Rule::alias => { 71 | // { ^"alias" ~ name ~ "=" ~ string } 72 | let mut inner_rules = stmt.into_inner(); 73 | 74 | let name: &str = inner_rules.next().unwrap().as_str(); 75 | let value: &str = inner_rules.next().unwrap().as_str(); 76 | 77 | diag.aliases.push(Alias { 78 | id: String::from(name), 79 | label: String::from(value), 80 | }); 81 | } 82 | Rule::pair => { 83 | // { name ~ edge ~ name ~ ":" ~ string } 84 | let mut inner_rules = stmt.into_inner(); 85 | 86 | let source: &str = inner_rules.next().unwrap().as_str(); 87 | let edge: &str = inner_rules.next().unwrap().as_str(); 88 | 89 | // Swap source and target if needed 90 | let (edge_style, edge_direction) = parse_edge(edge)?; 91 | let target: &str = inner_rules.next().unwrap().as_str(); 92 | let (source, target) = match edge_direction { 93 | EdgeDirection::Right => (source, target), 94 | EdgeDirection::Left => (target, source), 95 | }; 96 | let label: &str = match inner_rules.peek() { 97 | Some(_) => inner_rules.next().unwrap().as_str(), 98 | None => "", 99 | }; 100 | 101 | diag.messages.push(Message { 102 | source: String::from(source), 103 | target: String::from(target), 104 | payload: String::from(label), 105 | edge_style, 106 | }); 107 | } 108 | Rule::EOI => (), 109 | _ => unreachable!(), 110 | } 111 | } 112 | Ok(diag) 113 | } 114 | Err(e) => Err(ParserError::SyntaxError(e.to_string())), 115 | } 116 | } 117 | 118 | #[cfg(test)] 119 | mod test { 120 | use super::*; 121 | 122 | #[test] 123 | fn parse_diagram_empty() { 124 | let data = ""; 125 | let result = diagram(data).unwrap(); 126 | assert_eq!(result.aliases.len(), 0); 127 | assert_eq!(result.messages.len(), 0); 128 | } 129 | 130 | #[test] 131 | fn parse_comment() { 132 | let data = r#" 133 | # test 134 | // comment 135 | "#; 136 | let result = diagram(data).unwrap(); 137 | assert_eq!(result.aliases.len(), 0); 138 | assert_eq!(result.messages.len(), 0); 139 | } 140 | 141 | #[test] 142 | fn parse_empty_message() { 143 | let data = "a->b"; 144 | let result = diagram(data).unwrap(); 145 | assert_eq!(result.messages.len(), 1); 146 | assert_eq!(result.messages[0].payload, ""); 147 | } 148 | 149 | #[test] 150 | fn parse_handles_directions() { 151 | let data = "a->b"; 152 | let result = diagram(data).unwrap(); 153 | assert_eq!(result.messages[0].source, "a"); 154 | assert_eq!(result.messages[0].target, "b"); 155 | let data = "a<-b"; 156 | let result = diagram(data).unwrap(); 157 | assert_eq!(result.messages[0].source, "b"); 158 | assert_eq!(result.messages[0].target, "a"); 159 | } 160 | 161 | #[test] 162 | fn parse_message_payload_with_unicode() { 163 | let data = r#"a->b: "𩸽""#; 164 | let result = diagram(data).unwrap(); 165 | assert_eq!(result.messages.len(), 1); 166 | assert_eq!(result.messages[0].payload, "𩸽"); 167 | } 168 | 169 | #[test] 170 | // TODO: ensure that we handle the escape sequences correctly 171 | #[should_panic] 172 | fn parse_message_payload_with_escape_sequences() { 173 | let data = "a->b: \"\\\"hello\\\"\"\n"; 174 | let result = diagram(data).unwrap(); 175 | assert_eq!(result.messages.len(), 1); 176 | assert_eq!(result.messages[0].payload, "\"hello\""); 177 | } 178 | 179 | #[test] 180 | fn parse_message_distinguishes_edge_style() { 181 | let data = r#"a->b"#; 182 | let result = diagram(data).unwrap(); 183 | assert_eq!(result.messages[0].edge_style, EdgeStyle::Continuous); 184 | let data = r#"a-->b"#; 185 | let result = diagram(data).unwrap(); 186 | assert_eq!(result.messages[0].edge_style, EdgeStyle::Dashed); 187 | } 188 | 189 | #[test] 190 | fn disallows_keyword_identifiers() { 191 | let data = "alias alias = \"aliasson\""; 192 | let result = diagram(data); 193 | assert!(result.is_err()); 194 | } 195 | 196 | #[test] 197 | fn disallows_idedntifiers_with_numeric_prefix() { 198 | let data = "alias 1a = \"b\""; 199 | let result = diagram(data); 200 | assert!(result.is_err()); 201 | } 202 | 203 | #[test] 204 | fn allows_identifier_with_keyword_substring() { 205 | let data = "alias aliassson = \"aliasson\""; 206 | let result = diagram(data); 207 | assert!(!result.is_err()); 208 | } 209 | 210 | #[test] 211 | fn allows_underscores_in_identifiers() { 212 | let data = "alias _a_b_ = \"c\""; 213 | let result = diagram(data); 214 | assert!(!result.is_err()); 215 | } 216 | 217 | #[test] 218 | fn requires_a_space_after_alias_keyword() { 219 | let data = "aliasabc = \"d\""; 220 | let result = diagram(data); 221 | assert!(result.is_err()); 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /site/diagwiz/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ascii_canvas" 5 | version = "0.1.0" 6 | 7 | [[package]] 8 | name = "block-buffer" 9 | version = "0.7.3" 10 | source = "registry+https://github.com/rust-lang/crates.io-index" 11 | checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 12 | dependencies = [ 13 | "block-padding", 14 | "byte-tools", 15 | "byteorder", 16 | "generic-array", 17 | ] 18 | 19 | [[package]] 20 | name = "block-padding" 21 | version = "0.1.5" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" 24 | dependencies = [ 25 | "byte-tools", 26 | ] 27 | 28 | [[package]] 29 | name = "bumpalo" 30 | version = "3.6.1" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" 33 | 34 | [[package]] 35 | name = "byte-tools" 36 | version = "0.3.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 39 | 40 | [[package]] 41 | name = "byteorder" 42 | version = "1.4.3" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 45 | 46 | [[package]] 47 | name = "cassowary" 48 | version = "0.3.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 51 | 52 | [[package]] 53 | name = "cfg-if" 54 | version = "1.0.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 57 | 58 | [[package]] 59 | name = "diagram_base" 60 | version = "0.1.0" 61 | 62 | [[package]] 63 | name = "diagram_seq" 64 | version = "0.1.0" 65 | dependencies = [ 66 | "ascii_canvas", 67 | "cassowary", 68 | "diagram_base", 69 | "pest", 70 | "pest_derive", 71 | "unicode-segmentation", 72 | ] 73 | 74 | [[package]] 75 | name = "diagwiz" 76 | version = "0.1.0" 77 | dependencies = [ 78 | "diagram_base", 79 | "diagram_seq", 80 | "wasm-bindgen", 81 | ] 82 | 83 | [[package]] 84 | name = "digest" 85 | version = "0.8.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 88 | dependencies = [ 89 | "generic-array", 90 | ] 91 | 92 | [[package]] 93 | name = "fake-simd" 94 | version = "0.1.2" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 97 | 98 | [[package]] 99 | name = "generic-array" 100 | version = "0.12.4" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" 103 | dependencies = [ 104 | "typenum", 105 | ] 106 | 107 | [[package]] 108 | name = "lazy_static" 109 | version = "1.4.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 112 | 113 | [[package]] 114 | name = "log" 115 | version = "0.4.14" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 118 | dependencies = [ 119 | "cfg-if", 120 | ] 121 | 122 | [[package]] 123 | name = "maplit" 124 | version = "1.0.2" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 127 | 128 | [[package]] 129 | name = "opaque-debug" 130 | version = "0.2.3" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 133 | 134 | [[package]] 135 | name = "pest" 136 | version = "2.1.3" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 139 | dependencies = [ 140 | "ucd-trie", 141 | ] 142 | 143 | [[package]] 144 | name = "pest_derive" 145 | version = "2.1.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" 148 | dependencies = [ 149 | "pest", 150 | "pest_generator", 151 | ] 152 | 153 | [[package]] 154 | name = "pest_generator" 155 | version = "2.1.3" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" 158 | dependencies = [ 159 | "pest", 160 | "pest_meta", 161 | "proc-macro2", 162 | "quote", 163 | "syn", 164 | ] 165 | 166 | [[package]] 167 | name = "pest_meta" 168 | version = "2.1.3" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" 171 | dependencies = [ 172 | "maplit", 173 | "pest", 174 | "sha-1", 175 | ] 176 | 177 | [[package]] 178 | name = "proc-macro2" 179 | version = "1.0.24" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 182 | dependencies = [ 183 | "unicode-xid", 184 | ] 185 | 186 | [[package]] 187 | name = "quote" 188 | version = "1.0.9" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 191 | dependencies = [ 192 | "proc-macro2", 193 | ] 194 | 195 | [[package]] 196 | name = "sha-1" 197 | version = "0.8.2" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" 200 | dependencies = [ 201 | "block-buffer", 202 | "digest", 203 | "fake-simd", 204 | "opaque-debug", 205 | ] 206 | 207 | [[package]] 208 | name = "syn" 209 | version = "1.0.67" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" 212 | dependencies = [ 213 | "proc-macro2", 214 | "quote", 215 | "unicode-xid", 216 | ] 217 | 218 | [[package]] 219 | name = "typenum" 220 | version = "1.13.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" 223 | 224 | [[package]] 225 | name = "ucd-trie" 226 | version = "0.1.3" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 229 | 230 | [[package]] 231 | name = "unicode-segmentation" 232 | version = "1.7.1" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" 235 | 236 | [[package]] 237 | name = "unicode-xid" 238 | version = "0.2.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 241 | 242 | [[package]] 243 | name = "wasm-bindgen" 244 | version = "0.2.73" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" 247 | dependencies = [ 248 | "cfg-if", 249 | "wasm-bindgen-macro", 250 | ] 251 | 252 | [[package]] 253 | name = "wasm-bindgen-backend" 254 | version = "0.2.73" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" 257 | dependencies = [ 258 | "bumpalo", 259 | "lazy_static", 260 | "log", 261 | "proc-macro2", 262 | "quote", 263 | "syn", 264 | "wasm-bindgen-shared", 265 | ] 266 | 267 | [[package]] 268 | name = "wasm-bindgen-macro" 269 | version = "0.2.73" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" 272 | dependencies = [ 273 | "quote", 274 | "wasm-bindgen-macro-support", 275 | ] 276 | 277 | [[package]] 278 | name = "wasm-bindgen-macro-support" 279 | version = "0.2.73" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" 282 | dependencies = [ 283 | "proc-macro2", 284 | "quote", 285 | "syn", 286 | "wasm-bindgen-backend", 287 | "wasm-bindgen-shared", 288 | ] 289 | 290 | [[package]] 291 | name = "wasm-bindgen-shared" 292 | version = "0.2.73" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" 295 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ansi_term" 5 | version = "0.11.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 8 | dependencies = [ 9 | "winapi", 10 | ] 11 | 12 | [[package]] 13 | name = "ansi_term" 14 | version = "0.12.1" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 17 | dependencies = [ 18 | "winapi", 19 | ] 20 | 21 | [[package]] 22 | name = "ascii_canvas" 23 | version = "0.1.0" 24 | 25 | [[package]] 26 | name = "atty" 27 | version = "0.2.14" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 30 | dependencies = [ 31 | "hermit-abi", 32 | "libc", 33 | "winapi", 34 | ] 35 | 36 | [[package]] 37 | name = "bitflags" 38 | version = "1.2.1" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 41 | 42 | [[package]] 43 | name = "block-buffer" 44 | version = "0.7.3" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 47 | dependencies = [ 48 | "block-padding", 49 | "byte-tools", 50 | "byteorder", 51 | "generic-array", 52 | ] 53 | 54 | [[package]] 55 | name = "block-padding" 56 | version = "0.1.5" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" 59 | dependencies = [ 60 | "byte-tools", 61 | ] 62 | 63 | [[package]] 64 | name = "byte-tools" 65 | version = "0.3.1" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 68 | 69 | [[package]] 70 | name = "byteorder" 71 | version = "1.4.3" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 74 | 75 | [[package]] 76 | name = "cassowary" 77 | version = "0.3.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 80 | 81 | [[package]] 82 | name = "clap" 83 | version = "2.33.3" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 86 | dependencies = [ 87 | "ansi_term 0.11.0", 88 | "atty", 89 | "bitflags", 90 | "strsim", 91 | "textwrap", 92 | "unicode-width", 93 | "vec_map", 94 | ] 95 | 96 | [[package]] 97 | name = "ctor" 98 | version = "0.1.20" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" 101 | dependencies = [ 102 | "quote", 103 | "syn", 104 | ] 105 | 106 | [[package]] 107 | name = "diagram_base" 108 | version = "0.1.0" 109 | 110 | [[package]] 111 | name = "diagram_seq" 112 | version = "0.1.0" 113 | dependencies = [ 114 | "ascii_canvas", 115 | "cassowary", 116 | "diagram_base", 117 | "pest", 118 | "pest_derive", 119 | "pretty_assertions", 120 | "unicode-segmentation", 121 | ] 122 | 123 | [[package]] 124 | name = "diagwiz" 125 | version = "0.1.0" 126 | dependencies = [ 127 | "clap", 128 | "diagram_base", 129 | "diagram_seq", 130 | ] 131 | 132 | [[package]] 133 | name = "diff" 134 | version = "0.1.12" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" 137 | 138 | [[package]] 139 | name = "digest" 140 | version = "0.8.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 143 | dependencies = [ 144 | "generic-array", 145 | ] 146 | 147 | [[package]] 148 | name = "fake-simd" 149 | version = "0.1.2" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 152 | 153 | [[package]] 154 | name = "generic-array" 155 | version = "0.12.4" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" 158 | dependencies = [ 159 | "typenum", 160 | ] 161 | 162 | [[package]] 163 | name = "hermit-abi" 164 | version = "0.1.18" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 167 | dependencies = [ 168 | "libc", 169 | ] 170 | 171 | [[package]] 172 | name = "libc" 173 | version = "0.2.90" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" 176 | 177 | [[package]] 178 | name = "maplit" 179 | version = "1.0.2" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 182 | 183 | [[package]] 184 | name = "opaque-debug" 185 | version = "0.2.3" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 188 | 189 | [[package]] 190 | name = "output_vt100" 191 | version = "0.1.2" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" 194 | dependencies = [ 195 | "winapi", 196 | ] 197 | 198 | [[package]] 199 | name = "pest" 200 | version = "2.1.3" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 203 | dependencies = [ 204 | "ucd-trie", 205 | ] 206 | 207 | [[package]] 208 | name = "pest_derive" 209 | version = "2.1.0" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" 212 | dependencies = [ 213 | "pest", 214 | "pest_generator", 215 | ] 216 | 217 | [[package]] 218 | name = "pest_generator" 219 | version = "2.1.3" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" 222 | dependencies = [ 223 | "pest", 224 | "pest_meta", 225 | "proc-macro2", 226 | "quote", 227 | "syn", 228 | ] 229 | 230 | [[package]] 231 | name = "pest_meta" 232 | version = "2.1.3" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" 235 | dependencies = [ 236 | "maplit", 237 | "pest", 238 | "sha-1", 239 | ] 240 | 241 | [[package]] 242 | name = "pretty_assertions" 243 | version = "0.7.2" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" 246 | dependencies = [ 247 | "ansi_term 0.12.1", 248 | "ctor", 249 | "diff", 250 | "output_vt100", 251 | ] 252 | 253 | [[package]] 254 | name = "proc-macro2" 255 | version = "1.0.24" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 258 | dependencies = [ 259 | "unicode-xid", 260 | ] 261 | 262 | [[package]] 263 | name = "quote" 264 | version = "1.0.9" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 267 | dependencies = [ 268 | "proc-macro2", 269 | ] 270 | 271 | [[package]] 272 | name = "sha-1" 273 | version = "0.8.2" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" 276 | dependencies = [ 277 | "block-buffer", 278 | "digest", 279 | "fake-simd", 280 | "opaque-debug", 281 | ] 282 | 283 | [[package]] 284 | name = "strsim" 285 | version = "0.8.0" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 288 | 289 | [[package]] 290 | name = "syn" 291 | version = "1.0.64" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" 294 | dependencies = [ 295 | "proc-macro2", 296 | "quote", 297 | "unicode-xid", 298 | ] 299 | 300 | [[package]] 301 | name = "textwrap" 302 | version = "0.11.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 305 | dependencies = [ 306 | "unicode-width", 307 | ] 308 | 309 | [[package]] 310 | name = "typenum" 311 | version = "1.13.0" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" 314 | 315 | [[package]] 316 | name = "ucd-trie" 317 | version = "0.1.3" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 320 | 321 | [[package]] 322 | name = "unicode-segmentation" 323 | version = "1.7.1" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" 326 | 327 | [[package]] 328 | name = "unicode-width" 329 | version = "0.1.8" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 332 | 333 | [[package]] 334 | name = "unicode-xid" 335 | version = "0.2.1" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 338 | 339 | [[package]] 340 | name = "vec_map" 341 | version = "0.8.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 344 | 345 | [[package]] 346 | name = "winapi" 347 | version = "0.3.9" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 350 | dependencies = [ 351 | "winapi-i686-pc-windows-gnu", 352 | "winapi-x86_64-pc-windows-gnu", 353 | ] 354 | 355 | [[package]] 356 | name = "winapi-i686-pc-windows-gnu" 357 | version = "0.4.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 360 | 361 | [[package]] 362 | name = "winapi-x86_64-pc-windows-gnu" 363 | version = "0.4.0" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 366 | -------------------------------------------------------------------------------- /src/diagrams/seq/src/layout.rs: -------------------------------------------------------------------------------- 1 | /// Cassowary based layout generator 2 | use cassowary::strength::*; 3 | use core::marker::PhantomData; 4 | 5 | use ascii_canvas::{Draw, DrawResult, Rect, TextCanvas}; 6 | use cassowary::WeightedRelation::*; 7 | use cassowary::{Constraint, Expression, Solver, Variable}; 8 | use std::sync::Arc; 9 | use unicode_segmentation::UnicodeSegmentation; 10 | 11 | /// Renderable layout node 12 | /// A common set of variables for a renderable layout element 13 | struct Vars { 14 | /// X coordinate 15 | left: T, 16 | /// Y coordinate 17 | top: T, 18 | /// width 19 | width: T, 20 | /// height 21 | height: T, 22 | } 23 | 24 | // TODO: trait? 25 | impl Vars { 26 | /// Convenience method for creating new Vars 27 | fn new() -> Self { 28 | Self { 29 | left: Variable::new(), 30 | top: Variable::new(), 31 | width: Variable::new(), 32 | height: Variable::new(), 33 | } 34 | } 35 | 36 | fn right(&self) -> Expression { 37 | self.left + self.width 38 | } 39 | 40 | fn bottom(&self) -> Expression { 41 | self.top + self.height 42 | } 43 | 44 | fn center(&self) -> Expression { 45 | self.left + self.width / 2.0 46 | } 47 | } 48 | 49 | impl Vars { 50 | fn right(&self) -> usize { 51 | self.left + self.width 52 | } 53 | 54 | fn bottom(&self) -> usize { 55 | self.top + self.height 56 | } 57 | 58 | fn center(&self) -> usize { 59 | self.left + self.width / 2 60 | } 61 | } 62 | 63 | struct Node, C> { 64 | vars: Vars, 65 | constraints: Vec, 66 | data: T, 67 | _phantom: PhantomData, 68 | } 69 | 70 | impl, C> Node { 71 | fn coords(&self, solver: &Solver) -> Vars { 72 | // Into for Solver 73 | Vars { 74 | left: solver.get_value(self.vars.left) as usize, 75 | top: solver.get_value(self.vars.top) as usize, 76 | width: solver.get_value(self.vars.width) as usize, 77 | height: solver.get_value(self.vars.height) as usize, 78 | } 79 | } 80 | 81 | fn render(&self, canvas: &mut D, ctx: &C) -> DrawResult { 82 | self.data.render(canvas, &ctx) 83 | } 84 | } 85 | 86 | trait Render { 87 | fn render(&self, canvas: &mut D, ctx: &C) -> DrawResult; 88 | 89 | fn width(&self, _ctx: &C) -> Option { 90 | None 91 | } 92 | 93 | fn height(&self, _ctx: &C) -> Option { 94 | None 95 | } 96 | } 97 | 98 | #[derive(PartialEq)] 99 | pub struct Participant { 100 | pub id: String, 101 | pub name: String, 102 | } 103 | 104 | struct BareRenderCtx; 105 | 106 | impl Render for Arc { 107 | fn width(&self, _ctx: &BareRenderCtx) -> Option { 108 | let width = self.name.graphemes(true).count() + 4; 109 | 110 | // TODO: explore if we can do the rounding in the constraint solver instead 111 | // Ensure that the width is divisible by two to avoid decimals as we are rendering onto a 112 | // integer based coordinate system where decimals positions are not possible to represent 113 | Some((((width as f32) / 2.0).ceil() * 2.0) as usize) 114 | } 115 | 116 | fn height(&self, _ctx: &BareRenderCtx) -> Option { 117 | Some(3) 118 | } 119 | 120 | fn render(&self, canvas: &mut D, _ctx: &BareRenderCtx) -> DrawResult { 121 | let Rect { width, .. } = canvas.bounds(); 122 | let name_len = self.name.graphemes(true).count(); 123 | let mut repr = String::from(""); 124 | let segments = [ 125 | "┌", 126 | &"─".repeat(width - 2), 127 | "┐", 128 | "\n", 129 | "│", 130 | &" ".repeat(1), 131 | &self.name, 132 | &" ".repeat(width - name_len - 3), 133 | "│", 134 | "\n", 135 | "└", 136 | &"─".repeat(width - 2), 137 | "┘", 138 | ]; 139 | for segment in segments.iter() { 140 | repr.push_str(segment); 141 | } 142 | 143 | canvas.draw(0, 0, &repr.split('\n').collect::>())?; 144 | Ok(()) 145 | } 146 | } 147 | 148 | #[derive(Debug, Clone, PartialEq)] 149 | pub enum EdgeStyle { 150 | Continuous, 151 | Dashed, 152 | } 153 | 154 | pub struct Message { 155 | pub source: Arc, 156 | pub target: Arc, 157 | pub payload: String, 158 | pub edge_style: EdgeStyle, 159 | } 160 | 161 | struct MessageRenderCtx { 162 | source_idx: usize, 163 | target_idx: usize, 164 | } 165 | 166 | impl MessageRenderCtx { 167 | fn is_loop(&self) -> bool { 168 | self.source_idx == self.target_idx 169 | } 170 | } 171 | 172 | impl Render for Message { 173 | fn width(&self, ctx: &MessageRenderCtx) -> Option { 174 | let len = self.payload.graphemes(true).count(); 175 | let width = match ctx.is_loop() { 176 | // Put the text to the right of the loop arrow + some spacing 177 | true => len + 3 + 3, 178 | // Reserve enough space for the arrow + some spacing 179 | false => len + 4, 180 | }; 181 | // Ensure that the width is divisible by two to avoid decimals as we are rendering onto a 182 | // integer based coordinate system where decimals positions are not possible to represent 183 | Some((((width as f32) / 2.0).ceil() * 2.0) as usize) 184 | } 185 | 186 | fn height(&self, ctx: &MessageRenderCtx) -> Option { 187 | match ctx.is_loop() { 188 | true => Some(4), 189 | false => Some(3), 190 | } 191 | } 192 | 193 | fn render(&self, canvas: &mut D, ctx: &MessageRenderCtx) -> DrawResult { 194 | let Rect { width, .. } = canvas.bounds(); 195 | let payload = &self.payload; 196 | let len = payload.graphemes(true).count(); 197 | 198 | match ctx.is_loop() { 199 | true => { 200 | canvas.draw(0, 0, &["─┐", " │", "◀┘"])?; 201 | let spacer = " ".repeat(len); 202 | canvas.draw(3, 0, &[spacer.as_str(), payload.as_str(), spacer.as_str()])?; 203 | } 204 | false => { 205 | let left_padding = ((width - len) / 2) as usize; 206 | let arrow_char = match self.edge_style { 207 | EdgeStyle::Continuous => '─', 208 | EdgeStyle::Dashed => '-', 209 | }; 210 | 211 | let mut arrow = arrow_char.to_string().repeat(width - 2); 212 | match ctx.source_idx > ctx.target_idx { 213 | true => { 214 | arrow.push(arrow_char); 215 | arrow.insert(0, '◀'); 216 | } 217 | false => { 218 | arrow.insert(0, arrow_char); 219 | arrow.push('▶'); 220 | } 221 | } 222 | 223 | canvas.draw(left_padding, 0, &[payload.as_str()])?; 224 | canvas.draw(0, 1, &[arrow.as_str()])?; 225 | } 226 | } 227 | 228 | Ok(()) 229 | } 230 | } 231 | 232 | pub struct Layout { 233 | solver: Solver, 234 | participants: Vec, BareRenderCtx>>, 235 | messages: Vec>, 236 | } 237 | 238 | impl Layout { 239 | pub fn new() -> Self { 240 | Self { 241 | solver: Solver::new(), 242 | participants: Vec::new(), 243 | messages: Vec::new(), 244 | } 245 | } 246 | 247 | pub fn add_participant(&mut self, participant: Arc) { 248 | let spacing = 1.0; 249 | 250 | // Compute the left coordinate for the new participant 251 | let right = match self.participants.last() { 252 | Some(node) => node.vars.right() + spacing, 253 | None => Expression::from(0.0), 254 | }; 255 | 256 | // Setup the initial constraints 257 | let render_ctx = BareRenderCtx {}; 258 | let vars = Vars::new(); 259 | let constraints = vec![ 260 | vars.left | GE(REQUIRED) | right, 261 | vars.top | GE(REQUIRED) | 0.0, 262 | vars.width 263 | | EQ(REQUIRED) 264 | | participant 265 | .width(&render_ctx) 266 | .expect("Participant missing width") as f32, 267 | vars.height 268 | | EQ(REQUIRED) 269 | | participant 270 | .height(&render_ctx) 271 | .expect("Participant missing height") as f32, 272 | ]; 273 | 274 | self.participants.push(Node { 275 | vars, 276 | constraints, 277 | data: participant, 278 | _phantom: PhantomData, 279 | }); 280 | } 281 | 282 | pub fn add_message(&mut self, message: Message) { 283 | // Fetch the source and target nodes 284 | let mut participant_nodes = self.participants.iter_mut(); 285 | 286 | // Find the participant to the left of the message 287 | let source_or_target = 288 | |p: &&mut Node<_, _>| p.data == message.source || p.data == message.target; 289 | let left_participant = participant_nodes.find(source_or_target).unwrap(); 290 | 291 | // Find the participant to the right of the message. In case of loops, take just the 292 | // consecutive participant from the iterator. 293 | let right_participant = { 294 | let next_node = participant_nodes.next(); 295 | let target_node = participant_nodes.find(source_or_target); 296 | next_node.filter(source_or_target).or(target_node) 297 | }; 298 | 299 | // Compute the top coordinate for the new message 300 | let top = self 301 | .messages 302 | .last() 303 | .map(|msg| msg.vars.bottom()) 304 | .or_else(|| Some(left_participant.vars.bottom())) 305 | .unwrap(); 306 | 307 | // Construct the render context used to calculate the message with and height 308 | let render_ctx = MessageRenderCtx { 309 | source_idx: 0, 310 | target_idx: right_participant 311 | .as_ref() 312 | .map(|p| !(left_participant.data == p.data) as usize) 313 | .unwrap_or(0), 314 | }; 315 | 316 | // Constraint the new message bounds in relation to the participants 317 | let vars = Vars::new(); 318 | let mut constraints = vec![ 319 | vars.top | EQ(REQUIRED) | top, 320 | vars.left | EQ(REQUIRED) | (left_participant.vars.center() + 1.0), 321 | vars.width 322 | | GE(REQUIRED) 323 | | message.width(&render_ctx).expect("Message missing width") as f64, 324 | vars.height 325 | | EQ(REQUIRED) 326 | | message.height(&render_ctx).expect("Message missing height") as f64, 327 | ]; 328 | 329 | if let Some(right_participant) = right_participant { 330 | // Stretch the message to all the way to the participant on the right 331 | constraints.push(vars.right() | EQ(REQUIRED) | right_participant.vars.center()); 332 | 333 | // Make space for the new message 334 | right_participant 335 | .constraints 336 | .push(right_participant.vars.center() | GE(REQUIRED) | vars.right()); 337 | } 338 | 339 | self.messages.push(Node { 340 | vars, 341 | constraints, 342 | data: message, 343 | _phantom: PhantomData, 344 | }); 345 | } 346 | 347 | /// Renders the layout and consumes itself. 348 | pub fn render(mut self) -> String { 349 | self.solver 350 | .add_constraints( 351 | self.participants 352 | .iter() 353 | .flat_map(|node| &node.constraints) 354 | .collect::>(), 355 | ) 356 | .expect("Could not add the constraints"); 357 | self.solver 358 | .add_constraints( 359 | self.messages 360 | .iter() 361 | .flat_map(|node| &node.constraints) 362 | .collect::>(), 363 | ) 364 | .expect("Could not add the constraints"); 365 | 366 | // Compute the required canvas size 367 | let max_right = self 368 | .participants 369 | .iter() 370 | .map(|p| p.coords(&self.solver).right()) 371 | .chain(self.messages.iter().map(|p| p.coords(&self.solver).right())) 372 | .max() 373 | .map(|right| right + 1) 374 | .unwrap_or(0); 375 | let max_bottom = self 376 | .participants 377 | .iter() 378 | .map(|p| p.coords(&self.solver).bottom()) 379 | .chain( 380 | self.messages 381 | .iter() 382 | .map(|p| p.coords(&self.solver).bottom()), 383 | ) 384 | .max() 385 | .map(|bottom| bottom + 3) 386 | .unwrap_or(0); 387 | 388 | // Render the layout 389 | let bare_ctx = BareRenderCtx {}; 390 | 391 | // Setup the canvas 392 | let mut canvas = TextCanvas::new(max_right, max_bottom); 393 | 394 | // Draw the participants and their lifelines 395 | let lifeline = vec!["│"; max_bottom]; 396 | for node in &self.participants { 397 | let coords = node.coords(&self.solver); 398 | canvas 399 | .draw(coords.center(), 0, &lifeline) 400 | .expect("Draw failed"); 401 | 402 | node.render( 403 | &mut canvas.region(coords.left, coords.top, coords.width, coords.height), 404 | &bare_ctx, 405 | ) 406 | .expect("Draw failed"); 407 | node.render( 408 | &mut canvas.region(coords.left, max_bottom - 3, coords.width, coords.height), 409 | &bare_ctx, 410 | ) 411 | .expect("Draw failed"); 412 | } 413 | 414 | // Draw the messages 415 | for node in &self.messages { 416 | let coords = node.coords(&self.solver); 417 | let source_idx = self 418 | .participants 419 | .iter() 420 | .position(|p| p.data == node.data.source) 421 | .unwrap(); 422 | let target_idx = self 423 | .participants 424 | .iter() 425 | .position(|p| p.data == node.data.target) 426 | .unwrap(); 427 | node.render( 428 | &mut canvas.region(coords.left, coords.top, coords.width, coords.height), 429 | &MessageRenderCtx { 430 | source_idx, 431 | target_idx, 432 | }, 433 | ) 434 | .expect("Draw failed"); 435 | } 436 | canvas.content() 437 | } 438 | } 439 | 440 | #[cfg(test)] 441 | mod test { 442 | use super::*; 443 | 444 | #[test] 445 | fn smoke() { 446 | let mut layout = Layout::new(); 447 | let participant_alice = Arc::from(Participant { 448 | id: "alice".into(), 449 | name: "Alice".into(), 450 | }); 451 | let participant_bob = Arc::from(Participant { 452 | id: "bob".into(), 453 | name: "Bob".into(), 454 | }); 455 | layout.add_participant(participant_alice.clone()); 456 | layout.add_participant(participant_bob.clone()); 457 | layout.add_message(Message { 458 | source: participant_alice.clone(), 459 | target: participant_bob.clone(), 460 | payload: "hello".to_string(), 461 | edge_style: EdgeStyle::Continuous, 462 | }); 463 | layout.add_message(Message { 464 | source: participant_bob.clone(), 465 | target: participant_alice.clone(), 466 | payload: "hello back".to_string(), 467 | edge_style: EdgeStyle::Continuous, 468 | }); 469 | layout.add_message(Message { 470 | source: participant_bob.clone(), 471 | target: participant_bob.clone(), 472 | payload: "who am i?".to_string(), 473 | edge_style: EdgeStyle::Dashed, 474 | }); 475 | let output = layout.render(); 476 | assert!(output.len() > 0); 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /site/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "site", 3 | "version": "0.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.12.11", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", 10 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.10.4" 14 | } 15 | }, 16 | "@babel/helper-validator-identifier": { 17 | "version": "7.12.11", 18 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 19 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", 20 | "dev": true 21 | }, 22 | "@babel/highlight": { 23 | "version": "7.13.10", 24 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", 25 | "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", 26 | "dev": true, 27 | "requires": { 28 | "@babel/helper-validator-identifier": "^7.12.11", 29 | "chalk": "^2.0.0", 30 | "js-tokens": "^4.0.0" 31 | }, 32 | "dependencies": { 33 | "ansi-styles": { 34 | "version": "3.2.1", 35 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 36 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 37 | "dev": true, 38 | "requires": { 39 | "color-convert": "^1.9.0" 40 | } 41 | }, 42 | "chalk": { 43 | "version": "2.4.2", 44 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 45 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 46 | "dev": true, 47 | "requires": { 48 | "ansi-styles": "^3.2.1", 49 | "escape-string-regexp": "^1.0.5", 50 | "supports-color": "^5.3.0" 51 | } 52 | }, 53 | "color-convert": { 54 | "version": "1.9.3", 55 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 56 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 57 | "dev": true, 58 | "requires": { 59 | "color-name": "1.1.3" 60 | } 61 | }, 62 | "color-name": { 63 | "version": "1.1.3", 64 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 65 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 66 | "dev": true 67 | }, 68 | "has-flag": { 69 | "version": "3.0.0", 70 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 71 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 72 | "dev": true 73 | }, 74 | "supports-color": { 75 | "version": "5.5.0", 76 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 77 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 78 | "dev": true, 79 | "requires": { 80 | "has-flag": "^3.0.0" 81 | } 82 | } 83 | } 84 | }, 85 | "@codemirror/autocomplete": { 86 | "version": "0.18.3", 87 | "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-0.18.3.tgz", 88 | "integrity": "sha512-XAilIpYxsessr3Zh39nc5T97Zz9wLMwQTCDlIKapm/VK3JnX1I1jkoe8JqpbyVyabVxGXpB2K88GIVS9X+nLZQ==", 89 | "dev": true, 90 | "requires": { 91 | "@codemirror/language": "^0.18.0", 92 | "@codemirror/state": "^0.18.0", 93 | "@codemirror/text": "^0.18.0", 94 | "@codemirror/tooltip": "^0.18.4", 95 | "@codemirror/view": "^0.18.0", 96 | "lezer-tree": "^0.13.0" 97 | } 98 | }, 99 | "@codemirror/basic-setup": { 100 | "version": "0.18.0", 101 | "resolved": "https://registry.npmjs.org/@codemirror/basic-setup/-/basic-setup-0.18.0.tgz", 102 | "integrity": "sha512-3IU6gBIkVVCF+ZtKqzCmYU1GLfbA12OsPYPWWq9rSzEb5G/FrWCA51ERYJpS3CzOI7TfBFjZZYc5j0OiNIF2VQ==", 103 | "dev": true, 104 | "requires": { 105 | "@codemirror/autocomplete": "^0.18.0", 106 | "@codemirror/closebrackets": "^0.18.0", 107 | "@codemirror/commands": "^0.18.0", 108 | "@codemirror/comment": "^0.18.0", 109 | "@codemirror/fold": "^0.18.0", 110 | "@codemirror/gutter": "^0.18.0", 111 | "@codemirror/highlight": "^0.18.0", 112 | "@codemirror/history": "^0.18.0", 113 | "@codemirror/language": "^0.18.0", 114 | "@codemirror/lint": "^0.18.0", 115 | "@codemirror/matchbrackets": "^0.18.0", 116 | "@codemirror/rectangular-selection": "^0.18.0", 117 | "@codemirror/search": "^0.18.0", 118 | "@codemirror/state": "^0.18.0", 119 | "@codemirror/view": "^0.18.0" 120 | } 121 | }, 122 | "@codemirror/closebrackets": { 123 | "version": "0.18.0", 124 | "resolved": "https://registry.npmjs.org/@codemirror/closebrackets/-/closebrackets-0.18.0.tgz", 125 | "integrity": "sha512-O1RAgUkzF4nq/B8IyXenZKZ1rJi2Mc7I6y4IhWhELiTnjyQy7YdAthTsJ40mNr8kZ6gRbasYe3K7TraITElZJA==", 126 | "dev": true, 127 | "requires": { 128 | "@codemirror/language": "^0.18.0", 129 | "@codemirror/rangeset": "^0.18.0", 130 | "@codemirror/state": "^0.18.0", 131 | "@codemirror/text": "^0.18.0", 132 | "@codemirror/view": "^0.18.0" 133 | } 134 | }, 135 | "@codemirror/commands": { 136 | "version": "0.18.0", 137 | "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-0.18.0.tgz", 138 | "integrity": "sha512-4H63B4oqr8dmJ3VOKvMI7xrZIBJjAdtz3Z0V/Jt0HlIYTe76Omy4h9BS3b9EgyNaWjIO/Slz3KQPwihcC8uR5Q==", 139 | "dev": true, 140 | "requires": { 141 | "@codemirror/language": "^0.18.0", 142 | "@codemirror/matchbrackets": "^0.18.0", 143 | "@codemirror/state": "^0.18.0", 144 | "@codemirror/text": "^0.18.0", 145 | "@codemirror/view": "^0.18.0", 146 | "lezer-tree": "^0.13.0" 147 | } 148 | }, 149 | "@codemirror/comment": { 150 | "version": "0.18.0", 151 | "resolved": "https://registry.npmjs.org/@codemirror/comment/-/comment-0.18.0.tgz", 152 | "integrity": "sha512-yb/8dz/zIzXIa00L0Ed7/R8m2FupPZux/EMquwzbAOnTNcXeeaPVcp9kEMPf85b9D82csunXXdiOSalBVGjKWQ==", 153 | "dev": true, 154 | "requires": { 155 | "@codemirror/state": "^0.18.0", 156 | "@codemirror/text": "^0.18.0", 157 | "@codemirror/view": "^0.18.0" 158 | } 159 | }, 160 | "@codemirror/fold": { 161 | "version": "0.18.0", 162 | "resolved": "https://registry.npmjs.org/@codemirror/fold/-/fold-0.18.0.tgz", 163 | "integrity": "sha512-qZsl85rp1Wm2ifaw1E25paDRVGr0m2vKRIoUG5mv+G2NxJx6lsuMLgU7MKIJQ+3iDHUR2is2yU8d6lOwwp5IEg==", 164 | "dev": true, 165 | "requires": { 166 | "@codemirror/gutter": "^0.18.0", 167 | "@codemirror/language": "^0.18.0", 168 | "@codemirror/rangeset": "^0.18.0", 169 | "@codemirror/state": "^0.18.0", 170 | "@codemirror/view": "^0.18.0" 171 | } 172 | }, 173 | "@codemirror/gutter": { 174 | "version": "0.18.0", 175 | "resolved": "https://registry.npmjs.org/@codemirror/gutter/-/gutter-0.18.0.tgz", 176 | "integrity": "sha512-9hcKzBM5EjhWwrau5Xiv0ll/yOvkgiyLnH7DTsjFCUvuyfbS45WVEMhQ6C+HfsoRVR4TJqRVLJjaIktZqaAqnw==", 177 | "dev": true, 178 | "requires": { 179 | "@codemirror/rangeset": "^0.18.0", 180 | "@codemirror/state": "^0.18.0", 181 | "@codemirror/view": "^0.18.0" 182 | } 183 | }, 184 | "@codemirror/highlight": { 185 | "version": "0.18.3", 186 | "resolved": "https://registry.npmjs.org/@codemirror/highlight/-/highlight-0.18.3.tgz", 187 | "integrity": "sha512-NmRmkmWl8ht6Y6Y39ghov84AMPCqhUPIH9fmILs2NaWxZFZf4jGCTzrULnmREGsTie+26+LbKUncIU+PBu1Qng==", 188 | "dev": true, 189 | "requires": { 190 | "@codemirror/language": "^0.18.0", 191 | "@codemirror/rangeset": "^0.18.0", 192 | "@codemirror/state": "^0.18.0", 193 | "@codemirror/view": "^0.18.0", 194 | "lezer-tree": "^0.13.0", 195 | "style-mod": "^4.0.0" 196 | } 197 | }, 198 | "@codemirror/history": { 199 | "version": "0.18.1", 200 | "resolved": "https://registry.npmjs.org/@codemirror/history/-/history-0.18.1.tgz", 201 | "integrity": "sha512-Aad3p4zs6UYKCUMXYjh7cvPK0ajuL+rMib9yBZ61w81LLl6OkM31Xrn9J6CLJmPxCwP3OJFiqBmNSBQ05oIsTw==", 202 | "dev": true, 203 | "requires": { 204 | "@codemirror/state": "^0.18.3", 205 | "@codemirror/view": "^0.18.0" 206 | } 207 | }, 208 | "@codemirror/language": { 209 | "version": "0.18.1", 210 | "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-0.18.1.tgz", 211 | "integrity": "sha512-j/TWV8sNmzU79kk/hPLb9NqSPoH59850kQSpgY11LxOEBlKVRKgaWabgNtUCSeVCAnfisGekupk3aq2ftILqug==", 212 | "dev": true, 213 | "requires": { 214 | "@codemirror/state": "^0.18.0", 215 | "@codemirror/text": "^0.18.0", 216 | "@codemirror/view": "^0.18.0", 217 | "lezer": "^0.13.4", 218 | "lezer-tree": "^0.13.0" 219 | } 220 | }, 221 | "@codemirror/lint": { 222 | "version": "0.18.1", 223 | "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-0.18.1.tgz", 224 | "integrity": "sha512-2Ueg/ojU56vF5thxMdS67XQzvHNcBnPKw2zgbDVmL/Z+84SMjP7EKvHV5FlbrKFNGZiwnaAKk5MZRYUwBY3f0g==", 225 | "dev": true, 226 | "requires": { 227 | "@codemirror/panel": "^0.18.1", 228 | "@codemirror/state": "^0.18.0", 229 | "@codemirror/tooltip": "^0.18.4", 230 | "@codemirror/view": "^0.18.0", 231 | "crelt": "^1.0.5" 232 | } 233 | }, 234 | "@codemirror/matchbrackets": { 235 | "version": "0.18.0", 236 | "resolved": "https://registry.npmjs.org/@codemirror/matchbrackets/-/matchbrackets-0.18.0.tgz", 237 | "integrity": "sha512-dPDopnZVkD54sSYdmQbyQbPdiuIA83p7XxX6Hp1ScEkOjukwCiFXiA/84x10FUTsQpUYp8bDzm7gwII119bGIw==", 238 | "dev": true, 239 | "requires": { 240 | "@codemirror/language": "^0.18.0", 241 | "@codemirror/state": "^0.18.0", 242 | "@codemirror/view": "^0.18.0", 243 | "lezer-tree": "^0.13.0" 244 | } 245 | }, 246 | "@codemirror/panel": { 247 | "version": "0.18.1", 248 | "resolved": "https://registry.npmjs.org/@codemirror/panel/-/panel-0.18.1.tgz", 249 | "integrity": "sha512-5Zo9cUw0QDlFzX4nhIDYjTARPOnPk5rzxAUQo1O35kTLV+6zRh7wsGlvU7VrZnBcIoaAmHfKrZ4lt6+h7fbFGw==", 250 | "dev": true, 251 | "requires": { 252 | "@codemirror/state": "^0.18.0", 253 | "@codemirror/view": "^0.18.0" 254 | } 255 | }, 256 | "@codemirror/rangeset": { 257 | "version": "0.18.0", 258 | "resolved": "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.18.0.tgz", 259 | "integrity": "sha512-+dpK3T6EFv2vkoAc3sTZld0N5SHZDjD3YowFYuMWn0Xw3t+u6k+JZlGBuaFTXdsLeF0auclsm0XhRUpMVuXhTg==", 260 | "dev": true, 261 | "requires": { 262 | "@codemirror/state": "^0.18.0" 263 | } 264 | }, 265 | "@codemirror/rectangular-selection": { 266 | "version": "0.18.0", 267 | "resolved": "https://registry.npmjs.org/@codemirror/rectangular-selection/-/rectangular-selection-0.18.0.tgz", 268 | "integrity": "sha512-BQ4pp2zhXCVZNqct5LtLR3AOWVseENBF/3oOgBmwsCKH7c11NfTqIqgWG5EW8NLOXp8HP8cDm3np8eWez0VkGQ==", 269 | "dev": true, 270 | "requires": { 271 | "@codemirror/state": "^0.18.0", 272 | "@codemirror/text": "^0.18.0", 273 | "@codemirror/view": "^0.18.0" 274 | } 275 | }, 276 | "@codemirror/search": { 277 | "version": "0.18.2", 278 | "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-0.18.2.tgz", 279 | "integrity": "sha512-t90Ra34piJDF589hNDmuA1fVKCFDh0FTuTZTHDmmSaWS5OWq2++zAwRTQnOdQD+uGfEUwLQPiLJzu60NDhA5xw==", 280 | "dev": true, 281 | "requires": { 282 | "@codemirror/panel": "^0.18.1", 283 | "@codemirror/rangeset": "^0.18.0", 284 | "@codemirror/state": "^0.18.0", 285 | "@codemirror/text": "^0.18.0", 286 | "@codemirror/view": "^0.18.0", 287 | "crelt": "^1.0.5" 288 | } 289 | }, 290 | "@codemirror/state": { 291 | "version": "0.18.3", 292 | "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-0.18.3.tgz", 293 | "integrity": "sha512-LQlQWFAw+OLd1ufdf8o8yU/iJd88ixw8kOQ8KgEHDZJnegJOz0NafXvkFoWPiLNaiIUxif02KlZXJAPqDThZ4g==", 294 | "dev": true, 295 | "requires": { 296 | "@codemirror/text": "^0.18.0" 297 | } 298 | }, 299 | "@codemirror/text": { 300 | "version": "0.18.0", 301 | "resolved": "https://registry.npmjs.org/@codemirror/text/-/text-0.18.0.tgz", 302 | "integrity": "sha512-HMzHNIAbjCiCf3tEJMRg6ul01KPuXxQGNiHlHgAnqPguq/CX+L4Nvj5JlWQAI91Pupk18zhmM1c6eaazX4YeTg==", 303 | "dev": true 304 | }, 305 | "@codemirror/tooltip": { 306 | "version": "0.18.4", 307 | "resolved": "https://registry.npmjs.org/@codemirror/tooltip/-/tooltip-0.18.4.tgz", 308 | "integrity": "sha512-LDlDOSEfjoG24uapLN7exK3Z3JchYFKUwWqo1x/9YdlAkmD1ik7cMSQZboCquP1uJVcXhtbpKmaO6vENGVaarg==", 309 | "dev": true, 310 | "requires": { 311 | "@codemirror/state": "^0.18.0", 312 | "@codemirror/view": "^0.18.0" 313 | } 314 | }, 315 | "@codemirror/view": { 316 | "version": "0.18.3", 317 | "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-0.18.3.tgz", 318 | "integrity": "sha512-9scPYgDoUFRjDKjClCIxPBMZuoiATn01gKGm/OqSODUcsWQ37LS9qs/gJNdrIn8gQNlzI9wNRyBck7ycZo4Rng==", 319 | "dev": true, 320 | "requires": { 321 | "@codemirror/rangeset": "^0.18.0", 322 | "@codemirror/state": "^0.18.0", 323 | "@codemirror/text": "^0.18.0", 324 | "style-mod": "^4.0.0", 325 | "w3c-keyname": "^2.2.4" 326 | } 327 | }, 328 | "@eslint/eslintrc": { 329 | "version": "0.4.0", 330 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", 331 | "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", 332 | "dev": true, 333 | "requires": { 334 | "ajv": "^6.12.4", 335 | "debug": "^4.1.1", 336 | "espree": "^7.3.0", 337 | "globals": "^12.1.0", 338 | "ignore": "^4.0.6", 339 | "import-fresh": "^3.2.1", 340 | "js-yaml": "^3.13.1", 341 | "minimatch": "^3.0.4", 342 | "strip-json-comments": "^3.1.1" 343 | }, 344 | "dependencies": { 345 | "globals": { 346 | "version": "12.4.0", 347 | "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", 348 | "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", 349 | "dev": true, 350 | "requires": { 351 | "type-fest": "^0.8.1" 352 | } 353 | }, 354 | "ignore": { 355 | "version": "4.0.6", 356 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 357 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 358 | "dev": true 359 | } 360 | } 361 | }, 362 | "@nodelib/fs.scandir": { 363 | "version": "2.1.4", 364 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", 365 | "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", 366 | "dev": true, 367 | "requires": { 368 | "@nodelib/fs.stat": "2.0.4", 369 | "run-parallel": "^1.1.9" 370 | } 371 | }, 372 | "@nodelib/fs.stat": { 373 | "version": "2.0.4", 374 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", 375 | "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", 376 | "dev": true 377 | }, 378 | "@nodelib/fs.walk": { 379 | "version": "1.2.6", 380 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", 381 | "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", 382 | "dev": true, 383 | "requires": { 384 | "@nodelib/fs.scandir": "2.1.4", 385 | "fastq": "^1.6.0" 386 | } 387 | }, 388 | "@rollup/pluginutils": { 389 | "version": "4.1.0", 390 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.0.tgz", 391 | "integrity": "sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ==", 392 | "dev": true, 393 | "requires": { 394 | "estree-walker": "^2.0.1", 395 | "picomatch": "^2.2.2" 396 | } 397 | }, 398 | "@sveltejs/adapter-static": { 399 | "version": "1.0.0-next.4", 400 | "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-1.0.0-next.4.tgz", 401 | "integrity": "sha512-Atri/5jyiVmAklqDKb/5czmLkHos6LQOag61k/C6qWozMb8UopvL3bTm62hFQXGKvGnuSRq2xIueDOKWHM/7rA==", 402 | "dev": true 403 | }, 404 | "@sveltejs/kit": { 405 | "version": "1.0.0-next.71", 406 | "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.71.tgz", 407 | "integrity": "sha512-9oZEKtuFpmJanL0u7oJPWIoC4kWMtNSuN1SN7xKo+g54xI6JcsoH2J15OkTU89Hsd9Ctp4/OTh9j6/vgq9J7gw==", 408 | "dev": true, 409 | "requires": { 410 | "@sveltejs/vite-plugin-svelte": "^1.0.0-next.5", 411 | "cheap-watch": "^1.0.3", 412 | "sade": "^1.7.4" 413 | } 414 | }, 415 | "@sveltejs/vite-plugin-svelte": { 416 | "version": "1.0.0-next.5", 417 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.5.tgz", 418 | "integrity": "sha512-RVjafsqziWwnQm8VEy2y0qNaugNDvRd8tTaCt9rjgQkqaS/BDiyDCluXxA28PRC+ddZjvwUeq9k+0EfbLVObfg==", 419 | "dev": true, 420 | "requires": { 421 | "@rollup/pluginutils": "^4.1.0", 422 | "chalk": "^4.1.0", 423 | "debug": "^4.3.2", 424 | "hash-sum": "^2.0.0", 425 | "require-relative": "^0.8.7", 426 | "slash": "^3.0.0", 427 | "source-map": "^0.7.3", 428 | "svelte-hmr": "^0.13.3" 429 | } 430 | }, 431 | "@types/json-schema": { 432 | "version": "7.0.7", 433 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", 434 | "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", 435 | "dev": true 436 | }, 437 | "@types/lz-string": { 438 | "version": "1.3.34", 439 | "resolved": "https://registry.npmjs.org/@types/lz-string/-/lz-string-1.3.34.tgz", 440 | "integrity": "sha512-j6G1e8DULJx3ONf6NdR5JiR2ZY3K3PaaqiEuKYkLQO0Czfi1AzrtjfnfCROyWGeDd5IVMKCwsgSmMip9OWijow==", 441 | "dev": true 442 | }, 443 | "@types/node": { 444 | "version": "14.14.37", 445 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", 446 | "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", 447 | "dev": true 448 | }, 449 | "@types/pug": { 450 | "version": "2.0.4", 451 | "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.4.tgz", 452 | "integrity": "sha1-h3L80EGOPNLMFxVV1zAHQVBR9LI=", 453 | "dev": true 454 | }, 455 | "@types/sass": { 456 | "version": "1.16.0", 457 | "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.16.0.tgz", 458 | "integrity": "sha512-2XZovu4NwcqmtZtsBR5XYLw18T8cBCnU2USFHTnYLLHz9fkhnoEMoDsqShJIOFsFhn5aJHjweiUUdTrDGujegA==", 459 | "dev": true, 460 | "requires": { 461 | "@types/node": "*" 462 | } 463 | }, 464 | "@typescript-eslint/eslint-plugin": { 465 | "version": "4.20.0", 466 | "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.20.0.tgz", 467 | "integrity": "sha512-sw+3HO5aehYqn5w177z2D82ZQlqHCwcKSMboueo7oE4KU9QiC0SAgfS/D4z9xXvpTc8Bt41Raa9fBR8T2tIhoQ==", 468 | "dev": true, 469 | "requires": { 470 | "@typescript-eslint/experimental-utils": "4.20.0", 471 | "@typescript-eslint/scope-manager": "4.20.0", 472 | "debug": "^4.1.1", 473 | "functional-red-black-tree": "^1.0.1", 474 | "lodash": "^4.17.15", 475 | "regexpp": "^3.0.0", 476 | "semver": "^7.3.2", 477 | "tsutils": "^3.17.1" 478 | } 479 | }, 480 | "@typescript-eslint/experimental-utils": { 481 | "version": "4.20.0", 482 | "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.20.0.tgz", 483 | "integrity": "sha512-sQNlf6rjLq2yB5lELl3gOE7OuoA/6IVXJUJ+Vs7emrQMva14CkOwyQwD7CW+TkmOJ4Q/YGmoDLmbfFrpGmbKng==", 484 | "dev": true, 485 | "requires": { 486 | "@types/json-schema": "^7.0.3", 487 | "@typescript-eslint/scope-manager": "4.20.0", 488 | "@typescript-eslint/types": "4.20.0", 489 | "@typescript-eslint/typescript-estree": "4.20.0", 490 | "eslint-scope": "^5.0.0", 491 | "eslint-utils": "^2.0.0" 492 | } 493 | }, 494 | "@typescript-eslint/parser": { 495 | "version": "4.20.0", 496 | "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.20.0.tgz", 497 | "integrity": "sha512-m6vDtgL9EABdjMtKVw5rr6DdeMCH3OA1vFb0dAyuZSa3e5yw1YRzlwFnm9knma9Lz6b2GPvoNSa8vOXrqsaglA==", 498 | "dev": true, 499 | "requires": { 500 | "@typescript-eslint/scope-manager": "4.20.0", 501 | "@typescript-eslint/types": "4.20.0", 502 | "@typescript-eslint/typescript-estree": "4.20.0", 503 | "debug": "^4.1.1" 504 | } 505 | }, 506 | "@typescript-eslint/scope-manager": { 507 | "version": "4.20.0", 508 | "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.20.0.tgz", 509 | "integrity": "sha512-/zm6WR6iclD5HhGpcwl/GOYDTzrTHmvf8LLLkwKqqPKG6+KZt/CfSgPCiybshmck66M2L5fWSF/MKNuCwtKQSQ==", 510 | "dev": true, 511 | "requires": { 512 | "@typescript-eslint/types": "4.20.0", 513 | "@typescript-eslint/visitor-keys": "4.20.0" 514 | } 515 | }, 516 | "@typescript-eslint/types": { 517 | "version": "4.20.0", 518 | "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.20.0.tgz", 519 | "integrity": "sha512-cYY+1PIjei1nk49JAPnH1VEnu7OYdWRdJhYI5wiKOUMhLTG1qsx5cQxCUTuwWCmQoyriadz3Ni8HZmGSofeC+w==", 520 | "dev": true 521 | }, 522 | "@typescript-eslint/typescript-estree": { 523 | "version": "4.20.0", 524 | "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.20.0.tgz", 525 | "integrity": "sha512-Knpp0reOd4ZsyoEJdW8i/sK3mtZ47Ls7ZHvD8WVABNx5Xnn7KhenMTRGegoyMTx6TiXlOVgMz9r0pDgXTEEIHA==", 526 | "dev": true, 527 | "requires": { 528 | "@typescript-eslint/types": "4.20.0", 529 | "@typescript-eslint/visitor-keys": "4.20.0", 530 | "debug": "^4.1.1", 531 | "globby": "^11.0.1", 532 | "is-glob": "^4.0.1", 533 | "semver": "^7.3.2", 534 | "tsutils": "^3.17.1" 535 | } 536 | }, 537 | "@typescript-eslint/visitor-keys": { 538 | "version": "4.20.0", 539 | "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.20.0.tgz", 540 | "integrity": "sha512-NXKRM3oOVQL8yNFDNCZuieRIwZ5UtjNLYtmMx2PacEAGmbaEYtGgVHUHVyZvU/0rYZcizdrWjDo+WBtRPSgq+A==", 541 | "dev": true, 542 | "requires": { 543 | "@typescript-eslint/types": "4.20.0", 544 | "eslint-visitor-keys": "^2.0.0" 545 | } 546 | }, 547 | "@zerodevx/svelte-toast": { 548 | "version": "0.2.1", 549 | "resolved": "https://registry.npmjs.org/@zerodevx/svelte-toast/-/svelte-toast-0.2.1.tgz", 550 | "integrity": "sha512-3yOusE+/xDaVNxkBJwbxDZea5ePQ77B15tbHv6ZlSYtlJu0u0PDhGMu8eoI+SmcCt4j+2sf0A1uS9+LcBIqUgg==", 551 | "dev": true 552 | }, 553 | "acorn": { 554 | "version": "7.4.1", 555 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", 556 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", 557 | "dev": true 558 | }, 559 | "acorn-jsx": { 560 | "version": "5.3.1", 561 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", 562 | "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", 563 | "dev": true 564 | }, 565 | "ajv": { 566 | "version": "6.12.6", 567 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 568 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 569 | "dev": true, 570 | "requires": { 571 | "fast-deep-equal": "^3.1.1", 572 | "fast-json-stable-stringify": "^2.0.0", 573 | "json-schema-traverse": "^0.4.1", 574 | "uri-js": "^4.2.2" 575 | } 576 | }, 577 | "ansi-colors": { 578 | "version": "4.1.1", 579 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", 580 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", 581 | "dev": true 582 | }, 583 | "ansi-regex": { 584 | "version": "5.0.0", 585 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 586 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", 587 | "dev": true 588 | }, 589 | "ansi-styles": { 590 | "version": "4.3.0", 591 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 592 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 593 | "dev": true, 594 | "requires": { 595 | "color-convert": "^2.0.1" 596 | } 597 | }, 598 | "anymatch": { 599 | "version": "3.1.2", 600 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", 601 | "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", 602 | "dev": true, 603 | "requires": { 604 | "normalize-path": "^3.0.0", 605 | "picomatch": "^2.0.4" 606 | } 607 | }, 608 | "argparse": { 609 | "version": "1.0.10", 610 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 611 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 612 | "dev": true, 613 | "requires": { 614 | "sprintf-js": "~1.0.2" 615 | } 616 | }, 617 | "array-union": { 618 | "version": "2.1.0", 619 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", 620 | "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", 621 | "dev": true 622 | }, 623 | "astral-regex": { 624 | "version": "2.0.0", 625 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", 626 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", 627 | "dev": true 628 | }, 629 | "balanced-match": { 630 | "version": "1.0.0", 631 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 632 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 633 | "dev": true 634 | }, 635 | "binary-extensions": { 636 | "version": "2.2.0", 637 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 638 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 639 | "dev": true 640 | }, 641 | "brace-expansion": { 642 | "version": "1.1.11", 643 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 644 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 645 | "dev": true, 646 | "requires": { 647 | "balanced-match": "^1.0.0", 648 | "concat-map": "0.0.1" 649 | } 650 | }, 651 | "braces": { 652 | "version": "3.0.2", 653 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 654 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 655 | "dev": true, 656 | "requires": { 657 | "fill-range": "^7.0.1" 658 | } 659 | }, 660 | "call-bind": { 661 | "version": "1.0.2", 662 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 663 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 664 | "dev": true, 665 | "requires": { 666 | "function-bind": "^1.1.1", 667 | "get-intrinsic": "^1.0.2" 668 | } 669 | }, 670 | "callsites": { 671 | "version": "3.1.0", 672 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 673 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 674 | "dev": true 675 | }, 676 | "chalk": { 677 | "version": "4.1.0", 678 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 679 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 680 | "dev": true, 681 | "requires": { 682 | "ansi-styles": "^4.1.0", 683 | "supports-color": "^7.1.0" 684 | } 685 | }, 686 | "cheap-watch": { 687 | "version": "1.0.3", 688 | "resolved": "https://registry.npmjs.org/cheap-watch/-/cheap-watch-1.0.3.tgz", 689 | "integrity": "sha512-xC5CruMhLzjPwJ5ecUxGu1uGmwJQykUhqd2QrCrYbwvsFYdRyviu6jG9+pccwDXJR/OpmOTOJ9yLFunVgQu9wg==", 690 | "dev": true 691 | }, 692 | "chokidar": { 693 | "version": "3.5.1", 694 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", 695 | "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", 696 | "dev": true, 697 | "requires": { 698 | "anymatch": "~3.1.1", 699 | "braces": "~3.0.2", 700 | "fsevents": "~2.3.1", 701 | "glob-parent": "~5.1.0", 702 | "is-binary-path": "~2.1.0", 703 | "is-glob": "~4.0.1", 704 | "normalize-path": "~3.0.0", 705 | "readdirp": "~3.5.0" 706 | } 707 | }, 708 | "color-convert": { 709 | "version": "2.0.1", 710 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 711 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 712 | "dev": true, 713 | "requires": { 714 | "color-name": "~1.1.4" 715 | } 716 | }, 717 | "color-name": { 718 | "version": "1.1.4", 719 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 720 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 721 | "dev": true 722 | }, 723 | "colorette": { 724 | "version": "1.2.2", 725 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", 726 | "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", 727 | "dev": true 728 | }, 729 | "concat-map": { 730 | "version": "0.0.1", 731 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 732 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 733 | "dev": true 734 | }, 735 | "crelt": { 736 | "version": "1.0.5", 737 | "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", 738 | "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==", 739 | "dev": true 740 | }, 741 | "cross-spawn": { 742 | "version": "7.0.3", 743 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 744 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 745 | "dev": true, 746 | "requires": { 747 | "path-key": "^3.1.0", 748 | "shebang-command": "^2.0.0", 749 | "which": "^2.0.1" 750 | } 751 | }, 752 | "debug": { 753 | "version": "4.3.2", 754 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", 755 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", 756 | "dev": true, 757 | "requires": { 758 | "ms": "2.1.2" 759 | } 760 | }, 761 | "deep-is": { 762 | "version": "0.1.3", 763 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 764 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 765 | "dev": true 766 | }, 767 | "detect-indent": { 768 | "version": "6.0.0", 769 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", 770 | "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", 771 | "dev": true 772 | }, 773 | "dir-glob": { 774 | "version": "3.0.1", 775 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 776 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 777 | "dev": true, 778 | "requires": { 779 | "path-type": "^4.0.0" 780 | } 781 | }, 782 | "doctrine": { 783 | "version": "3.0.0", 784 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 785 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 786 | "dev": true, 787 | "requires": { 788 | "esutils": "^2.0.2" 789 | } 790 | }, 791 | "emoji-regex": { 792 | "version": "8.0.0", 793 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 794 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 795 | "dev": true 796 | }, 797 | "enquirer": { 798 | "version": "2.3.6", 799 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", 800 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", 801 | "dev": true, 802 | "requires": { 803 | "ansi-colors": "^4.1.1" 804 | } 805 | }, 806 | "esbuild": { 807 | "version": "0.9.7", 808 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.9.7.tgz", 809 | "integrity": "sha512-VtUf6aQ89VTmMLKrWHYG50uByMF4JQlVysb8dmg6cOgW8JnFCipmz7p+HNBl+RR3LLCuBxFGVauAe2wfnF9bLg==", 810 | "dev": true 811 | }, 812 | "escape-string-regexp": { 813 | "version": "1.0.5", 814 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 815 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 816 | "dev": true 817 | }, 818 | "eslint": { 819 | "version": "7.23.0", 820 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz", 821 | "integrity": "sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==", 822 | "dev": true, 823 | "requires": { 824 | "@babel/code-frame": "7.12.11", 825 | "@eslint/eslintrc": "^0.4.0", 826 | "ajv": "^6.10.0", 827 | "chalk": "^4.0.0", 828 | "cross-spawn": "^7.0.2", 829 | "debug": "^4.0.1", 830 | "doctrine": "^3.0.0", 831 | "enquirer": "^2.3.5", 832 | "eslint-scope": "^5.1.1", 833 | "eslint-utils": "^2.1.0", 834 | "eslint-visitor-keys": "^2.0.0", 835 | "espree": "^7.3.1", 836 | "esquery": "^1.4.0", 837 | "esutils": "^2.0.2", 838 | "file-entry-cache": "^6.0.1", 839 | "functional-red-black-tree": "^1.0.1", 840 | "glob-parent": "^5.0.0", 841 | "globals": "^13.6.0", 842 | "ignore": "^4.0.6", 843 | "import-fresh": "^3.0.0", 844 | "imurmurhash": "^0.1.4", 845 | "is-glob": "^4.0.0", 846 | "js-yaml": "^3.13.1", 847 | "json-stable-stringify-without-jsonify": "^1.0.1", 848 | "levn": "^0.4.1", 849 | "lodash": "^4.17.21", 850 | "minimatch": "^3.0.4", 851 | "natural-compare": "^1.4.0", 852 | "optionator": "^0.9.1", 853 | "progress": "^2.0.0", 854 | "regexpp": "^3.1.0", 855 | "semver": "^7.2.1", 856 | "strip-ansi": "^6.0.0", 857 | "strip-json-comments": "^3.1.0", 858 | "table": "^6.0.4", 859 | "text-table": "^0.2.0", 860 | "v8-compile-cache": "^2.0.3" 861 | }, 862 | "dependencies": { 863 | "ignore": { 864 | "version": "4.0.6", 865 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 866 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 867 | "dev": true 868 | } 869 | } 870 | }, 871 | "eslint-config-prettier": { 872 | "version": "8.1.0", 873 | "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz", 874 | "integrity": "sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw==", 875 | "dev": true 876 | }, 877 | "eslint-plugin-svelte3": { 878 | "version": "3.1.2", 879 | "resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.1.2.tgz", 880 | "integrity": "sha512-+aGgYFC/yjhGXmBevzwICFVif8tu++C9/lRg8cE6TTS45Hw8qZ6t5wItSXVNPqnxJ212ik+bad1F0Y9A3Swo0Q==", 881 | "dev": true 882 | }, 883 | "eslint-scope": { 884 | "version": "5.1.1", 885 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 886 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 887 | "dev": true, 888 | "requires": { 889 | "esrecurse": "^4.3.0", 890 | "estraverse": "^4.1.1" 891 | } 892 | }, 893 | "eslint-utils": { 894 | "version": "2.1.0", 895 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", 896 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", 897 | "dev": true, 898 | "requires": { 899 | "eslint-visitor-keys": "^1.1.0" 900 | }, 901 | "dependencies": { 902 | "eslint-visitor-keys": { 903 | "version": "1.3.0", 904 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 905 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 906 | "dev": true 907 | } 908 | } 909 | }, 910 | "eslint-visitor-keys": { 911 | "version": "2.0.0", 912 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", 913 | "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", 914 | "dev": true 915 | }, 916 | "espree": { 917 | "version": "7.3.1", 918 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", 919 | "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", 920 | "dev": true, 921 | "requires": { 922 | "acorn": "^7.4.0", 923 | "acorn-jsx": "^5.3.1", 924 | "eslint-visitor-keys": "^1.3.0" 925 | }, 926 | "dependencies": { 927 | "eslint-visitor-keys": { 928 | "version": "1.3.0", 929 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", 930 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", 931 | "dev": true 932 | } 933 | } 934 | }, 935 | "esprima": { 936 | "version": "4.0.1", 937 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 938 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 939 | "dev": true 940 | }, 941 | "esquery": { 942 | "version": "1.4.0", 943 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", 944 | "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", 945 | "dev": true, 946 | "requires": { 947 | "estraverse": "^5.1.0" 948 | }, 949 | "dependencies": { 950 | "estraverse": { 951 | "version": "5.2.0", 952 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 953 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 954 | "dev": true 955 | } 956 | } 957 | }, 958 | "esrecurse": { 959 | "version": "4.3.0", 960 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 961 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 962 | "dev": true, 963 | "requires": { 964 | "estraverse": "^5.2.0" 965 | }, 966 | "dependencies": { 967 | "estraverse": { 968 | "version": "5.2.0", 969 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 970 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", 971 | "dev": true 972 | } 973 | } 974 | }, 975 | "estraverse": { 976 | "version": "4.3.0", 977 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 978 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 979 | "dev": true 980 | }, 981 | "estree-walker": { 982 | "version": "2.0.2", 983 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 984 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 985 | "dev": true 986 | }, 987 | "esutils": { 988 | "version": "2.0.3", 989 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 990 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 991 | "dev": true 992 | }, 993 | "fast-deep-equal": { 994 | "version": "3.1.3", 995 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 996 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 997 | "dev": true 998 | }, 999 | "fast-glob": { 1000 | "version": "3.2.5", 1001 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", 1002 | "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", 1003 | "dev": true, 1004 | "requires": { 1005 | "@nodelib/fs.stat": "^2.0.2", 1006 | "@nodelib/fs.walk": "^1.2.3", 1007 | "glob-parent": "^5.1.0", 1008 | "merge2": "^1.3.0", 1009 | "micromatch": "^4.0.2", 1010 | "picomatch": "^2.2.1" 1011 | } 1012 | }, 1013 | "fast-json-stable-stringify": { 1014 | "version": "2.1.0", 1015 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1016 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1017 | "dev": true 1018 | }, 1019 | "fast-levenshtein": { 1020 | "version": "2.0.6", 1021 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1022 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 1023 | "dev": true 1024 | }, 1025 | "fastq": { 1026 | "version": "1.11.0", 1027 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", 1028 | "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", 1029 | "dev": true, 1030 | "requires": { 1031 | "reusify": "^1.0.4" 1032 | } 1033 | }, 1034 | "file-entry-cache": { 1035 | "version": "6.0.1", 1036 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 1037 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 1038 | "dev": true, 1039 | "requires": { 1040 | "flat-cache": "^3.0.4" 1041 | } 1042 | }, 1043 | "fill-range": { 1044 | "version": "7.0.1", 1045 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1046 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1047 | "dev": true, 1048 | "requires": { 1049 | "to-regex-range": "^5.0.1" 1050 | } 1051 | }, 1052 | "flat-cache": { 1053 | "version": "3.0.4", 1054 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 1055 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 1056 | "dev": true, 1057 | "requires": { 1058 | "flatted": "^3.1.0", 1059 | "rimraf": "^3.0.2" 1060 | } 1061 | }, 1062 | "flatted": { 1063 | "version": "3.1.1", 1064 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", 1065 | "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", 1066 | "dev": true 1067 | }, 1068 | "fs.realpath": { 1069 | "version": "1.0.0", 1070 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1071 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 1072 | "dev": true 1073 | }, 1074 | "fsevents": { 1075 | "version": "2.3.2", 1076 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1077 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1078 | "dev": true, 1079 | "optional": true 1080 | }, 1081 | "function-bind": { 1082 | "version": "1.1.1", 1083 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1084 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1085 | "dev": true 1086 | }, 1087 | "functional-red-black-tree": { 1088 | "version": "1.0.1", 1089 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 1090 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 1091 | "dev": true 1092 | }, 1093 | "get-intrinsic": { 1094 | "version": "1.1.1", 1095 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", 1096 | "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", 1097 | "dev": true, 1098 | "requires": { 1099 | "function-bind": "^1.1.1", 1100 | "has": "^1.0.3", 1101 | "has-symbols": "^1.0.1" 1102 | } 1103 | }, 1104 | "glob": { 1105 | "version": "7.1.6", 1106 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 1107 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 1108 | "dev": true, 1109 | "requires": { 1110 | "fs.realpath": "^1.0.0", 1111 | "inflight": "^1.0.4", 1112 | "inherits": "2", 1113 | "minimatch": "^3.0.4", 1114 | "once": "^1.3.0", 1115 | "path-is-absolute": "^1.0.0" 1116 | } 1117 | }, 1118 | "glob-parent": { 1119 | "version": "5.1.2", 1120 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1121 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1122 | "dev": true, 1123 | "requires": { 1124 | "is-glob": "^4.0.1" 1125 | } 1126 | }, 1127 | "globals": { 1128 | "version": "13.7.0", 1129 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.7.0.tgz", 1130 | "integrity": "sha512-Aipsz6ZKRxa/xQkZhNg0qIWXT6x6rD46f6x/PCnBomlttdIyAPak4YD9jTmKpZ72uROSMU87qJtcgpgHaVchiA==", 1131 | "dev": true, 1132 | "requires": { 1133 | "type-fest": "^0.20.2" 1134 | }, 1135 | "dependencies": { 1136 | "type-fest": { 1137 | "version": "0.20.2", 1138 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 1139 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 1140 | "dev": true 1141 | } 1142 | } 1143 | }, 1144 | "globby": { 1145 | "version": "11.0.3", 1146 | "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", 1147 | "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", 1148 | "dev": true, 1149 | "requires": { 1150 | "array-union": "^2.1.0", 1151 | "dir-glob": "^3.0.1", 1152 | "fast-glob": "^3.1.1", 1153 | "ignore": "^5.1.4", 1154 | "merge2": "^1.3.0", 1155 | "slash": "^3.0.0" 1156 | } 1157 | }, 1158 | "has": { 1159 | "version": "1.0.3", 1160 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1161 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1162 | "dev": true, 1163 | "requires": { 1164 | "function-bind": "^1.1.1" 1165 | } 1166 | }, 1167 | "has-flag": { 1168 | "version": "4.0.0", 1169 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1170 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1171 | "dev": true 1172 | }, 1173 | "has-symbols": { 1174 | "version": "1.0.2", 1175 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", 1176 | "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", 1177 | "dev": true 1178 | }, 1179 | "hash-sum": { 1180 | "version": "2.0.0", 1181 | "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", 1182 | "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", 1183 | "dev": true 1184 | }, 1185 | "ignore": { 1186 | "version": "5.1.8", 1187 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", 1188 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", 1189 | "dev": true 1190 | }, 1191 | "import-fresh": { 1192 | "version": "3.3.0", 1193 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1194 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1195 | "dev": true, 1196 | "requires": { 1197 | "parent-module": "^1.0.0", 1198 | "resolve-from": "^4.0.0" 1199 | } 1200 | }, 1201 | "imurmurhash": { 1202 | "version": "0.1.4", 1203 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1204 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 1205 | "dev": true 1206 | }, 1207 | "inflight": { 1208 | "version": "1.0.6", 1209 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1210 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1211 | "dev": true, 1212 | "requires": { 1213 | "once": "^1.3.0", 1214 | "wrappy": "1" 1215 | } 1216 | }, 1217 | "inherits": { 1218 | "version": "2.0.4", 1219 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1220 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1221 | "dev": true 1222 | }, 1223 | "is-binary-path": { 1224 | "version": "2.1.0", 1225 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1226 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1227 | "dev": true, 1228 | "requires": { 1229 | "binary-extensions": "^2.0.0" 1230 | } 1231 | }, 1232 | "is-boolean-object": { 1233 | "version": "1.1.0", 1234 | "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", 1235 | "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", 1236 | "dev": true, 1237 | "requires": { 1238 | "call-bind": "^1.0.0" 1239 | } 1240 | }, 1241 | "is-core-module": { 1242 | "version": "2.2.0", 1243 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", 1244 | "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", 1245 | "dev": true, 1246 | "requires": { 1247 | "has": "^1.0.3" 1248 | } 1249 | }, 1250 | "is-extglob": { 1251 | "version": "2.1.1", 1252 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1253 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1254 | "dev": true 1255 | }, 1256 | "is-fullwidth-code-point": { 1257 | "version": "3.0.0", 1258 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1259 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1260 | "dev": true 1261 | }, 1262 | "is-glob": { 1263 | "version": "4.0.1", 1264 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1265 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1266 | "dev": true, 1267 | "requires": { 1268 | "is-extglob": "^2.1.1" 1269 | } 1270 | }, 1271 | "is-number": { 1272 | "version": "7.0.0", 1273 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1274 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1275 | "dev": true 1276 | }, 1277 | "is-number-object": { 1278 | "version": "1.0.4", 1279 | "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", 1280 | "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", 1281 | "dev": true 1282 | }, 1283 | "is-string": { 1284 | "version": "1.0.5", 1285 | "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", 1286 | "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", 1287 | "dev": true 1288 | }, 1289 | "isexe": { 1290 | "version": "2.0.0", 1291 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1292 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1293 | "dev": true 1294 | }, 1295 | "js-tokens": { 1296 | "version": "4.0.0", 1297 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1298 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1299 | "dev": true 1300 | }, 1301 | "js-yaml": { 1302 | "version": "3.14.1", 1303 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 1304 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 1305 | "dev": true, 1306 | "requires": { 1307 | "argparse": "^1.0.7", 1308 | "esprima": "^4.0.0" 1309 | } 1310 | }, 1311 | "json-schema-traverse": { 1312 | "version": "0.4.1", 1313 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1314 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1315 | "dev": true 1316 | }, 1317 | "json-stable-stringify-without-jsonify": { 1318 | "version": "1.0.1", 1319 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1320 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 1321 | "dev": true 1322 | }, 1323 | "levn": { 1324 | "version": "0.4.1", 1325 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1326 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1327 | "dev": true, 1328 | "requires": { 1329 | "prelude-ls": "^1.2.1", 1330 | "type-check": "~0.4.0" 1331 | } 1332 | }, 1333 | "lezer": { 1334 | "version": "0.13.4", 1335 | "resolved": "https://registry.npmjs.org/lezer/-/lezer-0.13.4.tgz", 1336 | "integrity": "sha512-cLQxUVY28VBBqKBt/R8CYeH57KQnIvscAnoahzvhlZTK8qxMkIyGExR6ecEpYYDX06ZhROZrEm1IiPvjLAsTig==", 1337 | "dev": true, 1338 | "requires": { 1339 | "lezer-tree": "^0.13.2" 1340 | } 1341 | }, 1342 | "lezer-generator": { 1343 | "version": "0.13.3", 1344 | "resolved": "https://registry.npmjs.org/lezer-generator/-/lezer-generator-0.13.3.tgz", 1345 | "integrity": "sha512-dT+7HEAoIgU6cuRoThLVSRwjnMQ/mQSTvUjiG9rajLXI4SaqWQfzheUQZU6543htK7xFjXzOocs9+13W3TvctA==", 1346 | "dev": true, 1347 | "requires": { 1348 | "lezer": "^0.13.2" 1349 | } 1350 | }, 1351 | "lezer-tree": { 1352 | "version": "0.13.2", 1353 | "resolved": "https://registry.npmjs.org/lezer-tree/-/lezer-tree-0.13.2.tgz", 1354 | "integrity": "sha512-15ZxW8TxVNAOkHIo43Iouv4zbSkQQ5chQHBpwXcD2bBFz46RB4jYLEEww5l1V0xyIx9U2clSyyrLes+hAUFrGQ==", 1355 | "dev": true 1356 | }, 1357 | "lodash": { 1358 | "version": "4.17.21", 1359 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1360 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1361 | "dev": true 1362 | }, 1363 | "lodash.clonedeep": { 1364 | "version": "4.5.0", 1365 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 1366 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", 1367 | "dev": true 1368 | }, 1369 | "lodash.flatten": { 1370 | "version": "4.4.0", 1371 | "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", 1372 | "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", 1373 | "dev": true 1374 | }, 1375 | "lodash.truncate": { 1376 | "version": "4.4.2", 1377 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", 1378 | "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", 1379 | "dev": true 1380 | }, 1381 | "lru-cache": { 1382 | "version": "6.0.0", 1383 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1384 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1385 | "dev": true, 1386 | "requires": { 1387 | "yallist": "^4.0.0" 1388 | } 1389 | }, 1390 | "lz-string": { 1391 | "version": "1.4.4", 1392 | "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", 1393 | "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", 1394 | "dev": true 1395 | }, 1396 | "merge2": { 1397 | "version": "1.4.1", 1398 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1399 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1400 | "dev": true 1401 | }, 1402 | "micromatch": { 1403 | "version": "4.0.2", 1404 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", 1405 | "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", 1406 | "dev": true, 1407 | "requires": { 1408 | "braces": "^3.0.1", 1409 | "picomatch": "^2.0.5" 1410 | } 1411 | }, 1412 | "min-indent": { 1413 | "version": "1.0.1", 1414 | "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", 1415 | "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", 1416 | "dev": true 1417 | }, 1418 | "minimatch": { 1419 | "version": "3.0.4", 1420 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1421 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1422 | "dev": true, 1423 | "requires": { 1424 | "brace-expansion": "^1.1.7" 1425 | } 1426 | }, 1427 | "mri": { 1428 | "version": "1.1.6", 1429 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", 1430 | "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", 1431 | "dev": true 1432 | }, 1433 | "ms": { 1434 | "version": "2.1.2", 1435 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1436 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1437 | "dev": true 1438 | }, 1439 | "nanoid": { 1440 | "version": "3.1.22", 1441 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", 1442 | "integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==", 1443 | "dev": true 1444 | }, 1445 | "natural-compare": { 1446 | "version": "1.4.0", 1447 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1448 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1449 | "dev": true 1450 | }, 1451 | "normalize-path": { 1452 | "version": "3.0.0", 1453 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1454 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1455 | "dev": true 1456 | }, 1457 | "once": { 1458 | "version": "1.4.0", 1459 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1460 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1461 | "dev": true, 1462 | "requires": { 1463 | "wrappy": "1" 1464 | } 1465 | }, 1466 | "optionator": { 1467 | "version": "0.9.1", 1468 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 1469 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", 1470 | "dev": true, 1471 | "requires": { 1472 | "deep-is": "^0.1.3", 1473 | "fast-levenshtein": "^2.0.6", 1474 | "levn": "^0.4.1", 1475 | "prelude-ls": "^1.2.1", 1476 | "type-check": "^0.4.0", 1477 | "word-wrap": "^1.2.3" 1478 | } 1479 | }, 1480 | "parent-module": { 1481 | "version": "1.0.1", 1482 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1483 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1484 | "dev": true, 1485 | "requires": { 1486 | "callsites": "^3.0.0" 1487 | } 1488 | }, 1489 | "path-is-absolute": { 1490 | "version": "1.0.1", 1491 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1492 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1493 | "dev": true 1494 | }, 1495 | "path-key": { 1496 | "version": "3.1.1", 1497 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1498 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 1499 | "dev": true 1500 | }, 1501 | "path-parse": { 1502 | "version": "1.0.6", 1503 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1504 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1505 | "dev": true 1506 | }, 1507 | "path-type": { 1508 | "version": "4.0.0", 1509 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1510 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1511 | "dev": true 1512 | }, 1513 | "picomatch": { 1514 | "version": "2.2.2", 1515 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", 1516 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", 1517 | "dev": true 1518 | }, 1519 | "postcss": { 1520 | "version": "8.2.9", 1521 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.9.tgz", 1522 | "integrity": "sha512-b+TmuIL4jGtCHtoLi+G/PisuIl9avxs8IZMSmlABRwNz5RLUUACrC+ws81dcomz1nRezm5YPdXiMEzBEKgYn+Q==", 1523 | "dev": true, 1524 | "requires": { 1525 | "colorette": "^1.2.2", 1526 | "nanoid": "^3.1.22", 1527 | "source-map": "^0.6.1" 1528 | }, 1529 | "dependencies": { 1530 | "source-map": { 1531 | "version": "0.6.1", 1532 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1533 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1534 | "dev": true 1535 | } 1536 | } 1537 | }, 1538 | "prelude-ls": { 1539 | "version": "1.2.1", 1540 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 1541 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 1542 | "dev": true 1543 | }, 1544 | "prettier": { 1545 | "version": "2.2.1", 1546 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", 1547 | "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", 1548 | "dev": true 1549 | }, 1550 | "prettier-plugin-svelte": { 1551 | "version": "2.2.0", 1552 | "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.2.0.tgz", 1553 | "integrity": "sha512-Xdmqgr71tAuMqqzNCK52/v94g/Yv7V7lz+nmbO9NEA+9ol15VV3uUHOfydMNOo3SWvFaVlBcp947ebEaMWqVfQ==", 1554 | "dev": true 1555 | }, 1556 | "progress": { 1557 | "version": "2.0.3", 1558 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1559 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1560 | "dev": true 1561 | }, 1562 | "punycode": { 1563 | "version": "2.1.1", 1564 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1565 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1566 | "dev": true 1567 | }, 1568 | "queue-microtask": { 1569 | "version": "1.2.3", 1570 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1571 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1572 | "dev": true 1573 | }, 1574 | "readdirp": { 1575 | "version": "3.5.0", 1576 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", 1577 | "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", 1578 | "dev": true, 1579 | "requires": { 1580 | "picomatch": "^2.2.1" 1581 | } 1582 | }, 1583 | "regexpp": { 1584 | "version": "3.1.0", 1585 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", 1586 | "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", 1587 | "dev": true 1588 | }, 1589 | "require-from-string": { 1590 | "version": "2.0.2", 1591 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 1592 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 1593 | "dev": true 1594 | }, 1595 | "require-relative": { 1596 | "version": "0.8.7", 1597 | "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", 1598 | "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", 1599 | "dev": true 1600 | }, 1601 | "resolve": { 1602 | "version": "1.20.0", 1603 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 1604 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 1605 | "dev": true, 1606 | "requires": { 1607 | "is-core-module": "^2.2.0", 1608 | "path-parse": "^1.0.6" 1609 | } 1610 | }, 1611 | "resolve-from": { 1612 | "version": "4.0.0", 1613 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1614 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1615 | "dev": true 1616 | }, 1617 | "reusify": { 1618 | "version": "1.0.4", 1619 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1620 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1621 | "dev": true 1622 | }, 1623 | "rimraf": { 1624 | "version": "3.0.2", 1625 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1626 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1627 | "dev": true, 1628 | "requires": { 1629 | "glob": "^7.1.3" 1630 | } 1631 | }, 1632 | "rollup": { 1633 | "version": "2.44.0", 1634 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.44.0.tgz", 1635 | "integrity": "sha512-rGSF4pLwvuaH/x4nAS+zP6UNn5YUDWf/TeEU5IoXSZKBbKRNTCI3qMnYXKZgrC0D2KzS2baiOZt1OlqhMu5rnQ==", 1636 | "dev": true, 1637 | "requires": { 1638 | "fsevents": "~2.3.1" 1639 | } 1640 | }, 1641 | "run-parallel": { 1642 | "version": "1.2.0", 1643 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1644 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1645 | "dev": true, 1646 | "requires": { 1647 | "queue-microtask": "^1.2.2" 1648 | } 1649 | }, 1650 | "sade": { 1651 | "version": "1.7.4", 1652 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", 1653 | "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", 1654 | "dev": true, 1655 | "requires": { 1656 | "mri": "^1.1.0" 1657 | } 1658 | }, 1659 | "semver": { 1660 | "version": "7.3.5", 1661 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", 1662 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", 1663 | "dev": true, 1664 | "requires": { 1665 | "lru-cache": "^6.0.0" 1666 | } 1667 | }, 1668 | "shebang-command": { 1669 | "version": "2.0.0", 1670 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1671 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1672 | "dev": true, 1673 | "requires": { 1674 | "shebang-regex": "^3.0.0" 1675 | } 1676 | }, 1677 | "shebang-regex": { 1678 | "version": "3.0.0", 1679 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1680 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 1681 | "dev": true 1682 | }, 1683 | "slash": { 1684 | "version": "3.0.0", 1685 | "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 1686 | "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", 1687 | "dev": true 1688 | }, 1689 | "slice-ansi": { 1690 | "version": "4.0.0", 1691 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", 1692 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", 1693 | "dev": true, 1694 | "requires": { 1695 | "ansi-styles": "^4.0.0", 1696 | "astral-regex": "^2.0.0", 1697 | "is-fullwidth-code-point": "^3.0.0" 1698 | } 1699 | }, 1700 | "source-map": { 1701 | "version": "0.7.3", 1702 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 1703 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", 1704 | "dev": true 1705 | }, 1706 | "sprintf-js": { 1707 | "version": "1.0.3", 1708 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1709 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1710 | "dev": true 1711 | }, 1712 | "string-width": { 1713 | "version": "4.2.2", 1714 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", 1715 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", 1716 | "dev": true, 1717 | "requires": { 1718 | "emoji-regex": "^8.0.0", 1719 | "is-fullwidth-code-point": "^3.0.0", 1720 | "strip-ansi": "^6.0.0" 1721 | } 1722 | }, 1723 | "strip-ansi": { 1724 | "version": "6.0.0", 1725 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 1726 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 1727 | "dev": true, 1728 | "requires": { 1729 | "ansi-regex": "^5.0.0" 1730 | } 1731 | }, 1732 | "strip-indent": { 1733 | "version": "3.0.0", 1734 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", 1735 | "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", 1736 | "dev": true, 1737 | "requires": { 1738 | "min-indent": "^1.0.0" 1739 | } 1740 | }, 1741 | "strip-json-comments": { 1742 | "version": "3.1.1", 1743 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1744 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 1745 | "dev": true 1746 | }, 1747 | "style-mod": { 1748 | "version": "4.0.0", 1749 | "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", 1750 | "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", 1751 | "dev": true 1752 | }, 1753 | "supports-color": { 1754 | "version": "7.2.0", 1755 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1756 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1757 | "dev": true, 1758 | "requires": { 1759 | "has-flag": "^4.0.0" 1760 | } 1761 | }, 1762 | "svelte": { 1763 | "version": "3.37.0", 1764 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.37.0.tgz", 1765 | "integrity": "sha512-TRF30F4W4+d+Jr2KzUUL1j8Mrpns/WM/WacxYlo5MMb2E5Qy2Pk1Guj6GylxsW9OnKQl1tnF8q3hG/hQ3h6VUA==", 1766 | "dev": true 1767 | }, 1768 | "svelte-hmr": { 1769 | "version": "0.13.3", 1770 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.13.3.tgz", 1771 | "integrity": "sha512-gagW62pLQ2lULmvNA3pIZu9pBCYOaGu3rQikUOv6Nokz5VxUgT9/mQLfMxj9phDEKHCg/lgr3i6PkqZDbO9P2Q==", 1772 | "dev": true 1773 | }, 1774 | "svelte-preprocess": { 1775 | "version": "4.7.0", 1776 | "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.7.0.tgz", 1777 | "integrity": "sha512-iNrY4YGqi0LD2e6oT9YbdSzOKntxk8gmzfqso1z/lUJOZh4o6fyIqkirmiZ8/dDJFqtIE1spVgDFWgkfhLEYlw==", 1778 | "dev": true, 1779 | "requires": { 1780 | "@types/pug": "^2.0.4", 1781 | "@types/sass": "^1.16.0", 1782 | "detect-indent": "^6.0.0", 1783 | "strip-indent": "^3.0.0" 1784 | } 1785 | }, 1786 | "table": { 1787 | "version": "6.0.9", 1788 | "resolved": "https://registry.npmjs.org/table/-/table-6.0.9.tgz", 1789 | "integrity": "sha512-F3cLs9a3hL1Z7N4+EkSscsel3z55XT950AvB05bwayrNg5T1/gykXtigioTAjbltvbMSJvvhFCbnf6mX+ntnJQ==", 1790 | "dev": true, 1791 | "requires": { 1792 | "ajv": "^8.0.1", 1793 | "is-boolean-object": "^1.1.0", 1794 | "is-number-object": "^1.0.4", 1795 | "is-string": "^1.0.5", 1796 | "lodash.clonedeep": "^4.5.0", 1797 | "lodash.flatten": "^4.4.0", 1798 | "lodash.truncate": "^4.4.2", 1799 | "slice-ansi": "^4.0.0", 1800 | "string-width": "^4.2.0" 1801 | }, 1802 | "dependencies": { 1803 | "ajv": { 1804 | "version": "8.0.5", 1805 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.0.5.tgz", 1806 | "integrity": "sha512-RkiLa/AeJx7+9OvniQ/qeWu0w74A8DiPPBclQ6ji3ZQkv5KamO+QGpqmi7O4JIw3rHGUXZ6CoP9tsAkn3gyazg==", 1807 | "dev": true, 1808 | "requires": { 1809 | "fast-deep-equal": "^3.1.1", 1810 | "json-schema-traverse": "^1.0.0", 1811 | "require-from-string": "^2.0.2", 1812 | "uri-js": "^4.2.2" 1813 | } 1814 | }, 1815 | "json-schema-traverse": { 1816 | "version": "1.0.0", 1817 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 1818 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 1819 | "dev": true 1820 | } 1821 | } 1822 | }, 1823 | "text-table": { 1824 | "version": "0.2.0", 1825 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1826 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1827 | "dev": true 1828 | }, 1829 | "to-regex-range": { 1830 | "version": "5.0.1", 1831 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1832 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1833 | "dev": true, 1834 | "requires": { 1835 | "is-number": "^7.0.0" 1836 | } 1837 | }, 1838 | "tslib": { 1839 | "version": "2.1.0", 1840 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", 1841 | "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", 1842 | "dev": true 1843 | }, 1844 | "tsutils": { 1845 | "version": "3.21.0", 1846 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", 1847 | "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", 1848 | "dev": true, 1849 | "requires": { 1850 | "tslib": "^1.8.1" 1851 | }, 1852 | "dependencies": { 1853 | "tslib": { 1854 | "version": "1.14.1", 1855 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1856 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", 1857 | "dev": true 1858 | } 1859 | } 1860 | }, 1861 | "type-check": { 1862 | "version": "0.4.0", 1863 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 1864 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 1865 | "dev": true, 1866 | "requires": { 1867 | "prelude-ls": "^1.2.1" 1868 | } 1869 | }, 1870 | "type-fest": { 1871 | "version": "0.8.1", 1872 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", 1873 | "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", 1874 | "dev": true 1875 | }, 1876 | "typescript": { 1877 | "version": "4.2.3", 1878 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", 1879 | "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", 1880 | "dev": true 1881 | }, 1882 | "uri-js": { 1883 | "version": "4.4.1", 1884 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1885 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1886 | "dev": true, 1887 | "requires": { 1888 | "punycode": "^2.1.0" 1889 | } 1890 | }, 1891 | "v8-compile-cache": { 1892 | "version": "2.3.0", 1893 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", 1894 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", 1895 | "dev": true 1896 | }, 1897 | "vite": { 1898 | "version": "2.1.5", 1899 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.1.5.tgz", 1900 | "integrity": "sha512-tYU5iaYeUgQYvK/CNNz3tiJ8vYqPWfCE9IQ7K0iuzYovWw7lzty7KRYGWwV3CQPh0NKxWjOczAqiJsCL0Xb+Og==", 1901 | "dev": true, 1902 | "requires": { 1903 | "esbuild": "^0.9.3", 1904 | "fsevents": "~2.3.1", 1905 | "postcss": "^8.2.1", 1906 | "resolve": "^1.19.0", 1907 | "rollup": "^2.38.5" 1908 | } 1909 | }, 1910 | "vite-plugin-rsw": { 1911 | "version": "1.3.1", 1912 | "resolved": "https://registry.npmjs.org/vite-plugin-rsw/-/vite-plugin-rsw-1.3.1.tgz", 1913 | "integrity": "sha512-8/kdJFIXGX5ElJwIDKpfbs0H3VtJ29JhflzTbGjzbkVCURNn7+nhfvURdowUvjdt0OYy2sJd5Fl4zhb3kHx3cQ==", 1914 | "dev": true, 1915 | "requires": { 1916 | "chalk": "^4.1.0", 1917 | "chokidar": "^3.5.0", 1918 | "debug": "^4.3.2", 1919 | "which": "^2.0.2" 1920 | } 1921 | }, 1922 | "w3c-keyname": { 1923 | "version": "2.2.4", 1924 | "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", 1925 | "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==", 1926 | "dev": true 1927 | }, 1928 | "which": { 1929 | "version": "2.0.2", 1930 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1931 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1932 | "dev": true, 1933 | "requires": { 1934 | "isexe": "^2.0.0" 1935 | } 1936 | }, 1937 | "word-wrap": { 1938 | "version": "1.2.3", 1939 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", 1940 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 1941 | "dev": true 1942 | }, 1943 | "wrappy": { 1944 | "version": "1.0.2", 1945 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1946 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1947 | "dev": true 1948 | }, 1949 | "yallist": { 1950 | "version": "4.0.0", 1951 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1952 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1953 | "dev": true 1954 | } 1955 | } 1956 | } 1957 | --------------------------------------------------------------------------------